radare2-extras
radare2-extras copied to clipboard
Stack buffer overflow of parsing swf
Hi,
When I play with r2 and the swf plugin, it crashes with a buffer overflow.
(lldb) run
Process 54371 launched: '/usr/local/bin/r2' (x86_64)
2017-11-09 08:40:51.921302+0800 r2[54371:19870295] detected buffer overflow
Process 54371 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
frame #0: 0x00007fff98965d42 libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill:
-> 0x7fff98965d42 <+10>: jae 0x7fff98965d4c ; <+20>
0x7fff98965d44 <+12>: movq %rax, %rdi
0x7fff98965d47 <+15>: jmp 0x7fff9895ecaf ; cerror_nocancel
0x7fff98965d4c <+20>: retq
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
* frame #0: 0x00007fff98965d42 libsystem_kernel.dylib`__pthread_kill + 10
frame #1: 0x00007fff98a53457 libsystem_pthread.dylib`pthread_kill + 90
frame #2: 0x00007fff988cb420 libsystem_c.dylib`abort + 129
frame #3: 0x00007fff988cb592 libsystem_c.dylib`abort_report_np + 181
frame #4: 0x00007fff988f1f28 libsystem_c.dylib`__chk_fail + 48
frame #5: 0x00007fff988f1ef8 libsystem_c.dylib`__chk_fail_overflow + 16
frame #6: 0x00007fff988f1f8e libsystem_c.dylib`__memset_chk + 37
frame #7: 0x0000000101a2de09 bin_swf.dylib`r_bin_swf_get_header + 169
frame #8: 0x0000000101a2d9b7 bin_swf.dylib`entries + 119
frame #9: 0x0000000100357d90 libr_bin.dylib`r_bin_object_set_items(binfile=0x0000000101c09ca0, o=0x0000000101b373a0) at bin.c:770
frame #10: 0x000000010035aa35 libr_bin.dylib`r_bin_object_new(binfile=0x0000000101c09ca0, plugin=0x0000000101d00740, baseaddr=18446744073709551615, loadaddr=0, offset=0, sz=856) at bin.c:1377
frame #11: 0x0000000100359ebc libr_bin.dylib`r_bin_file_new_from_bytes(bin=0x0000000101b09220, file="testfk.swf", bytes="CWS\x1b, sz=856, file_sz=856, rawstr=0, baseaddr=18446744073709551615, loadaddr=0, fd=3, pluginname=0x0000000000000000, xtrname=0x0000000000000000, offset=0, steal_ptr=true) at bin.c:1567
frame #12: 0x00000001003598c4 libr_bin.dylib`r_bin_load_io_at_offset_as_sz(bin=0x0000000101b09220, fd=3, baseaddr=18446744073709551615, loadaddr=0, xtr_idx=0, offset=0, name=0x0000000000000000, sz=856) at bin.c:1118
frame #13: 0x0000000100358ad6 libr_bin.dylib`r_bin_load_io_at_offset_as(bin=0x0000000101b09220, fd=3, baseaddr=18446744073709551615, loadaddr=0, xtr_idx=0, offset=0, name=0x0000000000000000) at bin.c:1132
frame #14: 0x0000000100358970 libr_bin.dylib`r_bin_load_io(bin=0x0000000101b09220, fd=3, baseaddr=18446744073709551615, loadaddr=0, xtr_idx=0) at bin.c:1021
frame #15: 0x0000000100196584 libr_core.dylib`r_core_file_do_load_for_io_plugin(r=0x00000001000084e0, baseaddr=18446744073709551615, loadaddr=0) at file.c:406
frame #16: 0x000000010019507f libr_core.dylib`r_core_bin_load(r=0x00000001000084e0, filenameuri="testfk.swf", baddr=18446744073709551615) at file.c:563
frame #17: 0x0000000100003962 r2`main(argc=2, argv=0x00007fff5fbff548, envp=0x00007fff5fbff560) at radare2.c:1009
frame #18: 0x00007fff98837235 libdyld.dylib`start + 1
frame #19: 0x00007fff98837235 libdyld.dylib`start + 1
Checking the code, turns out a simple stack buffer overflow.
// https://github.com/radare/radare2-extras/blob/master/libr/bin/format/swf/swf_specs.h
#define SWF_HDR_MIN_SIZE 12
// https://github.com/radare/radare2-extras/blob/master/libr/bin/format/swf/swf.h
typedef struct __attribute__((__packed__)) {
ut8 signature[3];
ut8 version;
ut32 file_size;
ut8 rect_size;
ut16 frame_rate;
ut16 frame_count;
} swf_hdr;
// https://github.com/radare/radare2-extras/blob/master/libr/bin/p/bin_swf.c
static RList* entries(RBinFile *arch) {
RList *ret = NULL;
RBinAddr *ptr = NULL;
if (!(ret = r_list_new()))
return NULL;
if (!(ptr = R_NEW0 (RBinAddr)))
return ret;
swf_hdr header; // stack variable
header = r_bin_swf_get_header(arch);
// ...
}
// https://github.com/radare/radare2-extras/blob/master/libr/bin/format/swf/swf.c
swf_hdr r_bin_swf_get_header(RBinFile *arch) {
swf_hdr header; // stack variable
ut8 nBits;
/* First, get the rect size */
r_buf_read_at (arch->buf, 8, (ut8*)&nBits, 1);
nBits = (nBits & 0xf8) >> 3;
ut32 rect_size_bits = nBits*4 + 5;
ut32 rect_size_bytes = rect_size_bits / 8;
if (rect_size_bits % 8) rect_size_bytes++;
/* Read the whole header */
memset(&header, 0, SWF_HDR_MIN_SIZE + rect_size_bytes); // stack overflow
r_buf_read_at(arch->buf, 0, (ut8*)&header, 8);
// ...
}
the header
is a variable on the stack, the memset call with size of SWF_HDR_MIN_SIZE + rect_size_bytes
will easily exceeds the bound, leads to buffer overflow.
The parser needs to decompress the flash file first when it's compressed flash(CWS/ZWS) and proceed the parse logic IMHO.
Cheers.
Can you send a Pull Request fixing this.
what about providing a binary to reproduce the issue?
Hi @radare, try this one, it is a CWS compressed flash file. http://www.diyed.co.uk/diy-ed-information-book-sample/files/flash/expressInstall.swf you may use my trivial script to decompress, https://github.com/binjo/utils/blob/master/cws2fws.py
md5sum expressInstall.swf fws-expressInstall.swf
7b65fbfaec8b2955090389af60646e8b expressInstall.swf
7089405dc1945dd72bcfb14630900f46 fws-expressInstall.swf
it should crash on any flash file :<
@xarkes please have a look at this