Технологии безопасности

Сайт посвященный вопросам безопасности

0day в банковском ПО для геолокации

«SQLmap не видит, похоже нет тут никакой инъекции!»

С этих слов моего коллеги я присоединился к проекту по внешнему тестированию на проникновение одного из банков Азербайджана, и даже представить не мог насколько существенным будет результат.

В этой статье я расскажу вам о ручной эксплуатации уязвимости Time-based Blind SQL-injection в популярном ПО для геолокации, используемом банками для отслеживания положения и состояния инкассаторских машин и банкоматов. С полученным доступом к этому ПО потенциальному злоумышленнику не потребовалось бы:

выслеживать инкассаторские машины для их последующего ограбления;
торопиться, отламывая банкомат от стены;
обшивать кузов Газели железом для перевозки украденного банкомата.


Но обо всем по порядку. Итак мой коллега изучал логин-форму одного из сервисов известного банка Азербайджана в ходе проекта по внешнему тестированию на проникновение. Его сканер (Burp Suite Professional модуль Scanner) обнаружил уязвимость типа “межсайтовый скриптинг” (далее XSS) и подозрение на SQL-injection. Коллега натравил на несчастную форму все доступные ему сканеры и, конечно же, SQLmap. Однако никто из сканеров эту уязвимость не обнаружил и, докладывая тимлиду о промежуточных результатах, он и сказал эту фразу.

“Сильное заявление, проверять я его… наверное буду” — подумал я, хотя сомневаться в опыте коллеги я даже и не думал, в части веб-уязвимостей он был опытнее меня. Но ведь двое всегда лучше чем один?

Беглый осмотр формы входа показал, что уязвимость типа XSS эксплуатируется как по учебнику, никакой фильтрации входящих параметров нет, а уж WAF и подавно, строка в поле “login” выводит приятное взору пентестера окошко:

"><<<<<<<<<script>alert(2);</script>>>>>>


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

Итак фильтрации входных параметров нет, WAF нет, значит потенциально в этой форме входа может быть целый каскад уязвимостей всех сортов и расцветок и ее как минимум стоило просканить и профаззить. Однако фаззинг, как и сканирование, ничего не дали и у меня, хотя к настройке SQLmap я подошел особенно тщательно. Единственной зацепкой было подозрение выданное Burp’ом, которое, наконец, появилось и у меня. Burp подставлял следующую строку в поле:

1’script(alert(’XSS’))+OR sleep(10)+’

На этом моменте стоит напомнить читателю, что же такое — Time-Based Blind SQL-Injection (если теория вам не нужна, то можете смело пропустить текст под спойлером).

SQL-Injection ЛикБез
SQL-injection (Внедрение SQL-кода/SQL-инъекция) — уязвимость возникающая из-за недостаточной фильтрации входных параметров веб-приложения. Успешная эксплуатация подобной уязвимости позволяет злоумышленнику выполнить запрос к базе данных веб-приложения. В ходе эксплуатации классической SQL-инъекции веб-сервер выдает сообщения об ошибках и выводит результат выполнения запроса.

Blind SQL-injection (Слепая SQL-инъекция) — в отличие от классической SQl-инъекции в ходе эксплуатации подобной уязвимости не выводятся сообщения об ошибках.

Time-based blind SQL-Injection (Слепая SQL-инъекция, основанная на задержках) — одна из наиболее сложных к эксплуатации видов уязвимости. В отличие от классической SQL-инъекции в ходе эксплуатации этой уязвимости не появляются сообщения об ошибках и не выводится результат выполнения запроса.

Как же тогда возможно получить результат выполнения запроса, если он не выводится? Вот тут в дело и вступают функции SLEEP() и BENCHMARK() которые приостанавливают на определенное количество секунд работу СУБД. Мы можем проверить на истинность то или иное сравнение и в случае истинности выполнить команду SLEEP(10). И если сервер ответил нам без задержки, то сравнение ложно, или же в запросе ошибка. Если задержка присутствует, результат сравнения — истина! Таким образом перебирая варианты мы можем посимвольно вытащить из базы данных все данные, такой функционал есть у ПО SQLmap.

Мне стал понятен ход мысли коллеги. Ведь SQL-injection, возможно, срабатывала после кода, эксплуатирующего XSS. И та задержка, которую детектировал Burp, вполне могла быть обусловлена выполнением XSS или сетевыми задержками. Запрос в целом выглядел диковато, XSS явно мешала анализу, поэтому первое что было необходимо сделать — это от нее избавиться. В итоге задержка возникла при подстановке следующей строки в поле login:

demo’+sleep(10)+’

Сетевая задержка чувствовалась, однако выставляя счетчик секунд на значения больше 5 секунд, сомнения в том, выполняется ли код, постепенно развеялись. Суммарно (с таймером на телефоне в руке) было выполнено около 10 замеров. Таких совпадений быть не могло, код выполнялся. Успешный запрос к СУБД был повторно отправлен в SQLmap, вычищен от XSS, но SQLmap упорно не находил уязвимость. Были заданы параметры префикса и суффикса, но и это не помогло, оставалось лишь попытаться проэксплуатировать уязвимость вручную.

В этот момент я прекрасно понимал, что скорее всего до чего-то стоящего, например, хэша пароля администратора, я не доберусь. Мне просто не хватит терпения перебирать сначала имена таблиц, потом колонки, потом имена пользователей и в конце тот же хэш пароля. Но доказать наличие уязвимости, вытащив из базы данных хоть что-то, мне было необходимо. Этакий PoC(Proof of Concept) для отчета.
Я сформировал первый запрос и постепенно добавлял все новые и новые сравнения.

demo’+if((select count(*) from INFORMATION_SCHEMA.columns where TABLE_SCHEMA=database() and TABLE_NAME=’users’) = 1, sleep(10), null)+’

Имя таблицы стандартное — “users”

demo’+if((select count(*) from INFORMATION_SCHEMA.columns where TABLE_SCHEMA=database() and TABLE_NAME=’users’ and COLUMN_NAME=’name’) = 1, sleep(10), null)+’

Найдена колонка — “name”
И так далее, пока не был найден пользователь “admin”. Вот только неизвестно, какие у него права, и не на словах ли он админ, а на деле… вообще может быть заблокирован! Далее необходимо было проверить длину пароля:

‘+if((select length(select password from users where name=’admin’)) = 32, sleep(10), null)+’

32 символа, скорее всего MD5-хэш, и скорее всего соленый, но уже какой-никакой PoC. Но ведь не останавливаться же на PoC? А вдруг это настоящий админ и хэш подберется? Через модуль Intruder в Burp был запущен последовательный перебор всех символов от 0 до F с помощью вот такой вот подстановки:

‘+if(mid((select password from users where name=’admin’), 32,1) = ‘§a§’, sleep(10), null)+’

Где вместо §a§ подставлялись 16-тиричные символы.
И со временем хэш был получен: 0d8fc359c6b2852fb33356a1cc4a104f
Итак, хэш получен, осталось лишь найти соль, если она есть. Предположим, что ее нет, и попробуем загрузить хэш в онлайн-радужную таблицу, благо такие есть. Для этого хэша пароль в таблице оказался, и он был emin111. Если учесть что в Азербайджане это имя довольно распространено, то очень похоже на правду! Вводим логин и пароль в форму входа и….
И мы действительно админ, и мы действительно внутри, правда карта тормозит. Что же может админ:

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

Одним словом, он имеет полный доступ к веб-приложению.

Было принято решение зайти на сайт разработчика веб-приложения и посмотреть, кому оно поставлялось и есть ли у разработчика какой-либо демо-интерфейс. Ведь если эта уязвимость есть в этом банке, вполне возможно, что она есть и у остальных, пользующихся этой системой. Демо-интерфейс был найден по адресу trackinn.ru, и уязвимость была подтверждена и там (разумеется, без взлома системы). Письмо в банк и разработчику ПО было написано немедленно, и через пару дней уязвимость была успешно устранена. Еще через пару недель устранена она была и у всех клиентов, которым поставлялось ПО. Поэтому мы со спокойной душой публикуем эту статью. Надо отдать должное разработчику ПО, сотрудники которого исправили эти уязвимости буквально за выходные!

Что хотелось бы сказать в итоге? На протяжении 19ти лет уязвимости этого типа(SQL-injection) обнаруживаются злоумышленниками и пентестерами, причем и в очень критичном ПО. Сканеры уязвимостей не всегда способны ее обнаружить, особенно когда дело касается Time-Based. А ведь это только одна уязвимость, а далеко не самая распространенная.

Почему же так получается? Во многих организациях существует ПО, которое выпадет из типичного процесса управления уязвимостями, как правило потому, что оно специфично, администрируется отдельными подразделениями, или про него просто забывают. Если коротко, то мы видим следующие ошибки:

Сервис стал доступен из Интернет в результате серьезной недооценки рисков ИБ.
Фильтрация входных параметров отсутствовала, разработчики просто о ней не подумали.
WAF не был установлен и настроен должным образом службой безопасности банка.
Хэши паролей хранились без соли.

Надеюсь, мы нашли эту уязвимость раньше преступников.

Спасибо за внимание!
Материал подготовил Антон Бочкарев, специалист по тестированию на проникновение компании «Инфосистемы Джет».
При содействии Александра Семененко, специалиста по тестированию на проникновение компании «Инфосистемы Джет».