Современные подходы к SAST
Владимир Кочетков
Compilable Applications Analyzers Development / Team Lead
Positive Technologies
Образовательная программа «Практическая безопасность»
Disclaimer
Контент данного доклада предоставляется на
правах грязной фантазии на тему SAST и, хотя
он действительно имеет пересечение с PT AI,
речь пойдет не столько о конкретном проекте,
сколько о технологиях, которые лежат и/или
могли бы лежать в его основе.
Идеальный сферический SAST в вакууме:
― генерация эксплоитов для верификации полученных результатов;
― генерация патчей или подробных рекомендаций по устранению недостатков;
― поддержка нескольких подходов к статическому анализу;
― работа с невалидным исходным кодом;
Идеальный сферический SAST в вакууме:
― «еще один SAST, только лучше» - не нужен, нужен ?AST, с требованиями SAST,
но лишенный его ограничений, накладываемых тьюринговой моделью
вычислений;
― анализ по универсальному представлению кода, в которое будут
транслироваться исходники на всех поддерживаемых языках;
― все неразрешенные условия достижимости, не поддающиеся анализу
фрагменты кода и прочее – должно опционально отдаваться пользователю в
виде дополнительных условий уязвимости для их ручной проверки.
Теоретические пределы SAST
«Не существует программы, разрешающей
нетривиальные свойства программ» - теорема
Райса-Успенского
Теоретические пределы SAST
«Не существует программы, разрешающей
нетривиальные свойства программ» - теорема
Райса-Успенского
==
«Статический анализ защищенности программы
невозможен»
Теоретические пределы SAST
«Не существует программы, разрешающей
нетривиальные свойства программ» - теорема
Райса-Успенского
==
«Статический анализ защищенности программы
невозможен»
Но «программа» != «реальное приложение»
Проблема останова (внезапно) разрешима для:
― малых машин Тьюринга TM(k,l): k=2,l=3 ; k=2,l=2 ; k=3,l=2 ; k=4,l=2 , где k -
число состояний, l – количество символов входного алфавита;
Проблема останова (внезапно) разрешима для:
― малых машин Тьюринга TM(k,l): k=2,l=3 ; k=2,l=2 ; k=3,l=2 ; k=4,l=2 , где k -
число состояний, l – количество символов входного алфавита;
― программ машины Тьюринга с ограниченной памятью или стековых автоматов
с ограниченным стеком: поиск циклов в графе состояний эквивалентного
конечного автомата с Sn*x вершинами, где S – размер входного алфавита, n –
объем памяти, x – число допустимых состояний программы;
Проблема останова (внезапно) разрешима для:
― малых машин Тьюринга TM(k,l): k=2,l=3 ; k=2,l=2 ; k=3,l=2 ; k=4,l=2 , где k -
число состояний, l – количество символов входного алфавита;
― программ машины Тьюринга с ограниченной памятью или стековых автоматов
с ограниченным стеком: поиск циклов в графе состояний эквивалентного
конечного автомата с Sn*x вершинами, где S – размер входного алфавита, n –
объем памяти, x – число допустимых состояний программы;
― произвольных конечных автоматов.
Следовательно, возможен и
анализ защищенности для
фрагментов кода, попадающих
под эти критерии
Анализ в частных случаях
― код без циклов и рекурсии -> конечный или стековый автомат;
― цикл или рекурсия, условие выхода которых не зависит от входных данных ->
конечный или стековый автомат;
― цикл или рекурсия, условие выхода которых зависит от входных данных,
ограниченной длины -> машина Тьюринга или стековый автомат с
ограниченной памятью;
все остальное –> увы и ах
(только динамика, только хардкор).
"Modeling Computer Insecurity" (Sophie Engle, Sean Whalen and Matt Bishop):
провести полную динамическую оценку защищенности программы можно, только
выполнив ее на всех возможных наборах входных данных.
Пределы DAST
Статическая оценка защищенности программы, даже в
соответствии с определенными для нее критериями
защищенности, является неразрешимой проблемой.
Определение соответствия текущего состояния потока
вычисления критериям защищенности, очевидно,
разрешимо
Но, разве кто-то сказал, что
нужно выполнять ВСЮ
программу?
«Выполнять отдельные
фрагменты программы на всех
возможных наборах их входных
данных» – звучит, как план
Статический анализ
подразумевает работу с
представлением кода или
процесса его выполнения
Традиционные доступные представления
― AST (абстрактное синтаксическое дерево);
― CFG (граф потока управления);
― DFG (граф потоков данных);
― PDG (граф зависимостей программы);
― CPG (граф свойств кода);
― ???
AST (абстрактное синтаксическое дерево)
CFG (граф потока управления)
DFG (граф потока данных)
DFG (граф потока данных)
DFG (граф потока данных)
DFG (граф потока данных)
DFG (граф потока данных)
DFG (граф потока данных)
DFG (граф потока данных)
PDG (граф зависимостей программы)
CPG (граф свойств кода)
Даже CPG не представляет
достаточной информации для
верификации результатов
анализа
Нужно дополнить CPG
информацией, необходимой для
построения экплоитов и
патчей/рекомендаций по
исправлению
Возможные типы статического анализа
― Сигнатурный (по AST, сводится к задаче о поиске поддеревьев в дереве):
• быстрый, даже при полном переборе;
• не учитывает семантику кода;
― Классический taint-анализ (по CPG, сводится к задачам обхода графа и поиска
в нем путей):
• просто быстрый;
• не учитывает условия достижимости, работает только с известными функциями;
― Анализ модели вычисления (по дополненному CPG и DFG, сводится к
построению и решению системы уравнений достижимости их вершин):
• учитывает все свойства анализируемой модели, может работать с незнакомыми
функциями;
• экспоненциально медленный.
Построение унифицированного
представления кода и
сигнатурный анализ
(Иван Кочуркин)
Taint-анализ
Taint-анализ
var name = Request.Params["name"];
var key1 = Request.Params["key1"];
var parm = Request.Params["parm"];
var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm);
string str1;
if (name + "in" == "admin")
{
if (key1 == "validkey")
{
str1 = Encoding.UTF8.GetString(data);
}
else
{
str1 = "Wrong key!";
}
Response.Write(str1);
}
Taint-анализ
var name = Request.Params["name"];
var key1 = Request.Params["key1"];
var parm = Request.Params["parm"];
var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm);
string str1;
if (name + "in" == "admin")
{
if (key1 == "validkey")
{
str1 = Encoding.UTF8.GetString(data);
}
else
{
str1 = "Wrong key!";
}
Response.Write(str1);
}
Taint-анализ
var name = Request.Params["name"];
var key1 = Request.Params["key1"];
var parm = Request.Params["parm"];
var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm);
string str1;
if (name + "in" == "admin")
{
if (key1 == "validkey")
{
str1 = Encoding.UTF8.GetString(data);
}
else
{
str1 = "Wrong key!";
}
Response.Write(str1);
}
Taint-анализ
var name = Request.Params["name"];
var key1 = Request.Params["key1"];
var parm = Request.Params["parm"];
var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm);
string str1;
if (name + "in" == "admin")
{
if (key1 == "validkey")
{
str1 = Encoding.UTF8.GetString(data);
}
else
{
str1 = "Wrong key!";
}
Response.Write(str1);
}
Taint-анализ
var name = Request.Params["name"];
var key1 = Request.Params["key1"];
var parm = Request.Params["parm"];
var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm);
string str1;
if (name + "in" == "admin")
{
if (key1 == "validkey")
{
str1 = Encoding.UTF8.GetString(data);
}
else
{
str1 = "Wrong key!";
}
Response.Write(str1);
}
Taint-анализ
var name = Request.Params["name"];
var key1 = Request.Params["key1"];
var parm = Request.Params["parm"];
var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm);
string str1;
if (name + "in" == "admin")
{
if (key1 == "validkey")
{
str1 = Encoding.UTF8.GetString(data);
}
else
{
str1 = "Wrong key!";
}
Response.Write(str1);
}
Taint-анализ
var name = Request.Params["name"];
var key1 = Request.Params["key1"];
var parm = Request.Params["parm"];
var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm);
string str1;
if (name + "in" == "admin")
{
if (key1 == "validkey")
{
str1 = Encoding.UTF8.GetString(data);
}
else
{
str1 = "Wrong key!";
}
Response.Write(str1);
}
Taint-анализ
var name = Request.Params["name"];
var key1 = Request.Params["key1"];
var parm = Request.Params["parm"];
var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm);
string str1;
if (name + "in" == "admin")
{
if (key1 == "validkey")
{
str1 = Encoding.UTF8.GetString(data);
}
else
{
str1 = "Wrong key!";
}
Response.Write(str1);
}
― невозможно автоматизировать верификацию результатов;
― не учитываются условия достижимости опасной операции;
― семантика трансформирующих операций определяется исключительно базой
знаний;
― подход применим только к классам уязвимостей к атакам, основанным на
передаче в опасную операцию конкретных значений аргументов.
Недостатки taint-анализа
Абстрактная интерпретация:
символическое выполнение
AI, SE и PE
Абстрактная интерпретация (AI) – интерпретация семантики кода без его
выполнения в рамках некоторой семантической модели.
Символическое выполнение (SE) – абстрактная интерпретация кода в рамках
семантической модели потоков данных и потоков управления.
Частичное выполнение (PE) – конкретное выполнение отдельных фрагментов
кода в заданном контексте.
SE на пальцах
(x – неизвестная переменная, sqrt – неизвестная функция)
2x^2 + 4 = 12
2x^2 = 12 - 4
2x^2 = 12 - 4
x^2 = (12 - 4) / 2
x = sqrt((12 - 4) / 2)
x = sqrt((8) / 2)
x = sqrt(4)
x = 2
PT SE
Контекстуальное символическое выполнение – символическое выполнение кода с
целью построения контекстуального графа символического выполнения (SECG).
SECG изоморфен CPG, но позволяет также получить формулу достижимости
любых значений потоков данных в любой точке потока выполнения.
Формула достижимости опасных потоков данных в точке выполнения опасной
операции – формула уязвимости.
По формуле уязвимости строится уравнение, решение которого позволяет
построить контекстный вектор атаки.
Symbolic Execution Context Graph
ε {}
Symbolic Execution Context Graph
ε {
parm' {
ε Request.Params["parm1"]
}
}
Symbolic Execution Context Graph
Request.Params["cond1"] == "true" {
parm' {
ε Request.Params["parm1"]
}
}
Symbolic Execution Context Graph
Request.Params["cond1"] != "true" {
parm' {
Request.Params["cond1"] != "true"
Request.Params["parm1"]
}
}
Symbolic Execution Context Graph
Request.Params["cond1"] != "true"
&&
Request.Params["cond2"] == "true" {
parm' {
Request.Params["cond1"] != "true"
Request.Params["parm1"]
}
}
Symbolic Execution Context Graph
Request.Params["cond1"] != "true"
&&
Request.Params["cond2"] != "true" {
parm' {
Request.Params["cond1"] != "true"
Request.Params["parm1"]
}
}
Symbolic Execution Context Graph
Request.Params["cond1"] != "true" {
parm' {
Request.Params["cond2"] == "true"
Request.Params["parm2"]
||
Request.Params["cond2"] != "true"
"<div>Harmless value</div>"
}
}
ОК, модель построена. Но как ее
анализировать? Как строить
формулы и для каких вершин?
Формальные признаки инъекции
― Потенциально уязвимая операция PVO(text): операция прямой или косвенной
интерпретации текста text на формальном языке
― text = transform(argument), где argument – элемент множества аргументов
точки входа EP, а transform – функция промежуточных преобразований
― Существует и достижимо хотя бы одно множество таких значений элементов
EP, при которых происходит изменение структуры синтаксического дерева
значения text, достигающего PVO
Формализуемость уязвимостей к атакам
Строго формализуемые Слабо формализуемые
Injections Access Control
Buffer Overflow Session Management
Heap Overflow CSRF
Integer Overflow Concurrency
Memory Management Domain(Logical)
… …
Request.Params["cond1"] != "true" {
parm' {
Request.Params["cond2"] == "true"
Request.Params["parm2"]
||
Request.Params["cond2"] != "true"
"<div>Harmless value</div>"
}
}
Symbolic Execution Context Graph
По SECG для каждой PVO выводится формула уязвимости
Формула уязвимости
Request.Params["cond1"] != "true" ⇒
Response.Write(
"<a href="" +
parm ∈ {
Request.Params["cond2"] == "true" ⇒
Request.Params["parm2"]
;
Request.Params["cond2"] != "true" ⇒
"<div>Harmless value</div>"
}
+ "">"
)
Формула уязвимости
Request.Params["cond1"] != "true" ⇒
Response.Write(
"<a href="" +
parm ∈ {
Request.Params["cond2"] == "true" ⇒
Request.Params["parm2"]
}
+ "">"
)
Формула уязвимости
Request.Params["cond1"] != "true"
&&
Request.Params["cond2"] == "true" ⇒
Response.Write(
"<a href="" + Request.Params["parm2"] + "">"
)
Формула уязвимости
Request.Params["cond1"] != "true"
&&
Request.Params["cond2"] == "true" ⇒
Response.Write(
"<a href="" + Request.Params["parm2"] + "">"
)
Значение Request.Params["parm2"], определяемое типом точки инъекции,
приводит к выходу за пределы токена
<a href=" ">
Тип точки инъекции вычисляется синтаксической эвристикой в результате
прохода по уязвимому выражению в обе стороны от нее или с помощью
парсеров дополненных грамматик
Вычисление типа точки инъекции
Формула уязвимости
Request.Params["cond1"] != "true"
&&
Request.Params["cond2"] == "true"
&&
(Request.Params["parm2"] == ""><script>alert(0)</script>"
||
Request.Params["parm2"] == ""onmouseover="alert(0)") ⇒
Response.Write(
"<a href="" + Request.Params["parm2"] + "">"
)
Формула уязвимости
Request.Params["cond1"] != "true"
&&
Request.Params["cond2"] == "true"
&&
(Request.Params["parm2"] == ""><script>alert(0)</script>"
||
Request.Params["parm2"] == ""onmouseover="alert(0)") ⇒
Response.Write(
"<a href="" + Request.Params["parm2"] + "">"
)
В результате нахождения значений неизвестных в условии
формулы, строится символический вектор атаки
м
м
Символический вектор атаки
Уязвимое выражение:
"<a href="" + Request.Params["parm2"] + "">"
Тип точки инъекции:
HTML: 2-quoted attribute value
Векторные переменные:
Request.Params["parm2"] = ""><script>alert(0)</script>"
Условные переменные:
Request.Params["cond1"] = "__AI_akhivldp"
Request.Params["cond2"] = "true"
А как же ограничения
тьюринговой модели?
Частичное выполнение и обратные функции
var name = Request.Params["name"];
var key1 = Request.Params["key1"];
var parm = Request.Params["parm"];
var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm);
string str1;
if (name + "in" == "admin")
{
if (key1 == "validkey")
{
str1 = Encoding.UTF8.GetString(data);
}
else
{
str1 = "Wrong key!";
}
Response.Write(str1);
}
Частичное выполнение и обратные функции
string.IsNullOrEmpty("<script>alert(/XSS/)</script") =>
str1 = Encoding.UTF8.GetString(
Convert.FromBase64String(
"<script>alert(/XSS/)</script"
)
)
Частичное выполнение и обратные функции
true =>
str1 = Convert.ToBase64String (
Encoding.UTF8.GetBytes(
"<script>alert(/XSS/)</script"
)
)
Частичное выполнение и обратные функции
true =>
str1 = Convert.ToBase64String (
[…] // массив непечатных байт
)
Частичное выполнение и обратные функции
true =>
str1 = PHNjcmlwdD5hbGVydCgvWFNTLyk8L3NjcmlwdA==
Частичный фаззинг
Пусть Tf – множество трансформирующих функций с известной семантикой с
мощностью n.
Пусть С– множество всех сочетаний из n по k (k=1..3 хватит всем).
Тогда, для заданной строки s имеем возможных преобразований –
элементов размеченного множества St.
Тогда, имея результат преобразования s с помощью исследуемой функции f,
можем выполнить поиск его значения в St , тем самым, определяя семантику f.
Отложенная интерпретация
Интерпретация фрагментов кода, не имеющих побочных эффектов на внешний
контекст, может быть отложена на этап решения формулы уязвимости.
При решении формулы уязвимости каждый отложенный фрагмент
специфицируется текущими предполагаемыми значениями неизвестных и
выполняется конкретно, с помощью песочницы частичного выполнения.
Это позволит интерпретировать значительный процент циклов и рекурсивных
вызовов.
Все прочие неинтерпретированные фрагменты должны быть включены в
дополнительные условия уязвимости.
Вопросы?
Владимир Кочетков
vkochetkov@ptsecurity.com
@kochetkov_v
Compilable Applications Analyzers Development / Team Lead
Positive Technologies
Использованные материалы
― «Modeling and Discovering Vulnerabilities with Code Property Graphs», Fabian
Yamaguchi , Nico Golde , Daniel Arp and Konrad Rieck, https://goo.gl/zSuq1U
― «Modeling Computer Insecurity», Sophie Engle, Sean Whalen and Matt Bishop,
http://goo.gl/B9izbc
Современные подходы к SAST

Современные подходы к SAST

  • 2.
    Современные подходы кSAST Владимир Кочетков Compilable Applications Analyzers Development / Team Lead Positive Technologies Образовательная программа «Практическая безопасность»
  • 3.
    Disclaimer Контент данного докладапредоставляется на правах грязной фантазии на тему SAST и, хотя он действительно имеет пересечение с PT AI, речь пойдет не столько о конкретном проекте, сколько о технологиях, которые лежат и/или могли бы лежать в его основе.
  • 4.
    Идеальный сферический SASTв вакууме: ― генерация эксплоитов для верификации полученных результатов; ― генерация патчей или подробных рекомендаций по устранению недостатков; ― поддержка нескольких подходов к статическому анализу; ― работа с невалидным исходным кодом;
  • 5.
    Идеальный сферический SASTв вакууме: ― «еще один SAST, только лучше» - не нужен, нужен ?AST, с требованиями SAST, но лишенный его ограничений, накладываемых тьюринговой моделью вычислений; ― анализ по универсальному представлению кода, в которое будут транслироваться исходники на всех поддерживаемых языках; ― все неразрешенные условия достижимости, не поддающиеся анализу фрагменты кода и прочее – должно опционально отдаваться пользователю в виде дополнительных условий уязвимости для их ручной проверки.
  • 6.
    Теоретические пределы SAST «Несуществует программы, разрешающей нетривиальные свойства программ» - теорема Райса-Успенского
  • 7.
    Теоретические пределы SAST «Несуществует программы, разрешающей нетривиальные свойства программ» - теорема Райса-Успенского == «Статический анализ защищенности программы невозможен»
  • 8.
    Теоретические пределы SAST «Несуществует программы, разрешающей нетривиальные свойства программ» - теорема Райса-Успенского == «Статический анализ защищенности программы невозможен» Но «программа» != «реальное приложение»
  • 9.
    Проблема останова (внезапно)разрешима для: ― малых машин Тьюринга TM(k,l): k=2,l=3 ; k=2,l=2 ; k=3,l=2 ; k=4,l=2 , где k - число состояний, l – количество символов входного алфавита;
  • 10.
    Проблема останова (внезапно)разрешима для: ― малых машин Тьюринга TM(k,l): k=2,l=3 ; k=2,l=2 ; k=3,l=2 ; k=4,l=2 , где k - число состояний, l – количество символов входного алфавита; ― программ машины Тьюринга с ограниченной памятью или стековых автоматов с ограниченным стеком: поиск циклов в графе состояний эквивалентного конечного автомата с Sn*x вершинами, где S – размер входного алфавита, n – объем памяти, x – число допустимых состояний программы;
  • 11.
    Проблема останова (внезапно)разрешима для: ― малых машин Тьюринга TM(k,l): k=2,l=3 ; k=2,l=2 ; k=3,l=2 ; k=4,l=2 , где k - число состояний, l – количество символов входного алфавита; ― программ машины Тьюринга с ограниченной памятью или стековых автоматов с ограниченным стеком: поиск циклов в графе состояний эквивалентного конечного автомата с Sn*x вершинами, где S – размер входного алфавита, n – объем памяти, x – число допустимых состояний программы; ― произвольных конечных автоматов.
  • 12.
    Следовательно, возможен и анализзащищенности для фрагментов кода, попадающих под эти критерии
  • 13.
    Анализ в частныхслучаях ― код без циклов и рекурсии -> конечный или стековый автомат; ― цикл или рекурсия, условие выхода которых не зависит от входных данных -> конечный или стековый автомат; ― цикл или рекурсия, условие выхода которых зависит от входных данных, ограниченной длины -> машина Тьюринга или стековый автомат с ограниченной памятью; все остальное –> увы и ах (только динамика, только хардкор).
  • 14.
    "Modeling Computer Insecurity"(Sophie Engle, Sean Whalen and Matt Bishop): провести полную динамическую оценку защищенности программы можно, только выполнив ее на всех возможных наборах входных данных. Пределы DAST Статическая оценка защищенности программы, даже в соответствии с определенными для нее критериями защищенности, является неразрешимой проблемой. Определение соответствия текущего состояния потока вычисления критериям защищенности, очевидно, разрешимо
  • 15.
    Но, разве кто-тосказал, что нужно выполнять ВСЮ программу?
  • 16.
    «Выполнять отдельные фрагменты программына всех возможных наборах их входных данных» – звучит, как план
  • 17.
    Статический анализ подразумевает работус представлением кода или процесса его выполнения
  • 18.
    Традиционные доступные представления ―AST (абстрактное синтаксическое дерево); ― CFG (граф потока управления); ― DFG (граф потоков данных); ― PDG (граф зависимостей программы); ― CPG (граф свойств кода); ― ???
  • 19.
  • 20.
    CFG (граф потокауправления)
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
    Даже CPG непредставляет достаточной информации для верификации результатов анализа
  • 31.
    Нужно дополнить CPG информацией,необходимой для построения экплоитов и патчей/рекомендаций по исправлению
  • 32.
    Возможные типы статическогоанализа ― Сигнатурный (по AST, сводится к задаче о поиске поддеревьев в дереве): • быстрый, даже при полном переборе; • не учитывает семантику кода; ― Классический taint-анализ (по CPG, сводится к задачам обхода графа и поиска в нем путей): • просто быстрый; • не учитывает условия достижимости, работает только с известными функциями; ― Анализ модели вычисления (по дополненному CPG и DFG, сводится к построению и решению системы уравнений достижимости их вершин): • учитывает все свойства анализируемой модели, может работать с незнакомыми функциями; • экспоненциально медленный.
  • 33.
    Построение унифицированного представления кодаи сигнатурный анализ (Иван Кочуркин)
  • 34.
  • 35.
    Taint-анализ var name =Request.Params["name"]; var key1 = Request.Params["key1"]; var parm = Request.Params["parm"]; var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm); string str1; if (name + "in" == "admin") { if (key1 == "validkey") { str1 = Encoding.UTF8.GetString(data); } else { str1 = "Wrong key!"; } Response.Write(str1); }
  • 36.
    Taint-анализ var name =Request.Params["name"]; var key1 = Request.Params["key1"]; var parm = Request.Params["parm"]; var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm); string str1; if (name + "in" == "admin") { if (key1 == "validkey") { str1 = Encoding.UTF8.GetString(data); } else { str1 = "Wrong key!"; } Response.Write(str1); }
  • 37.
    Taint-анализ var name =Request.Params["name"]; var key1 = Request.Params["key1"]; var parm = Request.Params["parm"]; var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm); string str1; if (name + "in" == "admin") { if (key1 == "validkey") { str1 = Encoding.UTF8.GetString(data); } else { str1 = "Wrong key!"; } Response.Write(str1); }
  • 38.
    Taint-анализ var name =Request.Params["name"]; var key1 = Request.Params["key1"]; var parm = Request.Params["parm"]; var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm); string str1; if (name + "in" == "admin") { if (key1 == "validkey") { str1 = Encoding.UTF8.GetString(data); } else { str1 = "Wrong key!"; } Response.Write(str1); }
  • 39.
    Taint-анализ var name =Request.Params["name"]; var key1 = Request.Params["key1"]; var parm = Request.Params["parm"]; var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm); string str1; if (name + "in" == "admin") { if (key1 == "validkey") { str1 = Encoding.UTF8.GetString(data); } else { str1 = "Wrong key!"; } Response.Write(str1); }
  • 40.
    Taint-анализ var name =Request.Params["name"]; var key1 = Request.Params["key1"]; var parm = Request.Params["parm"]; var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm); string str1; if (name + "in" == "admin") { if (key1 == "validkey") { str1 = Encoding.UTF8.GetString(data); } else { str1 = "Wrong key!"; } Response.Write(str1); }
  • 41.
    Taint-анализ var name =Request.Params["name"]; var key1 = Request.Params["key1"]; var parm = Request.Params["parm"]; var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm); string str1; if (name + "in" == "admin") { if (key1 == "validkey") { str1 = Encoding.UTF8.GetString(data); } else { str1 = "Wrong key!"; } Response.Write(str1); }
  • 42.
    Taint-анализ var name =Request.Params["name"]; var key1 = Request.Params["key1"]; var parm = Request.Params["parm"]; var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm); string str1; if (name + "in" == "admin") { if (key1 == "validkey") { str1 = Encoding.UTF8.GetString(data); } else { str1 = "Wrong key!"; } Response.Write(str1); }
  • 43.
    ― невозможно автоматизироватьверификацию результатов; ― не учитываются условия достижимости опасной операции; ― семантика трансформирующих операций определяется исключительно базой знаний; ― подход применим только к классам уязвимостей к атакам, основанным на передаче в опасную операцию конкретных значений аргументов. Недостатки taint-анализа
  • 44.
  • 45.
    AI, SE иPE Абстрактная интерпретация (AI) – интерпретация семантики кода без его выполнения в рамках некоторой семантической модели. Символическое выполнение (SE) – абстрактная интерпретация кода в рамках семантической модели потоков данных и потоков управления. Частичное выполнение (PE) – конкретное выполнение отдельных фрагментов кода в заданном контексте.
  • 46.
    SE на пальцах (x– неизвестная переменная, sqrt – неизвестная функция) 2x^2 + 4 = 12 2x^2 = 12 - 4 2x^2 = 12 - 4 x^2 = (12 - 4) / 2 x = sqrt((12 - 4) / 2) x = sqrt((8) / 2) x = sqrt(4) x = 2
  • 47.
    PT SE Контекстуальное символическоевыполнение – символическое выполнение кода с целью построения контекстуального графа символического выполнения (SECG). SECG изоморфен CPG, но позволяет также получить формулу достижимости любых значений потоков данных в любой точке потока выполнения. Формула достижимости опасных потоков данных в точке выполнения опасной операции – формула уязвимости. По формуле уязвимости строится уравнение, решение которого позволяет построить контекстный вектор атаки.
  • 48.
  • 49.
    Symbolic Execution ContextGraph ε { parm' { ε Request.Params["parm1"] } }
  • 50.
    Symbolic Execution ContextGraph Request.Params["cond1"] == "true" { parm' { ε Request.Params["parm1"] } }
  • 51.
    Symbolic Execution ContextGraph Request.Params["cond1"] != "true" { parm' { Request.Params["cond1"] != "true" Request.Params["parm1"] } }
  • 52.
    Symbolic Execution ContextGraph Request.Params["cond1"] != "true" && Request.Params["cond2"] == "true" { parm' { Request.Params["cond1"] != "true" Request.Params["parm1"] } }
  • 53.
    Symbolic Execution ContextGraph Request.Params["cond1"] != "true" && Request.Params["cond2"] != "true" { parm' { Request.Params["cond1"] != "true" Request.Params["parm1"] } }
  • 54.
    Symbolic Execution ContextGraph Request.Params["cond1"] != "true" { parm' { Request.Params["cond2"] == "true" Request.Params["parm2"] || Request.Params["cond2"] != "true" "<div>Harmless value</div>" } }
  • 55.
    ОК, модель построена.Но как ее анализировать? Как строить формулы и для каких вершин?
  • 56.
    Формальные признаки инъекции ―Потенциально уязвимая операция PVO(text): операция прямой или косвенной интерпретации текста text на формальном языке ― text = transform(argument), где argument – элемент множества аргументов точки входа EP, а transform – функция промежуточных преобразований ― Существует и достижимо хотя бы одно множество таких значений элементов EP, при которых происходит изменение структуры синтаксического дерева значения text, достигающего PVO
  • 57.
    Формализуемость уязвимостей катакам Строго формализуемые Слабо формализуемые Injections Access Control Buffer Overflow Session Management Heap Overflow CSRF Integer Overflow Concurrency Memory Management Domain(Logical) … …
  • 58.
    Request.Params["cond1"] != "true"{ parm' { Request.Params["cond2"] == "true" Request.Params["parm2"] || Request.Params["cond2"] != "true" "<div>Harmless value</div>" } } Symbolic Execution Context Graph По SECG для каждой PVO выводится формула уязвимости
  • 59.
    Формула уязвимости Request.Params["cond1"] !="true" ⇒ Response.Write( "<a href="" + parm ∈ { Request.Params["cond2"] == "true" ⇒ Request.Params["parm2"] ; Request.Params["cond2"] != "true" ⇒ "<div>Harmless value</div>" } + "">" )
  • 60.
    Формула уязвимости Request.Params["cond1"] !="true" ⇒ Response.Write( "<a href="" + parm ∈ { Request.Params["cond2"] == "true" ⇒ Request.Params["parm2"] } + "">" )
  • 61.
    Формула уязвимости Request.Params["cond1"] !="true" && Request.Params["cond2"] == "true" ⇒ Response.Write( "<a href="" + Request.Params["parm2"] + "">" )
  • 62.
    Формула уязвимости Request.Params["cond1"] !="true" && Request.Params["cond2"] == "true" ⇒ Response.Write( "<a href="" + Request.Params["parm2"] + "">" ) Значение Request.Params["parm2"], определяемое типом точки инъекции, приводит к выходу за пределы токена
  • 63.
    <a href=" "> Типточки инъекции вычисляется синтаксической эвристикой в результате прохода по уязвимому выражению в обе стороны от нее или с помощью парсеров дополненных грамматик Вычисление типа точки инъекции
  • 64.
    Формула уязвимости Request.Params["cond1"] !="true" && Request.Params["cond2"] == "true" && (Request.Params["parm2"] == ""><script>alert(0)</script>" || Request.Params["parm2"] == ""onmouseover="alert(0)") ⇒ Response.Write( "<a href="" + Request.Params["parm2"] + "">" )
  • 65.
    Формула уязвимости Request.Params["cond1"] !="true" && Request.Params["cond2"] == "true" && (Request.Params["parm2"] == ""><script>alert(0)</script>" || Request.Params["parm2"] == ""onmouseover="alert(0)") ⇒ Response.Write( "<a href="" + Request.Params["parm2"] + "">" ) В результате нахождения значений неизвестных в условии формулы, строится символический вектор атаки м м
  • 66.
    Символический вектор атаки Уязвимоевыражение: "<a href="" + Request.Params["parm2"] + "">" Тип точки инъекции: HTML: 2-quoted attribute value Векторные переменные: Request.Params["parm2"] = ""><script>alert(0)</script>" Условные переменные: Request.Params["cond1"] = "__AI_akhivldp" Request.Params["cond2"] = "true"
  • 67.
    А как жеограничения тьюринговой модели?
  • 68.
    Частичное выполнение иобратные функции var name = Request.Params["name"]; var key1 = Request.Params["key1"]; var parm = Request.Params["parm"]; var data = string.IsNullOrEmpty(parm) ? new char[0]: Convert.FromBase64String(parm); string str1; if (name + "in" == "admin") { if (key1 == "validkey") { str1 = Encoding.UTF8.GetString(data); } else { str1 = "Wrong key!"; } Response.Write(str1); }
  • 69.
    Частичное выполнение иобратные функции string.IsNullOrEmpty("<script>alert(/XSS/)</script") => str1 = Encoding.UTF8.GetString( Convert.FromBase64String( "<script>alert(/XSS/)</script" ) )
  • 70.
    Частичное выполнение иобратные функции true => str1 = Convert.ToBase64String ( Encoding.UTF8.GetBytes( "<script>alert(/XSS/)</script" ) )
  • 71.
    Частичное выполнение иобратные функции true => str1 = Convert.ToBase64String ( […] // массив непечатных байт )
  • 72.
    Частичное выполнение иобратные функции true => str1 = PHNjcmlwdD5hbGVydCgvWFNTLyk8L3NjcmlwdA==
  • 73.
    Частичный фаззинг Пусть Tf– множество трансформирующих функций с известной семантикой с мощностью n. Пусть С– множество всех сочетаний из n по k (k=1..3 хватит всем). Тогда, для заданной строки s имеем возможных преобразований – элементов размеченного множества St. Тогда, имея результат преобразования s с помощью исследуемой функции f, можем выполнить поиск его значения в St , тем самым, определяя семантику f.
  • 74.
    Отложенная интерпретация Интерпретация фрагментовкода, не имеющих побочных эффектов на внешний контекст, может быть отложена на этап решения формулы уязвимости. При решении формулы уязвимости каждый отложенный фрагмент специфицируется текущими предполагаемыми значениями неизвестных и выполняется конкретно, с помощью песочницы частичного выполнения. Это позволит интерпретировать значительный процент циклов и рекурсивных вызовов. Все прочие неинтерпретированные фрагменты должны быть включены в дополнительные условия уязвимости.
  • 75.
  • 76.
    Использованные материалы ― «Modelingand Discovering Vulnerabilities with Code Property Graphs», Fabian Yamaguchi , Nico Golde , Daniel Arp and Konrad Rieck, https://goo.gl/zSuq1U ― «Modeling Computer Insecurity», Sophie Engle, Sean Whalen and Matt Bishop, http://goo.gl/B9izbc