
이번 문제는 Offset이라는 문제이다. 바로 ida를 통해 분석해 보면

puts로 문자열 하나 띄워준다음 gets로 입력을 받는다. 그다음 입력받은 문자열을 인자로 select_func라는 함수를 호출하는데 해당 함수를 보면.

v3 함수 포인터 변수가 'two'라는 함수를 가리키고 있고, strncpy 함수로 dest 라는 변수에 인자로 보내진 src를 0x1f 만큼 복사를 한다. 그리고 dest가 one이라는 문자렬이면 v3은 one을 가리키게 되고, 이후 if 문을 벗어나 v3을 호출한다. 여기서 나온 one과 two 함수를 살펴보면,

one이라는 함수는 다음과 같이 생겼고,

two 함수는 다음과 같이 생겼다. 그리고 하나 더 'print_flag'라는 함수가 있는데,

flag.txt 파일을 출력해 주는 함수이다. 우리는 당연히 이 print_flag 함수를 실행시켜야 되는데 여기서 이 함수를 호출시킬 수 있는 방법은
v3 함수 포인터 변수가 가리키는 함수를 print_flag로 만들면 된다. 우선 다시 select_func 함수로 돌아가 v3 변수의 위치를 보면,

인자 src의 값이 복사되는 dest는 ebp로부터 0x2 a 만큼 떨어져 있고, v3는 ebp로 부터 0xc 만큼 떨어져 있음을 확인할 수 있다. 이 둘의 차이는 0x2a - 0xc 즉 30 만틈이고 버퍼에서 31 부터 v3임을 확인 할 수 있다. 그런데 strncpy에서 복사할 수 있는 최대 사이즈는 strncpy 함수 인자에서도 봤듯이 0x1 f 즉 31 바이트만큼이고 우리가 덮을 수 있는 size는 오직 1 바이트 밖에 없다. 그러나 처음 v3가 가리키고 있는 two 함수와 print_flag 함수의 주소를 보면,

보다시피 ad를 d8로 1바이트만 바꾸어 주면 print_flag 함수의 주소로 덮이는 것을 확인할 수 있다. 즉, 우리는 30바이트 dest를 덮고 나머지 1 바이트를 d8로 바꾸어 주면 print_flag 함수의 주소를 가리키는 v3 가 호출되어 flag를 얻을 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
from pwn import*
#p = process("./offset")
payload = ''
payload += 'A'*30
payload += p32(0xd8)
p.recvuntil("\n")[:-1]
p.sendline(payload)
p.interactive()
|
다음과 같이 익스를 짜고 실행하면,

flag 를 딸 수 있당
FLAG : HackCTF{76155655017129668567067265451379677609132507783606}
'WARGAME > hack ctf' 카테고리의 다른 글
RTL_World (0) | 2020.03.09 |
---|---|
BOF_PIE (0) | 2020.03.09 |
Simple_Overflow_ver_2 (0) | 2020.03.09 |
x64 Simple_size_BOF (0) | 2020.03.09 |
x64 Buffer Overflow (0) | 2020.03.09 |