Идею о возможности проведения атак на веб-приложения описываемым в этой заметке методом я подчерпнул из темы на форуме antichat.ru, созданной Red_Red1 уже более года назад. Мне эта идея показалсь интересной, а потому я решил немного развить ее, а, теперь, и написать заметку (точнее, несколько, так как в одну у меня уложиться не получается ( ; ) о проведении веб-атак подобным методом.
Основная идея
Предположим, мы имеем скрипт users.php, который выводит список пользователей атакуемого веб-сайта. Обычно, подобные скрипты выводят этот список в виде таблицы, содержащей имя пользователя, дату его регистрации, статус на сайте и т.п. информацию. Кроме того данный скрипт позволяет сортировать вывод этой информации по каждому из этих параметров. Например, передав скрипту параметры "?orderby=name&direct=ASC", мы получаем список пользователей отсортированный в нисходящем порядке по параметру name, т.е. по имени пользователей. Обычно, таблица БД к которой обращаются подобные скрипты, помимо выводимых ими данных, содержит также секретные данные: например, пароли или хеши паролей юзерских аккаунтов.
Вот тут разработчиков веб-движков и может подстерегать опасная ошибка. Если передаваемый скрипту параметр "orderby", подставляется в SQL-запрос, без проверки его на "адекватность" его значения, то мы можем передать параметр "orderby" равный, к примеру, 'password' (или равный номеру колонки 'password' в таблице с пользователями), получив таким оразом вывод списка пользователей, отсортированный по полю 'password'. Дело в том, что тут действует одна важная особенность конструкции "ORDER BY" SQL-опертора SELECT: сортировка с помощью нее возможна по любому полю таблицы из которой извлекается информация, а не только по тем полям, по которым производится выборка SELECT'ом. Причем в данном случае никакой роли не сыграют различные защиты от sql-инъекций. Фактически, в случае обнаружения подобной уязвимости, мы имеем хоть и косвенное, но все же раскрытие секретной информации, что уже можно считать дырой в безопасности.
Является ли эта уязвимость распространенной? Нет. В серьезных движках с солидной историей обновлений ее трудно будет повстречать, но вот в разного рода самописных сайтовых движках, "фирменных" двигах всяких мелких веб-студий, вероятность обнаружить подобную багу всегда есть.
Является ли данная уязвимость действительно опасной? Да, в случае, если атакующий имеет доступ к аккаунту пользователя уязвимого сайта и имеется возможность изменять пароль данного юзера, или же есть возможность создавать некоторое количество новых юзеров, при этом нет возможности менять их пароли. Кроме того необходимое условие для атаки: пароли в БД хранятся либо в plain-text виде, либо в виде хеша, но без соли. Следует отметить, что в случе с хешами возможен подбор только криптографически слабых паролей.
Как уже наверняка стало понятным, можно использовать вывод списка пользователей, упорядоченный по их паролям, для брутфорса аккаунтов юзеров сайта, путем изменения пароля собственного пользовательского аккаунта и последующего наблюдения изменений в его местоположения в списке пользователей относительно аккаунта жертвы. "Жертвами", при этом, могут быть как простые юзеры, так и админы сайта, если информация об их аккаунтах хранится в одной таблице с остальными пользователями.
Причем брутфорс этот будет совсем не похож, на то, что обычно называют брутфорсом пользовательсих аккаунтов. Специфика его заключается в том, что мы имеем возможность искать верное значение не путем перебора значений по-одному с проверкой их на верность, а путем исключений неверных диапозонов искомых значений, вычисляя, таким образом, те значения, которые предположительно могут быть верными. Преимущество такого брутфорса - просто огромная эффективность: за относительно небольшое количество запросов к сайту можно перебрать огромный список возможных паролей. Кроме того, от него не спасут различные защиты от брутфорса аккаунтов сайта, например, таймаут после нескольких неудачных попыток авторизации.
Подбор хешированного пароля
Давайте рассмотрим несколько подробнее алгоритм реализации брутфорса по словарю. Для такого брутфорса будем использовать метод дихтомического (бинарного) поиска. Проведем для начала небольшой эксперимент, для чего нам потребуется СУБД, например, MySQL.
Для начала создадим словарь. В том случае, когда имеет место хранение паролей в БД в plain-text-виде, будем использовать просто отсортированный словарь, а в случаях, когда пароли хранятся в виде хешей - словарь из слов, отсортированных по их хешам. Алгоритм хеширования может быть любой, но, как я уже говорил, без использования случайно генерируемой соли. Главное что мы должны знать, это то какой используется алгоритм хеширования.
Допустим, мы будем брутить по словарю пароль, хешированный алгоритмом md5. Возьмем словарь и отсортируем слова в нем по их md5-хешам:
apple 12d5dfbba5861f516534031cd78a30a9:cannabis
bee 1f3870be274f6c49b3e31a0c6728957f:apple
cannabis 3a4e24a20ad52afef48852b613da483a:gameover
destroy 8c7e845bbfd7e7e0266975099e6d4801:hek
enigma сортируем их 8d8d1437907bca79900ac5f0ea1f5c73:north
gameover по md5-хешам 90954349a0e42d8e4426a4672bde16b9:enigma
forest ===========> 9dfd70fdf15a3cb1ea00d7799ac6651b:bee
hek b5c0b187fe309af0f4d35982fd961d7e:love
love e4f1ee70c698a129fd50624360191e91:victory
north f379cfd7a55b621577a8389d1817a102:forest
operation f7235a61fdc3adc78d866fd8085d44db:operation
victory fb14982288108e1fbd6207ef55f05027:destroy
В итоге мы имеем словарь, упорядоченный для дихотомического брутфорса:
cannabis
apple
gameover
hek
north
enigma
bee
love
victory
forest
operation
destroy
Теперь создадим в БД таблицу users и наполним ее несколькими записями:
mysql> CREATE TABLE users (
-> name VARCHAR(20),
-> password VARCHAR(32)
-> );
mysql> INSERT INTO users VALUES
-> ('admin', MD5('gameover')),
-> ('user1', MD5('lalala')),
-> ('user2', MD5('ololo'));
-> ('user3', MD5('123')),
-> ('user4', MD5('9999')),
-> ('user5', MD5('gogogo')),
-> ('cr0w', MD5('010101'));
mysql> SELECT * FROM users;
+-------+----------------------------------+
| name | password |
+-------+----------------------------------+
| admin | 3a4e24a20ad52afef48852b613da483a |
| user1 | 9aa6e5f2256c17d2d430b100032b997c |
| user2 | a619d974658f3e749b2d88b215baea46 |
| user3 | 202cb962ac59075b964b07152d234b70 |
| user4 | fa246d0262c3925617b0c72bb20eeb1d |
| user5 | 35af4bf130805f0b86b1b13e49c8101e |
| cr0w | 21ef05aed5af92469a50b35623d52101 |
+-------+----------------------------------+
Теперь притворимся, что мы не можем видеть содержимое таблицы users и не знаем пароля у юзера admin, но очень хотим его заполучить (: . При этом мы имеем возможность менять пароль пользователю cr0w и получать вывод имен пользователей отсортированный по полю 'password'.
Итак, начнем:
1. В словаре у нас 12 слов - ставим в качестве пароля юзеру cr0w 6-е (делим словарь надвое и берем то, что выше середины), т.е. 'enigma':
mysql> UPDATE users SET password=MD5('enigma') WHERE name='cr0w';
mysql> SELECT name FROM users ORDER BY password;
+-------+
| name |
+-------+
| user3 |
| user5 |
| admin |
| cr0w |
| user1 |
| user2 |
| user4 |
+-------+
Отсюда можно сделать вывод, что все пассы в словаре, находящиеся ниже 'enigma', не являются паролем admin'a (при этом, пароль 'enigma' может являться искомым паролем!). Осталось 6 вариантов возможных паролей.
2. Теперь ставим cr0w пасс 'gameover':
mysql> UPDATE users SET password=MD5('gameover') WHERE name='cr0w';
mysql> SELECT name FROM users ORDER BY password;
+-------+
| name |
+-------+
| user3 |
| user5 |
| admin |
| cr0w |
| user1 |
| user2 |
| user4 |
+-------+
Делаем вывод, что слова, находящиеся в словаре ниже 'gameover' не могут быть паролем юзера admin.
3. Пробуем пасс 'apple':
mysql> UPDATE users SET password=MD5('apple') WHERE name='cr0w';
mysql> SELECT name FROM users ORDER BY password;
+-------+
| name |
+-------+
| cr0w |
| user3 |
| user5 |
| admin |
| user1 |
| user2 |
| user4 |
+-------+
cr0w теперь выводится в списке пользователей выше admin'a, что означает, что его пароль или 'apple' или 'gameover'.
Кто-то может возразить по поводу выводов сделанных в последнем шаге, а именно по поводу утверждения о том, что оба пароля и 'apple', и 'gameover', могут являться паролем admin'a. Привести против этого утверждения можно 2 довода:
1. В выведенном списке юзеров между cr0w и admin находятся 2 юзера, а значит у них разные пароли. Этот довод банально неверен, потому что у всех этих юзеров: cr0w, user3, user5 и admin, теоретически, может быть одинаковый пароль.
2. Если у cr0w и admin одинаковые пароли, то cr0w должен находиться в отсортированном списке юзеров ниже чем admin, так как запись о пользователе cr0w была занесена в таблицу после записи о юзере admin. Этот довод также неверен, так как нет никакой гарантии, что используемый СУБД алгоритм сортировки будет таков, что после сортировки по определенному полю таблицы, записи с одинаковыми значениями в этом поле будут выведены в том порядке, в котором вносились в таблицу.
Но на практике нередко мы можем передать конструкции "ORDER BY" не один параметр, а несколько (нам достаточно двух), что позволит отсортировать записи нужным нам образом (чтобы мы точно знали, кто за кем будет следовать при одинаковых паролях). Это полезно, так как в случаях когда:
mysql> UPDATE users SET password=MD5('pass') WHERE name='cr0w';
mysql> SELECT name FROM users ORDER BY password,name;
+-------+
| name |
+-------+
| user3 |
| user5 |
| cr0w |
| admin |
| user1 |
| user2 |
| user4 |
+-------+
Можно будет делать выводы, что все пассы в словаре, находящиеся выше 'pass', не являются паролем admin'a и при этом, сам пароль 'pass' тоже не будет являться искомым паролем (вот в этом разница). Таким образом, в ряде случаев можно будет получать 1 предположительно верный пароль, заместо двух и, возможно, сократить число итераций брутфорса.
Итак, вернемся к решению проблемы с паролем admin'a. У нас осталось два возможных пароля. На этом дихотомический брутфорс можно завершить. Остается проверить правильность двух этих паролей обычным методом. Замечу, что в итоге могут не подойти оба пароля. Это значит пароль admin'a такой, что его md5-хеш находится где-то между хешем от 'apple' и 'gameover', и в нашем словаре он отсутствует. Итак, попробовав пароли 'apple' и 'gameover', мы обнаружим, что один и них верен, а значит, метод работает. ( :
Пока закончу на этом, но в последующих заметках обязательно продолжу тему.
Ссылки по теме:
Тема на форуме Античат, о которой я писал в начале
Advisory о подобной уязвимости в Fireboard
0 коммент.:
Отправить комментарий
Большая просьба: не оставляйте анонимных комментариев и не используйте в своих комментариях нецензурную лексику без дела.