Материалы моего доклада на PHDays V

kochetkov.vladimir kochetkov.vladimir
Материалы моего доклада PHDays V "Автоматическая генерация патчей для уязвимого исходного кода" можно почитать и скачать здесь. Видео с демкой встроено в презентацию.

P.S: 25 июня запланирован повтор данного доклада в формате вебинара в рамках программы Positive Technologies "Практическая безопасность".

UPD: Запись самого доклада уже также доступна здесь (нужно выбрать доклад в правой колонке, Амфитеатр/13:05).
wildwind
wildwind
06.06.2015 06:46
Здравствуйте, kochetkov.vladimir, Вы писали:

k> Материалы моего доклада PHDays V "Автоматическая генерация патчей для уязвимого исходного кода" можно почитать и скачать здесь. Видео с демкой встроено в презентацию.


Интересно.

А с какими языками умеет работать ваш Инспектор? Вы ориентированы только на шарп?
kochetkov.vladimir
kochetkov.vladimir
08.06.2015 08:40
Здравствуйте, wildwind, Вы писали:

W>А с какими языками умеет работать ваш Инспектор? Вы ориентированы только на шарп?


В текущей версии (AI2, выпущена в декабре 2014) поддерживаются PHP, Java и C#. В AI3 (планируется осенью 2015) добавится новый модуль анализа бинарных приложений (C/C++, собранных GCC, Clang и MSVC10-12 под Windows и Linux). AI4 еще толком не обсужали, но из личных хотелок, было бы неплохо реализовать в модуле бинарного анализа поддержку бинарников Delphi, и запилить поддержку Javascript и T-SQL с PL/SQL, как в виде самостоятельных модулей, так и с возможностью кросс-языкового анализа (когда поток данных проделывает путь C# -> T-SQL -> C# -> Javascript -> C#, например).
... << RSDN@Home 1.2.0 alpha 5 rev. 76>>
wildwind
wildwind
06.06.2015 07:06
Здравствуйте, kochetkov.vladimir, Вы писали:

k> Материалы моего доклада PHDays V "Автоматическая генерация патчей для уязвимого исходного кода" можно почитать и скачать


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

И что там насчет догфудинга? Есть у вас в проде такие патчи?
kochetkov.vladimir
kochetkov.vladimir
08.06.2015 08:40
Здравствуйте, wildwind, Вы писали:

W>И что там насчет догфудинга? Есть у вас в проде такие патчи?


Стоило все-таки посмотреть выступление, я там почти в самом начале ответил на этот вопрос Генерация патчей сейчас на этапе proof-of-concept и реализована только для одного модуля, в его экспериментальной ветке. Не факт, что оно вообще попадет в AI в хоть каком-то виде. Просто результаты одного из исследований, не более. Догфудинг на слайдах упомянут потому, что мы изначально писали AI для себя и под свои задачи. Внешним продуктом он стал слегка позже, но и сейчас мы гоняем его у себя на исключительно "боевых" задачах.

W>Как планируется применять эту технику? Как частичную автоматизацию рутины?


Наиболее вероятный сценарий применения — генерация подробных рекомендаций по устранению уязвимости (не общие слова, а "воткните вот сюда, вот такую проверку, вот с такой семантикой".

W>Мне кажется, никто в здравом уме не пустит в продакшен автоматически сгенерированный патч уязвимости (не проверенный и причесанный затем вручную).


Да, думаю, что так оно и есть.
... << RSDN@Home 1.2.0 alpha 5 rev. 76>>
Evgeny.Panasyuk
Evgeny.Panasyuk
08.06.2015 10:40
Здравствуйте, kochetkov.vladimir, Вы писали:

KV>Материалы моего доклада PHDays V "Автоматическая генерация патчей для уязвимого исходного кода" можно почитать и скачать здесь. Видео с демкой встроено в презентацию.


1. По идее можно использовать не только для поиска уязвимостей, но для поиска багов вообще. Например нахождение входных значений (или условий их описывающих) при которых сработает assert (естественно не для всех классов задач).
2. Насколько хорошо AI справляется со сложными циклами, рекурсией и т.п.? В презентации было упомянуто некоторое ноу-хау — справится ли оно например с напёрсточником типа quick sort?
kochetkov.vladimir
kochetkov.vladimir
09.06.2015 07:28
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>1. По идее можно использовать не только для поиска уязвимостей, но для поиска багов вообще. Например нахождение входных значений (или условий их описывающих) при которых сработает assert (естественно не для всех классов задач).


Запросто, с одним только ограничением: построение SCFG для среднего проекта может влегкую продлиться несколько часов (т.е. в фоновый процесс IDE подобное не встроишь).

EP>2. Насколько хорошо AI справляется со сложными циклами, рекурсией и т.п.? В презентации было упомянуто некоторое ноу-хау — справится ли оно например с напёрсточником типа quick sort?


"Насколько хорошо" в данном случае означает "как много частных случаев покрыто". Как только в коде появляются циклы / рекурсия он потенциально становится эквивалентным машине Тьюринга и разрешить его нетривиальные свойства в общем случае невозможно в соответствии с теоремой Райса. Посчитать символически циклы или рекурсию, условия выхода из которых не зависит от символических переменных, достаточно тривиально. Там, где зависят, возможны варианты типа всевозможных эвристик на наиболее частые сценарии условий выхода, канонизации цикла, прокрутки только первой итерации, ленивого вычисления всей конструкции (которое может никогда и не произойти, если код внутри цикла не влияет на достижимость опасной операции и значений ее аргументов, либо если опасные операции вообще отсутствуют) и т.п.

К примеру, для кода:

protected void Page_Load(object sender, EventArgs e)
{
    RecursiveCall(Request.Params["parm1"], int.Parse(Request.Params["parm2"]))
}

private void RecursiveCall(string parm, int i)
{
    if (i < 10)
    {
        RecursiveCall(i + 1);
    } else {
        Response.Write(parm)
    }
}


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

int.Parse(Request.Params["parm2"])) >= 10 ->
    Response.Write(Request.Params["parm1"]))


после чего солвер выведет, что в Request.Params["parm2"] должно быть передано значение "10", а Request.Params["parm1"] произвольный вектор XSS для точки инъекции TEXT.

В общем же случае, мы отдаем пользователю все условия, которые не удалось разрешить автоматически, для последующего ручного анализа. Это касается в т.ч. условий достижимости операций / значений внутри циклов / рекурсии, которые по каким-либо причинам не получилось посчитать символически в мере, достаточной для разрешения этих условий.
... << RSDN@Home 1.2.0 alpha 5 rev. 76>>
.
.
09.06.2015 12:29
Здравствуйте, kochetkov.vladimir, Вы писали:

Мне не очень понятно зачем делать сложные проверки?
KV>
private void RecursiveCall(string parm, int i)
KV>{
...
KV>        Response.Write(parm)
...
KV>}
KV>

Ведь такой код уже потенциально уязвим. Достаточно сделать grep по Response.Write. А откуда берётся param не важно, важно, что параметр метода надо всегда оборачивать внутрь encodeHtml. Скажем, param может браться из сессии, в которую положено из бд, в которую положено из куки, в которую положено из remote-call, в который положено из request, в который положено из дома, который построил Джек. Никакой автоматический анализ не сможет просечь подобное, либо он будет пыхтеть несколько недель в облаке.
Это можно реализовать на архитектурном уровне — тупо запретить использование Response.Write.
kochetkov.vladimir
kochetkov.vladimir
09.06.2015 01:03
Здравствуйте, ., Вы писали:

.>Ведь такой код уже потенциально уязвим. Достаточно сделать grep по Response.Write.


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

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

.>Скажем, param может браться из сессии, в которую положено из бд, в которую положено из куки, в которую положено из remote-call, в который положено из request, в который положено из дома, который построил Джек. Никакой автоматический анализ не сможет просечь подобное, либо он будет пыхтеть несколько недель в облаке.



Это называется high-order attacks и элементарно просекается на автомате вообще-то (AI умеет). У тебя в условии на значение param появляется некий поток данных, значение которого приходит из источника, не являющегося HTTP-запросом (или сетевым пакетом, в общем случае, если речь об удаленных атаках). Ты объявляешь присвоение этому потоку данных опасного значения опасной операцией и повторяешь анализ для всех точек входа, в которых достижим этот поток. В результате многократного выполнения этой процедуру у тебя на руках появляется цепочка векторов атак, последовательное выполнение которых дает эксплуатацию уязвимости в исходной опасной операции.

.>Это можно реализовать на архитектурном уровне — тупо запретить использование Response.Write.


Все опасные операции не запретишь, да и речь же не о разработке защищенного ПО, а о анализе защищенности уже имеющегося.
... << RSDN@Home 1.2.0 alpha 5 rev. 76>>
.
.
09.06.2015 02:12
Здравствуйте, kochetkov.vladimir, Вы писали:

KV>Даже в среднем проекте таких "потенциально уязвимых мест" уже будут сотни. В проектах наших клиентов, анализ защищенности которых мы проводили, их счет порой шел на тысячи. При этом реально уязвимых мест там было обычно с десяток-другой. Никто в здравом уме не станет править тысячу мест в проекте только потому, что они потенциально уязвимы. Особенно, если учесть, что далеко не все классы уязвимостей закрываются в одно действие, как инъекции. Анализ защищенности как услугу для того и заказывают, чтобы получить точную картину того, какие уязвимости нужно закрывать ASAP, на что обратить внимание в очередном релизе, а на что и вовсе забить до лучших времен.

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

.>>Скажем, param может браться из сессии, в которую положено из бд, в которую положено из куки, в которую положено из remote-call, в который положено из request, в который положено из дома, который построил Джек. Никакой автоматический анализ не сможет просечь подобное, либо он будет пыхтеть несколько недель в облаке.

KV>Это называется high-order attacks и элементарно просекается на автомате вообще-то (AI умеет). У тебя в условии на значение param появляется некий поток данных, значение которого приходит из источника, не являющегося HTTP-запросом (или сетевым пакетом, в общем случае, если речь об удаленных атаках). Ты объявляешь присвоение этому потоку данных опасного значения опасной операцией и повторяешь анализ для всех точек входа, в которых достижим этот поток. В результате многократного выполнения этой процедуру у тебя на руках появляется цепочка векторов атак, последовательное выполнение которых дает эксплуатацию уязвимости в исходной опасной операции.
А не получится ли туча false-positive, которые и будут эквивалентны правке тысячи мест? А если неаккуратно отфильтровать false-positive, то в итогде нарвёшься на false-negative...

.>>Это можно реализовать на архитектурном уровне — тупо запретить использование Response.Write.

KV>Все опасные операции не запретишь, да и речь же не о разработке защищенного ПО, а о анализе защищенности уже имеющегося.
+1
kochetkov.vladimir
kochetkov.vladimir
10.06.2015 03:40
Здравствуйте, ., Вы писали:

KV>>Это называется high-order attacks и элементарно просекается на автомате вообще-то (AI умеет). У тебя в условии на значение param появляется некий поток данных, значение которого приходит из источника, не являющегося HTTP-запросом (или сетевым пакетом, в общем случае, если речь об удаленных атаках). Ты объявляешь присвоение этому потоку данных опасного значения опасной операцией и повторяешь анализ для всех точек входа, в которых достижим этот поток. В результате многократного выполнения этой процедуру у тебя на руках появляется цепочка векторов атак, последовательное выполнение которых дает эксплуатацию уязвимости в исходной опасной операции.

.>А не получится ли туча false-positive, которые и будут эквивалентны правке тысячи мест? А если неаккуратно отфильтровать false-positive, то в итогде нарвёшься на false-negative...

Если в ходе описанной процедуры не удается найти такой вход, который бы привел к "выстреливанию" всей цепочки уже построенных векторов, то формула такой уязвимости складывается в неразрешенные условия и сообщается как потенциальная уязвимость, подлежащая ручной проверке. Таких потенциальных уязвимостей действительно может много, но тут уж никуда не денешься — чудес не бывает. По крайней мере, у пользователя есть: а) четкое понимание того, какие именно условия нужно проверить для верификации уязвимости, б) возможность скрыть все подобные результаты или отфильтровать их по степени опасности уязвимости или вообще не осуществлять поиск уязвимостей к атакам высшего порядка.
... << RSDN@Home 1.2.0 alpha 5 rev. 76>>
Evgeny.Panasyuk
Evgeny.Panasyuk
09.06.2015 01:33
Здравствуйте, kochetkov.vladimir, Вы писали:

EP>>1. По идее можно использовать не только для поиска уязвимостей, но для поиска багов вообще. Например нахождение входных значений (или условий их описывающих) при которых сработает assert (естественно не для всех классов задач).

KV>Запросто, с одним только ограничением: построение SCFG для среднего проекта может влегкую продлиться несколько часов (т.е. в фоновый процесс IDE подобное не встроишь).

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

EP>>2. Насколько хорошо AI справляется со сложными циклами, рекурсией и т.п.? В презентации было упомянуто некоторое ноу-хау — справится ли оно например с напёрсточником типа quick sort?

KV>"Насколько хорошо" в данном случае означает "как много частных случаев покрыто". Как только в коде появляются циклы / рекурсия он потенциально становится эквивалентным машине Тьюринга и разрешить его нетривиальные свойства в общем случае невозможно в соответствии с теоремой Райса.

Собственно поэтому и спрашиваю.

Вообще, то что в mainstream языках в любом месте можно написать конструкции полные по Тьюрингу — это расточительная роскошь. По-хорошему вся мощь должна быть доступна только в специально отведённых для этого местах (по типу unsafe из C#) — внутри реализаций алгоритмов/ФВП/и т.п., и не доступна для обычного кода, в котором достаточно использования уже готовых алгоритмов типа for_each, transform, accumulate, partition, sort и т.п.

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


Что такое "зависимость от символических" переменных? Достаточно двух коротких примеров с зависимостью и без.

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


Понятно, например можно неразрешённые внутренние условия включать в конечную формулу как входной/внешний параметр.
kochetkov.vladimir
kochetkov.vladimir
10.06.2015 03:40
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Несколько часов это мелочи, если оно сможет находить реальные баги — то пусть хоть целую неделю работает.


Должен признаться, возможность разработки на базе AI анализатора ошибок, не относящихся к защищенности, мы пока даже не рассматривали

EP>Вообще, то что в mainstream языках в любом месте можно написать конструкции полные по Тьюрингу — это расточительная роскошь. По-хорошему вся мощь должна быть доступна только в специально отведённых для этого местах (по типу unsafe из C#) — внутри реализаций алгоритмов/ФВП/и т.п., и не доступна для обычного кода, в котором достаточно использования уже готовых алгоритмов типа for_each, transform, accumulate, partition, sort и т.п.


Давно посещает та же мысль Более того, в критическом софте свод правил кодинга обычно направлен как раз на то, чтобы по-возможности избежать полноты по Тьюрингу и свести большую часть кода к эквивалентам конечных или детерминированных стековых автоматов с небольшой глубиной стека, чтобы код было реально исследовать автоматизированными средствами. Например, правила NASA (http://pixelscommander.com/wp-content/uploads/2014/12/P10.pdf): не используйте goto, рекурсию и ограничивайте количество итераций в цикле доказуемо-достижимой конечной величиной. Все, до свидания Тьюринг и прочие Райсы с Успенским на пару

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

EP>Что такое "зависимость от символических" переменных? Достаточно двух коротких примеров с зависимостью и без.

Неточно выразился. Правильнее "зависимость от символических переменных, с хотя бы одним неизвестным значением". Скажем, в

for(var i = Request.Params["param"].Length; i > 0; i--)


первоначальное значение i является символической переменной с единственным значением, являющимся неизвестной величиной (т.к. длина значения параметра HTTP-запроса param ограничена только спекой HTTP и настройками веб-сервера). А в

var initialValue = Request.Params["param"].Length > 10 ? 10 : 0;
for(var i = initialValue; i > 0; i--)


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

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

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

Да, оно примерно так и выглядит, только для всех неразрешенных условий используется отдельная от основной формула.
... << RSDN@Home 1.2.0 alpha 5 rev. 76>>