Доброго времени суток! Это первая статья из трех частей, которая посвящена базовым принцыпам автоматического поиска XSS уязвимостей в PHP коде. Опишем суть проблемы. Имеется некоторый PHP файл index.php, который потенциально уязвим. Начнем с простого PHP: <?php $bar = $foo; echo "Test variable:" . $bar; ?> Если в настройках указано register_globals = on, то переменная $bar открывает пасивную XSS уязвимость. Это можно определить просто передав в нее некотрую последовательность символов, таких как '"<> которые являются спец символами языка HTML и должны быть экранированны. Таким образом изначальный код приведем к такому виду PHP: <?php $foo = '@@@ name=foo template=\'"<> @@@'; $bar = '@@@ name=bar template=\'"<> @@@'; $bar = $foo; echo "Test variable:" . $bar; ?> Мы выполнили поиск всех переменных и вставили их в начало скрипта. Переменные все инициализированны текстовой строкой которая содержет в себе: 1. название самой переменной 2. и список уязвимых символов. Результатом выполнения скрипта будет вывод: Code: Test variable: @@@ name=foo template='"<> @@@ Отстается выполнить парсинг вывода, его можно сделать например так: PHP: // Предполагается, что $dump содержит // текстовый вывод работы предыдущего скрипта preg_match_all('/@@@(.*?)@@@/s', $dump, $matches); for($i=0;$i<count($matches[0]);$i++){ $attrs = array(); $pairs = explode(' ', $matches[1][$i]); foreach($pairs as $pair){ if(!trim($pair)) continue; preg_match('/(.*?)=(.*)/s', $pair, $match); list($null, $key, $value) = $match; $key = trim($key); $value = trim($value); $attrs[$key] = $value; } if($attrs['template'] == '\'"<>'{ // Если вывод переменной равен изначальному шаблону, то найдена уязвимость echo $attrs['name'] . '<br/>'; } } В результате автоматически найдена пасивная уязвимость, которая заключается в передаче переменной $foo любого вредоносного кода: Code: index.php?foo=<script>alert('Hello from hole')</script> Возможна ситуация, что экранируется часть символов, например \'\"<> тогда подобное сравнение не будет подходить и нужно сравнивать посимвольно. На этом пока всё, следующие статьи посвещу тому как можно обходить все ветвления программы, а не идти по одной из веток if else операторов. О том как раскрывать циклы... Пару дней назад нашей командой был открыт сервис поиска уязвимостей /thread229263.html
со скулями посложнее будет)) Идея по доработке принципа: собирать имена переменных GET и POST, но работать со скриптом не добавляя к нему свой код, а через curl. имхо очень много нюансов и подводных камней нужно учесть чтобы сделать систему, которая с большой вероятностью найдет уязвимость, которая там есть. (уязвимость не только такую простую как та что в статье, а речь о проверке безопасности) Например, регулярное выражение для проверки поля if(preg_match('#[a-z0-9]{8,15}#uis' ... Такие вещи трудно найти парсером кода... * безопасное выражение '#^[a-z0-9]{8,15}$#uis'
В основном использовал статьи по формальным грамматикам и всяким лексическим анализаторам. Эта работа мне послужала дипломом В ближайшее время планирую протестировать большинство известных скриптов интернет магазинов и CMS, расскажу что из этого получилось.
Если после проверки логина предпологается вывод его по типу Code: Привет %username% или запись в базу, то по сути происходит следующее 1. Передача параметра ?login=<...> на обработку скрипту 2. Проверка и фильтрация логина какими угодно способами 3. В итоге происходит вывод этого логина на экран либо запись переменной логина в базу. И на сколько б не был сложный и запутанный 2й этап, если в вывод попадает неэкранированная переменная то уязвимость обнаружена.
Небольшой видео обзор уже рабочей системы которая использует описанный подход http://www.youtube.com/watch?v=FwxPbFWyYyg