В этой статье мы рассмотрим такой тип уязвимостей в web-приложениях, как - XPath Injection.
Каждый день мы слышим сообщения о взломе веб-сайтов и обычно думаем, что хакер, который добился успеха, должен быть невероятно умным. Обычно на самом деле все наоборот. Большинство хакеров, которые портят веб-сайты, - это хакеры-новички, которые совершают эти поступки ради популярности. Веб-дизайнеры сосредотачиваются на разработке своих веб-сайтов, а хакеры - на эксплойтах.
Примечание: эта статья предназначена только для образовательных целей. Будьте частью конструктивного общества.
Веб-приложения хранят данные и получают доступ к ним различными способами и формами в зависимости от их вариантов использования. Исторически реляционные базы данных были популярным выбором среди других баз данных для хранения большого количества данных. Однако растет тенденция к использованию XML для хранения данных. При использовании XML данные хранятся во вложенной структуре в виде древа, а не столбцов и строк. У этого есть много недостатков, но его можно использовать для статических данных, таких как параметры конфигурации. Это связано с тем, что такие статические данные требуют меньше операций чтения/записи, что очень медленно происходит в базах данных XML.
При аудите веб-приложения можно легко упустить из виду определенные типы уязвимостей, если не проводить систематическую проверку каждого из них в отдельности. Инъекционные эксплойты хорошо известны, и действительно, они заняли первое место в рейтинге OWASP Top 10; однако в этой статье мы обсудим атаку, которая гораздо менее популярна, чем внедрение SQL, XPath и XQuery.
Что такое XPATH и XQuery?
XPATH - это язык, который запрашивает XML-документ, чтобы найти часть информации, элементы, соответствующие определенному шаблону или содержащие нужный атрибут. Если у клиента есть доступ к части используемого запроса XPath, и этот ввод не фильтруется, тогда клиент получит доступ ко всему XML-документу, если он сможет определить его структуру.
Данные, хранящиеся в XML, можно запрашивать через XPath, который концептуально аналогичен SQL. Это также язык запросов, который используется для поиска определенных элементов в XML-документе. Разрешения на уровне доступа отсутствуют, и можно ссылаться практически на любую часть XML-документа, в отличие от SQL, который допускает ограничения для баз данных, таблиц или столбцов.
Это связано с тем, что XPath отличается от других языков баз данных, поскольку в нем отсутствуют элементы управления доступом или аутентификация пользователей.
XQuery - это расширенный набор языка XPath, который добавляет синтаксис, подобный SQL, а также некоторые полезные функции для запросов к документу.
Что такое XPath Injection?
Проблемы, которые могут возникнуть при хранении данных с использованием XML, также аналогичны проблемам, возникающим в SQL. Внедрение XPath - это тип атаки, при которой злонамеренный ввод может привести к несанкционированному доступу или раскрытию конфиденциальной информации, такой как структура и содержимое XML-документа. Это происходит, когда ввод пользователя используется при построении строки запроса. Большое количество методов, которые можно использовать в атаке с использованием SQL-инъекции, зависят от характеристик диалекта SQL, используемого целевой базой данных, тогда как атаки с использованием XPath-инъекции могут быть гораздо более адаптируемыми и повсеместными.
Принцип XPath-инъекции очень похож на SQL-инъекцию. Цель атаки тоже очень похожа. Единственная разница между этими атаками заключается в том, что внедрение XPath использует XML-файл для хранения данных вместо базы данных. Один из способов получить данные из XML-файла, должен использоваться XPath.
В некоторых случаях параметры в теле SOAP напрямую используются в качестве входных данных для запроса xpath. Если этот ввод пользователя не подтвержден, вероятно, злоумышленник может изменить запрос Xpath по своему желанию. В худшем случае злоумышленник сможет прочитать весь запрошенный XML-документ.
- SOAP - протокол обмена структурированными сообщениями в распределённой вычислительной среде. Первоначально SOAP предназначался в основном для реализации удалённого вызова процедур (RPC). Сейчас протокол используется для обмена произвольными сообщениями в формате XML, а не только для вызова процедур. Официальная спецификация последней версии 1.2 протокола никак не расшифровывает название SOAP. SOAP является расширением протокола XML-RPC.
Подобно SQL Injection, атаки XPath Injection происходят, когда веб-сайт использует предоставленную пользователем информацию для построения запроса XPath для данных XML. Отправляя преднамеренно искаженную информацию на веб-сайт, злоумышленник может узнать, как структурированы данные XML, или получить доступ к данным, к которым у него обычно нет доступа. Они могут даже иметь возможность повысить свои привилегии на веб-сайте, если данные XML используются для аутентификации (например, файл пользователя на основе XML).
Запрос XML выполняется с помощью XPath, типа простого описательного оператора, который позволяет XML-запросу находить фрагмент информации. Как и в SQL, вы можете указать определенные атрибуты для поиска и шаблоны для сопоставления. При использовании XML для веб-сайта обычно принимают некоторую форму ввода в строке запроса, чтобы идентифицировать контент, который нужно найти и отобразить на странице. Этот ввод необходимо обработать, чтобы убедиться, что он не портит запрос XPath и не возвращает неверные данные.
XPath - стандартный язык; его нотация / синтаксис всегда не зависит от реализации, что означает, что атака может быть автоматизирована. Нет разных диалектов, как это происходит в запросах к базам данных SQL.
Поскольку нет уровня управления доступом, можно получить весь документ. Мы не столкнемся с какими-либо ограничениями, которые могут быть известны из атак с использованием SQL-инъекций.
Пример уязвимости XPath Injection
Мы будем использовать этот фрагмент XML для примеров:
<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Employee ID="1">
<FirstName>Arnold</FirstName>
<LastName>Baker</LastName>
<UserName>ABaker</UserName>
<Password>SoSecret</Password>
<Type>Admin</Type>
</Employee>
<Employee ID="2">
<FirstName>Peter</FirstName>
<LastName>Pan</LastName>
<UserName>PPan</UserName>
<Password>NotTelling</Password>
<Type>User</Type>
</Employee>
</Employees>
Предположим, у нас есть система аутентификации пользователей на веб-странице, которая использует такой файл данных для входа пользователей. После ввода имени пользователя и пароля программа может использовать XPath для поиска пользователя:
VB:
Dim FindUserXPath as String
FindUserXPath = "//Employee[UserName/text()='" & Request("Username") & "' And
Password/text()='" & Request("Password") & "']"
C#:
String FindUserXPath;
FindUserXPath = "//Employee[UserName/text()='" + Request("Username") + "' And
Password/text()='" + Request("Password") + "']";
С обычным именем пользователя и паролем этот XPath будет работать, но злоумышленник может отправить неверное имя пользователя и пароль и выбрать узел XML, не зная имени пользователя или пароля, например:
Username: blah' or 1=1 or 'a'='a
Password: blah
FindUserXPath becomes //Employee[UserName/text()='blah' or 1=1 or
'a'='a' And Password/text()='blah']
Logically this is equivalent to:
//Employee[(UserName/text()='blah' or 1=1) or
('a'='a' And Password/text()='blah')]
В этом случае истинной должна быть только первая часть XPath. Часть пароля становится неактуальной, а часть UserName будет соответствовать ВСЕМ сотрудникам из-за части «1 = 1».
Рассмотрим следующее хранилище данных XML:
<addressBook>
<address>
<firstName>William</firstName>
<surname>Gates</surname>
<password>MSRocks!</password>
<email>billyg@microsoft.com</email>
<ccard>5130 8190 3282 3515</ccard>
</address>
<address>
<firstName>Chris</firstName>
<surname>Dawes</surname>
<password>secret</password>
<email>cdawes@craftnet.de</email>
<ccard>3981 2491 3242 3121</ccard>
</address>
<address>
<firstName>James</firstName>
<surname>Hunter</surname>
<password>letmein</password>
<email>james.hunter@pookmail.com</email>
<ccard>8113 5320 8014 3313</ccard>
</address>
</addressBook>
Запрос XPath для получения всех адресов электронной почты из этого хранилища данных будет выглядеть следующим образом:
//address/email/text()
Запрос на возврат всех сведений о пользователе Dawes будет выглядеть так:
//address[surname/text()=’Dawes’]
В некоторых приложениях предоставленные пользователем данные могут быть встроены непосредственно в запросы XPath, а результаты запроса могут быть возвращены в ответе приложения или использованы для определения некоторых аспектов поведения приложения.
Давайте посмотрим, как мы можем выполнить инъекцию на этом примере. Этот код поступает из веб-приложения, которое предоставляет информацию о кредитной карте пользователям, вошедшим в него. Запрос XPath, который эффективно проверяет предоставленные пользователем учетные данные и извлекает номер соответствующей кредитной карты пользователя, может быть:
//address[surname/text()=’Dawes’ and password/text()=’secret’]/ccard/text()
Так же, как и в случае внедрения SQL-кода, злоумышленник может перехватить запрос приложения, предоставив пароль со следующим значением:
‘ or ‘a’=’a
Это приведет к следующему запросу XPath, который извлекает данные кредитных карт всех пользователей:
//address[surname/text()=’Dawes’ and password/text()=’’ or ‘a’=’a’]/ccard/text()
Помните, что в отличие от запросов SQL, ключевые слова в запросах XPath чувствительны к регистру, как и имена элементов в самом документе XML.
Чтобы продолжить, можно использовать недостатки внедрения XPath для извлечения произвольной информации из целевого XML-документа. Один из широко используемых способов сделать это, используя ту же технику, что мы видели при внедрении SQL, заставляя приложение реагировать по-разному, в зависимости от условия, указанного злоумышленником.
Отправка следующих двух операторов в поле пароля приложения приведет к разному поведению приложения. Результаты возвращаются в первом случае, но не во втором:
‘ or 1=1 and ‘a’=’a
‘ or 1=2 and ‘a’=’a
Это различие в поведении может быть использовано для проверки истинности любого указанного условия и, следовательно, для извлечения произвольной информации по одному байту за раз. Как и в случае с SQL, язык XPath содержит функцию подстроки, которую можно использовать для проверки значения строки по одному символу за раз. Например, предоставив следующий оператор:
‘ or //address[surname/text()=’Thomas’ and substring(password/text(),1,1)=‘S’] and ‘a’=’a
Это приводит к следующему запросу:
//address[surname/text()=’Mel’ and password/text()=’’ or //address[surname/text()=’Thomas’ and substring(password/text(),1,1)= ‘S’] and ‘a’=’a ‘]/ccard/text()
Который возвращает результаты, если первым символом пароля пользователя Thomas является S. Путем циклического перебора каждой позиции символа и проверки каждого возможного значения мы можем извлечь полное значение пароля Thomas.
Поиск уязвимостей XPath Injection
Допустим, разработчик хранит данные аутентификации в XML-файле со следующей структурой:
...
<user>
<name>UserName</UserName>
<password>Password</password>
</user>
...
При аутентификации разработчик строит выражение Xpath следующим образом:
string//user[name/text()='"txtUserName.Text"' and password/text()='" txtPassword.Text"'])
Переменные txtUserName и txtPassword являются стандартными текстовыми полями ASPX. Когда злоумышленник вставляет выражение с кавычкой (') в одно из текстовых полей, он завершает строку и может написать свое собственное выражение XPath. Как я и говорил выше, сценарий похож на SQL-инъекцию.
Первый известный мне метод обнаружения подобного рода уязвимости, омнова на ручном вводе, пробуем подставлять следующие данные:
- 'whatever – basic test
- DROP
- Something
Во все поля ввода / параметры URL / и что угодно. Если вы видите какую-либо ошибку, связанную с классами, которые обеспечивают манипуляции с XML в ASP.NET, вы, вероятно, обнаружили угрозу иньекции XPath.
Второй способ - поиск уязвимостей в коде. Вы можете искать следующие строки:
- Xpath - многие классы, которые работают с XPath, имеют в своем имени строку 'xpath'
- SelectSingleNode () и SelectNodes () - методы, используемые для получения данных из файлов XML через XPath.
Практический пример XPath Injection
Исходный код формы выглядит так:
$xml = simplexml_load_file("passwords/heroes.xml");
$result = $xml->xpath("/heroes/hero[login='" . $login . "' and password='" . $password . "']");
Используем следующую полезную нагрузку:
blah' or id='2
За ID берём условный порядковый номер пользователя в системе и подставляем в форму логина и пароля:
Пробуем перебирать ID чтобы получать новые логины и пароли пользователей.
Следующий пример - это форма поиска:
Подставив кавычку в запрос в URL мы можем вызвать ошибку, которая намекает нам на дальнейшие действия:
http://192.168.0.115/bWAPP/xmli_2.php?genre=action%27&action=search
Используем следующую полезную нагрузку для получения паролей пользователей:
http://192.168.0.115/bWAPP/xmli_2.php?genre=horror%27)]/password%20|%20a[contains(a,%27&action=search
Защита от XPath Injection
- Необходимо использовать параметризованный интерфейс XPath, если он доступен, или избегать ввода пользователя, чтобы его можно было безопасно включить в динамически создаваемый запрос.
- Если вы используете кавычки для завершения ненадежного ввода в динамически созданном запросе XPath, вам нужно экранировать эту цитату в ненадежном вводе, чтобы ненадежные данные не могли вырваться из этого цитируемого контекста.
В следующем примере одинарные кавычки (‘) используются для завершения параметров имени пользователя и пароля. Итак, нам нужно заменить все символы ‘ в этом вводе версией этого символа в кодировке XML, то есть « ’».
VB:
Dim FindUserXPath as String
FindUserXPath = "//Employee[UserName/text()='" & Request("Username").Replace("'", "'") & "' And
Password/text()='" & Request("Password").Replace("'", "'") & "']"
C#:
String FindUserXPath;
FindUserXPath = "//Employee[UserName/text()='" + Request("Username").Replace("'", "'") + "' And
Password/text()='" + Request("Password").Replace("'", "'") + "']";
- Использование предварительно скомпилированного запроса XPath1. Предварительно скомпилированные запросы XPath уже задаются до выполнения программы, а не создаются на лету после того, как пользовательский ввод был добавлен в строку. Это лучший способ, потому что вам не нужно беспокоиться об отсутствии символа, который нужно было экранировать.
- Пользовательский ввод можно отфильтровать, например, цитату (‘) можно заменить на «' ». Проверка должна быть добавлена как на стороне клиента, так и на стороне сервера.
- Использование параметризованных запросов (например, подготовленные операторы в SQL), в которых запросы предварительно скомпилированы, а пользовательский ввод передается как параметры, а не выражения.
"//users[LoginID/text()= $LoginID and passwd/text()= $password]”
Использование корректных страниц вывода ошибок, не раскрывающие никакой информации, которая может быть использована злоумышленником.