radare2 – Use after free

Słowo wstępu

Projekt radare2, z racji moich zainteresowań oraz wykonywanej pracy jest mi dosyć bliski. Narzędzia wykorzystywane do analizy binarnej plików, są w mojej opinii fenomenalnym wektorem ataku na zaawansowanego użytkownika  – rzadko kiedy ktoś zastanawia się nad tym, czy odpalany plik jest potencjalnie niebezpieczny, nie zdając sobie sprawy co dzieje się “pod spodem”, w momencie jego ładowania. 

Znane podatności w tego typu oprogramowaniu mogą zostać wykorzystane przez malware, celem utrudnienia lub uniemożliwienia analizy za pomocą konkretnego narzędzia. Dla dociekliwych dwa linki o tej tematyce od lcamtufa oraz j00ru (polecam obydwa!).

Pomijając wcześniejsze rozważania, sam rzut oka na obsługiwaną ilość formatów zachęca do poszukiwania błędów w ich implementacji (przypomnę tylko, że projekt utrzymuje również wielki zbiór przypadków testowych idealnych do fuzzingu) 😉

r2 is a rewrite from scratch of radare in order to provide a set of libraries and tools to work with binary files.

Radare project started as a forensics tool, a scriptable commandline hexadecimal editor able to open disk files, but later support for analyzing binaries, disassembling code, debugging programs, attaching to remote gdb servers, ..

radare2 is portable.

  • Architectures: * 6502, 8051, CRIS, H8/300, LH5801, T8200, arc, arm, avr, bf, blackfin, xap, dalvik, dcpu16, gameboy, i386, i4004, i8080, m68k, malbolge, mips, msil, msp430, nios II, powerpc, rar, sh, snes, sparc, tms320 (c54x c55x c55+), V810, x86-64, zimg, risc-v.
  • File Formats:
    • bios, CGC, dex, elf, elf64, filesystem, java, fatmach0, mach0, mach0-64, MZ, PE, PE+, TE, COFF, plan9, dyldcache, Commodore VICE emulator, Game Boy (Advance), Nintendo DS ROMs and Nintendo 3DS FIRMs.
  • Operating Systems:
    • Android, GNU/Linux, [Net|Free|Open]BSD, iOS, OSX, QNX, w32, w64, Solaris, Haiku, FirefoxOS
  • Bindings:
    • Vala/Genie, Python (2, 3), NodeJS, LUA, Go, Perl, Guile, php5, newlisp, Ruby, Java, OCaml, …

Po długim wstępie, krótki opis podatności

Błąd znajdował się w wersji 0.9 (Git HEAD: f49448faf03c2faff8c79a99b28872e8a931efb6).

Niewłaściwa obsługa zarządzania pamięcią w module analizującym skompilowane klasy Java powodowała, na etapie późniejszym, odczyt 4 bajtów zwolnionej pamięci w funkcji ustalającej konwencję wywołania funkcji (powtórzenie zamierzone). Dla ciekawskich, błąd wymagał wprowadzenia zmian w siedmiu plikach oraz dopisania dodatkowych 98 linijek kodu.

W obrazowy sposób pokazuje to z jaką dozą ostrożności trzeba podchodzić do “ręcznego” zarządzania pamięcią w językach programowania C oraz C++. Dociekliwym czytelnikom z poprzedniego zdania polecam również przejrzeć commita naprawiającego 🙂

Log z ASAN:

==35187==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000005ce8 at pc 0x7ff97c5f0585 bp 0x7ffc1c0b2f10 sp 0x7ffc1c0b2f08
READ of size 4 at 0x611000005ce8 thread T0
 #0 0x7ff97c5f0584 in fcn_callconv XYZ/radare2/libr/core/anal.c:2001
 #1 0x7ff97c5f0584 in ?? ??:0
 #2 0x7ff97c5f4b5c in r_core_anal_all XYZ/radare2/libr/core/anal.c:2536
 #3 0x7ff97c5f4b5c in ?? ??:0
 #4 0x7ff97c543480 in cmd_anal_all XYZ/radare2/libr/core/./cmd_anal.c:4503
 #5 0x7ff97c543480 in ?? ??:0
 #6 0x7ff97c50173a in cmd_anal XYZ/radare2/libr/core/./cmd_anal.c:4829
 #7 0x7ff97c50173a in ?? ??:0
 #8 0x7ff97c5e6c6c in r_cmd_call XYZ/radare2/libr/core/cmd_api.c:213
 #9 0x7ff97c5e6c6c in ?? ??:0
 #10 0x7ff97c534810 in r_core_cmd_subst_i XYZ/radare2/libr/core/cmd.c:1960 (discriminator 4)
 #11 0x7ff97c534810 in ?? ??:0
 #12 0x7ff97c4fe4a3 in r_core_cmd_subst XYZ/radare2/libr/core/cmd.c:1311
 #13 0x7ff97c4fe4a3 in ?? ??:0
 #14 0x7ff97c4fb344 in r_core_cmd XYZ/radare2/libr/core/cmd.c:2477
 #15 0x7ff97c4fb344 in ?? ??:0
 #16 0x5587c9eb7566 in main XYZ/radare2/binr/radare2/radare2.c:961
 #17 0x5587c9eb7566 in ?? ??:0
 #18 0x7ff975fcf2b0 in __libc_start_main ??:?
 #19 0x7ff975fcf2b0 in ?? ??:0
 #20 0x5587c9de5889 in _start ??:?
 #21 0x5587c9de5889 in ?? ??:0

0x611000005ce8 is located 40 bytes inside of 208-byte region [0x611000005cc0,0x611000005d90)
freed by thread T0 here:
 #0 0x5587c9e83cd0 in __interceptor_cfree.localalias.0 asan_malloc_linux.cc.o:?
 #1 0x5587c9e83cd0 in ?? ??:0
 #2 0x7ff976ee4384 in r_hashtable64_free XYZ/radare2/libr/util/./ht.c:177
 #3 0x7ff976ee4384 in ?? ??:0
 #4 0x7ff97a6e5b02 in r_anal_state_free XYZ/radare2/libr/anal/state.c:70
 #5 0x7ff97a6e5b02 in ?? ??:0
 #6 0x7ff97a654b24 in analyze_from_code_buffer XYZ/radare2/libr/..//libr/anal/p/anal_java.c:502
 #7 0x7ff97a654b24 in ?? ??:0
 #8 0x7ff97a654369 in analyze_from_code_attr XYZ/radare2/libr/..//libr/anal/p/anal_java.c:533
 #9 0x7ff97a654369 in ?? ??:0
 #10 0x7ff97a652de4 in java_analyze_fns XYZ/radare2/libr/..//libr/anal/p/anal_java.c:664
 #11 0x7ff97a652de4 in ?? ??:0
 #12 0x7ff97c5ebf80 in r_core_anal_fcn XYZ/radare2/libr/core/anal.c:1234
 #13 0x7ff97c5ebf80 in ?? ??:0
 #14 0x7ff97c5f4670 in r_core_anal_all XYZ/radare2/libr/core/anal.c:2496
 #15 0x7ff97c5f4670 in ?? ??:0
 #16 0x7ff97c543480 in cmd_anal_all XYZ/radare2/libr/core/./cmd_anal.c:4503
 #17 0x7ff97c543480 in ?? ??:0
 #18 0x7ff97c50173a in cmd_anal XYZ/radare2/libr/core/./cmd_anal.c:4829
 #19 0x7ff97c50173a in ?? ??:0
 #20 0x7ff97c5e6c6c in r_cmd_call XYZ/radare2/libr/core/cmd_api.c:213
 #21 0x7ff97c5e6c6c in ?? ??:0
 #22 0x7ff97c534810 in r_core_cmd_subst_i XYZ/radare2/libr/core/cmd.c:1960 (discriminator 4)
 #23 0x7ff97c534810 in ?? ??:0
 #24 0x7ff97c4fe4a3 in r_core_cmd_subst XYZ/radare2/libr/core/cmd.c:1311
 #25 0x7ff97c4fe4a3 in ?? ??:0
 #26 0x7ff97c4fb344 in r_core_cmd XYZ/radare2/libr/core/cmd.c:2477
 #27 0x7ff97c4fb344 in ?? ??:0
 #28 0x5587c9eb7566 in main XYZ/radare2/binr/radare2/radare2.c:961
 #29 0x5587c9eb7566 in ?? ??:0
 #30 0x7ff975fcf2b0 in __libc_start_main ??:?
 #31 0x7ff975fcf2b0 in ?? ??:0

previously allocated by thread T0 here:
 #0 0x5587c9e84040 in calloc ??:?
 #1 0x5587c9e84040 in ?? ??:0
 #2 0x7ff97a6c1784 in r_anal_bb_new XYZ/radare2/libr/anal/bb.c:10 (discriminator 1)
 #3 0x7ff97a6c1784 in ?? ??:0
 #4 0x7ff97a6e3e07 in r_anal_ex_get_bb XYZ/radare2/libr/anal/anal_ex.c:174
 #5 0x7ff97a6e3e07 in ?? ??:0
 #6 0x7ff97a6e4996 in r_anal_ex_analysis_driver XYZ/radare2/libr/anal/anal_ex.c:287
 #7 0x7ff97a6e4996 in ?? ??:0
 #8 0x7ff97a654a40 in analyze_from_code_buffer XYZ/radare2/libr/..//libr/anal/p/anal_java.c:491
 #9 0x7ff97a654a40 in ?? ??:0
 #10 0x7ff97a654369 in analyze_from_code_attr XYZ/radare2/libr/..//libr/anal/p/anal_java.c:533
 #11 0x7ff97a654369 in ?? ??:0
 #12 0x7ff97a652de4 in java_analyze_fns XYZ/radare2/libr/..//libr/anal/p/anal_java.c:664
 #13 0x7ff97a652de4 in ?? ??:0
 #14 0x7ff97c5ebf80 in r_core_anal_fcn XYZ/radare2/libr/core/anal.c:1234
 #15 0x7ff97c5ebf80 in ?? ??:0
 #16 0x7ff97c5f4670 in r_core_anal_all XYZ/radare2/libr/core/anal.c:2496
 #17 0x7ff97c5f4670 in ?? ??:0
 #18 0x7ff97c543480 in cmd_anal_all XYZ/radare2/libr/core/./cmd_anal.c:4503
 #19 0x7ff97c543480 in ?? ??:0
 #20 0x7ff97c50173a in cmd_anal XYZ/radare2/libr/core/./cmd_anal.c:4829
 #21 0x7ff97c50173a in ?? ??:0
 #22 0x7ff97c5e6c6c in r_cmd_call XYZ/radare2/libr/core/cmd_api.c:213
 #23 0x7ff97c5e6c6c in ?? ??:0
 #24 0x7ff97c534810 in r_core_cmd_subst_i XYZ/radare2/libr/core/cmd.c:1960 (discriminator 4)
 #25 0x7ff97c534810 in ?? ??:0
 #26 0x7ff97c4fe4a3 in r_core_cmd_subst XYZ/radare2/libr/core/cmd.c:1311
 #27 0x7ff97c4fe4a3 in ?? ??:0
 #28 0x7ff97c4fb344 in r_core_cmd XYZ/radare2/libr/core/cmd.c:2477
 #29 0x7ff97c4fb344 in ?? ??:0
 #30 0x5587c9eb7566 in main XYZ/radare2/binr/radare2/radare2.c:961
 #31 0x5587c9eb7566 in ?? ??:0
 #32 0x7ff975fcf2b0 in __libc_start_main ??:?
 #33 0x7ff975fcf2b0 in ?? ??:0

SUMMARY: AddressSanitizer: heap-use-after-free (/usr/local/lib/libr_core.so+0x267584)
Shadow bytes around the buggy address:
 0x0c227fff8b40: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
 0x0c227fff8b50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
 0x0c227fff8b60: fd fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa
 0x0c227fff8b70: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
 0x0c227fff8b80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa
=>0x0c227fff8b90: fa fa fa fa fa fa fa fa fd fd fd fd fd[fd]fd fd
 0x0c227fff8ba0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
 0x0c227fff8bb0: fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa fa
 0x0c227fff8bc0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
 0x0c227fff8bd0: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa
 0x0c227fff8be0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
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
 Heap right redzone: fb
 Freed heap region: fd
 Stack left redzone: f1
 Stack mid redzone: f2
 Stack right redzone: f3
 Stack partial redzone: f4
 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
==35187==ABORTING

Log z Valgrinda (bardziej czytelny):


==54153== Invalid read of size 4
==54153==    at 0x10013E552: fcn_callconv (anal.c:2001)
==54153==    by 0x100141E1E: r_core_anal_all (anal.c:2536)
==54153==    by 0x1000C9F88: cmd_anal_all (cmd_anal.c:4503)
==54153==    by 0x100095C6F: cmd_anal (cmd_anal.c:4829)
==54153==    by 0x100138496: r_cmd_call (cmd_api.c:213)
==54153==    by 0x1000C00C8: r_core_cmd_subst_i (cmd.c:1960)
==54153==    by 0x10009336C: r_core_cmd_subst (cmd.c:1311)
==54153==    by 0x100090FF6: r_core_cmd (cmd.c:2477)
==54153==    by 0x100083CB4: r_core_prompt_exec (core.c:1684)
==54153==    by 0x10000436F: main (in /usr/local/bin/r2)
==54153==  Address 0x11020e1c8 is 40 bytes inside a block of size 208 free'd
==54153==    at 0x100074EF7: free (in /usr/local/Cellar/valgrind/3.11.0_1/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==54153==    by 0x10046E38F: r_anal_bb_free (bb.c:58)
==54153==    by 0x10166749B: r_hashtable64_free (ht.c:177)
==54153==    by 0x100486425: r_anal_state_free (state.c:70)
==54153==    by 0x1004105BC: analyze_from_code_buffer (anal_java.c:502)
==54153==    by 0x10041011F: analyze_from_code_attr (anal_java.c:533)
==54153==    by 0x10040EFCB: java_analyze_fns (anal_java.c:664)
==54153==    by 0x10013BCFB: r_core_anal_fcn (anal.c:1234)
==54153==    by 0x100141A8C: r_core_anal_all (anal.c:2496)
==54153==    by 0x1000C9F88: cmd_anal_all (cmd_anal.c:4503)
==54153==    by 0x100095C6F: cmd_anal (cmd_anal.c:4829)
==54153==    by 0x100138496: r_cmd_call (cmd_api.c:213)
==54153==  Block was alloc'd at
==54153==    at 0x1000751B9: calloc (in /usr/local/Cellar/valgrind/3.11.0_1/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==54153==    by 0x10046E0FA: r_anal_bb_new (bb.c:10)
==54153==    by 0x100484A4F: r_anal_ex_get_bb (anal_ex.c:174)
==54153==    by 0x1004850C8: r_anal_ex_analysis_driver (anal_ex.c:287)
==54153==    by 0x100484E78: r_anal_ex_perform_analysis (anal_ex.c:230)
==54153==    by 0x10041072C: analyze_method (anal_java.c:571)
==54153==    by 0x1004104B6: analyze_from_code_buffer (anal_java.c:491)
==54153==    by 0x10041011F: analyze_from_code_attr (anal_java.c:533)
==54153==    by 0x10040EFCB: java_analyze_fns (anal_java.c:664)
==54153==    by 0x10013BCFB: r_core_anal_fcn (anal.c:1234)
==54153==    by 0x100141A8C: r_core_anal_all (anal.c:2496)
==54153==    by 0x1000C9F88: cmd_anal_all (cmd_anal.c:4503)
==54153==
==54153== Invalid read of size 4
==54153==    at 0x10013E568: fcn_callconv (anal.c:2004)
==54153==    by 0x100141E1E: r_core_anal_all (anal.c:2536)
==54153==    by 0x1000C9F88: cmd_anal_all (cmd_anal.c:4503)
==54153==    by 0x100095C6F: cmd_anal (cmd_anal.c:4829)
==54153==    by 0x100138496: r_cmd_call (cmd_api.c:213)
==54153==    by 0x1000C00C8: r_core_cmd_subst_i (cmd.c:1960)
==54153==    by 0x10009336C: r_core_cmd_subst (cmd.c:1311)
==54153==    by 0x100090FF6: r_core_cmd (cmd.c:2477)
==54153==    by 0x100083CB4: r_core_prompt_exec (core.c:1684)
==54153==    by 0x10000436F: main (in /usr/local/bin/r2)
==54153==  Address 0x11020e1c8 is 40 bytes inside a block of size 208 free'd
==54153==    at 0x100074EF7: free (in /usr/local/Cellar/valgrind/3.11.0_1/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==54153==    by 0x10046E38F: r_anal_bb_free (bb.c:58)

Issue #6034 na GitHubie

Commit naprawiający: 5800b23e8feb06df42c7898299b4872572b7b979

CVE: N/A

2 thoughts on “radare2 – Use after free

Leave a Reply

Your email address will not be published. Required fields are marked *