Обфускация атак с использованием кодировок
В этом разделе мы покажем, как воспользоваться стандартным декодированием, выполняемым веб-сайтами, чтобы обходить фильтры ввода и внедрять вредоносные полезные нагрузки для различных типов атак, таких как XSS и SQL‑инъекция.
Контекстно-зависимое декодирование
И клиенты, и серверы используют различные кодировки для передачи данных между системами. Когда им нужно фактически использовать данные, это часто означает, что сначала необходимо их декодировать. Точная последовательность шагов декодирования зависит от контекста, в котором появляются данные. Например, параметр строки запроса обычно URL‑декодируется на стороне сервера, тогда как текстовое содержимое HTML‑элемента может HTML‑декодироваться на стороне клиента.
При конструировании атаки следует задуматься, куда именно внедряется ваша полезная нагрузка. Если на основе контекста вы можете вывести, как декодируется ваш ввод, вы потенциально можете определить альтернативные способы представить ту же полезную нагрузку.
Несоответствия в декодировании
Инъекционные атаки часто включают внедрение полезных нагрузок, использующих узнаваемые шаблоны, такие как HTML‑теги, функции JavaScript или SQL‑операторы. Поскольку ввод для этих полезных нагрузок почти никогда не должен содержать пользовательский код или разметку, веб‑сайты часто блокируют запросы, содержащие эти подозрительные шаблоны.
Однако такие фильтры ввода также должны декодировать ввод, чтобы проверить, безопасен он или нет. С точки зрения безопасности крайне важно, чтобы декодирование, выполняемое при проверке ввода, совпадало с декодированием, выполняемым бэкенд-сервером или браузером при последующем использовании данных. Любое несоответствие может позволить злоумышленнику протащить вредоносные полезные нагрузки через фильтр, применив различные кодирования, которые затем будут автоматически сняты.
Обфускация с помощью URL‑кодирования
В URL‑адресах ряд зарезервированных символов имеет особое значение. Например, амперсанд (&) используется как разделитель для отделения параметров в строке запроса. Проблема в том, что ввод на основе URL может содержать эти символы по другой причине. Рассмотрим параметр, содержащий поисковый запрос пользователя. Что произойдет, если пользователь ищет что-то вроде «Fish & Chips»?
Браузеры автоматически URL‑кодируют любые символы, которые могут вызвать неоднозначность для парсеров. Обычно это означает замену их на символ % и их 2‑значный шестнадцатеричный код следующим образом:
[...]/?search=Fish+%26+ChipsЭто гарантирует, что амперсанд не будет принят за разделитель.
Любой ввод на основе URL автоматически URL‑декодируется на стороне сервера перед присвоением соответствующим переменным. Это означает, что, по мнению большинства серверов, последовательности вида %22, %3C и %3E в параметре строки запроса равнозначны символам ", < и > соответственно. Иными словами, вы можете внедрять URL‑кодированные данные через URL, и они обычно все равно будут корректно интерпретированы серверным приложением.
Иногда можно обнаружить, что WAF и подобные решения не выполняют надлежащее URL‑декодирование вашего ввода при его проверке. В этом случае вы можете протащить полезные нагрузки к приложению бэкенда, просто закодировав любые символы или слова, находящиеся в черном списке. Например, в атаке SQL‑инъекции вы можете кодировать ключевые слова, так что SELECT превращается в %53%45%4C%45%43%54 и так далее.
Обфускация с помощью двойного URL‑кодирования
По тем или иным причинам некоторые серверы выполняют два прохода URL‑декодирования для любых получаемых URL. Само по себе это не обязательно проблема, при условии, что любые механизмы безопасности также выполняют двойное декодирование ввода при его проверке. В противном случае это несоответствие позволяет атакующему протащить вредоносный ввод к бэкенду, просто закодировав его дважды.
Предположим, вы пытаетесь внедрить стандартный XSS пейлоад, например <img src=x onerror=alert(1)>, через параметр строки запроса. В этом случае URL может выглядеть так:
При проверке запроса, если WAF выполняет стандартное URL‑декодирование, он легко распознает эту хорошо известную полезную нагрузку. Запрос блокируется и не достигает бэкенда. Но что если вы закодируете инъекцию дважды? На практике это означает, что сами символы % заменяются на %25:
Поскольку WAF декодирует это только один раз, он может не распознать опасность запроса. Если сервер бэкенда впоследствии выполнит двойное декодирование этого ввода, полезная нагрузка будет успешно внедрена.
Обфускация с помощью HTML‑кодирования
В HTML‑документах некоторые символы требуется экранировать или кодировать, чтобы предотвратить неправильную интерпретацию браузером как части разметки. Это достигается заменой проблемных символов на ссылку, начинающуюся с амперсанда и заканчивающуюся точкой с запятой. Во многих случаях для ссылки можно использовать имя. Например, последовательность : представляет символ двоеточия.
В качестве альтернативы ссылку можно задать с использованием десятичной или шестнадцатеричной позиции символа, в данном случае, соответственно, : и :. В определенных местах внутри HTML, например в текстовом содержимом элемента или в значении атрибута, браузеры автоматически декодируют эти ссылки при разборе документа. При внедрении в таких местах вы иногда можете использовать это для обфускации полезных нагрузок для атак на стороне клиента, скрывая их от любых серверных механизмов защиты. Если внимательно посмотреть на XSS‑полезную нагрузку из предыдущего примера, можно заметить, что она внедряется внутрь HTML‑атрибута, а именно обработчика события onerror. Если серверные проверки явно ищут полезную нагрузку alert(), они могут не заметить ее, если вы HTML‑кодируете один или несколько символов:
Когда браузер отрендерит страницу, он декодирует и выполнит внедренную полезную нагрузку.
Ведущие нули
Интересно, что при использовании десятичного или шестнадцатеричного стиля HTML‑кодирования вы можете опционально добавлять произвольное количество ведущих нулей в кодовых точках. Некоторые WAF и другие фильтры ввода не учитывают это должным образом.
Если ваша полезная нагрузка по‑прежнему блокируется после HTML‑кодирования, вы можете обойти фильтр, просто добавив несколько нулей в начало кодовых точек:
Обфускация с помощью XML‑кодирования
XML тесно связан с HTML и также поддерживает кодирование символов с использованием тех же числовых escape‑последовательностей. Это позволяет включать специальные символы в текстовое содержимое элементов, не нарушая синтаксис, что может пригодиться, например, при тестировании XSS через ввод на основе XML.
Даже если вам не нужно кодировать какие‑либо специальные символы, чтобы избежать синтаксических ошибок, вы потенциально можете воспользоваться этим поведением, чтобы обфусцировать полезные нагрузки так же, как при HTML‑кодировании. Разница в том, что ваша полезная нагрузка декодируется самим сервером, а не браузером на стороне клиента. Это полезно для обхода WAF и других фильтров, которые могут блокировать ваши запросы, если обнаружат определенные ключевые слова, связанные с атаками SQL‑инъекции.
Обфускация с помощью экранирования Unicode
Последовательности экранирования Unicode состоят из префикса \u, за которым следует четырехзначный шестнадцатеричный код символа. Например, \u003a представляет двоеточие. ES6 также поддерживает новую форму экранирования Unicode с использованием фигурных скобок: \u{3a}.
При разборе строк большинство языков программирования декодируют такие последовательности Unicode. Это включает движок JavaScript, используемый браузерами. При внедрении в строковый контекст вы можете обфусцировать полезные нагрузки на стороне клиента с помощью Unicode так же, как мы делали с HTML‑экранированием в примере выше.
Например, предположим, что вы пытаетесь эксплуатировать DOM XSS, где ваш ввод передается в приемник eval() как строка. Если изначальные попытки блокируются, попробуйте экранировать один из символов следующим образом:
Поскольку это останется закодированным на стороне сервера, оно может остаться незамеченным до тех пор, пока браузер не декодирует его снова.
Также стоит отметить, что стиль экранирования Unicode в ES6 допускает необязательные ведущие нули, поэтому некоторые WAF могут быть легко обмануты тем же приемом, что мы использовали для HTML‑кодировок. Например:
Обфускация с помощью шестнадцатеричного экранирования
Еще один вариант при внедрении в строковый контекст — использовать шестнадцатеричное экранирование, которое представляет символы с использованием их шестнадцатеричной кодовой точки, с префиксом \x. Например, строчная буква a представляется как \x61. Как и экранирование Unicode, это будет декодировано на стороне клиента, если ввод интерпретируется как строка:
Обратите внимание, что иногда вы также можете обфусцировать SQL‑операторы аналогичным образом, используя префикс 0x. Например, 0x53454c454354 может быть декодировано до ключевого слова SELECT.
Обфускация с помощью восьмеричного экранирования
Восьмеричное экранирование работает практически так же, как и шестнадцатеричное, за исключением того, что ссылки на символы используют систему счисления по основанию 8, а не 16. Они помечаются одинарной обратной косой чертой, то есть строчная буква a представляется как \141.
Обфускация с помощью множественных кодирований
Важно отметить, что вы можете комбинировать кодирования, скрывая полезные нагрузки за несколькими уровнями обфускации. Посмотрите на URL с префиксом javascript: в следующем примере:
Браузеры сначала HTML‑декодируют \, в результате чего получается обратная косая черта. Это превращает произвольные символы u0061 в последовательность экранирования Unicode \u0061:
Затем это декодируется дальше и образует работоспособную XSS‑полезную нагрузку:
Очевидно, что для успешного внедрения полезной нагрузки таким образом вам необходимо хорошо понимать, какое декодирование выполняется над вашим вводом и в каком порядке.
Обфускация с помощью функции SQL CHAR()
Хотя это не строго форма кодирования, в некоторых случаях вы можете обфусцировать атаки SQL‑инъекции с помощью функции CHAR(). Она принимает десятичный или шестнадцатеричный код для одного символа и возвращает соответствующий символ. Шестнадцатеричные коды должны иметь префикс 0x. Например, и CHAR(83), и CHAR(0x53) возвращают заглавную букву S.
Объединяя возвращаемые значения, вы можете использовать этот подход для обфускации заблокированных ключевых слов. Например, даже если SELECT находится в черном списке, можно использовать следующую инъекцию, которая изначально выглядит безобидной:
Однако при обработке этого SQL запроса оно динамически сформирует ключевое слово SELECT и выполнит внедренный запрос.
Last updated