...

среда, 9 апреля 2014 г.

Тестирование безопасности клиент-серверного API

2 года назад я выступал на конференции CodeFest с темой «Пентест на стероидах. Автоматизируем процесс» и делал пересказ выступления в качестве статьи. В этом году я с большим удовольствием снова принял участие в конференции и выступил с темой «BlackBox тестирование безопасности клиент-серверного API» и, видимо уже в качестве традиции, также делаю пересказ выступления.



Уязвимости в API встречаются. Правда.


О чем разговор?




Разговор про API, но API бывает разным — API операционной системы, сайта, дектопной программы, да хоть чего. Вкратце — API это обращение к методам чего-либо (например в случае ОС — запись в файл) через определенный метод. И запуск какого-нибудь файла с т.ч. зрения разработки произойдет схожим образом (тоже через API метод ОС), хотя результат выполнения команды совершенно разный. В веб-технологиях многие тоже реализуют API к своим проектам, и если на пальцах: можно отправить сообщение в соц. сети зайдя на сайт, а можно — сформировав специальный HTTP запрос. И при реализации подобного альтернативного использования функционала допускаются (как и везде) ошибки в безопасности. Статья как раз о специфичных ошибках при реализации подобного функционала в веб-проектах.



От интерфейса к API методам




Разберем уязвимость в API на youtube, которая не получила широкой огласки. Youtube запрещает из интерфейса использовать спец. символы типа (которые нужны для html тэгов и проведения атаки XSS) в названии роликов. Но! Если найти API и попробовать изменить название этого же видео, то все пройдет успешно. Как итог: нет, xss не выполнилась на странице youtube. Но выполнилась в письме на gmail (когда приходит письмо с роликом), что еще критичнее.

Выводы? Логично — проблема в разной работе методов. А вот почему она случилась — это более интересный вопрос. Здесь бы я выделил следующее:



  • Практически все большие проекты используют ООП и паттерны подобные MVC. И реализации API должны были просто отнаследоваться от метода в интерфейсе и забрать все его ограничения. Значит или нет подобного шаблона и метод писался с нуля (бред? кто знает) или кастомный «хак» в работе интерфейса;

  • Кастомный хак? Проблема разработчика, конечно. Но еще и тимлида, нужно постоянно доносить до разработчиков, где и что нужно реализовывать. Т.е. четко для всех разобрать извечный тред: где в процессе разработки мы валидируем данные (в модели, сервисе, контроллере, где-то еще). Это последствия проблемы применения сложных паттернов при разработке, которые тимлид то понимает нормально, а разработчики не дотягивают и часть валидаций в проекте в одном месте, часть — в другом. Для API корректно отнаследовались, но получили уязвимость.


Что для тестировщиков?



  1. Нужно вообще забыть всё, что мы знали об интерфейсе (его ограничениях) и тестировать проект с нуля;

  2. Проверять подмену параметров, яркий пример со скрином про FaceBook — из интерфейса нельзя было подменить id отправителя, а вот из API — можно;

  3. Проверять «стандартные» атаки, типа sqli/xss;

  4. Если есть автотесты — то это круто. Можно заменить стандартный пейлоад типа testValue1 на различные спецсимволы типа ', ", >, < и матчить их (ищем XSS).


Сжатие




Часто API начинают разрабатывать для применения для мобильных устройств. И, при реализации, добавляют различные сжатия перед отправкой и разжатие после принятия. И есть старая, бородатая атака (ей ложили различные файлообменники) как ZIP бомбы. Вот вопрос: какого размера при распаковке может достичь архив в 42 кб? 4,5 петабайта. Скачать здесь, и тут. Суть простая — создается файл забитый нулями и сжимается. Поэтому сжатие, точнее распаковка — опасное дело, будьте внимательны.

Зло JSON




Иногда API предоставляется не только для какого-то конечного юзера, а порой и для пересылки данных внутри проекта. Часто это встречается на больших, крупных сайтах с различными доменами. И как-то надо взаимодействовать на стороне клиента между доменами, и тут на помощь приходит JSONP. Это такой JSON с нужными на домене 1, который оборачивается в callback. При обращении на домен 1 юзер отправит свои куки, и можно проверить, авторизован ли он и выдать нужные данные. На втором домене вставляется подобный JS

<script type="application/javascript"
src="http://ift.tt/1iuCJMJ">
</script>


с уже определенной функцией parseResponse. Но суть в том, что злоумышленник может также вставить на своем домене этот скрипт, определить свой callback и, если там sensetive данные — как-то их использовать. Прекрасный пример использования подобной уязвимости продемонстрирован в статье «Сражаясь с анонимностью».


Криптография




Говоря про API сразу на им приходит подписывание запросов. Так как доступ к API часто выдается различным пользователям нужна схема их идентификации. И чаще всего используют следующую схему: каждому выдается свой API ключ, которым разработчик подписывает свои запросы, как-то так:

sign = sha*(... + DATA + ...)


Data — отправляемые данные, вместо многоточия API ключ.

И вопрос, где ставить ключ, слева или справа? Только справа (мы говорим про подписывание запросов именно с применением подобной, очень популярной схемы). Почему? Существует атака на расширение строки. Давайте подробнее.

Представим, что у нас есть данные A=1&B=2&C=3, подпись от них 07ce36c769ae130708258fb5dfa3d37ca5a67514, подпись идет по ошибочной схеме sign=sha1(KEY+DATA).

А теперь ситуация: кто-то перехватил буквально один запрос от клиента к серверу и теперь хочет поменять данные в запросе, но ему потребуется новая подпись, а ключ для подписи не передается (оно и логично). Что он знает? Оригинальные данные и их подпись. Вкратце: есть техническая возможность создать расширить строку (дописать свои данные) и сделать новую подпись (хэш), не зная N байт в начале. На практике новые данные с отступом N байт при хэшировании в начале выглядят так: A=1&B=2&C=3\x80\x00\x00…\x02&C=4 . где



  • A=1&B=2&C=3 — изначальные данные

  • \x80\x00\x00…\x02 — спец. байты для «отступа» (ключ для подписи) при хэшировании

  • &c=4 — наши новые данные




При отправке одного и того же параметра например PHP — возьмет второй. Как раз то, что и нужно для атаки. Так как на первый мы не можем повлиять


Зло победило: можно подписывать запросы, менять параметры не зная ключа для подписи. А вот выдержка из документации по работе с API VK и Mail.RU



Vkontakte: sig = md5(name1=value1name2=value2api_secret)
Mail.RU sig = md5(uid + params + private_key)



Как видим — ключ справа.

Я обмолвился про кражу всего одного запроса. На практике это бывает чуть проще, чем кажется (история #1, статья)


Небезопасный XML




Думаю каждый встречался с XML, ничем не примечательный тип данных

<recipe name="хлеб" preptime="5" cooktime="180">
<title>Простой хлеб</title>
<composition>
<ingredient amount="3" unit="стакан">Мука</ingredient>
</composition>
...
</recipe>


Но уже менее людей встречались с сущностями в XML


DTD Example:



<!ENTITY writer "Donald Duck.">
<!ENTITY copyright "Copyright W3Schools.">


XML example:



<author>&writer;&copyright;</author>


Которые позволяют что-то определить, а потом повторно использовать. На примере выше — просто строки.

А еще меньше людей сталкивались с внешними XML сущностями…



<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM
"file:///etc/passwd" >]>

<foo>&xxe;</foo>




В качестве сущности может выступить что-то внешнее, локальный файл, внешний файл по http и т.д. Т.е. это стандарт. Изначально задумывался в благих целях, например нужно отдать XMLку клиенту и взять текущее время с другого сервера (другого xml файла, доступного по HTTP).

Долго не рассуждая, уязвимость очевидна. Используя различные врапперы — file:///, http:// атакующий может получать информацию о системе, сети и т.п. Иногда это может привести и к удаленному выполнению команд, например в PHP существует враппер expect://, который сначала выполняет команду на ОС и возвращает результат её работы. Так что по-умолчанию этой атаке подвержены все стандартные парсеры XML. Одно из решений приходит таким: отключить поддержку внешних сущностей. Тогда атакущий может применить XML бомбу:



<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>


И «положить» сервер. Суть в постоянной пересылке сущности на сущность.

Стоит помнить, что это может быть проблема не только сервера, но и клиента (например дектопное ПО клиента парсит XML).

Самый яркий пример использования уязвимости — взлом FaceBook в ноябре 2013, который мог повлечь и выполнение команд от ОС.


Резюмируя:



  • В первую очередь перетестировать все «интересные» ограничения интерфейса;

  • Разобраться со сжатием;

  • Внимательно следит за JS callbac'ами;

  • Криптография. Может быть не только атака на расширение строки, а просто слабый (например — короткий) ключ, или как-то предсказуемый.

  • А еще можно встретить просто зашитые в мобильное приложение API данные. Кстати, их можно найти через сервис http://hackapp.com;

  • XML — XXE;

  • Что угодно ещё.


Презентация:


Демо видео sha padding и XXE:


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий