This vulnerability is of type Improper Validation of Array Index. 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/ne/ne.c
) and the bug’s basic explanation are highlighted as follows:
85 RBinSection *bs = R_NEW0 (RBinSection);
// i is not well validated.
86 NE_image_segment_entry *se = &bin->segment_entries[i];
87 if (!bs) {
88 return segments;
89 }
// seed1 can trigger this heap overflow.
90 bs->size = se->length;
91 bs->vsize = se->minAllocSz ? se->minAllocSz : 64000;
92 bs->bits = R_SYS_BITS_16;
93 bs->is_data = se->flags & IS_DATA;
94 bs->perm = __translate_perms (se->flags);
487 char *name;
488 if (rel.index > bin->ne_header->ModRefs) {
489 name = r_str_newf ("UnknownModule%d_%x", rel.index, off); // ????
490 } else {
491 printf("modref addr: %X, bin addr: %X, bin->ne_header addr: %X \n",modref,bin,&(bin->ne_header));
// Seed2 can trigger this heap overflow. The rel.index is not validated and can be zero.
492 offset = modref[rel.index - 1] + bin->header_offset + bin->ne_header->ImportNameTable;
493 name = __read_nonnull_str_at (bin->buf, offset);
494 }
495 if (rel.flags & IMPORTED_ORD) {
496 imp->ordinal = rel.func_ord;
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:
# seed1
=================================================================
==28776==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62f00000deda at pc 0x7ffff2a83101 bp 0x7fffffffd820 sp 0x7fffffffd818
READ of size 2 at 0x62f00000deda thread T0
#0 0x7ffff2a83100 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x619100)
#1 0x7ffff2a84696 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x61a696)
#2 0x7ffff264667f (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x1dc67f)
#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)
0x62f00000deda is located 2 bytes to the right of 56024-byte region [0x62f000000400,0x62f00000ded8)
allocated by thread T0 here:
#0 0x5555555ed772 (/src/cmdline-fuzz/exprs/radare2-5.5.4/radare2+0x99772)
#1 0x7ffff2a895dd (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x61f5dd)
#2 0x7ffff2a8b3fb (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x6213fb)
#3 0x7ffff262a1fe (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x1c01fe)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x619100)
Shadow bytes around the buggy address:
0x0c5e7fff9b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c5e7fff9b90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c5e7fff9ba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c5e7fff9bb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c5e7fff9bc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c5e7fff9bd0: 00 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa
0x0c5e7fff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c5e7fff9bf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c5e7fff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c5e7fff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c5e7fff9c20: 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
==28776==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 0x00005555555f3828 in __asan_report_load2 ()
#7 0x00007ffff2a83101 in r_bin_ne_get_segments (bin=<optimized out>) at /src/cmdline-fuzz/exprs/radare2-5.5.4/src/libr/../libr/bin/p/../format/ne/ne.c:90
#8 0x00007ffff2a84697 in r_bin_ne_get_entrypoints (bin=<optimized out>) at /src/cmdline-fuzz/exprs/radare2-5.5.4/src/libr/../libr/bin/p/../format/ne/ne.c:359
#9 0x00007ffff2646680 in r_bin_object_set_items (bf=<optimized out>, bo=<optimized out>) at bobj.c:306
#10 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
#11 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
#12 0x00007ffff25cd9fc in r_bin_open_buf (bin=<optimized out>, buf=<optimized out>, opt=<optimized out>) at bin.c:279
#13 0x00007ffff25ccad7 in r_bin_open_io (bin=0x616000000680, opt=<optimized out>) at bin.c:339
#14 0x00007ffff384136d in r_core_file_do_load_for_io_plugin (r=0x7fffec2d3800, baseaddr=18446744073709551615, loadaddr=0) at cfile.c:435
#15 r_core_bin_load (r=0x7fffec2d3800, filenameuri=<optimized out>, baddr=<optimized out>) at cfile.c:636
#16 0x00007ffff7548698 in r_main_radare2 (argc=<optimized out>, argv=<optimized out>) at radare2.c:1188
#17 0x00007ffff72bc0b3 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
#18 0x000055555557239e in _start ()
# seed2
=================================================================
==28700==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200006c50e at pc 0x7ffff2a88d19 bp 0x7fffffffd610 sp 0x7fffffffd608
READ of size 2 at 0x60200006c50e thread T0
#0 0x7ffff2a88d18 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x61ed18)
#1 0x7ffff26477f9 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x1dd7f9)
#2 0x7ffff2645004 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x1db004)
#3 0x7ffff262a1fe (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x1c01fe)
#4 0x7ffff25cd9fb (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x1639fb)
#5 0x7ffff25ccad6 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x162ad6)
#6 0x7ffff384136c (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_core.so+0x6b236c)
#7 0x7ffff7548697 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_main.so+0x99697)
#8 0x7ffff72bc0b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
#9 0x55555557239d (/src/cmdline-fuzz/exprs/radare2-5.5.4/radare2+0x1e39d)
0x60200006c50e is located 2 bytes to the left of 1-byte region [0x60200006c510,0x60200006c511)
allocated by thread T0 here:
#0 0x5555555ed5fd (/src/cmdline-fuzz/exprs/radare2-5.5.4/radare2+0x995fd)
#1 0x7ffff2a86194 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x61c194)
#2 0x7ffff26477f9 (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x1dd7f9)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/src/cmdline-fuzz/exprs/radare2-5.5.4/src/install/lib/libr_bin.so+0x61ed18)
Shadow bytes around the buggy address:
0x0c0480005850: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
0x0c0480005860: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
0x0c0480005870: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
0x0c0480005880: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
0x0c0480005890: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
=>0x0c04800058a0: fa[fa]01 fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c04800058b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c04800058c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c04800058d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c04800058e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c04800058f0: 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
==28700==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 0x00005555555f3828 in __asan_report_load2 ()
#7 0x00007ffff2a88d19 in r_bin_ne_get_relocs (bin=<optimized out>) at /src/cmdline-fuzz/exprs/radare2-5.5.4/src/libr/../libr/bin/p/../format/ne/ne.c:490
#8 0x00007ffff26477fa in r_bin_object_set_items (bf=<optimized out>, bo=<optimized out>) at bobj.c:349
#9 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
#10 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
#11 0x00007ffff25cd9fc in r_bin_open_buf (bin=<optimized out>, buf=<optimized out>, opt=<optimized out>) at bin.c:279
#12 0x00007ffff25ccad7 in r_bin_open_io (bin=0x616000000680, opt=<optimized out>) at bin.c:339
#13 0x00007ffff384136d in r_core_file_do_load_for_io_plugin (r=0x7fffec2d3800, baseaddr=18446744073709551615, loadaddr=0) at cfile.c:435
#14 r_core_bin_load (r=0x7fffec2d3800, filenameuri=<optimized out>, baddr=<optimized out>) at cfile.c:636
#15 0x00007ffff7548698 in r_main_radare2 (argc=<optimized out>, argv=<optimized out>) at radare2.c:1188
#16 0x00007ffff72bc0b3 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
#17 0x000055555557239e in _start ()