πNSA Codebreaker 2023 Writeup
Tasks Completed: 6/9
Last updated
Tasks Completed: 6/9
Last updated
As a school, UNG was able to get 2nd place !
This was also a bonus challenge/extra credit opportunity for my CYBR 3410 Database Security course for those that completed 6 or more challenges :)
NSA has two main jobs - collecting foreign signals intelligence and providing cybersecurity for the US government. As part of the latter mission, NSA works with partner agencies to provide technical assistance where our skills can be useful.
In this scenario, the US Coast Guard discovers an unidentified signal near US waters. You play the role of an NSA employee providing technical assistance to the USCG to identify and investigate the unknown object producing the signal.
Interpret and discover a signal of unknown origin identified by the USCG, locate and analyze what produced the signal, discover an active collection operation tasked by a rogue server and subvert the rogue server to stop the collection device.
"The US Coast Guard (USCG) recorded an unregistered signal over 30 nautical miles away from the continental US (OCONUS). NSA is contacted to see if we have a record of a similar signal in our databases. The Coast guard provides a copy of the signal data. Your job is to provide the USCG any colluding records from NSA databases that could hint at the objectβs location. Per instructions from the USCG, to raise the likelihood of discovering the source of the signal, they need multiple corresponding entries from the NSA database whose geographic coordinates are within 1/100th of a degree. Additionally, record timestamps should be no greater than 10 minutes apart."
File provided by the USCG contain metadata about the unknown signal (USCG.log)
NSA database of signals (database.db)
I first opened the database.db file in sqlitebrowser and changed the datatypes of longitude and latitude to "REAL" to avoid any problems when further querying the database.
Let's further analyze the database.db using sqlite3, i first used ".tables" to see what tables exist in the current database. Then i used ".schema location" to get the schema for the location table, it looks like it has 4 fields that are id, latitude, longitude, and elevation. Let's query for records matching the parameters within 1/100 of a degree. This gave us the database record ids that fit the parameters specified by the USCG.
"Thanks to your efforts the USCG discovered the unknown object by trilaterating the geo and timestamp entries of their record with the correlating entries you provided from the NSA databases. Upon discovery, the device appears to be a device with some kind of collection array used for transmitting and receiving. Further visual inspection shows the brains of the device to be reminiscent of a popular hobbyist computer. Common data and visual ports non-repsonse; the only exception is a boot prompt output when connecting over HDMI. Most interestingly there is a 40 pin GPIO header with an additional 20pin header. Many of these physical pins show low-voltage activity which indicate data may be enabled. There may be a way to still interact with the device firmware..."
"Find the correct processor data sheet, and then use it and the resources provided to enter which physical pins enable data to and from this device"
Provide the correct physical pin number to power the GPIO header
Provide a correct physical pin number to ground the board
Provide the correct physical pin number for UART transmit function
Provide the correct physical pin number for a UART receive function
Rendering of debug ports on embedded computer(pinout.svg)
Image of device (cpu.jpg)
Copy of display output when attempting to read from HDMI(boot_prompt.log)
My initial thought when looking at the pinout.svg file is that it appears to belong to a raspberry pi or micro computer of some sort.
The image of the cpu further confirms my suspicions of this belonging to a raspberry pi, and after doing a google search, the code "BCM2837RIFBG" corresponds to a Broadcom CPU, specifically the Broadcom BCM2837. This CPU is known for its use in the Raspberry Pi 3 Model B and Raspberry Pi 3 Model B+ single-board computers.
We know this is the display output when attempting to read from HDMI. Some important information to note here is the Alternative Function Assignment "ALT5", which will be useful when analyzing the alterantive function assignments for the GPIO pins later on.
Now, after some googling, i found a good pin numbering schema like the similar to the pinout.svg file that lets us see that P1 is used to power the GPIO header and P39 is ground.
To get the correct physical pin number for UART transmit and receive functions i searched up the data sheet βBROADCOM BCM2837 datasheetβ and clicked on the first link, go to page 102 for the Alternative Function assignments, here we see that for ALT5 the TXD0 and RXD0 function assignments are GPIO 32 and GPIO 33, which on the pinout.svg file translate to physical pins P55 and P56.
"Leveraging that datasheet enabled you to provide the correct pins and values to properly communicate with the device over UART. Because of this we were able to communicate with the device console and initiate a filesystem dump.
To begin analysis, we loaded the firmware in an analysis tool. The kernel looks to be encrypted, but we found a second-stage bootloader that loads it. The decryption must be happening in this bootloader. There also appears to be a second UART, but we don't see any data coming from it.
Can you find the secret key it uses to decrypt the kernel?"
U-Boot program loader binary(u-boot.bin)
Recovered device tree blob file(device_tree.dtb)
Docker source files to build the QEMU/aarch64 image(cbc_qemu_aarch64-source.tar.bz2)
A majority of the this task took quite a while due to setting up the docker image/container. So i first extracted the .tar.bz2 file and followed the commands specified in the README.md file provided. I then moved the u-boot.bin and device_tree.dtb file into a new directory called βmyfilesβ.
Following the commands in the README.md file, it was now time to build and run the container while in a directory that can reach the files in the "myfiles" directory we created.
Once in the docker container image we can export the files in the "myfiles" directory to environment variables. We'll leave this pane for now and come back to it later.
The README.md file provided specifies running two netcat listeners in two different docker shells using docker exec and specifying the docker id and shell we want to use /bin/bash. One listener listens on port 10000 and the other listening on port 10001, on two separate docker shells, in this case i used tmux to manage the panes.
On the initial pane where we exported the files into environment variables and while the two listeners are running, we ran the qemu with this command.
Switching back to the window where the βnc -l 10000β listener is running, we are now in the u-boot cli.
Once in u-boot I used βprintenvβ to see the environment variables, and I noticed βkeyaddrβ environment variable
So in this challenge we are looking for the secret key it uses to decrypt the kernel, this isnt exactly the "key" but the key address, the location where the key can be found. Printing out the contents of keyaddr using the u-boot command for memory display in the byte format starting at the $keyaddr gives us the key, ed63c773befa27922d2f18c59cce542b.
"We were able to extract the device firmware, however there isn't much visible on it. All the important software might be protected by another method. There is another disk on a USB device with an interesting file that looks to be an encrypted filesystem.
Can you figure out how the system decrypts and mounts it?
Recover the password used to decrypt it. You can emulate the device using the QEMU docker container from task 3."
Main SD card image (sd.img.bz2)
USB drive image (usb.img.bz2)
Linux Kernel (kernel8.img.bz2)
Device tree blob for emulation (bcm2710-rpi-3-b-plus-dtb.bz2)
To begin this task i first extracted the downloads above, which gave us sd.img, usb.img. kernel8.img, and bcm2710-rpi-3-b-plus-dtb. Using the file command, the usb.img appears to contain DOS/MBR boot sector info with 2 partitions that we may be able to mount.
Knowing this, I created two mount points at β/mnt/usb_mount1β and β/mnt/usb_mount2β
Mounting the 1st partition in usb.img and checking its contents we discover:
Hostname: jazzymoon
βpart.encβ file
βmount_partβ script
The part.enc file looks interesting so i made a copy of it. Knowing the challenge prompt does mention an encrypted file system, could this be it!? Surely, it is the encrypted file system, we can verify this using the file command. It looks like the part.enc file is a LUKS encrypted file.
I also decided to mount the 2nd parition on the usb.img file but it has the exact same files as the first partition. Moving on, we can go back and analyze the "mount_part" bash script we found in the first mounted partition. It looks like the script shows that the password used is the hostname plus three other characters and that it is hashed using SHA-1 before being used on the LUKS encrypted drive.
Recall that the hostname is jazzymoon, so the password used to decrypt the encrypted filesystem must be jazzymoon???.
Some things to consider though:
Does the encrypted drive accept jazzymoon???
or does it require the SHA-1 hashed form of the password?
Let's write up some python scripts to make this much easier to visualize:
Creates βunhashed_passphrases.txtβ and βhashed_passphrases.txtβ generating all possible combinations of βjazzymoon???β using the charset of abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.
βhashed_passphrases.txtβ will be used as the wordlist when we try to crack it
Does the same as Genword.py but generates the clear text and hashed password side by side into βpassphrases_combined.txtβ
This way we can easily find the cleartext and hashed password side by side when we crack part.enc
Before trying these wordlist out and trying to crack LUKS file, we must prep the file for usage with hashcat. This post was really helpful, https://diverto.github.io/2019/11/18/Cracking-LUKS-passphrases.
Now, with the generated "hashes_passphrases.txt" wordlist we can try cracking hashcat.luks file with hashcat using mode 14600 for LUKS.
We got a match! We can just look this up in the passphrases_combined.txt wordlist to see what matches this SHA-1 hash.
jazzymoona61, d8cf7f90d6b4cf2aae777f3d2de9bbcb926d16c2
We got the password, now we can decrypt the file system.
Now we can mount encrypted file system and access any files and executables we find on there. It looks like we found some executables agent, diagclient, and dropper.
"Based on the recovered hardware the device seems to to have an LTE modem and SIM card implying it connects to a GSM telecommunications network. It probably exfiltrates data using this network. Now that you can analyze the entire firmware image, determine where the device is sending data. Analyze the firmware files and determine the IP address of the system where the device is sending data."
I tried reverse engineering the executables found in the decrypted file system from Task 4 in Ghidra but no results.
I then tried binwalk on the dropper executable to extract any files and I found the IP address in a file extracted from the dropper executable.
It looks like the device is sending data to this IP, which is a mongodb database.
"While you were working, we found the small U.S. cellular provider which issued the SIM card recovered from the device:
Blue Horizon Mobile. As advised by NSA legal counsel we reached out to notify them of a possible compromise and shared the IP address you discovered.
Our analysts explained that sophisticated cyber threat actors may use co-opted servers to exfiltrate data and Blue Horizon Mobile confirmed that the IP address is for an old unused database server in their internal network.
It was unmaintained and (unfortunately) reachable by any device in their network. We believe the threat actor is using the server as a "dead drop", and it is the only lead we have to find them.
Blue Horizon has agreed to give you limited access to this server on their internal network via an SSH "jumpbox". They will also be sure not to make any other changes that might tip off the actor. They have given you the authority to access the system, but unfortunately they could not find credentials. So you only have access to the database directly on TCP port 27017.
Use information from the device firmware, and (below) SSH jumpbox location and credentials to login to the database via an SSH tunnel and discover the IP address of the system picking up a dead drop. Be patient as the actor probably only checks the dead drop periodically. Note the jumpbox IP is 100.127.0.2 so don't report yourself by mistake."
SSH private key to authenticate to jumpbox: user@external-support.bluehorizonmobile.com on TCP port 22(jumpbox.key)
First, i connected via SSH tunnel and local port forwarding to the IP discovered in task 5 on port 27017 used for mongodb.
Then i logged in to the database on the local host and the forwarded port with the credentials found in task 5.
While in the database
Enumerate the database and collections on the mongo database
Check for system profiling information
IP address found: 100.80.74.224
This year's NSA Codebreaker challenge was really fun, and i also really enjoyed putting off school work to work on this . I was also able to learn and apply new things like sqlite3, docker containers, hashcat, python scripting, working with LUKS, mongodb, Ghidra(sorry i couldnt show any, forgot to take screenshots). On the bright side i was able to get 6/9 challenges this year(got 4/9 last year)! and UNG got 2nd place