pwnat: A NAT traversal tool for reverse shells and remote control via NATed networks

pwnat: A NAT traversal tool for reverse shells and remote control via NATed networks

I still remember the first time I ran into a network topology where both my attacking box and my target were sitting behind separate NAT gateways, with no port forwarding, no VPS relay, and no way to punch a hole through either firewall using the usual tricks. That’s the exact problem pwnat was built to solve. It’s an old tool — it hasn’t seen much upstream development in years — but the technique it uses is still worth understanding deeply, because the underlying idea (using ICMP as a rendezvous signal) shows up again and again in more modern NAT traversal and tunneling tools.

pwnat lets a client behind one NAT connect to a server behind a different NAT, with no port forwarding, no STUN/TURN server, and no man-in-the-middle relay involved. It does this by having the server periodically send ICMP echo requests to a well-known “fake” destination (like 3.3.3.3), and having the client sniff for those packets to learn the server’s public IP and use ICMP time-exceeded tricks to signal back. Once the two sides discover each other’s public IP/port mapping, they establish a UDP-based tunnel that behaves like a proxy, and normal TCP traffic gets encapsulated over it.

How It Actually Works Internally

pwnat’s core trick relies on three things:

  1. ICMP as a beacon. The server, sitting behind NAT, has no public IP a client could dial into directly. But it can send outbound ICMP echo requests. It repeatedly pings a fixed address that doesn’t really matter (traditionally 3.3.3.3) — this is never meant to reach anything, it’s a beacon.
  2. Client sniffs the beacon. Because the client also doesn’t know the server’s public NAT-mapped address, it needs a way to discover it. It listens (using raw sockets) for the server’s ICMP echo requests destined for that fixed address, as those pass across the intermediate network segments it can see (this only works when the client can see that traffic — e.g., same broadcast domain, a mirrored span port, or the server periodically informing the client out-of-band). In pwnat’s actual design, the client instead triggers the server to reply, and the client watches for ICMP Time Exceeded or Destination Unreachable messages generated by the server’s own IP stack.
  3. UDP hole punch, then TCP-over-UDP tunnel. Once addresses are known, both sides start sending UDP packets to each other’s public NAT-mapped port. Once the NAT devices see outbound UDP from both directions, they permit inbound replies — this is the “hole” being punched. From that point, pwnat multiplexes a TCP-like proxy protocol on top.

The practical result: you run pwnat in server mode on the “target-side” box you control, and pwnat in client mode on your “attacker-side” box, and you get a local SOCKS-like proxy or forwarded port that tunnels through to the other side — despite neither box having a routable public IP.

Installation

On Debian/Kali-based systems, pwnat is available via apt, though it may need to be pulled from a slightly older repo snapshot in newer Kali releases since it isn’t actively maintained upstream:

sudo apt update
sudo apt install pwnat

If it’s not in your repos, build from source — this is the more reliable path since the tool hasn’t changed in a long time:

git clone https://github.com/samyk/pwnat.git
cd pwnat
make
sudo cp pwnat /usr/local/bin/

Verify it’s installed:

pwnat -h

Expected output (abbreviated):

usage: ./pwnat [-h] [-6] [-v[v]] [-i <int>] [-f <int>] [-4|-p <port>|-s|-u] [<dest-host> <dest-port> [<src-host>] [<src-port>]]
        -h                this help message
        -v                verbose (twice for more verbosity)
        -i interface      set the interface to use (default eth0)
        -f fwd-port       specify a udp port to use, other than default 2222
        -4                do not attempt IPv6 UDP forwarding
        -p src-port       proxy TCP port to bind on client, or on server to be forwarded to

Syntax and Command Examples

Server mode (run on the machine behind the “hidden” NAT, forwarding a service — say SSH on port 22 — out to the client):

sudo pwnat -s 0.0.0.0 22

This tells pwnat: “Act as server, forward connections to 0.0.0.0:22 (local SSH) once a client tunnels in.”

Client mode (run on your attacking machine):

sudo pwnat -p 2222

This opens a local port 2222 on the client. Any connection to localhost:2222 gets tunneled through the NAT-traversal channel to the server’s forwarded service.

Once both are running and have discovered each other via the ICMP beacon exchange, you can do:

ssh -p 2222 user@127.0.0.1

And that SSH session is actually reaching the “server” box behind its own NAT, despite you never touching port forwarding on either router.

Typical console output during a successful session

[server] waiting for ICMP...
[server] got request from client, sending handshake
[server] connection established with 203.0.113.44:41231
[client] sending probe to 3.3.3.3
[client] received handshake response
[client] tunnel established, listening on 127.0.0.1:2222

(Exact log lines vary slightly by version and verbosity level — run with -v or -vv for more detail.)

Real-World Use Cases in Authorized Engagements

I’ve used pwnat-style NAT traversal in a couple of specific authorized red team scenarios:

  • Post-exploitation callback from a deeply NATed internal host. If I’ve landed an implant on a segmented internal host that has outbound ICMP allowed (common — ICMP is frequently left open when TCP/UDP egress is locked down) but no other viable egress, ICMP-beacon-based tunneling becomes a fallback channel to maintain access.
  • Bypassing restrictive corporate firewalls during scoped engagements where the client explicitly wants me to test whether ICMP-based covert channels are viable data exfiltration/C2 paths, so they can tune their IDS/IPS ICMP anomaly detection.
  • Simulating dual-NAT lab environments to test detection coverage — I set up two isolated NAT segments in a lab, run pwnat between them, and see whether the SOC’s monitoring picks up the anomalous ICMP beacon pattern (repeated pings to unreachable/rare destinations at regular intervals is a strong IOC).

Integration with Other Tools

pwnat by itself is just a raw pipe. In practice I chain it with:

  • SSH — tunnel a full SSH session through it, then use SSH’s own -D dynamic port forwarding to get a SOCKS proxy on top, effectively layering two tunneling mechanisms.
  • proxychains4 — once you have a local port from pwnat’s client mode, you can point proxychains4 at it (if you’ve layered SOCKS via SSH) to route arbitrary tool traffic (nmap, curl, etc.) through the tunnel.
  • tcpdump — I always run tcpdump alongside pwnat during lab testing to actually observe the ICMP beacon traffic, since visualizing the packets makes the handshake mechanism click.

Troubleshooting and Common Mistakes

  • Nothing happens after starting both ends. This is almost always an ICMP filtering issue — check that ICMP echo (type 8) and time-exceeded/unreachable (types 3/11) aren’t being dropped by an intermediate firewall. Run tcpdump icmp on both ends to confirm the beacon packets are actually leaving and arriving.
  • Permission denied on startup. pwnat needs raw socket access for ICMP, so it must run as root (or with CAP_NET_RAW).
  • Works on LAN but not through real-world double-NAT. Some carrier-grade NAT (CGNAT) setups do connection tracking in ways that break the timing assumptions pwnat relies on. This is a known limitation — it’s not a universal double-NAT solution, just a clever one for many home/office router setups.
  • Confusing client and server roles. The “server” is the side that has the service you want reached; the “client” is the side that wants to reach it. This trips people up because it’s inverted from how you might think about which side initiates.

Performance Considerations

pwnat’s tunnel isn’t fast — it’s UDP-encapsulated and wasn’t designed with throughput in mind. For interactive shells (SSH, simple C2 beaconing) it’s fine. For bulk data transfer, expect it to be noticeably slower than a direct connection, so I don’t rely on it for exfiltrating large datasets; I use it to get a foothold or a management channel, then pivot to something faster once I have more conventional access.

FAQ

Is pwnat still maintained? Not actively — the last real development was years ago. It still works on most Linux systems, but don’t expect fixes for edge cases.

Does it work between two Windows machines? No — pwnat is Linux-only (relies on raw ICMP socket behavior specific to the Linux network stack).

Is this the same as UDP hole punching used in P2P apps like Skype/WebRTC? Conceptually related (both punch a NAT-to-NAT hole), but pwnat’s discovery mechanism via ICMP is distinct from STUN/TURN/ICE, which typically use a third-party rendezvous server.

Can this bypass a fully symmetric NAT? Not reliably. Symmetric NATs assign a different external port for every destination, which breaks the address-prediction pwnat depends on.

Lab Example

In an isolated lab (two virtual routers doing NAT, two internal hosts, no shared broadcast domain):

# On "internal-server" behind NAT A, exposing SSH
sudo pwnat -s 0.0.0.0 22

# On "attacker" behind NAT B
sudo pwnat -p 2222

# From attacker, once tunnel is up
ssh -p 2222 labuser@127.0.0.1

Confirm the tunnel is actually traversing both NATs (not just local loopback) by checking netstat -tunp on both routers for the UDP hole-punch session.

Summary

pwnat solves a specific, narrow problem — NAT-to-NAT connectivity without a relay — using a genuinely clever abuse of ICMP for peer discovery. It’s not fast, it’s not actively maintained, and it won’t defeat symmetric NAT, but as a red-team fallback channel or a teaching tool for understanding NAT traversal and ICMP-based covert signaling, it’s still worth having in your toolkit and worth knowing how to detect as a defender.

References

  • GitHub repository: https://github.com/samyk/pwnat
  • Original DEF CON presentation by Samy Kamkar (the author) covers the design rationale in depth.
  • Kali Linux tool listing: https://www.kali.org/tools/pwnat/
Total
0
Shares

Leave a Reply

Previous Post
ptunnel: A tool to create a tunnel over ICMP for bypassing firewalls

ptunnel: A tool to create a tunnel over ICMP for bypassing firewalls

Next Post
sslh: A protocol multiplexer that allows services like HTTPS, SSH, and OpenVPN to share the same port

sslh: A protocol multiplexer that allows services like HTTPS, SSH, and OpenVPN to share the same port

Related Posts