ANTICHAT.XYZ    VIDEO.ANTICHAT.XYZ    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  
Баннер 1   Баннер 2
Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей. Здесь обсуждаются безопасность, программирование, технологии и многое другое. Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
Вернуться   Форум АНТИЧАТ > ИНФО > Статьи > Авторские статьи
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

Новая альтернатива Benchmark'y или эффективный blind SQL-injection
  #1  
Старый 11.03.2007, 03:38
Аватар для Elekt
Elekt
Banned
Регистрация: 05.12.2005
Сообщений: 982
Провел на форуме:
4839935

Репутация: 1202


Отправить сообщение для Elekt с помощью ICQ
По умолчанию Новая альтернатива Benchmark'y или эффективный blind SQL-injection


Новая альтернатива Benchmark'y или эффективный blind SQL-injection


В статье Вам будет показан новый и универсальный способ обходиться без использования benchmark в blind sql-inj
в так называемых в народе "неюзабельных" бажных запросах как UPDATE, DELETE, REPLACE, UPDATE и прочих.

Найденный Альтернативный способ позволяет именно ПОЛУЧАТЬ требуемую информацию из базы данных, а не банально модифицировать записи.

Будут описаны все особенности известных способов атак SQL-inj, применимых к перечисленным выше операторам.

А также мы подробно рассмотрим аспекты практического использования бенчмарка при написании эксплойтов.

Примечание: в статье приведены примеры для mysql, однако опиcанное сработает практичеcки на всех субд(с поправкой на синтаксис запросов, разумеется).



[1] INTRO

Программисты умнеют, багов в селект-запросах становится всё меньше, а проблема инъекций в
INSERT,UPDATE,REPLACE,DELETE и прочих остаётся актуальной.
Часто вижу вопросы на форумах: "..подскажите, что мне делать, если - 'mysql error INSERT INTO table_name VALUES(...'"
Видя такую ошибку, новичок в хаке закроет браузер, любитель постит сотый вопрос на форумах...
В ответ как правило тишина, либо советы которыми он не в силах воспользоваться,
поскольку раскрутка blind sql, ввиду объёма запросов, требует применения автоматизации, то есть умения писать эксплоит.

Способы давно известны и подробно расписаны 1dt.w0lf ещё за 14 ноября 2004, не читал её только ленивый:
http://www.securitylab.ru/contest/212099.php
Данную статью можно считать её продолжением.



[2] INSERT и другие
описаны известные атаки на insert\update и тд, кто знает - пропускаем

Что можно из этого выжать?

1) (случай общий)Модификация данных без возможности просмотра результата
Идеальный случай - sql-inj в имени таблицы. Здеcь возможно всё:
Код:
INSERT INTO [SQL] VALUES ('stat','stat2');
Добавление нового пользователя:
Код:
INSERT INTO mysql.user (user, host, password) VALUES ('newadmin', 'localhost', PASSWORD('passwd'))/* VALUES ('stat');
2) DoS-атака
Но подобные sql-inj в 99% присутствуют в имени столбца, что не позволяют изменить модифицируемую таблицу на полезную нам.
Код:
INSERT INTO table VALUES ('stat','[SQL]');
А раз так, то кроме порчи\засорения\dosa бд мы модификацией данных ничего не добьемся.
SQL:
Код:
INSERT INTO table VALUES ('stat','bla'),('test', 'demo');
DoS:
Код:
INSERT INTO table VALUES ('stat','bla' and BENCHMARK(10000000,BENCHMARK(10000000,md5(now()))) ) /*');
3) Разделение запросов в MSSQL, PostgreSql, Oracle
Что же объединяет эти три популярные субд?
Такая замечательная вещь, как поддержка разделения запросов, используя точку с запятой, перевод каретки и прочее.
Таким образом мы можем добавить абсолютно ЛЮБОЙ sql-запрос, отделив его ";" от основного.
Что можно полезного вставить - ищем в гугле под конкретную бд.

4) Модификация данных с возможностью просмотра результата
Здесь уже не важно, где инъекция - в имени таблицы или столбца.
Мы можем увидеть результат выполнения запроса, пускай и косвенно.
А значит провести атаку не проблема - чисто технические особенности выяснения результата.
Пример: пусть веб-приложение ПУБЛИЧНО ведёт статистику посещений и есть уязвимость в столбце с User-Agent.
Тогда, результат выполнения sql-inj мы можем наблюдать на паге вывода статистики посещаемости.

5) Использование BENCHMARK
Мы используем BENCHMARK, что позволяет по времени ответа сервера определить результат выполнения запроса.
Этот запрос будет для if положителен и ответ от сервера придёт сразу:
Код:
INSERT INTO table VALUES ('stat','1' and 1=if(ascii(lower(substring((select users from mysql.user limit 1),1,1)))>=1,1,benchmark(999999,md5(now()))) )/* ,'stat2');
А этот - отрицателен и на исполнение бенчмарка уйдёт время, потому ответ от сервера придёт сразу:
Код:
INSERT INTO table VALUES ('stat','1' and 1=if(ascii(lower(substring((select users from mysql.user limit 1),1,1)))>=254,1,benchmark(999999,md5(now()))) )/* ,'stat2');
Разумеется, вместо INSERT может стоять любой другой оператор, в том числе и SELECT, ведь с ним тоже бывают cложные случаи инъекций.



[3] Bencmark для хакера
особенности эксплуатации benchmark, кто знает - пропускаем

Применение бенчмарка это своего рода переход ко второму измерению.
От измерения разности получаемой информации к измерению разности времени на исполнение запроса.

Если кто-то сомневается, что под бенчмарк вообще пишут эксплойты - пробегитесь по багтракам и уверьтесь в обратном - они есть, правда не много.

В реализации сплойт на бенчмарке чуть-чуть сложнее чем для слепого посимвольного брута.

Особенности benchmark:

- пожалуй самая важная деталь - бенчмарк создаёт серьёзную нагрузку на процессор сервера.
Причём эта нагрузка длиться практически постоянно во время работы эксплойта.
Администратор может не смотреть логи обращений\ошибок, но вполне может поинтересоваться, почему сервер притормаживает и в top->P "mysqld" занимает первое место...

- время работы эксплойта тем больше, чем большую длину записи мы хотим получить.
На моей практике для перебора 32-х символьного хеша уходит больше часа.
Иногда несколько часов - по обстоятельствам, описанным ниже.

- взломщику и серверу требуется широкий надежный канал. От этого зависит качество и стабильность брута.
Я не говорю, что на диалапе у вас ничего не получится.
Но глюков будет больше, особенно, если вы, с целью экономии времени, выберите слишком маленький параметр...

- параметр измерения производительности, то есть количество итераций, в нашем примере - 999999
benchmark(999999,md5(user())
По личному опыту, с момента написания статьи 1dt.w0lf'ом это число изменилось почти на порядок вместе с ростом производительности современных серверов.
В эксплойте желательно делать автоподстройку этого параметра для универсальности, добиваясь приемлемого времени ответа....

- и соответственно, подобрав число в benchmark'e нужно задать таймаут ответа - timeout
Это будет среднее арифметическое от времени выполнения true\false запроса.

- Замечу: при написании эксплойта учитывайте, что по статистике общее число "неверных" запросов превышает общее число верных,
а значит нужно поставить бенчмарк-задержку так, чтобы она срабатывала при ВЕРНОМ ответе. Вот так:
Код:
if( ?,  true, false )
1 = if( 1=1 , benchmark(999999,md5(user()), 1 )
Тем самым мы сэкономим время и снизим нагрузку на сервер.

- не забывайте, что серверу необходимо дать отдых после каждого бенчмарка, дать восстановиться так сказать.
Иначе следующий запрос может иметь непредвиденное время выполнения и даст вам ошибочные данные.
Об этой маленькой детали часто забывают, поскольку тестят двиг локально, либо непонятно о чём думают, релизя свой код без предварительного тестирования.
Сам лично долго удивлялся, непонимая, почему первый символ брутится правильно, но дальше идёт мусор - сервер просто давился бенчмарком.
Желательно выбирать время задержки в расчете на 1-1,5 больше, чем время исполнения бенчмарка.
Да, это существенно замедлит брут, но обеспечит качество результата.

Если обратится непосредственно к коду, то символьный брутер 1dt.w0lf'а без труда модифицируется с учетом бенчмарка:
необходимо

- изменить sql под бенчмарк
Код:
$http_query = $path."?Cat=&page=1&like=".$username."' AND 1=if(ascii(substring(CONCAT(U_LoginName,CHAR(58),U_Password),".$s_num.",1))".$ccheck.",benchmark(999999,md5(user()),1)/*";
- timeout - таймаут.
Но вот возвращать sub check($) теперь должна результат в зависимости от того, уложился ли сервер в таймаут, или нет.
Код:
$mcb_reguest = LWP::UserAgent->new(timeout=>$timeout) or die;
- sleep()
После каждого ложного запроса, а значит подвергнутого пытке бенчмарком, дадим серверу отдохнуть N секунд. пусть восстановится.

вот и всё.



[4] Альтернатива benchmark'y
ну вот, собственно, самое сладкое

Копаясь с бенчмарком меня как и любого из Вас одолевало желание найти замену этому геморойному, но единственному способу.
И способ был найден!

На самом деле разность выводимой инфы и времени - не единственные факторы.

Давайте вернёмся к началу и вспомним, с чего начинается любая sql-inj?
Конечно с ковычки в запросе! ...и выводе сообщения ошибки соответственно.
Но подойдем к этому логически - мы ставим ковычку, mysql проверяет запрос, находит в нём ошибку - сообщает нам.
Следите за мыслью: мускул сначала проверяет на корректность, затем либо проводит запрос и выводит результат, либо выводит еррор.
А теперь зададим себе вопрос - может ли быть иначе? Ну, разумеется может, в том то всё и дело.
Может возникнуть ситуация, когда проверку на корректность запрос пройдет, выполнится,.. но результат даст нам сообщение об ошибке.
Тогда наша задача сводится к простейшей ПРОВАКАЦИИ такого запроса + необходимо связать параметры в запросе таким образом, чтобы
мы могли манипулировать результатом запроса и соответственно получать полезные данные.

Ставим задачу:
Срыв запроса неявным условием и как следствие - намеренный вызов ошибки, которая и поможет отличить true\false query.

Эта мысль приходит в голову и я начинаю вспоминать различные ошибки бд.

Сначала попытался используя IF сорвать запрос путем подстановки неверных имён таблиц\столбцов\типов данных:
Код:
select if(1=1,null,blaaaah);
Однако mysql, сцуко, умный и проверяет тип данных перед выполнением на корректность, что меня обломало.
You have an error in your SQL syntax
Попытка изменять имя не столбца, а таблицы также не увенчалась успехом.
Код:
select null from if(1=1,users,blaaaah);
Кстати, видимо алгоритм парсинга запроса в мускуле на корректность предполагает имя таблицы как константы, а здесь она не задана явно.
Он проверяет существование столбца в заведомо известной таблице и если таблица не определена, например я через if её задаю, то мускул шлёт меня подальше.
Принцип проверки в других базах данных я не проверял, так что возможно такие простые, а главное, универсальные трюки там прокатят.

Какие ещё ошибки могут возникнуть при выполнении запроса?
Самой популярной после "You have an error in your SQL syntax" является пожалуй "The used SELECT statements have a different number of columns"
Но здесь проверка так же происходит до выполнения.

"Operand should contain 1 column(s)" - опять же нельзя по той же причине.

"warning: mysql_fetch_array..." - можно, но php-ошибка специфическая, под конкретный двиг.


..а следующая по популярности в моём рейтинге идёт "Subquery returns more than 1 row".... Да, да, он самый, вездесущий лимит.

Вот то, что нам нужно.
Мускул проверяет корректность данных, но не может проверить число возвращаемых ответов, не сделав самого запроса.

Встаёт вопрос, как запрос надо задать, чтобы вероятно вызвать такую ошибку?

Требуется спровоцировать два условия:
когда ошибка 100% выведется и 100% не выведется.

Предположим, что нам заведомо известны имена таблиц и столбцов в уязвимом приложении.
Пусть пароль хешируется md5. Тогда длинна любого пароля = 32 символа.
А длина id или логина наверняка будет меньше, не правда ли?...
length(id)=(1-5..) и length(password)=(32)
Тогда наш эксплоит будет выглядеть следующим образом:

false:
Код:
...123' and 1=(select null from users where length(if(ascii(substring((select password from users where uid=1),1,1))>254,password,uid))>5)/*
Первый символ пароля наверняка меньше чем ascii(254).
Значит if возвратит length(id)>5, а так как столько пользователей наверняка нет(ну можно циферку и побольше брать), то селект возвратит NULL.
В результате мы ничего не увидим, будто и нет никакой инъекции.

true:
Код:
...123' and 1=(select null from users where length(if(ascii(substring((select password from users where uid=1),1,1))>1,password,uid))>5)/*
Поскольку первый символ пароля наверняка больше ascii(1), то условие истинно
Значит if возвратит length(password)>5, что приведёт к выводу N результатов в селект запросе.
Но в условие может быть сравнен только один результат 1=(*),... что спровоцирует ошибку "Subquery returns more than 1 row" !!!

Как всё просто, не правда ли?

Уверен, что поискав найдутся и другие подобные ошибки, проявляющиеся именно после выполнения query.


Особенности "more than 1 row":

1) важнейшее: стандартная скорость посимвольного брута при полной заменяемости бенчмарка, экономим время и не грузим сервер.

2) цена этой производительности - масса ерроров в логах mysql, что может привлечь внимание администратора.

3) единственно, требуется знать некоторые данные, как то - имена столбцов и таблиц, чтобы провоцировать ошибку "more than 1 row"



Возможно, вы найдете более совершенный и универсальный способ, в отличии от моего. Удачи!



[5] Links

Ссылки. Публичные эксплойты, использующие benchmark blind SQL-inj :


08 марта, 2007 г. PHP-Nuke <= 8.0 Final (INSERT) Blind SQL Injection Exploit (mysql)

08 марта, 2007 г. PHP-Nuke <= 8.0 Final (HTTP Referers) Remote SQL Injection Exploit

08 марта, 2007 г. PHP-Nuke <= 8.0 Final (INSERT) Remote SQL Injection Exploit

21 февраля 2007 г. Blind sql injection attack in INSERT syntax on PHP-nuke <=8.0 Final

1 декабря 2006 г. Invision Gallery 2.0.7 SQL Injection Vulnerability

8 сентября 2006 г. PHPFusion <= 6.01.4 extract()/_SERVER[REMOTE_ADDR] sql injection exploit

25 июля 2006 г. SQL-Injection in Shop-Script PRO & Shop-Script Premium all version

3 мая 2006 г. sBlog SQL Injection and Path Disclosure Vulnerability

24 марта 2004 г. MS Analysis v2.0 module for PhpNuke MS Analysis


10 февраля 2004 г. SQL injection in Php-Nuke 7.1.0


Последний раз редактировалось Elekt; 31.03.2007 в 16:30..
 
Ответить с цитированием

  #2  
Старый 11.03.2007, 03:46
Аватар для Elekt
Elekt
Banned
Регистрация: 05.12.2005
Сообщений: 982
Провел на форуме:
4839935

Репутация: 1202


Отправить сообщение для Elekt с помощью ICQ
По умолчанию

Сразу скажу, я обещал пару месяцев назад статью для .uT!L!Te.
Статья будет отдана ему для публикации где-то там.
Как только он свой езин выпустит, либо по наступлении апреля - я спускаю её в паблик.
 
Ответить с цитированием

  #3  
Старый 11.03.2007, 22:52
Аватар для podkashey
podkashey
Познавший АНТИЧАТ
Регистрация: 18.06.2005
Сообщений: 1,004
Провел на форуме:
2821162

Репутация: 1320


По умолчанию

Элект, давай исправляй на UNION, "чтоб не вводить других в заблуждение"(c) Elekt
гыыг...
 
Ответить с цитированием

  #4  
Старый 12.03.2007, 21:53
Аватар для Elekt
Elekt
Banned
Регистрация: 05.12.2005
Сообщений: 982
Провел на форуме:
4839935

Репутация: 1202


Отправить сообщение для Elekt с помощью ICQ
По умолчанию

езин вышел (http://www.pyccxak.com/goch_1/), а значит статью пора спускать.

Наслаждайтесь оригиналом - форматирование текста не урезанное, читать приятнее =)

Последний раз редактировалось Thanat0z; 12.03.2007 в 23:53..
 
Ответить с цитированием

  #5  
Старый 13.03.2007, 11:38
Аватар для VampiRUS
VampiRUS
Участник форума
Регистрация: 31.12.2005
Сообщений: 231
Провел на форуме:
1106266

Репутация: 366
Отправить сообщение для VampiRUS с помощью Yahoo
По умолчанию

статья отличная.
ток ещё ошибки подправить надо:
Цитата:
А этот - отрицателен и на исполнение бенчмарка уйдёт время, потому ответ от сервера придёт не сразу:
Цитата:
После каждого ложного запроса, а значит подвергнутого пытке бенчмарком, дадим серверу отдохнуть N секунд. пусть восстановится.
говорилось что
Цитата:
а значит нужно поставить бенчмарк-задержку так, чтобы она срабатывала при ВЕРНОМ ответе.
следовательно
После каждого Верного запроса, а значит подвергнутого пытке бенчмарком, дадим серверу отдохнуть N секунд. пусть восстановится.
 
Ответить с цитированием

  #6  
Старый 31.03.2007, 16:47
Аватар для Elekt
Elekt
Banned
Регистрация: 05.12.2005
Сообщений: 982
Провел на форуме:
4839935

Репутация: 1202


Отправить сообщение для Elekt с помощью ICQ
По умолчанию

=================================

Как совершенно верно заметил podkashey мне в асю - "CREATE, DROP" притянуты зауши, так как не держат после себя условий.
Потому насчет этих функций я прогнал - извините. поправил.
Ну, расстраиваться собственно неочем - крейт с дропом используются в основном только при инсталяции.

=================================

Как совершенно верно заметил товарищ ZaCo,

Что же объединяет эти три популярные субд?
Такая замечательная вещь, как поддержка разделения запросов точкой с запятой...


- "...вообще говоря, ';' не так чтобы и разделитель двух запросов... два запроса можно разделить исполльзуя ЛЮБОЙ разделитель в том числе пробел\перевод каретки табуляция и тд..."

поправил.

=================================

Цитата:
Где здесь + ставить =)
Всего через два часа после публикации алгоритма podkashey нашел более универсальный метод провакации основаный на union.
select 1 union select 2
куда это вставить, сами подумайте =)

а плюсы можно ставить ему же =)

=================================

Цитата:
Thanat0z, скажи честно, кто тебе сказал, что статья хорошая?
Это сказал ему я =)))
Спасибо за редактирование и правку грамматики, для меня это было не столь важно.

На самом деле нет ничего удивительного в том, что актуальность материала начинает доходит до всех спустя некоторое время.
Материал специфисеский и осознать его полезность сразу может лишь тот, кто не по наслышке знаком с реализацией сабжа.
Фактически, это маленький прорыв в sql-inj, своего рода полезнейшая фича, без которой было очень неудобно.
 
Ответить с цитированием

  #7  
Старый 13.09.2007, 14:40
Аватар для Elekt
Elekt
Banned
Регистрация: 05.12.2005
Сообщений: 982
Провел на форуме:
4839935

Репутация: 1202


Отправить сообщение для Elekt с помощью ICQ
По умолчанию

пришло на мыло дополнение

Цитата:
Hi Elekt,
i write this e-mail because i found really very very good your
paper about benchmark alternative in exploiting blind sql injection.
I would contribute with your research with this simple trick.

If u type : ... AND (SELECT 1,2,3,4)=1
mysql returns "Operand should contain 4 column(s)". It can be used as
an alternative of your method !
see ya
Luca
 
Ответить с цитированием

  #8  
Старый 17.11.2007, 07:47
Аватар для Elekt
Elekt
Banned
Регистрация: 05.12.2005
Сообщений: 982
Провел на форуме:
4839935

Репутация: 1202


Отправить сообщение для Elekt с помощью ICQ
По умолчанию


Insert, Update, Replace

При попытке присвоить колонке значение NULL, которая не может быть равна NULL, вызывает ошибку:

(Column '[column]' cannot be null)

Пример:
INSERT INTO table (`a`,`b`,`c`) VALUES ('1',if(1=1,NULL,'2'),'3')

 
Ответить с цитированием

  #9  
Старый 17.11.2007, 16:31
Аватар для Scipio
Scipio
Members of Antichat - Level 5
Регистрация: 02.11.2006
Сообщений: 781
Провел на форуме:
5939734

Репутация: 1917


Отправить сообщение для Scipio с помощью ICQ
По умолчанию

Можно еще добавть, что с помощью таких выражений возможна инъекция после order by, т.к. в order by тоже возможно использование выражений (вот в limit помоему нельзя)
возможен вариант:
SELECT * FROM `table1` order by (select+if(2=1,1,(select 1 union select id)))
в данном случае выдаст ошибку
Цитата:
#1242 - Subquery returns more than 1 row
, т.к 2=1 - false
если подставить выражение 1=1 ошибки не будет
пример
SELECT * FROM `table1` order by (select+if(substring(version(),1,1)=4,1,(select 1 union select id)))

если версия мускула 4 ошибки не будет, если не 4 то будет ошибка. ну и класика жанра:
SELECT * FROM `table1` order by -id*(substring(version(),1,1)=4)
если версия мускула 4, то сортировка пойдет по полю ид в обратном порядке, т.к. -id*1 (aka true) будет -id, а -id*0 (ака false) будет 0, ну и с бенчмарком тоже самое
из всех предложенных вариантов вариант с иф - бенчмарк самый универсальный, но самый долгий
__________________
Карфаген должен быть разрушен...
 
Ответить с цитированием

  #10  
Старый 23.12.2007, 14:56
Аватар для ZaCo
ZaCo
Banned
Регистрация: 20.06.2005
Сообщений: 880
Провел на форуме:
4610226

Репутация: 1332


По умолчанию

статья стоящая, жаль что была проигнорирована большинством.

добавлю к сообщению Scipio - твой способ подходит исключительно для операции select, предлагаю вариант, который может использоваться в любых логических условиях и без использования подзапросов:

Код:
select username from users 
where "x" regexp concat("x{1,25", if(@@version<>5, "5}", "6}")) /*в случае else строка выражения выйдет за максимальный предел квантификатора*/
естественно методов "провокации" в регекспах довольно много, но достаточно только одного.
 
Ответить с цитированием
Ответ



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
SQL Injection в Oracle k00p3r Чужие Статьи 0 12.06.2005 12:41
SQL инъекция в сервере MySQL k00p3r Чужие Статьи 0 12.06.2005 12:41
Sql injection или где %) Чаты 9 30.05.2003 01:31
Новая статья по взлому sql Algol Чаты 2 17.01.2003 18:24



Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT.XYZ