When working in security consulting, you often need a lot of complicated networking setups that are a bit difficult to figure out without some knowledge of some basic Linux networking tools. I’m going to outline a few tools I use for networking setups and then show some ways to use them together for various networking setups. What follows might not be optimal (hence MacGyver), but will typically work. My standard toolbox for networking, in no particular order, includes:

  • iptables
  • ssh
  • socat
  • nc
  • adb where available (this is on more than just Android these days)

These tools are often all you’ll need to handle some specific networking task.

Tool overview

iptables NAT

Eventually I’ll have to update this for nftables since iptables is being phased out, but I think it’ll be around long enough to still be worth the discussion here. Every consultant should know some generic iptables functionality, if only just for setting up your laptop’s firewall rules to block all incoming traffic. One of the primary things you’ll be using iptables for when hacking together some networking is Network Address Translation (NAT). As an example, say you’re on a VPN (interface tun0, subnet with your coworker, and you have a router on your personal network (interface wlan0, subnet that you want to give them access to. Your IP in the VPN is, your coworker is, the router is, and your IP on wlan0 is

It only takes a few iptables commands to set this up:

# Change the destination IP

iptables -t nat -I PREROUTING -i tun0 -d '' -s '' -j DNAT --to-destination ''

# Allow forwarding to happen

iptables -I FORWARD -o wlan0 -i tun0 -m conntrack --ctstate NEW -j ACCEPT
iptables -I FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Change the source to our IP on the local network so we can get packets
# back.

iptables -t nat -I POSTROUTING -o wlan0 -j SNAT --to-source

# Can also MASQUERADE instead which is simpler and does more or less the
# same thing
# iptables -t nat -I POSTROUTING -o wlan0 -j MASQUERADE

One gotcha, for this to work:

$ cat /proc/sys/net/ipv4/ip_forward

Must return 1, if it doesn’t, write 1 to that file.

These iptables commands are basically saying, in plain English:

Inspect all input coming in the tun0 interface. If the input source IP is (coworker) and it is sent to (me), translate the destination to Allow new forwards from tun0 to wlan0 and track them, then allow all tracked connections to continue. Finally, change the source address of all packets leaving wlan0 to our IP on the interface.

This, for all practical purposes, turns your host into the router on the VPN. Every port on the router is accessible by hitting the same port on your host. Neat. If you don’t want that and only want a specific port, you can specify --dport and a port in --to-destination, like so (allowing SSH for example):

iptables -t nat -I PREROUTING -i tun0 -d '' --dport 22 -s '' -j DNAT --to-destination ''

iptables VM transparent proxy

iptables can also be used for setting up a transparent proxy for a VM. For example, imagine a setup where you have a VM with “host only” networking on interface vmnet1 with eth0 as your host’s gateway interface. Your host on vmnet1 is and the VM is

Giving the VM internet is as simple as:

# Allow traffic from VM, this is important if you want to start transparently
# proxying traffic elsewhere
iptables -I INPUT -i vmnet1 -s -j ACCEPT

# Allow forwarding
iptables -I FORWARD -i vmnet1 -o eth0 -m conntrack --ctstate NEW -j ACCEPT
iptables -I FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Change the source to our IP on the local network so we can get packets
# back.
iptables -t nat -I POSTROUTING -o eth0 -j SNAT --to-source

# Can also MASQUERADE instead which is simpler and does more or less the
# same thing
# iptables -t nat -A POSTROUTING -o "$GWIFACE" -j MASQUERADE

Now if you want to transparently proxy all HTTP/HTTPS traffic:

iptables -t nat -N HTTP_PROXY
iptables -t nat -I HTTP_PROXY -p tcp -j DNAT --to-destination "$PROXYIP:$PROXYPORT"
iptables -t nat -I PREROUTING -p tcp -i vmnet1 -s --dport 80 -j HTTP_PROXY
iptables -t nat -I PREROUTING -p tcp -i "$IFACE" -s --dport 443 -j HTTP_PROXY

Note if you set up the VM with a host only interface you likely need to add a default route (to use in this case) and set the DNS server.


SSH is not just a way to get a terminal, it also has some awesome networking capabilities and I’d recommend checking out the man page for all the cool stuff you can do, but here I’ll talk about a few important things:

  • DynamicForward or the -D flag
  • RemoteForward or the -R flag
  • LocalForward or the -L flag
  • ProxyJump or the -J flag

When talking about SSH features, we’ll always talk about the local host (you) and the remote host (the host running the SSH server you’re connecting to). Another useful feature of SSH that I won’t go into here is the ControlMaster config option and other related options which can help keep an SSH session alive and allow multiple sessions to use a single session. This is nice when using ProxyJump when you have to authenticate at each jump for example.


DynamicForward (-D) is used to open a port on your local machine that acts as a SOCKS server. Essentially what this means is that if you are using a SOCKS aware client (or redsocks if you dare) you can make a request on your local host using SSH’s socks server and it will send the request from the remote host.

As a concrete example:


This will open your SSH session and start a SOCKS server on You can use this SOCKS server with tools like Burp, mitmproxy, and curl. For example with curl:

curl --socks5 https://cnn.com

This will send the HTTP request over the SOCKS proxy to the remote host which will then be the source of the HTTP request. This can be very helpful for accessing services on internal networks from your local machine. You’ll often want to do this when you want to use a tool you have installed on your local machine but not on a jumpbox in a client’s local a network.


RemoteForward (-R) is used to open a port on the remote host and forward that traffic to your local host. Essentially what this is doing is running a TCP (or Unix socket) server on the remote host and just trivially forwarding all traffic back to you.

As a concrete example, say you have an HTTP server running on your local host and want to open it to the world via an intermediate remote host:

ssh -R 8080: REMOTEHOST

Let’s say the remote host is and has port 8080 open to the internet:


will then send an HTTP request to the remote host and since that port is a simple TCP server started by the SSH server on the remote host, it will be forwarded back to on your local host. You’ve essentially put a single port from your local host onto the internet. I use this a lot when exploiting SSRF issues or opening reverse shells since it’s always nicer to work on your own computer with all the tools you’re familiar with.


LocalForward (-L) is basically the reverse of RemoteForward: it starts a server on your local host that forwards traffic to the remote host. For example, say you’re working on a client’s server that has a service listening on, but you can’t actually route to because it is on a different interface.

You can use SSH to set up a tunnel to this service with:

ssh -L 8080: REMOTEHOST

This will run a TCP server on your local host at port 8080 that is tunneled to on the remote host. You can now interact with the service from your local host as if you were on the remote host, allowing you to use all of your favorite tools on your localhost.


ProxyJump (-J) basically chains SSH connections together. As an example, say you are working on a client’s network through a jumpbox at, and you want to SSH into a box on the network at You can’t reach from your local host, so a naive approach would be to manually ssh into your jumpbox at and then, from there, ssh into the box at

localhost$ ssh -i KEY jumpboxuser@
jumpbox$ ssh -i KEY targetuser@

But that’s kinda clunky and it’ll be a bit tedious to use all the cool SSH forwarding features while doing that.

This can be solved with ProxyJump (-J):

localhost$ ssh -J jumpboxuser@ targetuser@

I almost never use -J and instead use ProxyJump in my ssh config file (~/.ssh/config) because it allows configuring parameters for each host in the chain. ProxyJump is not limited to a single host! You can jump through multiple hosts and all of your -R, -L, and -D command line options will work: it’s kinda amazing.


socat is an amazing tool. I can’t describe all of the things socat can do in this writeup so I highly recommend man socat, but let me go over a few things I’ve used socat for that you might not expect would be so easy.

One of the cooler uses for socat is to allow access to a serial port via a TCP server. As an example, say you have a serial port connected to /dev/ttyUSB0 and want to open it up to a coworker via a VPN (interface tun0 subnet Your IP on the VPN is

To send TCP traffic to this serial port all you need to do is:

socat 'TCP4-LISTEN:8657,nonblock=1,fork,nodelay,reuseaddr,range=,bind=' '/dev/ttyUSB0,rawer,b115200,nonblock=1'

This command opens a TCP server on and forwards what it receives to the serial port (baud rate 115200). Since I typically have a restrictive firewall setup I need to also accompany this with an iptables rule:

# iptables -I INPUT -p TCP -s -d --dport 8657 -j ACCEPT

Now your coworker just needs to run:

socat TCP4: '-,rawer,escape=0x1d'

and they will be able to use the serial port remotely! (This sets Ctrl + ] as the escape)

Another thing I often use socat for is to set up a TLS listener and forward it to a normal TCP server so I don’t have to deal with TLS in the server I’m writing:

socat OPENSSL-LISTEN:8657,nonblock=1,fork,nodelay,reuseaddr,cert=/path/to/cert_and_key.pem TCP:

Some other fun things you can do with socat:

  • Translate IP6 to IP4
  • Trigger a local program to run with an incoming TCP connection
  • Replacement for the full iptables NAT functionality to forward traffic to specific ports

There is a ton you can do with socat and if the other tools aren’t suiting your purposes, chances are socat can do what you need.


nc is nice for quickly setting up a TCP listener. I’ll often use this just to see what an SSRF is sending me or to set up a listener for a reverse shell. You can also make outgoing requests with nc, and in combination with printf this can often be an easy way to send some quick binary data to a target server.

To set up a TCP listener with nc it is as simple as:


When using it just to see if I receive a connection I like to add some -v flags. If -l isn’t specified, nc will instead connect:


You can pipe data into nc when connecting to send whatever you want to the remote target.


adb is showing up in more and more places and it provides a lot of functionality. adb reverse is simliar to RemoteForward with ssh and adb forward is similar to LocalForward with ssh. adb can also run as a TCP server on the target device and other networking tools can be used to give access to this.

Some common use cases

What follows are some common ways I use these tools, once again, this may not be the optimal way to do these tasks, but they work and only require some basic knowledge of the tools outlined above.

SSRF Check

Say you’ve found what you believe to be an SSRF on your target and you want to see what it sends. There are various tools to handle this, and I often use Burp intruder, but you can also do this very simply with a server on the internet, ssh, and nc. Here is how:

localhost$ ssh -R 8080: MYSERVER
localhost$ while true; do printf 'HTTP/1.1 200 OK\r\n\r\n' | nc -l 8080; done

This uses SSH to open our local port to the internet via RemoteForward and then uses nc to create the simplest HTTP server you can come up with. Sometimes you may need to open port 80 on the remote host and you’ll get a failure since it’s a low port. No worries:

localhost$ ssh -R 8080: MYSERVER
remotehost$ sudo socat TCP4-LISTEN:80,nonblock=1,fork,nodelay,reuseaddr,user=nobody,group=nogroup TCP:,nonblock=1,nodelay
localhost$ while true; do printf 'HTTP/1.1 200 OK\r\n\r\n' | nc -l 8080; done

This uses socat on the remote host to forward incoming TCP connections on 8080 to port 80.

Reverse shell

Similar to the SSRF check, tunnel a reverse shell from an internet facing server to your local host.

localhost$ ssh -R 12345: MYSERVER
localhost$ nc -v -l 12345

Note that this typically gives you a kinda crappy reverse shell. If you have some other utilities on the host there are ways to get a PTY for your reverse shell and make it work kinda nicely. Check out this great blog post for some ways to upgrade your reverse shell.

Allow someone on a VPN to use your SOCKS proxy

localhost$ ssh -D JUMPBOX
localhost# iptables -I INPUT -d --dport 1080 -s -j ACCEPT

Allow someone on a VPN to use adb on a target device

VPN: tun0 subnet Local network: wlan0 subnet You on VPN: Coworker on VPN: You on local network: Target device on network:

localhost$ adb tcpip 5035
localhost# iptables -t nat -I PREROUTING -i tun0 -p tcp -d -s --dport 5035 -j DNAT --to-destination
localhost# iptables -I FORWARD -o wlan0 -i tun0 -m conntrack --ctstate NEW -j ACCEPT
localhost# iptables -I FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
localhost# iptables -t nat -I POSTROUTING -o wlan0 -d -j SNAT --to-source
# OR 
localhost# iptables -t nat -I POSTROUTING -o wlan0 -j MASQUERADE

This sets up adb to use a TCP server instead of a USB connection and then uses iptables to NAT traffic. This can also be done with socat:

localhost$ adb tcpip 5035
localhost$ socat 'TCP-LISTEN:5035,reuseaddr,nonblock=1,nodelay,range=,bind=' 'TCP:,nonblock=1,nodelay'

I prefer the iptables method, but both will work just fine.

Run a VPN in a VM

I never run client VPNs directly on my host but instead isolate them in a VM. Since Windows also supports SSH, this can be really helpful. Basically just set up the VPN in the VM and then you can set up a SOCKS proxy to the VM and use that proxy for most of your tools.

ssh -D VM

Most tools can be configured to use a SOCKS proxy, but if they can’t, there is always redsocks which is an awesome tool.

Transparently forward traffic to Burp from a rooted Android phone

I use this one all the time since I typically do my MITM setups on a rooted Android device. It is a very clean way to deal with MITMing Android application traffic.

localhost$ adb reverse tcp:9090 tcp:9090
phone# iptables -t nat -I OUTPUT -p tcp -m owner --uid-owner u0_aXXX -j DNAT --to-destination