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

Post on 17-Jan-2017

544 views 2 download

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

Современные подходы к 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 = 122x^2 = 12 - 42x^2 = 12 - 4x^2 = (12 - 4) / 2x = 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 ManagementHeap Overflow CSRFInteger 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 LeadPositive 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