Altering packets on the fly with scapy as a MITM

2019-05-11 08:51发布

问题:

Assuming I managed to be in the middle of the communication between a client and a server (let's say that I open up a hotspot and cause the client to connect to the server only through my machine).

How can I alter packets that my client sends and receives without interrupting my own communication with other services? There must be a way to route all of the packets the client both sends and is about to receive (before forwarding them to him) through my script.

I think that the correct direction of going about accomplishing this is with iptables but not sure exactly what arguments would fit to make this work. I already have the following simple script:

hotspotd start #a script that runs dnsmasq as both a DNS and DHCP server, configures and starts a hotspot
iptables -P FORWARD ACCEPT
iptables --append FORWARD --in-interface wlan0 -j ACCEPT
iptables --table nat --append POSTROUTING --out-interface eth0 -j MASQUERADE 
#wlan0 is the interface on which the hotspot is.
#eth0 is the interface that is connected to the internet

Now, this perfectly works for a passive MITM - I can see everything that the client sends and receives. But now I want to step it up and redirect every message he sends and receives through me.

My eventual purpose is to get to a level where I could execute the following script:

from scapy.all import *
from scapy_http.http import *

def callback(pkt):
   #Process the packet here, see source and destination addresses, ports, data
   send(pkt)

sniff(filter='port 666', prn=callback) #Assuming all relevant packets are redirected to port 666

How do I accomplish redirecting every packet the client sends and is-about-to-receive?

回答1:

You can use NFQUEUE which has python bindings.

NFQUEUE is a userspace queue that is a valid iptables target. You can redirect some traffic to the NFQUQUE:

iptables -I INPUT -d 192.168.0.0/24 -j NFQUEUE --queue-num 1

Then access the packets from your code:

from netfilterqueue import NetfilterQueue

def print_and_accept(pkt):
    print(pkt)
    pkt.accept()

nfqueue = NetfilterQueue()
nfqueue.bind(1, print_and_accept)
try:
    nfqueue.run()
except KeyboardInterrupt:
    print('')

nfqueue.unbind()

Note the pkt.accept() call. This returns a verdict to the nfqueue, telling it that it should accept the packet - i.e. allow it to continue along its normal route in the kernel. To modify a packet, instead of accepting it, you'd need to copy it, return a drop verdict, and finally resend it with the included modifications.