28 Мая, 2014

Об анализе исходного кода и автоматической генерации эксплоитов

Владимир Кочетков

        В последнее время об анализе защищенности исходного кода не написал только ленивый. Оно и понятно, ведь тот парень из Gartner, как предложил рассматривать анализ исходного кода в качестве нового хайпа несколько лет назад, так до сих пор и не дал отмашку на то, чтобы прекратить это делать. А, учитывая текущее направление моей работы (участие в разработке PT Application Inspector , далее AI), и тот факт, что в последнее время годных статей на тему анализа исходного кода в общем-то не было, как-то даже странно, что до сегодняшнего дня в этом блоге не было ни одной грязной подробности на эту животрепещущую тему. Что ж, исправляюсь :)

        

Дальше »
или введите имя

CAPTCHA
Ivan Novikov
28 Мая, 2014
Привет! Спасибо! Продолжение тех же самых вопоросов. Есть задача найти уязвимость и есть задача сделать эксплоит. С точки зрения поиска уязвимостей - предложенный подход отличается от RIPS. С точки зрения посторения эксплоитов - тоже отличается. Но не в части определения точек входа. Здесь все как раз тоже самое. Разница в посторении эксплоитов в том, что предлагаемый подход предусматривает также возможность использования захардкоженых пар для функций кодирования. То есть если вы встретили base64_decode - то из конфига берется обратная к ней base64_encode и применяется для данных в payload сплоита. То есть это только встроенные функции. Плюс их реализация должна быть захардкожена в сканер. Смущают обновления, версионность, регрессии этих функций. Для явы вообще такой подход пугает, где названия функций часто ни о чем не говорят - все переопределяется в каких-то jar'никах, которые лежат в архиве, а какую из них подцепит приложение вообще ведает только конкретный класслоадер. Это все то самое, что говорил Дима - https://twitter.com/d_olex/status/471646006723883008 А второе отличие в построении сплоитов заключается в прохождению по вызовам с целью выполнения условий из констант if ($magic=="abcd"){... и фаззите какие-то комбинации типа 1,2,3 переборов. Собственно, что на докладе, что в блогпосте вопрос один - поясни, пожалуйста, какую задачу решаем? Какая постановка? Я, видать, переобщался с академическим @p3tand, но так ничего не понятно. Я хочу и дальше спорить о жизнеспособности такого подхода для явы, но не могу - так как подозреваю, что задача стояла анализировать простые РНР приложения (cgi вариации на тему)...
0 |
28 Мая, 2014
Отвечу не по порядку, если не против. >поясни, пожалуйста, какую задачу решаем Дык я обозначил ее в посте: по-максимуму переложить рутину по анализу защищенности исходников с человека на машину. Найти все уязвимости в коде и для каждой из них вывести множество факторов необходимое и достаточное для проведения успешной атаки. Если информации в базе знаний достаточно, чтобы вывести из этих факторов конкретный HTTP-запрос, то построить и его. Если нет, то передать множество факторов человеку для дальнейшей работы. >подозреваю, что задача стояла анализировать простые РНР приложения Это не так и в плане языка (я, к примеру, участвую в реализации поддержки шарпа, который все же ближе к яве), и в плане простоты: пусть не смущает тривиальный пример из поста - подход более чем оправдывает себя и на масштабных приложениях) >То есть если вы встретили base64_decode - то из конфига берется обратная к ней base64_encode и применяется для данных в payload сплоита. Да, именно так. Других вариантов-то с парными функциями особо нет, т.к. вывести по исходникам произвольной функции обратную к ней алгоритмически разрешимо только в том случае, если функция определена в виде конечного автомата (и то, с рядом существенных оговорок). С такими функциями мы работать умеем, но если функция определена не КА, либо не описана в базе знаний, то сделать что-либо дальше с ней уже не получится. Разве что только рассматривать ее, как неподвижную точку (что в большинстве случаев позволяет проскочить через функцию с минимальными потерями на этапе резолва) =/ >То есть это только встроенные функции. Не обязательно встроенные, но обязательно парные. Ничего не мешает описать в базе знаний парные функции и из популярных фреймворков, например. Функции без пары описывать нет смысла, т.к. интересующие нас их свойства мы и так выведем на этапе "фаззинга" символьной формулы. >Плюс их реализация должна быть захардкожена в сканер. Смущают обновления, версионность, регрессии этих функций. Не, хардкод их реализации не требуется. Они уже реализованы в стандартной библиотеке и фреймворках, нам ничего не мешает вызвать их реализацию прямо оттуда. Причем той версии, которая используется непосредственно в приложении. По крайней мере, в .NET с этим проблем вообще нет, да и в яве, насколько я знаю тоже (коль скоро парная функция определена - см. ниже). >Для явы вообще такой подход пугает, где названия функций часто ни о чем не говорят - все переопределяется в каких-то jar'никах, которые лежат в архиве, а какую из них подцепит приложение вообще ведает только конкретный класслоадер. Нет, разумеется речь не идет только об именах функций. В ядре .NET к примеру, пары описываются как методы конкретных типов из конкретных пространств имен, определенных (далее опционально) в конкретных сборках, конкретных версий под конкретные версии рантайма. Информация о типах в анализируемом коде также полностью доступна, за исключением совсем уж исключительных случаев (как та обезъянка + альбинос, да). В общем-то, в яве дела обстоят примерно так же за исключением того, что нам приходится использовать эвристические подходы, чтобы отрезолвить типы классов (к чему, в т.ч. и сводится задача поиска парных функций по базе знаний). Т.е. по сути эмулировать семантику класслоадеров там, где это возможно. >А второе отличие в построении сплоитов заключается в прохождению по вызовам с целью выполнения условий из констант if ($magic=="abcd"){... и фаззите какие-то комбинации типа 1,2,3 переборов. Почему только из констант? Значения для прохождения условий типа таких: if (Regex.IsMatch(str1.SubString(1,5), "^[0-9a-zA-Z]+$")) {... мы тоже успешно резолвим, в общем-то =/
0 |