just another infosec blog

IMF – Walkthrough

This segment of my Vulnhub series covers the walkthrough for the IMF Boot2Root virtual machine. From the description:

IMF is a intelligence agency that you must hack to get all flags and ultimately root. The flags start off easy and get harder as you progress. Each flag contains a hint to the next flag. Difficulty: Beginner/Moderate.

Let’s dive in!

Test lab environment

My test lab consists of:

Virtual Box

Parrot OS

IMF VM

Discovery Scan

This image uses DHCP – this means no nasty setup is required. Finding the assigned IP-address is trivial:

$ sudo nmap -sn target_network/24

Service Scan

With the IP-address nailed down, let’s discover if the target has some services running:

$ sudo nmap -p1-65535 -A -T4 -sS target_ip

Nmap service scan

Only port 80 is open – fair enough.

Flag 1

Finding the first flag required some digging. I found it reading through the HTML source of each page available. The flag is in the source code for the contact.php page hidden in a comment (Base64 encoded):

Raw: flag1{YWxsdGhlZmlsZXM=}

Dec: allthefiles

What allthefiles refer to is unclear at this moment.

Flag 2

Still working on contact.php I noticed a Javascript filename that stood out. From the looks of it, it appears Base64 encoded too.

Raw: eVlYUnZjZz09fQ==.min.js

Dec: yYXRvcg==}

initial attempt didn’t make any sense. Looking at the same Javascript inclusion segment I notice other files with peculiar names:

This new string decodes to flag2{aW1mYWRtaW5pc3RyYXRvcg==}, the inner string aW1mYWRtaW5pc3RyYXRvcg== decodes to imfadministrator

String appears to be a username or a path of some sort.

Flag 3

Trying the path of least resistance I added imfadministrator to the URL and got a login form. The HTML source revealed a hint:

<!-- I couldn't get the SQL working, so I hard-coded the password. It's still mad secure through. - Roger -->

The first thing that comes to mind is that I have to exploit a PHP function comparing strings. The most likely candidate is Strcmp paired with type confusion. But first I need a decent username. Perhaps I could use one of the contact email addresses? I quickly harvest the emails on the contact page:

rmicheals@imf.local

akeith@imf.local

estone@imf.local

Researching Strcmp PHP documentation I found that when comparing an array to a string, Strcmp will return NULL. This may trigger some interesting side effects.

To exploit this I changed the name of the password field using Firefox from “pass” to “pass[]”, entered rmichaels as username and submitted the form. This’ll force Strcmp to handle “pass” as an array and Bam! The third flag!

Flag 3

Raw: flag3{Y29udGludWVUT2Ntcw==}

Dec: continueTOcms

Flag 4

Visiting that link lead me to this page:

IMF CMS

By looking at the page navigation the navigation happens through GET parameter “pagename”. Inputting a simple ” ‘ ” revealed a MySQL error message which means it’s time for some SQLInjections! For once I let SQLMap do the lifting.

Lots and lots of output later I acquire the content of the pages table holding the navigation:

id

pagename

1

upload

2

home

3

tutorials-incomplete

4

disavowlist

The table retrieved reveal one page not listed in the main navigation. Visiting “tutorials-incomplete”:

IMF Classroom QR

There’s a QR code in this picture. For those periodically reading my blog may remember I call them cows and that I don’t like them since they may lead to danger. Shoot. Anyways, I uploaded the whole image to zxing to decode it. It decodes to:

I notice that after each successful upload the upload script places a hashed comment in the HTML code:

<!-- e596c395c91f -->

I have seen this behavior before. It’s quite typical to rename uploaded files to avoid naming collisions. The next mystery is to figure out where content is uploaded to. Most naturally content would be uploaded to a folder close to home bearing a name of “upload” or something similar. I reason the following

We’re inside a confined environment, e.g. the management tool behind imfadministrator. The folder should be somewhere further down the path.

The site itself seems pretty basic following basic naming conventions.

I uploaded an image named “upload-mime.gif”. The path /imfadministrator/uploads/upload-mime.gif returns a HTTP 404. This is done to test my hypothesis on the hash comment.

Investigating the hash found in the HTML after upload, the path /imfadministrator/uploads/e596c395c91f.gif spat out the string “GIF98”. The very same string I prepped my “image” with. I consider I’ve found the image.

By the looks of it, it either misinterpreted my image or the web-server actually tried to execute the content of the image. I then prep my “gif” image with the following code:

GIF98
<?php
phpinfo();
?>

Then I uploaded it and access it by the same route as earlier. I got this:

PHPInfo triggered from GIF

OK. This begs for a shell! Wohoo! Finally! I whip out my trusty old PHP shell:

I then add a single line at the top saying “GIF98” and update my shell with my IP and desired port. Uploading the shell yields an error:

IMF Web Application Firewall (WAF)

Look at that! The author of this game actually thought of testing for fsock-open! Kudos! Back to the drawing board. Lets obfuscate the script in case the author only checks for plain strings.

I tested:

WAF recognizes “eval” function, but not “assert”

WAF recognized “base64_decode” but not “str_rot13”

WAS doesn’t recognize “urldecode”

My plan is to take the PHP shell code and URL-encode it, then encode yet again with ROT13. Upon execution I reverse the process and should be set to go! But first, my shell is somewhat badly coded. I must move the “printit” method to the top of the script since it must be initialized before being referenced. Other than that, it’s pretty much rock and roll!

This fools the file upload script. I then move on to starting a Netcat listener:

$ nc -lvp 7777

Reverse shell

After a brief look around I found the fifth flag in /var/www/html/imfadministrator/uploads:

Flag 5

It reads:

RAW: flag5{YWdlbnRzZXJ2aWNlcw==}

DEC: agentservices

Flag 6

Flag 5 seems to be a hint towards services. It’s good habit to try to identify listening services once we got a shell

Listening services

From netstat I see there are two services listening on localhost. I can’t connect to any of these due to limitations in my shell.

Further peeking around I found a reference to knockd in /etc/init.d. A quick peek at ps -aux confirms it running. Further investigation leads to the configuration file in /etc/knockd.conf. I am not allowed to read this one. Whilst in the /etc folder I navigate to the xinetd.d folder.

Xinetd.d content and agent content

The agent configuration contains references to port 7788, which I discovered earlier using netstat. Upon further investigation /usr/local/bin contains two files:

access_codes

agent

Running agent on the server I got this output:

Agent program running on server

I am closing in on this server. The file access_codes contains the text “SYN 7482,8279,9467“, which I assume is a port knock sequence. I hurry installing knockd on my Parrot computer and start knocking!

Investigating the agent executable

I decide to try to download the agent executable locally for further inspection. Whilst on target I base64 encode the agent executable:

$ cat agent| base64 -w 0

Then copy the string and save locally on Parrot in a text file, then reassembling and executing it:

$ cat agent.txt| base64 --decode > agent
$ chmod a+x agent
$ ./agent

Next step, run agent through the strings command to see if I can find something interesting:

Running “strings” on “agent” program

From this I see evidence of two places where “%s” is used which could very well be a valid injection point. Most often this can be exploited by sending way too much data into it making a overflow. I make a note of it and continues hunting for the agent id. This time by running __ltrace__command

$ ltrace agent

Ltrace on agent

By this I see that agent tests input against the value 48093572. Using this agent id and toying around I find that if send to much junk into the reporting tool it’ll crash.

Agent core dump

Exploring binary and memory

From this point on things get a bit technical. I advice you to keep the following resources at hand:

Next running agent through GDB. I had to install Peda prior to this to get better output:

$ gdb -q agent

Having fun with GDB

Having Peda installed I also got this gem of a output:

Peda ang GDB

I make a note of the EAX address 0x8048563. I’ll use this to launch my backdoor later on! Also, I need to find a offset to make this backdoor work. I use the pattern_offset.rb script from Metasploit for this:

Getting offset

Ok – quite much stuff to dig through and at time I acknowledge my reverse engineering skills are quite rusty …

Exploiting agent crashing

With the information gathered I set out to create a backdoor. For this I turn to MSFVenom creating a TCP reverse shell.

Conclusion

This game started a bit daft with quite ordinary challenges. Things got interesting at Flag 5 and Flag 6 really made my day! I got to exercise my rusty reverse engineering skills, which was fun! All in all, I am quite happy playing IMF!

If you enjoyed this walkthrough, please share and contact me on Twitter (@reedphish)!