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
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
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 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,
chat. Let's see what these are serving.
dev has a login page using
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
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:
chat.player.htb. We'll add that hostname to our
hosts file and kick off the enumeration.
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
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.
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
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
password. We will continue to use this method to obtain the
PHP source of
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
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,
Neither set of credentials work on the
dev login page. So now we'll use them on our
SSH port. Looks like the
telegen credentials work out.
On login we get some data about our session. We see that we are in
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
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
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
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
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
su -s /bin/bash -c '/bin/bash' telegen. Once we've switched our user we can
echo our command into the
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
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.