Skip to content

Instantly share code, notes, and snippets.

@YSaxon
Last active November 13, 2024 16:39
Show Gist options
  • Save YSaxon/82f59e63ce972072fb9b15c4af0cea80 to your computer and use it in GitHub Desktop.
Save YSaxon/82f59e63ce972072fb9b15c4af0cea80 to your computer and use it in GitHub Desktop.
notes on MITMing mobile device network traffic with pf.conf RDR and NAT rules

TLDR

  • Change the network gateway on the device you want to intercept traffic from to your local computer IP. Or, alternatively do ARP spoofing, in which case you can probably skip the nat rule below.

  • Add the following to your pf.conf file (modifying the assignments appropriately)

set loginterface pflog0 # if on macOS

ext_if = en0
phone = 192.168.0.100
computer = $ext_if:0
redirect_to = 123.123.123.123
redirect_to_port = 4444

nat log on $ext_if from $phone to any -> $computer
rdr log on $ext_if proto udp from $phone to any -> $redirect_to port $redirect_to_port
rdr log on $ext_if proto tcp from $phone to any -> $redirect_to port $redirect_to_port

additionally, if you are on a vpn, then you'll need to add

vpn_if = utun0 # route get default | grep interface | awk '{print $2}'
vpn_ip = $vpn_if:0
nat log on $vpn_if from $phone to any -> $vpn_ip

If you are on macOS and want to log the redirects for debugging, execute sudo ifconfig pflog0 create. Otherwise leave out the log modifiers above, and just make it nat on or rdr on.

  • Then execute
sudo sysctl -w net.inet.ip.forwarding=1
sudo pfctl -v -f /etc/pf.conf
sudo pfctl -e
  • If you want to redirect the tcp traffic back to your computer on port 8080 so it goes through burp then set up a VM with its own networks stack and ssh -R 4444:localhost:8080, or use ngrok tcp 8080, and either way, modify the redirect_to above to point to the right ip. Another option would be to forward to the redirect port given to you by ssh [email protected]

Explanation

There are essentially two steps to MITMing network traffic:

  • Making sure the packets go through you (accomplished through ARP spoofing or changing the network gateway)
  • Redirecting the packets where you want them to go (accomplished with port forwarding rules such as pf.conf)

Let's take the following scenario: Router = 192.168.0.1 Phone (target) = 192.168.0.100 Computer (you) = 192.168.0.200

One way to accomplish step 1 is with ARP spoofing, where you convince the router that packets destined for the phones MAC address should go through you, and convince the phone that packets for the router's MAC should go through you.

Another way (what we will be discussing) which works if the phone is yours, is to simply set 192.168.0.200 (your computer's IP) as the gateway address in the phones network settings.

Now you need to redirect the packets. This can be done with an rdr rule in pf.conf

# note that log is optional and might mess things up if you haven't configured the logging
ext_if = en0
phone = 192.168.0.100
computer = 192.168.0.200
redirect_to = 123.123.123.123
redirect_to_port = 4444
rdr log on $ext_if proto udp from $phone to any -> $redirect_to port $redirect_to_port
rdr log on $ext_if proto tcp from $phone to any -> $redirect_to port $redirect_to_port

Add that to your /etc/pf.conf (or create a new anchor file and write it there)

You’ll also need to execute

sudo sysctl -w net.inet.ip.forwarding=1

If you try to test this on TCP with netcat, it won't work. And if you open up Wireshark on your computer, you'll see that it starts to connect but then gets a Reset packet sent.

Let's try it in UDP mode instead. On your redirect_to server (ssh [email protected] is great for this purpose), set up a netcat udp listener. ncat -lvnu {whatever port they gave you} And then on your phone (eg through adb shell), do nc 5.5.5.5 55 (the 5s being entirely arbitrary, just to test the interception)/ Then start typing, and you'll find that this rdr rule actually is working in the outbound direction. But try to start typing on the other side, and you'll quickly see Ncat: Connection refused.. If you try to figure out why in Wireshark, all you'll see is a Destination unreachable (Port unreachable).

This already explains why TCP couldn't work, since TCP as a protocol requires bidirectional traffic to set up the connection.

Let's review what we have now: 192.168.0.100 (phone) is sending packets to 5.5.5.5 through you. Your rdr rule is sucessfully changing the destination address to divert them to 123.123.123.123 123.123.123.123 (redirect_host) is trying to send packets back to 192.168.0.100

There are two potential problems with the return trip packets: the source IP and the destination IP. Firstly, the source IP of the return trip packet will say 123.123.123.123, and the phone may not be expecting such a source address, since it thought it was talking to 5.5.5.5 Secondly, the destination IP of the return trip packet will say 192.168.0.100, which means the router (which you haven't altered) has no reason to send the packet back through your computer at all!

Luckily both of these problems can be fixed together with something called Network Address Translation or NAT. All you need is the following rule:

nat log on $ext_if from $phone to any -> $computer

What this will do (if I understand it correctly) is change the source address on the outgoing packet from 192.168.0.100 (phone) to 192.168.0.200 (your computer). It also somehow keeps track of that packet to be able to rewrite it to the correct source address later. Then, when the return packet comes, it bears the destination address of your computer, which now has a chance to rewrite both the source address (from 123.123.123.123 -> 5.5.5.5) and the destination address (from 192.168.0.200 -> 192.168.0.100) before forwarding it on again.

Now the TCP rdr should work as well.

(update: this will stop working if you go onto a VPN, because the NAT rule needs to be defined according to the VPN interface. See the TLDR above for the right commands to add)

A couple more points we should address:

First of all, which of the two reasons I gave above is actually the primary or real reason? Is it that the return packets are addressed directly to the phone, so that we never see them? Or is it that the source address is unexpected?

An experiment we could run is to run an ARP spoofing attack against the router, convincing it that packets bound for the phone should go through us, without using the NAT rule. Let's try it:

sudo arpoison -i en0 -d 192.168.0.1 -s {phone ip} -r {computer mac address} -t {router mac address}

While this arp spoofing is active, even if we comment out the nat rule and refresh, we find that it still works! How can this be? Well it seems like pf is smart enough to rewrite the source address 123.123.123.123 back to 5.5.5.5, since it was the one that altered it with the rdr rule to begin with on the outbound. So the real problem all along was just the fact that the packet was being sent back to the phone directly, which meant we never picked it up to be able to alter it.

Still, the NAT rule saves us from having to maintain ARP spoofing (so long as we can alter the gateway address on the phone) so that's still quite nice.

Finally, for simplicity, we've been using the segfault.net server as the redirect_to server, but can we instead redirect to a port on our own computer? So far I haven't gotten that to work. It works if you rdr to a different host, whether a local IP or an external one, but if you try to rdr to a port on your own computer, whether via 127.0.0.1, or your local ip, or even an alias ip, it doesn't work for me. Possible workarounds:

  • ngrok
  • a lightweight VM with ssh port forwarding
  • a raspberry pi

Basically, anything with its own network stack that you can forward back to your computer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment