Hack the Box - Player

hack the box Jan 18, 2020

Welcome! Today we are doing the machine Player on Hack the Box. Let's jump in!

Like we normally do with every CTF box, start with nmap -sC -sV -oA player_scan. The results that come back are fairly small:

Nmap scan report for 10.10.10.145
Host is up (0.051s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 6.6.1p1 Ubuntu 2ubuntu2.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   1024 d7:30:db:b9:a0:4c:79:94:78:38:b3:43:a2:50:55:81 (DSA)
|   2048 37:2b:e4:31:ee:a6:49:0d:9f:e7:e6:01:e6:3e:0a:66 (RSA)
|   256 0c:6c:05:ed:ad:f1:75:e8:02:e4:d2:27:3e:3a:19:8f (ECDSA)
|_  256 11:b8:db:f3:cc:29:08:4a:49:ce:bf:91:73:40:a2:80 (ED25519)
80/tcp open  http    Apache httpd 2.4.7
|_http-server-header: Apache/2.4.7 (Ubuntu)
|_http-title: 403 Forbidden
Service Info: Host: player.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.42 second

So we'll run the scan again but this time against all ports; nmap -sC -sV -T4 -p- -oA player_all_ports.

Not shown: 65532 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 6.6.1p1 Ubuntu 2ubuntu2.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   1024 d7:30:db:b9:a0:4c:79:94:78:38:b3:43:a2:50:55:81 (DSA)
|   2048 37:2b:e4:31:ee:a6:49:0d:9f:e7:e6:01:e6:3e:0a:66 (RSA)
|   256 0c:6c:05:ed:ad:f1:75:e8:02:e4:d2:27:3e:3a:19:8f (ECDSA)
|_  256 11:b8:db:f3:cc:29:08:4a:49:ce:bf:91:73:40:a2:80 (ED25519)
80/tcp   open  http    Apache httpd 2.4.7
|_http-server-header: Apache/2.4.7 (Ubuntu)
|_http-title: 403 Forbidden
6686/tcp open  ssh     OpenSSH 7.2 (protocol 2.0)
Service Info: Host: player.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 27.12 seconds

These results just show one additional port open, 6686. We aren't able to SSH into these boxes. So we'll have to do some further enumeration. We can use the virtual host scanning function of nmap.

We are going to assume that the hostname of the target machine has been set to player.htb, since we didn't see it leak anywhere. We'll add it to our host file to make our lives easier. Next we'll fire off nmap with the vhosts script.

nmap -p 80 --script http-vhosts --script-args http-vhosts.domain=player.htb 10.10.10.145

We get back some much better results than a standard nmap scan.

Nmap scan report for 10.10.10.145
Host is up (0.052s latency).

PORT   STATE SERVICE
80/tcp open  http
| http-vhosts: 
| dev.player.htb : 200
| chat.player.htb : 200
|_125 names had status 403

Nmap done: 1 IP address (1 host up) scanned in 6.92 seconds

We see two vhosts listed, dev and chat. Let's see what these are serving. dev has a login page using POST requests. chat has a chat transcript. We see that they make mention of a staging location that has some items exposed. Probably another virtual host. We'll need to do a better job of enumerating. Let's use wfuzz for this.

wfuzz -c -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt --hc 400,404,403 -H "Host: FUZZ.player.htb" -u http://player.htb -t 100

Lets break down this command a bit.
-c for use colors.
-w for specifying a wordlist.
--hc will hide the responses we list, so in this case 404,400,403.
-H tells wfuzz to use headers. So in this case we are fuzzing on the headers rsponse for vhosts.
-u is our URL.
-t dictates the amount of concurrent connections.

After we let it run, we see that there are three vhosts found. Just like we thought, there is a staging vhost as well. So we will now enumerate all four hostnames we have: player.htb, dev.player.htb, staging.player.htb and chat.player.htb. We'll add that hostname to our hosts file and kick off the enumeration.

We'll use gobuster to enumeration each of the sites:

gobuster dir -r -x php -t 100 -u http://player.htb -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt -o /home/user/Documents/htb/player/player_gobust.txt

We'll repeat this command for each of the four hosts. We get the following results

player.htb

player.htb results

dev.player.htb

dev.player.htb results

chat.player.htb

chat.player.htb results

staging.player.htb

Now that we've done some enumeration, lets see what the staging site is hosting.

We are seemingly viewing production application, just being held in the staging location before deployment. We see two links, product updates and contact core team. The Product Updates page seems to loads data from internal services every 5 seconds. We know that it's using PHP. When we try to use the contact form we are redirected to an error page.

Time to load up Burpsuite and start looking at what's going on behind the scenes. When we look at the response that the contact form is giving us, we see some new information.

Fix.php is a new page that didn't show up on our initial enumeration. When we curl that resource we get nothing back. There doesn't seem like there's too much going on in the staging page. Let's visit the /launcher path we found with our enumeration and see what that has going on.

This directs us to a countdown page. When we look at what the page is doing in Burpsuite we see that every time we submit an email we get a different request.

This might be useful. After looking through all of the enumeration we've done so far, there wasn't anything that particularly stuck out to me. When I went back to read the chat again, there was mention of a source code disclosure. Researching that we come across a PHP Temporary File Source Code Disclosure. So if we try to access the temporary backup version of the code using a ~. We might be able to obtain more information.

We curl the temporary URL and we indeed get some PHP back!

We see the site is making use of JWT to give access. Lets look at what that token actually shows. We snag the cookie that we were getting via burpsuite previously and stick it into JWT.io.

Now we have a a decoded token that matches what the source we saw earlier. So we should try to modify our token's validation signature to match the one listed that will grant us access. To do this we use the verify signature portion of JWT.io. If we enter our key found earlier (_S0_R@nd0m_P@ss_) into the verify signature it should change our token. When we do this we see that our token value returns to the original JWT values?! What we can take away from this is that if we take the access_code given in the leaked PHP source (0E76658526655756207688271159624026011393) and feed it into this JWT, we should get a new JWT value back.

Now that we have a new token value, lets set that value in Burpsuite and see where it gets us.

We get a location back in our response. lets visit that location and see what it might be.

An upload page for secure media. I uploaded some text files and they came back as 'file could not be found'. When we upload an image it does work. Probably some media filtering going on. When looking at the file we see the following:

Some googling around show a few FFMpeg exploits. This and this both seem like they might fit the bill (since they are practically the same thing). We can use this exploit to obtain files from the remote system. A good start might be /var/www/backup/service_config.

We  generate the malicious AVI and upload it to the site to get our desired content. Our 'Buffed' media comes back as follows:

We now have a username and password. We will continue to use this method to obtain the PHP source of dev, fix.php and the apache sites locations. We can't get any contents of the fix.php most likley due to permissions. We do get the contents of the apache sites config.

We see another location called demo and it seems to route to dev. Let's get the content of this directory index.php. As we parse through the content we see a file called users.php.

We'll get the content of that as well.

We now have another username and a hashed or encrypted password. This time for another user, peter.

Neither set of credentials work on the dev login page. So now we'll use them on our 6686 SSH port. Looks like the telegen credentials work out.

On login we get some data about our session. We see that we are in lshell or limited shell. Most commands are forbidden in this shell scenario. We know that we're running OpenSSH 7.2. Some searching around shows that we have a relevant vulnerability. CVE-2016-3115. Here is an exploitDB posting and this is the corresponding GitHub. We can use the POC provided in the GitHub to test if it is indeed vulnerable.

It indeed is vulnerable. So we'll use it to snage our users.txt file. We'll use this process to enumerate files on the system. After enumerating other system files we will look at the fix.php file.

We now have some credentials for Peter. They don't seem to work for SSH. They might work in our dev login portal.

They do indeed work. We are greated with a web based IDE called Codiad. After reading the documentation a bit, we will create a new project in the IDE and set its path to the tmp directory. When we try to do this, we get a promp that says it should be hosted in /var/www/demo/home. So we make that the path and create the project.

From here we can create a new PHP file which will be our reverse shell.

We save our configurations for our shell file. Start up a netcat listener and browse to our newly created file.

We get a response back as www-data as expected. Now we can start enumerating the system and see what we can leverage. LinEnum shows a cron tab running PHP5 frequently. I didn't see any further usage of it in the report so we'll launch pspy64 to see if we can catch what it might be.

This looks to be the process being called. When we look at the source of the file we see that a database call is being processed every time someone uploads a file to the media system. Since this file is launched as root we should be able to append a reverse shell onto the PHP file in place already and obtain a reverse shell as root when it fires off.

We also see that there is an unserialized function in the buff.php file.

The above is considered a magic method. You can read more about them here. If we feed the ___wakeup() function serialized data, it will run it. In this case we can get the function to run the content we put into merge.log.

Here is our payload.

The above payload will add the telegen user to the sudoers file with all the access we need. next we need to convert it to a serialized string. Once we do that, we will add the code to the merge.log. When we try to do it as www-data we see that we don't have permissions but telegen does. We can switch users by calling a new shell as telegen: su -s /bin/bash -c '/bin/bash' telegen. Once we've switched our user we can echo our command into the merge.log file.

Now you can upgrade our shell with the python upgrade trick: python -c 'import pty;pty.spawn("/bin/bash")'. We should now be able to sudo su to root.

There we have it, our root flag!

Hopefully something was learned. If you found this write-up helpful, consider sending some respect my way: Lovecore's HTB Profile.

Tags

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.