Man In The Middle Attack (MITM) Part 2 — Packet Sniffer

Dharmil Chhadva
Level Up Coding
Published in
9 min readAug 13, 2020

--

Building a packet sniffer using Python 🐍 that extracts visited URLs and user credentials.

This is part 2 of Man In The Middle (MITM) attack. If you haven’t read part 1 then I strongly suggest you read that before reading part 2. You can find the link to Part 1 in the next section.

What is a Packet Sniffer?

A packet sniffer is a tool that is used to monitor networks and to diagnose any network problems. It is commonly used by network technicians. Hackers often use this to spy on user’s network traffic and for extracting passwords.

Packet sniffers log network traffic on a network interface that they have access to. It can see every packet that flows to and from an interface.

You’d be wondering that we are designing a packet sniffer but the title says Man In The Middle Attack. This is because in Part 1 we wrote a Python script (ARP Spoofing) that allows us to become a Man In The Middle. The purpose of the packet sniffer is to capture the victim’s (the user which has been attacked using ARP Spoofing) network traffic and extract visited URLs and credentials.

Modules Used:

  1. argparse: To understand what this does read my first article here.
  2. Scapy: Enables the user to send, sniff and dissect and forge network packets. This capability allows the development of tools that can probe, scan, or attack networks. It can forge or decode packets of a wide number of protocols, send them on the wire, capture them, match requests and replies, and much more. It easily handles most tasks like scanning, tracerouting, probing, unit tests, attacks, or network discovery.
  3. time: We only use the time module to generate a delay of 2 seconds. To learn more about this module read the docs.

What functionality the Python 🐍 script must have?

  • get_args() — A function to get command-line arguments. In this case, we need an input value from the user for the interface on which we want to sniff the packets.
  • sniffer(interface) — A function that takes the interface value as an input and sniffs the packets on that interface.
  • process_packet(packet) — A function that is called by the sniffer function for every new packet that is sniffed. This checks whether the packet is of type HTTP Request or not. For this use case, we only need the packets which are of the HTTP Request type because the information we want is sent in this packet. It then uses get_url(packet) and get_credentials(packet) functions.
  • get_url(packet) — A function that extracts the URL from the packet that was passed to it.
  • get_credentials(packet) — A function that also takes packet as input and extracts credentials such as username and password.

Without further ado, let’s start writing the script in Python.

Python Script for Packet Sniffer

In this section, we’ll build the script step by step. I’ll explain everything in each step, so read carefully.

Step 1: Importing Necessary Modules

Importing Modules

Step 2: Writing the get_args() function

Function — get_args()

The above function adds functionality which allows the user to pass user input values as the command-line arguments. After the addition of the above code, the user will be able to pass the name of the interface on which the packets are supposed to be sniffed in the same instruction that is used to run the script. For example,

root@kali:~# python3 sniffer.py -i interface_name

OR

root@kali:~# python3 sniffer.py --interface interface_name

To learn how exactly this function works, read the entire Step 2 from the article on how to change MAC Address of a device.

Step 3: Writing the sniffer(interface) function

Function — sniffer(interface)

The above gist contains the definition of the sniffer(interface) function. It takes an interface name as an input that is used inside it. It uses a method called sniff provided by the scapy module. The methodsniff requires an interface name iface as an input. The next argument, store tells scapy whether to store the packets in memory or not. store = False tells scapy not to store the packets. The last argument is prn, it tells scapy which function to be called each time a new packet is sniffed. In this case, process_packet function is called for every new packet.

Step 4: Writing the process_packet(packet) function

Before jumping into the function, let’s take a look at how a scapy packet looks like.

###[ Ethernet ]###
dst = 52:54:00:12:35:00
src = 08:00:27:35:21:2e
type = IPv4
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 441
id = 22651
flags = DF
frag = 0
ttl = 64
proto = tcp
chksum = 0xf1f9
src = 10.0.2.9
dst = 176.28.50.165
\options \
###[ TCP ]###
sport = 48556
dport = http
seq = 790303956
ack = 327206
dataofs = 5
reserved = 0
flags = PA
window = 64240
chksum = 0xf075
urgptr = 0
options = []
###[ HTTP 1 ]###
###[ HTTP Request ]###
Method = 'GET'
Path = '/login.php'
Http_Version= 'HTTP/1.1'
A_IM = None
Accept = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
Accept_Charset= None
Accept_Datetime= None
Accept_Encoding= 'gzip, deflate'
Accept_Language= 'en-US,en;q=0.5'
Access_Control_Request_Headers= None
Access_Control_Request_Method= None
Authorization= None
Cache_Control= 'max-age=0'
Connection= 'keep-alive'
Content_Length= None
Content_MD5= None
Content_Type= None
Cookie = None
DNT = None
Date = None
Expect = None
Forwarded = None
From = Non
Front_End_Https= None
HTTP2_Settings= None
Host = 'testphp.vulnweb.com'
If_Match = None
If_Modified_Since= None
If_None_Match= None
If_Range = None
If_Unmodified_Since= None
Keep_Alive= None
Max_Forwards= None
Origin = None
Permanent = None
Pragma = None
Proxy_Authorization= None
Proxy_Connection= None
Range = None
Referer = 'http://testphp.vulnweb.com/login.php

The above block shows the contents of the packet. The line that starts with ###[text]### is called a layer. The lines after that are the fields that come under that layer until the next layer is encountered. For instance, from the above block, ###[ Ethernet ]### is a layer and the following lines are the fields under the Ethernet. These fields contain information about Ethernet. Similarly, ###[ TCP ]###, ###[ HTTP Request ]###, etc. are layer. Now, let's jump to the process_packet function.

Function — process_packet(packet)

This function needs the sniffed packet as an input. In this function, we are first checking if the packet has a HTTP Request layer. This is done by using a method provided by scapy called haslayer(). If the packet does not has the layer then it is not processed.

If it has the HTTP Request layer then, we perform two operations:

  1. Call get_url(packet) function to extract URL from the packet. It takes the packet as an input. This function returns a URL, we store this is in a variable called url and then we print the value of url.
  2. Then we call another function called get_credentials(packet). It also takes packet as an input. It checks the packet for possible credentials and if found any then it returns those credentials. We store it in a variable named cred and then we print its value.

I’ll explain get_url(packet) and get_credentials(packet) functions in the later steps.

Step 5: Writing the get_url(packet) function

Function — get_url(packet)

The get_url(packet) function also needs a packet as an input to extract the URL within the packet. The function extracts the contents of theHost and Path subfields of the HTTPRequest layer of the packet. We then join both the parts and return the URL extracted from the packet. The following is an example of the contents present in Host and Path subfields.

Path      = '/login.php'
Host = 'testphp.vulnweb.com'

The code packet[http.HTTPRequest] allows us to access the layers and is possible because of Scapy.

Step 6: Writing the get_credentials(packet) function

Function — get_credentials(packet)

In the above code, you can see a Python tuple named keywords . Before understanding why it is required let's understand the function itself.

This function also needs a packet to work with. Now, when we looked at the contents of the packet at the beginning of step 4, there was no such layer called Raw . This layer is crucial for what we are trying to achieve because the additional information such as credentials is added to the Raw layer. The below code block shows the Raw layer. It also shows that the credentials are stored inside a subfield called load.

###[ Raw ]###
load = 'uname=hdhd&pass=hshs'

Now back to the function. At first, the function checks whether the packet has the Raw layer. If the packet has the layer, then it extracts the value of the load subfield and stores it in a variable called field_load.

The next step is using a for loop to loop over the tuple we discussed earlier. The tuple contains the keywords that are potential names of the form fields used at the time of making an HTML Form. These keywords are derived by guessing common names given to HTML Form elements that are used to design HTML Signup and Login forms.

The for loop loops over each element in the tuple and checks whether any of the keywords is present the field_load variable. If anyone keyword matched then the field_load is returned to the process_packet(packet) function to display potential credentials.

Step 7: Final Step

Now, all that's left to do is call get_args() and sniffer(interface) function.

Call the sniffer function

With this, we complete the entire script and all that's left to do is test it.

Entire Script

Entire Script

Working Demo

Okay, before jumping to writing the code in Python I’ll tell you about the setup that I have: I am currently on Windows 10 and I have Virtualbox running with two VMs (1. Kali Linux and 2. Windows 10). I will execute the python script that we made in Part 1 — ARP Spoofing on my Kali Linux machine and attack my Windows 10 VM to become Man In The Middle. Then, I’ll execute the packet sniffer script from this part on my Kali Linux Machine. After that, I’ll log in to a website and see whether the sniffer script is able to extract the credentials or not.

Note: The VMs are configured to use NatNetwork in Virtualbox. When the VMs are set to use NatNetwork, the VMs thinks the host as the router (access point). To know more about NatNetwork and how to configure a VM to use it, read this.

Note: The packet sniffer only works on websites using the HTTP protocol. It does not work with HTTPS. To test, use this website — Test Vuln Login.

Kali Linux Machine

  • IP Address = 10.0.2.9
  • MAC Address = 08:00:27:35:21:2e

Windows 10

  • IP Address = 10.0.2.15
  • MAC Address = 08:00:27:e6:e5:59

Access Point or Default Gateway

  • IP Address = 10.0.2.1
  • MAC Address = 52:54:00:12:35:00
Becoming Man In The Middle using ARP Spoofing
Proof that we are the MITM

MITM — Man In The Middle

Executing Packet Sniffer Script
Testing Form
Testing Form with credentials
Extracted URLs
Extracted Credentials

In the above image, you can see that we have extracted the captured username and password from the packet that was sniffed. In the testing form, we entered username = test_user and password = test_user123 and in the above image, you can see that we are getting the same username and password value in the output.

Conclusion

We successfully wrote a Python 🐍 script to capture packets. We also tested it with Man In The Middle Attack — ARP Spoofing. The script works perfectly as we wanted it to.

You can find the entire script on my Github Repository. Thank You 😃 for reading.

--

--