Initial Enumeration
Having located the VM on 192.168.189.129, we run an nmap scan to see what port action is available:
No known vulnerabilities for the services were found. Taking the ports one at a time:
21/ftp
anonymous FTP access is allowed:
PUT and MKDIR are not allowed: 550 Permission denied
Server is anonymous only so no root, or other user, access allowed
22/SSH
external ssh appears to be allowed
80/HTTP
Website found:
Dirb finds files and listable directories:
root@kali:~/temp# dirb https://192.168.189.129
—————–
DIRB v2.22
By The Dark Raver
—————–
START_TIME: Thu Aug 16 09:01:20 2018
URL_BASE: https://192.168.189.129/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
—————–
GENERATED WORDS: 4612
—- Scanning URL: https://192.168.189.129/ —-
+ https://192.168.189.129/cgi-bin/ (CODE:403|SIZE:291)
==> DIRECTORY: https://192.168.189.129/css/
+ https://192.168.189.129/development (CODE:401|SIZE:482)
==> DIRECTORY: https://192.168.189.129/img/
+ https://192.168.189.129/index (CODE:200|SIZE:334)
+ https://192.168.189.129/index.html (CODE:200|SIZE:13516)
==> DIRECTORY: https://192.168.189.129/js/
+ https://192.168.189.129/LICENSE (CODE:200|SIZE:1093)
+ https://192.168.189.129/robots (CODE:200|SIZE:21)
+ https://192.168.189.129/robots.txt (CODE:200|SIZE:21)
+ https://192.168.189.129/server-status (CODE:403|SIZE:296)
==> DIRECTORY: https://192.168.189.129/vendor/
—- Entering directory: https://192.168.189.129/css/ —-
(!) WARNING: Directory IS LISTABLE. No need to scan it.
(Use mode ‘-w’ if you want to scan it anyway)
—- Entering directory: https://192.168.189.129/img/ —-
(!) WARNING: Directory IS LISTABLE. No need to scan it.
(Use mode ‘-w’ if you want to scan it anyway)
—- Entering directory: https://192.168.189.129/js/ —-
(!) WARNING: Directory IS LISTABLE. No need to scan it.
(Use mode ‘-w’ if you want to scan it anyway)
—- Entering directory: https://192.168.189.129/vendor/ —-
(!) WARNING: Directory IS LISTABLE. No need to scan it.
(Use mode ‘-w’ if you want to scan it anyway)
—————–
END_TIME: Thu Aug 16 09:01:24 2018
DOWNLOADED: 4612 – FOUND: 8
root@kali:~/temp#
===============================================================
dirbuster
dirbuster finds some directories:
Before digging into these, let’s collect some more information with Nikto in case there is anything relevant there:
The main new info there is “The following alternatives to index were found: index.html.bak” – which might indicate a backup file.
Having checked into the directories found by dirb and dirbuster the most interesting is /development:
Checking out hte index.html.bak file:
Excellent, so a user “frank” and his password hash protecting the development path.
hash-identifier identifies it as a possible MD5(APR) hash.
Cracking the hash
After creating a hash file for John the Ripper, we run john on it and get a quick and easy win:
Thanks to an apparently lax and forgetful developer, we now, hopefully, have the credentials for the developer directory.
We’re in. We reset dirbuster up to scan from this point on and in the meantime try some obvious things given the info on the screen and again hit lucky with /developer/uploader, finding the aforementioned tool:
This is an obvious possible route to uploading a shell. The text hints that uploading code might be a bit tricky but not impossible. And trying to upload various test files, we see that it is indeed restricting uploads. It will only allow image file types (jpg, gif etc):
Simply renaming a php file to one of the allowed extensions does not work:
It appears to be able to detect image formats and a little web research comes up with a simple trick to add an identifier to the start of a file to identify it as a gif:
This is now allowed:
We now have to find the location of “my uploads path”. I tried entering in variations of “upload”, “uploaded” etc into a text file for Dirbuster to use but cannot find it. So for the time being, we move on to the, so far, unexplored port: 8011
8011/HTTP
Running dirb:
Maybe the /api/ directory is of interest:
This reveals an API capable of communicating with the Frank server on port 80.
Trying the php files in turn, the the only one that appears to exist is the files_api.php:
It’s always worth reading what the system is telling you: “no parameter called file passed to me”. So maybe a php parameter like .php?file=filename is expected here. Let’s try to see if we can find the /etc/passwd file:
A gotcha! And as it turns out, it’s not triggered by looking for “etc/passwd” but rather
this error occurs for file= anything. It could be just one big red-herring but probably not, and if it’s not then on what basis is it rejecting the request? There are various ways data can be included in HTTP requests and we know the request is not a GET request since that is rejected out of hand so it’s not unreasonable to think that whatever application is supposed to use this API might be using the POST method to send data since it’s the most common method, so let’s try that. You can’t just create a URL query string for POST data like you can GET but the curl command does it:
Great, a working LFI.
the -d option in curl is short for –data and sends a POST request with the payload after the -d, in
Incidentally there was another bit of info given to us by the author of this vulnerable box. He mentioned that the app doesn’t use JSON. This is also important since when you use curl to POST data, it create a basic default header. This is usually fine for apps/apis expecting browser-created posts like forms but might well not be for specific data like JSON. If that was the case we might need to have curl specify the data type and header, like: curl -d ‘{json}’ -H ‘Content-Type: application/json’ https://192.168.189.129/whatever
Using the LFI
So we have an LFI capable of outputting the contents of files that the www-data service has access to. In order to leverage this into a shell we’re going to need to get some data onto the server. Earlier on the port 80 site we found the file uploading service at /development/uploader/upload.php and uploaded a file but we couldn’t then find it. Maybe if we can output the contents of the upload.php file we can see where it stores the files:
So here we’ve successfully located the upload.php code on the server’s file system. And we can see the output is the same as on the website. Clearly the php is being executed by the PHP interpreter. This is great for executing our shell, once we find it, but not so good in seeing the contents of upload.php (the source code). Luckily there are some tricks we can use to get around this. Any php code is going to be executed, so how can we both see the code and yet not have it executed? We can’t but if we could encode the PHP then it wouldn’t be executed and we could decode it later. And for that we can use php filter wrapper:
As you can see we’ve prepended the file path with: php://filter/convert.base64-encode/resource= which tell the php interpreter to base64 encode the resource. I found this trick here: https://kaoticcreations.blogspot.com/2011/12/lfi-tip-how-to-read-source-code-using.html
Now we just need to decode the base64. To do this on Kali just echo the base64 code and | it to the command base64 –decode
OK so immediately we can find where uploaded files go to: $target_dir = “FRANKuploads/”;
Whilst we’re here let’s check out the code. It uses the getimagesize function to check the file is an image. I’m guessing that it expects images and throws up an error if it thinks a file isn’t an image but it’s not designed to be a comprehensive check and indeed https://php.net/manual/en/function.getimagesize.php says that it should not be used to check if a file is an image.
Uploading a webshell
Let’s see if we can find our uploaded files now:
At this point I amended the standard reverse PHP shell in Kali to point back to the Kali box’s IP and uploaded it as webshell.gif. If we just click on that or GET it via curl it will not get interpreted as PHP, rather will just throw up an image file error since PHP thinks it’s an image but it isn’t. Of course we already have a way of triggering php code via the LFI which outputs the content of any file we can access, so:
And with the netcat listener waiting we have a limited webshell:
Upgrading the shell
The first thing I tend to do is to try to upgrade the shell to at least a tty so I can check sudo status (otherwise you get a “no tty present” error). The best shell upgrade I’ve found so far is to follow this sequence, that I have in my notes:
python -c ‘import pty; pty.spawn(“/bin/bash”)’
Background the shell by pressing Ctrl-Z
on your local terminal:
echo $TERM
stty -a | head -n1
stty raw -echo
fg (will not show on screen)
export HOME=/root
export SHELL=/bin/bash
export TERM=(whatever output you got from “echo $TERM” above)
stty rows X columns Y (using the output from “stty -a | head -n1” above)
Whether we need to do all this for this particular box isn’t known at this point, but it’s easy to do and it ensures not only a tty shell but one that will interact with editors like Vi and nano properly which is often invaluable. Plus it gives you good stuff like autocomplete etc which saves lots of annoying typing. Here it is in action and you can see the sudo -l command works. I won’t bother demoing the
Before getting into privesc, I want to see what the files_api.php looks like. I did previously have a quick go at finding it but I couldn’t guess which directory it was in. Now I should be able to, and I found it in /var/anotherwww/api/:
The LFI vulnerability is clear and very simple as you’d expect and you can see the hacker alert code checking for a GET. Furthermore you can even see the commented out code for checking for someone requesting /etc/passwd, maybe put in for laughs.
Privilege Escalation
I used wget to download a couple of privesc enumeration tools into /tmp and didn’t find a lot other than a pretty old kernel for which there are several kernel exploits
searchsploit shows one for 2.6.35 but it’s not relevant so I search for < 2.6.36
Using the python module SimpleHTTPServer I set up an ad hoc webserver on the Kali box so I can wget files onto the server.
linuxprivescchecker.py mentioned the ia32syscall as a likely candidate but the “CAN BCM” one is specific to the correct Ubuntu version so I try that first. But it doesn’t work. So next I try the ia32syscall and it compiles fine on the target system and works out of the box:
Root Proof
So with root access we can now access the root directory where the root proof file should be:
Summary
This was an interesting box requiring a combination of techniques. I learned a bit:
- Thinking about the http methods being used and not just blindly going for url based LFIs
- How to use php filter to view php code
Leave a Reply