attacking mongodb
DESCRIPTION
My presentation about mongoDB vulns from ZeroNights'12 My E-mail: [email protected] Programs: https://github.com/cyberpunkych/attacking_mongodbTRANSCRIPT
Удар по MongoDB
Фирстов Михаил
Что это вообще такое?
MongoDB — документо-ориентированная СУБД с открытым исходным кодом, не требующая описания схемы таблиц. (wiki)
Особенности:
1. Документо-ориентированное хранилище.
2. Достаточно гибкий язык для формирования запросов
3. Динамические запросы
4. Полная поддержка индексов
5. Профилирование запросов
6. Поддержка отказоустойчивости и масштабируемости
А на чем он?
CC++JavaJavascript.NET (C# F#, PowerShell,
etc)Node.js PerlPHPPythonRubyScala
У Mongodb существуют официальные драйвера для основных ЯП:
./mongo – офф. клиент, написанный на C++ и JS
./mongod — это серверная часть, написанная на C++
Где используются
Краткий список компаний использующих MongoDB:
1. SAP (Крупный производитель программного обеспечения)
2. SourceForge (Хостинг открытого исходного кода)
3. The New York Times
4. GitHub (Проект социального хостинга)
5. Foursquare (Достаточно крупный и известный стартап)
6. Yandex (некоторые сервисы)
Веб-службы RESTful в MongoDB используют интерфейс API для связи с базами данных, просмотра логов и исполнения других ф-ций администрирования.
Что такое RESTful?
А как я узнаю его?
Он по дефолту запускается на порту «28017».
Он может быть запущен без параметра –rest, тогда будет вот эта ошибка:
А как я узнаю его?
Какие там уязвимости?
Во время исследования были найдены следующие уязвимости:
Исполнение произвольного серверного JS кода
Хранимая XSS в логах обращения к БД
Хранимая XSS в журнале запросов
CSRF в удаленном обращении к БД
Our SSJS code
Проведение атаки
MongoDBMongoDB
--REST--REST
HackerHacker
Site with Site with mongoDB mongoDB driver supportdriver support
Admin’s browserAdmin’s browser
1) Посылаем запрос с тегом script, и адресом нашего скрипта.
Hacker’s Hacker’s ServerServer
Проведение атаки
MongoDBMongoDB
--REST--REST
HackerHacker
Site with Site with mongoDB mongoDB driver supportdriver support
Admin’s browserAdmin’s browser
1) Посылаем запрос с тегом script, и адресом нашего скрипта.
Hacker’s Hacker’s ServerServer
2) В результате нашего запроса, в REST интерфейсе будет подгружаться наш скрипт
Проведение атаки
MongoDBMongoDB
--REST--REST
HackerHacker
Site with Site with mongoDB mongoDB driver supportdriver support
Admin’s browserAdmin’s browser
1) Посылаем запрос с тегом script, и адресом нашего скрипта.
Hacker’s Hacker’s ServerServer
2) В результате нашего запроса, в REST интерфейсе будет подгружаться наш скрипт
3) Через XSS в браузере подгружается наш скрипт
Проведение атаки
MongoDBMongoDB
--REST--REST
HackerHacker
Site with Site with mongoDB mongoDB driver supportdriver support
Admin’s browserAdmin’s browser
1) Посылаем запрос с тегом script, и адресом нашего скрипта.
Hacker’s Hacker’s ServerServer
4) Посылаем команду, браузеру жертвы
2) В результате нашего запроса, в REST интерфейсе будет подгружаться наш скрипт
3) Через XSS в браузере подгружается наш скрипт
Проведение атаки
MongoDBMongoDB
--REST--REST
HackerHacker
Site with Site with mongoDB mongoDB driver supportdriver support
Admin’s browserAdmin’s browser
1) Посылаем запрос с тегом script, и адресом нашего скрипта.
Hacker’s Hacker’s ServerServer
4) Посылаем команду, браузеру жертвы
5) Ждем, пока скрипт не запросит команду (JSONP) ( скрипт запрашивает новую команду каждые 30 секунд)
2) В результате нашего запроса, в REST интерфейсе будет подгружаться наш скрипт
3) Через XSS в браузере подгружается наш скрипт
Проведение атаки
MongoDBMongoDB
--REST--REST
HackerHacker
Site with Site with mongoDB mongoDB driver supportdriver support
Admin’s browserAdmin’s browser
1) Посылаем запрос с тегом script, и адресом нашего скрипта.
Hacker’s Hacker’s ServerServer
4) Посылаем команду, браузеру жертвы
5) Ждем, пока скрипт не запросит команду (JSONP) ( скрипт запрашивает новую команду каждые 30 секунд)
2) В результате нашего запроса, в REST интерфейсе будет подгружаться наш скрипт
3) Через XSS в браузере подгружается наш скрипт
6) Выполняем полученную команду, через недокументированное исполнение SSJS, и получаем ответ
Проведение атаки
MongoDBMongoDB
--REST--REST
HackerHacker
Site with Site with mongoDB mongoDB driver supportdriver support
Admin’s browserAdmin’s browser
1) Посылаем запрос с тегом script, и адресом нашего скрипта.
Hacker’s Hacker’s ServerServer
4) Посылаем команду, браузеру жертвы
5) Ждем, пока скрипт не запросит команду (JSONP) ( скрипт запрашивает новую команду каждые 30 секунд)
7) Отправляем результат исполнения команды на запись в БД
2) В результате нашего запроса, в REST интерфейсе будет подгружаться наш скрипт
3) Через XSS в браузере подгружается наш скрипт
6) Выполняем полученную команду, через недокументированное исполнение SSJS, и получаем ответ
Проведение атаки
MongoDBMongoDB
--REST--REST
HackerHacker
Site with Site with mongoDB mongoDB driver supportdriver support
Admin’s browserAdmin’s browser
1) Посылаем запрос с тегом script, и адресом нашего скрипта.
Hacker’s Hacker’s ServerServer
4) Посылаем команду, браузеру жертвы
8) Получаем результат исполнения команды
5) Ждем, пока скрипт не запросит команду (JSONP) ( скрипт запрашивает новую команду каждые 30 секунд)
7) Отправляем результат исполнения команды на запись в БД
2) В результате нашего запроса, в REST интерфейсе будет подгружаться наш скрипт
3) Через XSS в браузере подгружается наш скрипт
6) Выполняем полученную команду, через недокументированное исполнение SSJS, и получаем ответ
Видео
Разве такое можно встретить?
Стабильный CRASH
MongoDB очень часто падает если вызвать ф-цию с нестандартными параметрами. На скриншотах можно увидеть результат:
Интересные фичи
Ф-ции ls, cat, (остальные - help admin) работают только из самой консоли Mongo.
Скорее всего существуют и другие варианты NoSQL-инъекций, с другими языками программирования.
Очень интересна ф-ция nativeHelper, которая как раз и отвечает за работу с ФС из консоли mongo.
Чаще всего путь к файлам бд – «/data/db» или «/var/lib/mongodb». Структура каталога простая: (dbname).(num). Чтобы извлечь информацию достаточно сделать $ strings users.*
Сетевое взаимодействие
Добавление пользователя:
Исходный код:
Расшифровываем соль:
Сетевое взаимодействие
Перехваченные пакеты авторизации:
Нужные нам данные передаются в открытом виде:
Сетевое взаимодействие
Логика работы скрипта, для перехвата и перебора паролей:
Перехватываем Перехватываем n n пакетов, связанных пакетов, связанных с с mongodbmongodb
Проверяем Проверяем их на их на наличие наличие пакетов пакетов авторизацииавторизации
ВыходВыходНе нашли
Получаем из данных Получаем из данных key, nonce, loginkey, nonce, login
Нашли
key2 = md5(nonce + user + key2 = md5(nonce + user + md5(user + ":mongo:" + passw)), md5(user + ":mongo:" + passw)), где где passw passw это строка из словаряэто строка из словаря
Получаем Получаем следующую следующую строку из строку из словарясловаря
key key ==== key2 key2
false
Выводим Выводим user:passwduser:passwd
true
Сетевое взаимодействие
Сетевое взаимодействие. MiTM атака
adminadmin
mongoDBmongoDB
HackerHacker
1. Запрос авторизации
Сетевое взаимодействие. MiTM атака
adminadmin
mongoDBmongoDB
HackerHacker
1. Запрос авторизации
2. Отдаем nonce, под который сгенерированы rainbow tables
Сетевое взаимодействие. MiTM атака
adminadmin
mongoDBmongoDB
HackerHacker
1. Запрос авторизации
2. Отдаем nonce, под который сгенерированы rainbow tables
3. Клиент отдает нам login и получившийся key
Сетевое взаимодействие. MiTM атака
adminadmin
mongoDBmongoDB
HackerHacker
1. Запрос авторизации
2. Отдаем nonce, под который сгенерированы rainbow tables
3. Клиент отдает нам login и получившийся key
4. Подбираем 4. Подбираем пароль по заранее пароль по заранее сгенерированным сгенерированным к этомук этому nonce nonce радужным радужным таблицамтаблицам
Сетевое взаимодействие. MiTM атака
adminadmin
mongoDBmongoDB
HackerHacker
1. Запрос авторизации
2. Отдаем nonce, под который сгенерированы rainbow tables
3. Клиент отдает нам login и получившийся key
4. Подбираем 4. Подбираем пароль по заранее пароль по заранее сгенерированным сгенерированным к этомук этому nonce nonce радужным радужным таблицамтаблицам
5. Успешно авторизовываемся с полученными данными
Что такое BSON
Что такое BSON?
Это Бинарный Это Бинарный JSONJSON. . BSON это расширение JSON, которое позволяет хранить данные в различных форматах: дата и время, бинарные данные и т.п.
Пример?
Типы данных
string – строкаint - целое числоdouble - двойное число с плавающей запятойDateTime – датаbyte[] - массив байт (бинарные данные)bool - булевые (true/false)null - нольBsonObject - BSON объектBsonObject[] - массив BSON объектов
Перезапись переменных
Имеется таблица с двумя записями:
Также запрос, в который мы можем внедриться:
Вставляем BSON документ, который перезаписывает переменную isadmin:
Проверяем:
Чтение произвольных участков памяти
Exploit:
В действии:
LengthLength
Чтение произвольных участков памяти
В действии:
Особенности разных ЯП
Ruby on Rails
nodejs
PHP
Особенности разных ЯП
Ruby on Rails
Особенности разных ЯП
Mass assignment в Ruby on Rails:
Особенности разных ЯП
Mass assignment в Ruby on Rails:
Особенности разных ЯП
NodeJS
Особенности разных ЯП
JSON injection в NodeJS + MongoDB:
VULNERABLE SOURCE CODE:VULNERABLE SOURCE CODE:VULNERABLE SOURCE CODE:VULNERABLE SOURCE CODE:
RESULT QUERY:RESULT QUERY:RESULT QUERY:RESULT QUERY:
SENDSEND SENDSEND
Хакер 02/12 (157)
Особенности разных ЯП
PHP
Уязвимости
Типы обнаруженных уязвимостей:
Обход авторизации через подстановку массива в php
Внедрение SSJS (Server Side JavaScript) кода
Слепое внедрение SSJS, Time-based
Особенности разных ЯП
Как известно, php обрабатывает символы “[]” из GPC как массив:
В официальном классе mongoDB для для php есть ф-ция find()
password[$ne]=parol1password[$ne]=parol1
Особенности разных ЯП
Формируется вот такой NoSQL запрос к MongoDB, и авторизация проходит успешно:
Таким образом, если в коде нет проверки, мы можем обойти авторизацию разными способами:
Особенности разных ЯП
Внедрение напрямую в js запрос.
Предположим в коде вот такие вот строки:
Также в ответ выводятся наш id и login.
Теперь пробуем внедриться в запрос:
Видно, что тут идет перезапись переменной «loginn» на результат команды db.version()
$q = “function() { var loginn = ‘$login’; var passs = ‘$pass’; db.members.insert({id : 2, $q = “function() { var loginn = ‘$login’; var passs = ‘$pass’; db.members.insert({id : 2, login : loginn, pass : passs}); }”;login : loginn, pass : passs}); }”;$db->execute($q);$db->execute($q);
Особенности разных ЯП
Иногда невозможно увидеть результат исполнения SSJS-кода.
Для этих случаем лучше использовать технику Time-based:
Специально для этого был написан скрипт для перебора и вывода нужных пользователю данных.
NoSQL-injection Cheat Sheet
db.getName() - имя текущей БД можно просто db
db.members.count() - количество записей в таблице members
db.members.validate({ full : true}) - основная информация о таблице members
db.members.stats() - почти то же что и предыдущее, но немного в укороченном варианте
db.members.remove() - очистить таблицу members, синтаксис такой-же как и у ф-ции find()
db.members.find().skip(0).limit(1) - еще один способ получения записи. Просто перебираем значение skip.
db.getMongo().getDBNames().toString() – Получаем список всех доступных БД
db.members.find()[0][‘pass’] – получаем значение поля pass из первой записи
Спасибо за внимание!
Фирстов МихаилНоябрь 2012