This week I have decided to try something a little different... a boot2root capture the flag challenge. I grabbed the first beginner/moderate level one that caught my eye on vulnhub.com: Impossible Mission Force by geckom.
Despite never attempting a CTF, I was confident enough in my ability to try it blindly and began setting up a lab environment. I configured a private network with VirtualBox to isolate and connect a fresh Kali Linux VM with the IMF VM.
Once set up, I kicked things off with a full network scan to discover the address of the target.
Nmap yields both the target address and a quick port scan reveals a potential web server on port 80. Let's check it out...
A minimal website greets us with three static pages immediately available. On the contact page there was a potential attack surface in the form. I inspected the source to see if the submit button was actually functional and was pleasantly surprised.
The public facing contact information of three individuals under this fictitious agency are marked as a flag! The flag appears to have a base64 string embedded in it, so I did a quick decode and it yielded the string "allthefiles".
At this point, I could begin attacking the web form, but I was headed to bed at the time and thought I'd run a directory brute force search on the server over night. Dirbuster is a very loud tool, as any brute force is, and I hadn't used it before. Luckily it ships with a very straightforward Java UI. Here was the simple scan I configured:
Here were the results:
I checked out each of the javascript files and did a quick exploit-db lookup on the bootstrap, WOW, and jQuery versions that I found. Nothing of interest came up and I turned to the oddly named files. With names like that I expected the files to be packed and obfuscated but strangely enough, they weren't. After reading through their source I couldn't find any leads so I took a step back to attack the contact form.
I tried a few manual XSS and SQLi scripts from a handy cheatsheet but nothing worked. I ran a nikto scan on the target and had a quick flashback to when a friend of mine ported perl to iOS 3 so that we could use nikto.
Anyways, It didn't give me anything interesting other than a newly discovered apache default file: "/icons/README". I opened it up and was disappointed to find that it was unmodified.
I spent a few hours stuck at this point before I finally understood the hint from flag 1. I combined the odd javascript filenames into one string and base64 decoded it:
"flag2{aW1mYWRtaW5pc3RyYXRvcg==}"
Well that was pretty simple... and when we base64 decode the embedded string on this flag we get: "imfadministrator". A likely username for future use? But since there's no login page on the server and no other open ports I had no idea where to use it. So I just put it as the only entry in a new wordlist and re-ran dirbuster with as many file extensions as I could think of.
My hunch wasn't quite right, but a new directory was discovered on the server. Browsing to the new page yields a login page:
And immediately looking at the source:
I tried test:test to see what would happen and the response was identical to the first but with an "Invalid Username" warning. A server that validates usernames to unknown users? Interesting... So now I tried imfadministrator:test to confirm that its a valid account. But it wasn't...
I tried each of the three usernames indicated from the contact page, and rmichaels was a valid account.
The HTML comment implies that SQL is not going to be the solution. Since I'm new to web attacks, the only tool I had any experience with was thc-hydra. I read through the documentation and ran it with the following configuration:
hydra -s 80 -l rmichaels -P /usr/share/wordlists/rockyou.txt -t 16 -w 15 -m '/imfadministrator/index.php:user=^USER^&pass=^PASS^:Invalid password' 192.168.56.101 http-post-form
Since I knew this was the only attack I could come up with on my own, I cautiously scrolled through a solution to the third flag to see if I was on the right track. Unsurprisingly, I was incorrect. The proper solution required exploiting PHP's strcmp function by turning the password field into an array. I took the time to learn why this works.
If the password was hard-coded like the HTML comment suggests, then it makes sense that strcmp is used. The expected behavior of strcmp is to return 0 for equal strings, and non-zero for different strings. However, strcmp will return null if it is asked to compare a non-string. In php, evaluating 'null==0' yields true, making an array appear to match the hardcoded password string.
So after renaming the 'pass' field to 'pass[]' and using the known username, I successfully captured flag 3:
Decoding the flag, we have "continueTOcms". Doing so brings us to a subsite with 3 pages.
I was really excited to see a potential file upload attack surface, but the "Upload Report" page was under construction. In fact the source code for all three pages was incredibly bare. I decided to take a look at our newly acquired cookie to see if there was any leads.
Nothing but a session ID. Next I decided to bring back the SQLi cheatsheet and test the pagename parameter of the site. Immediately I get a MySQL warning, but after manually messing around with the parameter I was unable to exfiltrate any information from the database. I decided to refresh my memory of sqlmap.
Since the php error indicates that the site is using the MySQL API, we can dump the database in one quick command:
sqlmap -u "http://192.168.56.101/imfadministrator/cms.php?pagename=home" --dbms mysql --cookie "PHPSESSID=168u04joc9nq0rg50bgg12g0o7" --dump
Here we can see one additional page, "tutorials-incomplete". After navigating to it, we find an image with a QR code embedded in it.
The QR code is a text type, "flag4{dXBsb2Fkcjk0Mi5waHA=}". Decoded: "uploadr942.php". Looks like I'll get to practice an upload/execute attack after all!
First I generated a php meterpreter shell payload with msfvenom:
msfvenom -p php/meterpreter/bind_tcp LPORT=6666
Upon uploading the php file, I am told that it is not a valid filetype. So I tried a whole bunch of different file extensions and made progress as a GIF. However, it was flagged as invalid file data.
So I added a GIF file header to the php file and voila... Wait a minute...
I regenerated the payload with base64 encoding, but CrappyWAF flags the use of PHP's base64decode function. So I spent a long time looking for other obfuscators and came upon this one. It uses base64 as well as rot13 encoding. So as an alternative to base64, I manually went back and rot13 encoded parts of the msfvenom payload. I eventually got one past CrappyWAF but it never called back to msfconsole...
After this, I decided to give up on a complete shell and instead go for hard-coded commands. I wrote a few custom payloads, but I couldn't run any of the system execution functions in PHP without flagging CrappyWAF. So I tried encoding those and executing them as a php script inside of a php script with eval(), but of course CrappyWAF blocked eval().
Since assert() is said to execute code just like eval(), I spent a while trying various combinations of encodings and assert() calls to no avail. I got past CrappyWAF but everything assert would output was just "1".
After many hours of frustration, I stumbled upon a poorly written article detailing a tool called Weevely. I generated a payload:
weevely generate password ~/shell6.php
Then I added a GIF header and uploaded it successfully. I connected to the shell with
weevely http://192.168.56.101/imfadministrator/uploads/a26b7651464c.gif password
and had a full shell within moments. After such a long and grueling battle with CrappyWAF, Weevely was my new favorite tool. I now had a full shell as apache's www-data user:
You can see the many different payloads I got onto the server and the final flag: flag5{YWdlbnRzZXJ2aWNlcw==} which decodes to agentservices
I think I'll save this hint to the bonus flag for another day.