Clicker
Last updated
Last updated
Let's start with scanning the target using Nmap
:
The Nmap
output gives us information about many open ports. Let's discuss the content of the most important of them. We can see that port 22 (SSH
) is open. On port 80, there is an Apache
HTTP server with the domain http://clicker.htb/
. On port 111 there is a RPC
, which is a remote procedure calling protocol. RPC allows you to register various services and make them available on different ports.
First, let's add the domain clicker.htb
from port 80 to /etc/hosts
:
Let's start by checking the content of the website http://clicker.htb/
. The website contains a game Clicker
:
The website allows us to register and log in. So let's create a new account:
Next, log in to the created account:
After logging in, we can only play the game or log out:
Analyzing queries in the Burp
leads us to increase our number of clicks and raise our level:
Analysis of the rest of the HTTP requests in the Burp
does not provide any other interesting information at the moment. So we have to keep looking for ways to gain a foothold.
We can use the Nmap
script called nfs-ls
, to check what directory is shared by NFS
and check its content:
Nmap returned one available directory /mnt/backups
. We can mount this directory in our system via the following command:
The -o nolock
option in the command disables file locking, which is enabled by default. This setting is sometimes required when connecting to older NFS
servers. Now we can check what it gives us.
Let's copy the file clicker.htb_backup.zip
to our directory and unzip it:
List the content of the clicker.htb
directory:
The content of the extracted clicker.htb
directory contains PHP source code for the Clicker
website. One of the more interesting files is admin.php
. At the beginning of the file, it is checked whether the user role is Admin
:
So let's look for the possibility of assigning a role to an ordinary user. In the save_game.php
file, which saves the game state, we can see that there is a check whether one of the parameters sent in the GET
query is role
:
This check is probably intended to protect against modification of the role
sent as a GET
query parameter. If we managed to bypass this limitation, we should be able to assign ourselves the Admin
role and gain access to the administrator panel, i.e. admin.php
.
Let's capture a GET
query containing the current game state using the Burp
and let's try to bypass the restrictions on the role
parameter. We can try to bypass it using CRLF injection.
Let's send one of the following payloads:
CR (%0d):
or LF (%0a):
or sending %0d%0a at once
It causes that game was saved correctly:
This machine is therefore vulnerable to CRLF Injection. Now after logging in again, we are user with Admin
role and we gain access to the administration panel:
In Administration Panel
we get information about Top players
and we can export them to txt
, json
or html
format:
After clicking the Export
button, a POST
query is sent with two parameters threshold
and extension
:
Additionally, the website does not seem to check the value of extension
parameter provided in the query, so we can set it to any value, for example php
:
After exporting the data to the txt
format, we receive the path to which the data was saved:
Let's save the top players in the txt
format. After going to the file preview, we can see that in addition to the 4 best users, the first line contains information about our current user:
Let's look at the export.php
code. On line 47 we can see that the username of the current user, which is displayed in the exported file, is stored by the nickname
:
We know that we can change the format of the exported data to any format. If we change the file format to PHP and overwrite the nickname
in a certain way, we should get a web shell.
We already know that we can add additional parameters when sending a POST
query to the save_game.php
, so we will try to modify the nickname
with this query. As a payload, we will use the following PHP web shell code:
This payload should allow us to send commands in the cmd
parameter of the GET
query:
Let's send the request via Burp
:
Then send a query that will allow us to generate a PHP file:
Now, we can use the generated file by setting the cmd
parameter to id
:
We have remote code execution. We can now try to get a reverse shell. Let's prepare the listener:
Sending the prepared payload as the value of the cmd
parameter gives a reverse shell:
Let's upgrade the shell:
We got a reverse shell as www-data
user:
In /opt/manage
directory we find 2 files belonging to the user jack
:
Let's print the file README.txt
:
The execute_query
file turns out to be a shared library:
Let's download this library to our attacking machine. To download the file on the target machine let's start the Python HTTP server:
and then download it:
Now let's decompile the execute_query
code.
The content of the main function shows that if a value other than an integer from 0 to 4 is given as an argument, the following line should be executed:
In this line, the third element from the argv
table is copied to dest
. The first element of the argv
array is the program name, and its next elements are the arguments of the call. The value of the dest
variable is set as the given argument of the execute_query
and then in the next line the following path is added to this variable:
If the file path is correct and readable, the system command running mysql is executed with the path obtained from concatenating the path /home/jack/queries/
with the string given in the argument of execute_query
application:
Everything indicates that it may be possible to read files located in the /home/jack/queries/
directory. However, we can add "../"
and try to read other files that are inaccessible to us. Because port 22 is open, we want to check whether there is an SSH key in the home directory of the user jack
. By default, the key should be located at the following path:
In this case, SSH
private key directory should be located in the following location:
Executing the following command returned the contents of the id_rsa
file:
Let's save this SSH private key as id_rsa
file on the attacking machine, Due to the fact the private key format was not returned correctly, we need to modify its beginning and end. Let's generate a key pair to see what the correct OpenSSH key format should look like:
Change deformed lines in id_rsa
to the same as in the generated ssh_test_key
private key.
Let's try to log in to SSH as jack
using private key id_rsa
:
We have successfully logged in as jack
.
We can obtain a user flag from /home/jack/user.txt
.
Let's check if jack
can run commands with sudo
privileges:
It turns out that jack
can run the /opt/monitor.sh
script with sudo
privileges without a password. So let's check the contents of the monitor.sh
script:
At the beginning of the script, a check is made whether the EUID
value is other than 0, then the user is asked to run the script as root. EUID
(Effective UID) is the user ID the process is executing. Then the PATH
variable is set and the PERL5LIB
and PERLLIB
variables are unset. Then, a the GET
request is made using curl
to the Clicker
application, more precisely to its page /diagnostic.php
. This page returns data that is stored in the data variable and then calls /usr/bin/xml_pp
with this data. Then, if the NOSAVE
variable is set to a value other than true
, echo
is used to write the data to the XML file.
Let's check what /usr/bin/xml_pp
is:
Let's look for more information about the possibility of using Perl for privilege escalation.
We can't use PERL5LIB
and PERLLIB
, due to the fact they are unset in /opt/monitor.sh
script, so we will try to use PERL5OPT
and PERL5DB
variables.
Indirectly calling the /usr/bin/xml_pp
script by calling the /opt/monitor.sh
script with sudo
permissions should allow us to add the SUID attribute to the /bin/bash
file via Perl environment variables, which should result in the ability to elevate privileges.
Let's prepare PERL5OPT
and PERL5DB
variables:
Now let's execute the /opt/monitor.sh
script with sudo
permissions, providing the prepared variables in Perl:
Then let's run the bash
shell in privileged mode and let's check who we are with the whoami
command:
We get shell as root
user.
The previous steps lead us to the root
user. The root flag can be obtained from /root/root.txt
.
The HackTricks indicates that a service on port 111 is a portmapper. Portmapper is utilized for mapping network service ports to RPC program numbers. The NFS
is running on port 2049. Due to the HackTricks , NFS allows users access files over a network as though these files were located within a local directory.
The available on HackTricks indicates that NFS does not have a built-in authentication or authorization mechanism. It also indicates that if NFS
is running with RPC
, we will probably be able to download or view some files, which may lead us to get more information about the target machine.
We will use PHP exec
payload from page:
From the we learn that it is possible to use specific Perl environment variables, as well as environment variables of other scripting languages to execute arbitrary code. For this purpose, certain environment variables must be set in a specific way. The article cites an example of a vulnerability known as perl_startup, classified as CVE-2016-1531. An for this vulnerability indicates the possibility of using variables PERL5LIB
and PERL5OPT
to code execution. The cited article also indicates the possibility of using the PERL5DB
environment variable for the same purpose:
From the Perl environment variables , it appears that the PERL5OPT
variable is used to specify the default command line switches for Perl. This variable therefore gives you the ability to influence Perl's behavior by setting command line options. Setting the PERL5OPT
variable to -d
indicates a program execution under a debugger. From the Perl help command:
According to the information from the Ubuntu , the PERL5DB
variable contains the code that runs the Perl debugger. This variable can be changed to set a different debugger or any code, that will be executed.