Введение в XPath-инъекции | Raz0r — Web3 Security (original) (raw)
XPath (XML Path Language) – это язык, который предназначен для произвольного обращения к частям XML документа. XML (eXtensible Markup Language) – это всем известный язык разметки, с помощью которого создаются XML документы, имеющие древовидную структуру. Пример простейшего XML документа:
XPath необходим для получения конкретной информации из XML документов; это достигается путем использования специальных операторов и выражений. Обращение к элементам XML документа с помощью XPath напоминает взаимодействие с файловой системой:
/foo/bar
Этот элементарный XPath-запрос возвратит элемент bar из XML документа выше:
C другой стороны, XPath похож и на SQL, так как позволяет накладывать условия выборки. Для этого в XPath существуют логические операторы, числовые, строковые и другие функции. Образно говоря, XML документ – это база данных, а XPath – это средство, с помощью которого возможно получить из нее данные. Если провести параллель со SQL, то станет очевидным, что XPath-инъекции во многом похожи на SQL-инъекции. Для обоих типов уязвимостей главным фактором, который позволяет проводить подобного рода инъекции, является недостаточная фильтрация входных данных.
Рассмотрим классический пример: имеется XML документ, в котором хранятся данные пользователей сайта, а также уязвимый скрипт, не проверяющий поступающие от пользователя данные при авторизации:
Переменные login и password никак не проверяются, что позволяет внедрить собственный XPath-запрос в оригинальный. Если в SQL, это было бы нечто вроде abc’ OR 1=1/*, то в XPath всилу того, что в этом языке не предусмотрены символы, обозначающие комментарий, можно успешно обойти авторизацию таким образом:
‘ or 1=1 or ”=’
или еще более простым способом:
‘ or ‘1’=’1
В итоге выполнится следующий запрос и мы успешно пройдем авторизацию:
//users/user[login/text()=admin and password/text()=’‘ or ‘1’=’1′]
Если обход авторизации не был конечной целью атакующего, например ему необходимо было получить исходный пароль администратора, то в этом случае достичь успеха поможет Blind XPath Injection. Дело в том, что в XPath не существует возможности провести UNION как при SQL-инъекциях, поэтому получить строковое или численное значение из XML-документа можно только с помощью техники слепых инъекций. Если Вы знакомы с аналогичной техникой в SQL, то без труда поймете, как данный способ реализовывается в XPath. Напомню лишь, что в основе лежит разделение ответов сервера, одно из которых принимается за истинное, а другое – за ложное, что позволяет судить о правильности и неправильности выполненных запросов.
Следующие функции необходимы или могут участвовать при осуществлении Blind XPath Injection:
- int count(node-set) возвращает количество элементов в node-set
- string name([node-set]) возвращает полное имя первого тэга в множестве
- boolean contains(string, string) возвращает истину, если первая строка содержит вторую, иначе возвращает ложь
- string substring(string, number, [number]) возвращает строку вырезанную из строки начиная с указанного номера, и если указан второй номер — количество символов
- int string-length([string]) возвращает длину строки
Этих функций будет вполне достаточно для осуществления полноценной XPath-инъекции. Итак, первое, что необходимо сделать – это узнать количество тэгов, присутствующих в записи каждого пользователя:
‘] | //*[1][count(*)=’1‘] | /foo[bar=’
‘] | //*[1][count(*)=’2‘] | /foo[bar=’
‘] | //*[1][count(*)=’3‘] | /foo[bar=’
Разберем данный запрос.
‘] | //*[1][count(*)=’1′] | /foo[bar=’
этим мы закрываем ранее открытые квадратные скобки, выражения внутри которых позволяют задавать более четкие критерии для элемента, т.е. накладывать условия
‘] | //*[1][count(*)=’1’] | /foo[bar=’
снова открываем, чтобы не возникала ошибка
‘] | //*[1][count(*)=’1′] | /foo[bar=’
выражение между двумя | (логическое или) является основой нашего запроса
‘] | //*[1][count(*)=’1′] | /foo[bar=’
выделяем первый узел из всего XML документа
‘] | //*[1][count**(*)**=’1′] | /foo[bar=’
выделяем все элементы внутри этого узла
‘] | //*[1][count(*)=’1′] | /foo[bar=’
наше условие
Перебор проводим до тех пор, пока сервер не возвратит нужный ответ. Допустим мы установили, что у каждого пользователя 4 тэга, в которых хранятся их данные. Теперь необходимо получить название каждого тэга (грубо говоря, названия полей, как при SQL-инъекциях). Здесь нам поможет функция name():
‘] | //*[name(*[3])=’password’] | /foo[bar=’
Если сервер возвратит истину, то третий элемент любого узла имеет имя password
‘] | //*[name(*[*****])=’password’] | /foo[bar=’
В этом случае, если сервер возвратит истину, то один из элементов любого узла имеет имя password
Получить полные имена тэгов можно с помощью посимвольного перебора:
‘] | //*[1][substring(name(*[1]),1,1)=’a’] | /foo[bar=’
‘] | //*[1][substring(name(*[1]),1,1)=’b’] | /foo[bar=’
‘] | //*[1][substring(name(*[1]),1,1)=’c’] | /foo[bar=’
Стоит отметить, что в XPath не предусмотрена функция, которая переводила бы символы в ASCII-коды, наподобие ORD() или ASCII() в SQL.
Узнав название элемента, получаем его значение:
‘] | //*[1][substring(password,1,1)=’a’] | /foo[bar=’
‘] | //*[1][substring(password,1,1)=’b’] | /foo[bar=’
‘] | //*[1][substring(password,1,1)=’c’] | /foo[bar=’
Как при переборе названий элементов, так и их значений можно предварительно узнать количество символов:
‘] | //*[1][string-length(name(*[1]))=7] | /foo[bar=’
‘] | //*[1][string-length(password)=7] | /foo[bar=’
Таким образом, перебирая названия и значения элементов, мы можем полностью реконструировать исходный XML-документ.
Несмотря на общую схожесть SQL и XPath инъекций, они имеют ряд важных особенностей, во многом отличающие их друг от друга:
- при XPath-инъекциях необходимо знать лишь общую структуру оригинального запроса, что существенно облегчает атаку, в то время как при некоторых типах SQL-инъекций для удачной атаки нужно полностью знать весь или определенную часть запроса.
- XPath – это универсальный язык, существует лишь две его разновидности XPath версии 1.0 и 2.0; SQL имеет множество реализаций, особенности каждой из которых необходимо учитывать
- Модель доступа к элементам XML документа с помощью XPath предполагает обращение к любой его части, однако в SQL атакующий может быть ограничен определенной базой данных или лишен каких-либо привилегий
Спасибо моему другу Kuzya за его великолепную книгу “Методы атак web-приложений“, в которой он доступно осветил данный тип уязвимостей
Рекомендую почитать: