Heap buffer overflow in libr/bin/format/mach0/mach0.c in radareorg/radare2
Reported on
Apr 4th 2022
This vulnerability is of type heap-buffer-overflow. And after quick investigation I think it is very likely to be successfully exploited to remote code execution. The bug exists in latest stable release (radare2-5.6.6) and lastest master branch (8317a34b7e4ab731e230dcdd81adc9323c5b518b, updated in April 03, 2022). Specifically, the vulnerable code (located at libr/bin/format/mach0/mach0.c
) and the bug's basic explanation are highlighted as follows:
3177 size_t i;
3178 for (i = 0; i < num; i++) {
3179 struct relocation_info a_info = info[I];
3180 ut32 sym_num = a_info.r_symbolnum;
3181 if (sym_num > bin->nsymtab) {
3182 continue;
3183 }
3184
// heap-buffer-overflow here.
3185 ut32 stridx = bin->symtab[sym_num].n_strx;
3186 char *sym_name = get_name (bin, stridx, false);
3187 if (!sym_name) {
3188 continue;
3189 }
Proof of Concept
Build the radare2 (8317a34b7e4ab731e230dcdd81adc9323c5b518b, updated in April 03, 2022) and run it using the input POC.
# build the radare2 with address sanitizer
export CFLAGS=" -fsanitize=address "; export CXXFLAGS=" -fsanitize=address "; export LDFLAGS=" -fsanitize=address ";
CFGARG=" --enable-shared=no " PREFIX=`realpath install` bash sys/build.sh
# disable some features of address sanitizer to avoid false positives
export ASAN_OPTIONS=detect_leaks=0:abort_on_error=1:symbolize=0:allocator_may_return_null=1:detect_odr_violation=0
# trigger the crash
./radare2 -A -q POC_FILE
The crash stack is:
=================================================================
==25752==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6060000151e0 at pc 0x7ffff29fcb2c bp 0x7fffffffcff0 sp 0x7fffffffcfe8
READ of size 4 at 0x6060000151e0 thread T0
#0 0x7ffff29fcb2b (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x592b2b)
#1 0x7ffff29cc2e5 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x5622e5)
#2 0x7ffff26477f9 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x1dd7f9)
#3 0x7ffff2645004 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x1db004)
#4 0x7ffff262a1fe (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x1c01fe)
#5 0x7ffff25cd9fb (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x1639fb)
#6 0x7ffff25ccad6 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x162ad6)
#7 0x7ffff384136c (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_core.so+0x6b236c)
#8 0x7ffff7548697 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_main.so+0x99697)
#9 0x7ffff72bc0b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
#10 0x55555557239d (/src/cmdline-fuzz/exprs/radare2-5.5.4/radare2+0x1e39d)
0x6060000151e0 is located 0 bytes to the right of 64-byte region [0x6060000151a0,0x6060000151e0)
allocated by thread T0 here:
#0 0x5555555ed772 (/src/cmdline-fuzz/exprs/radare2-5.5.4/radare2+0x99772)
#1 0x7ffff2a24ab2 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x5baab2)
#2 0x7ffff29d7a58 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x56da58)
#3 0x7ffff29d9417 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x56f417)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x592b2b)
Shadow bytes around the buggy address:
0x0c0c7fffa9e0: 00 00 00 00 00 00 04 fa fa fa fa fa 00 00 00 00
0x0c0c7fffa9f0: 00 00 00 01 fa fa fa fa 00 00 00 00 00 00 00 01
0x0c0c7fffaa00: fa fa fa fa 00 00 00 00 00 00 00 06 fa fa fa fa
0x0c0c7fffaa10: 00 00 00 00 00 00 00 01 fa fa fa fa 00 00 00 00
0x0c0c7fffaa20: 00 00 00 02 fa fa fa fa 00 00 00 00 00 00 00 02
=>0x0c0c7fffaa30: fa fa fa fa 00 00 00 00 00 00 00 00[fa]fa fa fa
0x0c0c7fffaa40: fd fd fd fd fd fd fd fa fa fa fa fa fd fd fd fd
0x0c0c7fffaa50: fd fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0c7fffaa60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0c7fffaa70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0c7fffaa80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==25752==ABORTING
Program received signal SIGABRT, Aborted.
0x00007ffff72db18b in raise () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) bt
#0 0x00007ffff72db18b in raise () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x00007ffff72ba859 in abort () from /lib/x86_64-linux-gnu/libc.so.6
#2 0x000055555560ba77 in __sanitizer::Abort() ()
#3 0x0000555555609fa1 in __sanitizer::Die() ()
#4 0x00005555555f14e4 in __asan::ScopedInErrorReport::~ScopedInErrorReport() ()
#5 0x00005555555f30aa in __asan::ReportGenericError(unsigned long, unsigned long, unsigned long, unsigned long, bool, unsigned long, unsigned int, bool) ()
#6 0x00005555555f38b8 in __asan_report_load4 ()
#7 0x00007ffff29fcb2c in parse_relocation_info (bin=0x618000004880, relocs=<optimized out>, offset=<optimized out>, num=1054) at /src/cmdline-fuzz/exprs/radare2-5.5.4/src/libr/../libr/bin/p/../format/mach0/mach0.c:3185
#8 get_relocs_64 (bin=0x618000004880) at /src/cmdline-fuzz/exprs/radare2-5.5.4/src/libr/../libr/bin/p/../format/mach0/mach0.c:3734
#9 0x00007ffff29cc2e6 in relocs (bf=0x60d000000ad0) at /src/cmdline-fuzz/exprs/radare2-5.5.4/src/libr/../libr/bin/p/bin_mach0.c:433
#10 0x00007ffff26477fa in r_bin_object_set_items (bf=<optimized out>, bo=<optimized out>) at bobj.c:349
#11 0x00007ffff2645005 in r_bin_object_new (bf=<optimized out>, plugin=<optimized out>, baseaddr=<optimized out>, loadaddr=<optimized out>, offset=<optimized out>, sz=<optimized out>) at bobj.c:168
#12 0x00007ffff262a1ff in r_bin_file_new_from_buffer (bin=0x616000000680, file=<optimized out>, buf=<optimized out>, rawstr=<optimized out>, baseaddr=<optimized out>, loadaddr=<optimized out>, fd=<optimized out>,
pluginname=<optimized out>) at bfile.c:585
#13 0x00007ffff25cd9fc in r_bin_open_buf (bin=<optimized out>, buf=<optimized out>, opt=<optimized out>) at bin.c:279
#14 0x00007ffff25ccad7 in r_bin_open_io (bin=0x616000000680, opt=<optimized out>) at bin.c:339
#15 0x00007ffff384136d in r_core_file_do_load_for_io_plugin (r=0x7fffec2d3800, baseaddr=18446744073709551615, loadaddr=0) at cfile.c:435
#16 r_core_bin_load (r=0x7fffec2d3800, filenameuri=<optimized out>, baddr=<optimized out>) at cfile.c:636
#17 0x00007ffff7548698 in r_main_radare2 (argc=<optimized out>, argv=<optimized out>) at radare2.c:1188
#18 0x00007ffff72bc0b3 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
#19 0x000055555557239e in _start ()
(gdb) frame 7
#7 0x00007ffff29fcb2c in parse_relocation_info (bin=0x618000004880, relocs=<optimized out>, offset=<optimized out>, num=1054) at /src/cmdline-fuzz/exprs/radare2-5.5.4/src/libr/../libr/bin/p/../format/mach0/mach0.c:3185
3185 ut32 stridx = bin->symtab[sym_num].n_strx;
(gdb) p bin->symtab
$2 = (struct nlist_64 *) 0x6060000151a0
(gdb) p bin->symtab[4]
$3 = {n_strx = 3429799609, n_type = 185 '\271', n_sect = 150 '\226', n_desc = 52334, n_value = 105965433213424}
(gdb) p &(bin->symtab[4])
$4 = (struct nlist_64 *) 0x6060000151e0
Impact
If address sanitizer is disabled during the compiling, the program should executes into the r_str_ncpy
function. Therefore I think it is very likely to be exploitable. For more general description of heap buffer overflow, see CWE.