Содержание. __ от редакции. Биография сетевого периметра в картинках
Скачать 5.92 Mb.
|
positive research 2016 88 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 02 04 06 08 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 разБор конкурСа besT reVerser НА PHDAYS V Когда мы придумывали задание для конкурса по обратной разработ- ке, то хотели отразить реальные проблемы, с которыми сталкиваются специалисты по RE, но при этом избежать шаблонных решений. Как обычно выглядят задачки на реверс? Есть исполняемый файл под Windows (или Linux, или MacOS, или другую популярную операцион- ную систему), его можно запускать, смотреть под отладчиком, кру- тить как угодно в виртуальных средах. Формат файла — известный. Система команд процессора — x86, AMD64 или ARM. Библиотечные функции и системные вызовы — задокументированы. Доступ к оборудованию — только через механизмы операционной системы. С использованием существующих инструментов (например, IDAPro с HеxRays и всеми сопутствующими возможностями) анализ подобных приложений становится практически детской забавой: все получает- ся просто и быстро. Конечно, иногда для усложнения задачи в программу добавляют виртуальные машины со своим набором инструкций, замусоривание кода, защиту от отладки и т. п. Но если говорить честно — насколько часто крупные производители ПО используют все это в своих испол- няемых файлах? Да почти никогда! Какой же смысл делать конкурс, нацеленный на демонстрацию навыков, которые редко требуются в реальной жизни?.. Однако есть еще одна область применения reverse engineering, все больше востребованная в последние годы, — анализ firmware. И тут ситуация оказывается совсем иной. Входной файл (с прошив- кой) может быть в любом формате, может быть даже запакован или Дмитрий Скляров habrahabr.ru/company/pt/blog/261375/ зашифрован. Операционная система может быть совсем не попу- лярная — или вообще может отсутствовать. Часть кода может быть жестко прописана в устройстве и не обновляться через прошивку. Архитектура процессора может быть любая! IDAPro, например, «зна- ет» более 100 разных процессоров, но далеко не все. И, разумеется, нет почти никакой документации, почти никогда не доступна отлад- ка, а зачастую и обычное выполнение кода невозможно: прошивка есть, а устройства нет… Примерно такую задачу мы и решили предложить конкурсантам (принять участие мог любой интернет-пользователь). Каждый из них должен был проанализировать исполняемый файл (phdays.ru/ download/fwldr.zip) и найти правильный ключ, соответствующий его email. первая чаСть: заГрузчик На первом этапе входным файлом был ELF, скомпилированный кросс-компилятором под архитектуру PA-RISC. IDA умеет работать с этой архитектурой, но не так хорошо, как с x86. Многие обращения к стековым переменным автоматически не распознаются, и приходит- ся помогать IDA руками. Но хотя бы видны все библиотечные функции (log, printf, memcpy, strlen, fprintf, sscanf, memset, strspn) и даже сим- волические имена некоторых функций программы (с32, exk, cry, pad, dec, cen, dde). Довольно просто понять, что программа ждет на вход два аргумен- та — email и key. Легко выяснить также, что key должен состоять из двух частей, разде- ленных символом ‘-’. Первая часть (7 знаков) должна состоять только из разрешенных символов MIME64 (0-9A-Za-z+/), а вторая (32 зна- ка) — из шестнадцатеричных символов, которые превращаются в 16 байт. Далее видны вызовы функции c32, складывающиеся в: t = c32(-1, argv[1], strlen(argv[1])+1) k = c32(t, argv[2], strlen(argv[2])+1) Имя c32 является подсказкой: используется СRC32, что подтвержда- ется константой 0xEDB88320. Далее идет вызов функции dde (сокращение от doDecrypt), принима- ющей в первом аргументе инвертированный выход CRC32 — ключ шифрования, а во втором и третьем — адрес и размер расшифровы- ваемого массива. Расшифрование выполняется алгоритмом BTEA на основе кода, по- заимствованного из Википедии. Догадаться, что это именно BTEA, // наша школа 89 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97 99 101 103 03 05 07 09 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 можно по константе DELTA==0x9E3779B9. Правда, она используется и в других алгоритмах, являющихся предшественниками BTEA, но ва- риантов совсем немного. Ключ должен быть 128-битовый, а CRC32 возвращает 32-битовое зна- чение, так что три дополнительных DWORD получаются в функции exk (expand_key) домножением предыдущего значения на все то же значение DELTA. Правда, BTEA применяется не совсем обычно. Во-первых, у этого алгоритма настраиваемый размер блока, и в задании используется 12-байтовый блок: если бывают процессоры с 24-битовыми регистра- ми и ячейками памяти, то почему размер блока должен быть степе- нью двойки? :) А во-вторых, функции зашифрования и расшифрова- ния поменяны местами — так тоже можно. Поскольку шифруется поток данных, применяется зацепление бло- ков в режиме CBC (Cipher Block Chaining). Для расшифрованных дан- ных в функции cen (calc_enthropy) вычисляется энтропия, и если ее значение превысит 7, то результат расшифрования признается не- верным, и программа завершается с соответствующим сообщением. Так как ключ шифрования имеет длину всего 32 бита, может показать- ся, что его легко подобрать. Однако если следовать логике програм- мы, для проверки каждого ключа надо сначала расшифровать 80 ки- лобайт данных, a потом подсчитать для них энтропию. И поиск ключа шифрования в лоб займет слишком много времени. Однако после проверки энтропии вызывается еще одна функция, pad (оригинальное название — strip_pad), которая проверяет и от- резает PKCS#7 padding. Из-за свойств режима CBC для проверки до- полнения надо расшифровать только один блок (самый последний), взять из него последний байт N, проверить, что его значение лежит в диапазоне от 1 до 12 включительно и что каждый из последних N байт имеет значение N. Это позволяет значительно сократить количество операций для проверки одного ключа, но если последний расшифрованный байт будет равен 1 (а это будет справедливо для 1/256 ключей), все равно придется делать полную проверку… Чтобы найти ключ быстрее, достаточно предположить, что расшиф- рованные данные будут иметь длину, выравненную на DWORD (4 бай- та). Тогда в последнем DWORD последнего блока может оказаться только одно из трех возможных значений — 0x04040404, 0x08080808 или 0x0C0C0C0C. И используя такую эвристику можно перебрать все возможные ключи (и гарантированно найти правильный) менее чем за 20 минут. Если все проверки после расшифрования (энтропия и целостность паддинга) пройдены успешно, вызывается функция fire_second_proc, которая симулирует запуск второго процессора и загрузку в него расшифрованных данных (прошивки) — ведь в современных устрой- ствах часто более одного процессора, причем с совершенно разны- ми архитектурами. Если второй процессор удалось успешно запустить, ему через функ- цию send_auth_data передается email пользователя и 16 байт со второй частью ключа. В этом месте мы случайно допустили ошибку: вместо размера второй части ключа использовался размер строки с email. вторая чаСть: проШивка С анализом второй части все несколько сложнее. Там не ELF, а про- сто образ памяти — без заголовков, имен функций и прочей мета- информации. И разумеется, неизвестен ни тип процессора, ни адрес загрузки. Задуманный нами алгоритм определения архитектуры процессо- ра — обычный перебор. Открываем в IDA, ставим следующий тип, смотрим на получившийся мусор, и повторяем до тех пор, пока IDA не покажет что-то похожее не код. Перебор, в идеале, должен приве- сти к выводу, что это big-endian SPARC. Теперь надо определить адрес загрузки. Функция по смещению 0x22E0 ниоткуда не вызывается, но содержит довольно много кода. Можно предположить, что это точка входа в программу, функция start. В третьей инструкции функции start идет вызов неизвестной библи- отечной функции с одним аргументом == 0x126F0, и эта же функция вызывается из start еще 4 раза, всегда с разными, но близкими по зна- чению аргументами (0x12718, 0x12738, 0x12758, 0x12760). А в середине программы, начиная со смещения 0x2490, присутствуют как раз 5 тек- стовых строк с сообщениями: 00002490 .ascii "Firmware loaded, sending ok back." <0> 000024B8 .ascii "Failed to retrieve email." <0> 000024D8 .ascii "Failed to retrieve codes." <0> 000024F8 .ascii "Gratz!" <0> 00002500 .ascii "Sorry may be next time..." <0> Если предположить, что адрес загрузки равен 0x126F0-0x2490 == 0x10260, то все аргументы при вызове библиотечной функции будут точно указывать на строки, а сама неизвестная функция окажется функцией printf (или puts, что в данном случае не важно). После изменения базы загрузки код будет выглядеть примерно так: Значение 0x0BA0BAB0, передаваемое в функцию sub_12194, также встречается в первой части задания, в функции fire_second_proc, и сравнивается с тем, что получается из read_pipe_u32(). Значит, sub_12194 должна называться write_pipe_u32. Аналогично, два вызова библиотечной функции sub_24064 — это memset(someVar, 0, 0x101) для email и code, а sub_121BC — это read_ pipe_str(), обратная write_pipe_str() из первой части. Самая первая функция (по смещению 0 или адресу 0x10260) имеет характерные константы, которые позволяют в ней безошибочно определить MD5_Init: positive research 2016 90 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 02 04 06 08 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 А рядом с тем местом, где к MD5_Init идет единственное обращение, легко обнаружить функции MD5_Update() и MD5_Final (), перед кото- рыми идет вызов библиотечной strlen(). В функции start() остается совсем немного неизвестных функций. Функция sub_12480 переворачивает байтовый массив заданной длины. Фактически это memrev, на вход которой подается массив code длиной 16 байт. Очевидно, что в sub_24040 принимается решение о том, правиль- ный ли был код. При этом в аргументах передается указатель на вычисленное значение MD5(email), указатель на массив, заполнен- ный в функции sub_12394, и число 16. Здесь вполне мог быть просто вызов memcmp! Основная магия выполняется в функции sub_12394. Подсказок там почти никаких нет, зато сам алгоритм описывается одной фразой — перемножение двоичной матрицы размерности 128 на двоичный вектор размера 128. Матрица хранится в теле прошивки по адресу 0x240B8. Таким образом, код будет признан верным если MD5(email) == matrix_mul_vector(matrix, code). вычиСление правильноГо ключа Чтобы найти правильное значение code, надо решить систему двоичных уравнений, описываемую матрицей, когда в правой ча- сти стоят соответствующие биты из MD5(email). Если кто-то забыл линейную алгебру: это легко сделать методом гаусса. Когда известна правая часть ключа (32 шестнадцатеричных симво- ла), надо подобрать первые 7 символов таким образом, чтобы ре- зультат вычисления CRC32 оказался равен найденному значению ключа для BTEA. Таких значений примерно 1024 штуки, и искать их можно как простым перебором (довольно быстро), так и обращая CRC32 и проверяя валидные символы (вообще моментально). Остается собрать все вместе и получить ключ, который прой- дет все проверки и будет признан нашим верификатором как валидный. Мы опасались, что задание окажется слишком сложным и никто не сможет его решить самостоятельно от начала и до конца. К сча- стью, Виктор Алюшин показал, что наши страхи были беспочвен- ными. Напомним, Виктор победил в Best Reverser второй раз: он был лучшим и в 2013 году. оБучаем практичеСкой БезопаСноСти В 2015 году компания Positive Technologies отпраздновала трехлетие образовательной программы Positive Education, в рамках которой мы оказываем содействие российским вузам в подготовке ИБ-специалистов. Сейчас в программе Positive Education участвуют более шестидесяти ведущих учебных заведений России, в их числе МИФИ, МгУ, МгТУ, МАТИ, СПбгЭУ, ДВФУ, ОмгТУ, НгУ. Суть проекта заключается в том, что компания бесплатно предоставляет вузам защитное ПО и методиче- ские материалы. Так, с помощью межсетевого экрана PT Application Firewall преподаватели смогут проводить курсы по без- опасности веб-приложений, а студенты узнают о проблемах в устройстве приложений и на специальных учебных сайтах отработают навыки по их защите. Системы контроля защищенности XSpider и MaxPatrol позволяют учащимся увидеть, как выполняются тесты на проникновение и поиск уязвимостей. Кроме того, компания приглашает студентов на практику: это реальный шанс попасть в команду экспертов Positive Technologies. По вопросам практики и организации курсов пишите на edu@ptsecurity.com. // наша школа 91 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97 99 101 103 03 05 07 09 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 конкурС WAF bypAss НА PHDAYS V Арсений Реутов habrahabr.ru/company/pt/blog/259129/ На международном форуме Positive Hack Days V проходил, как и го- дом ранее, конкурс WAF Bypass. Задача участников — обойти защи- ту PT Application Firewall. Специально для конкурса был создан сайт Choo Choo Roads с типовыми уязвимостями — Cross-Site Scripting, SQL Injection, XML External Entities Injection, Open Redirect и др. Результатом обхода проверки для каждой уязвимости были MD5-флаги, за которые присуждались очки. Флаги располагались в файловой системе, базе данных, в куки-параметрах, которые присваивались специальному боту, написанному с использованием Selenium. Конфигурация WAF, подготовленная для конкурса, предусматривала конкретные пути обхода, однако в итоге мы получили и нестандарт- ные решения. Собственно, для этого конкурс и создавался — дать возможность участникам попытать свои силы в обходе проверок и тем самым помочь нам улучшить механизмы защиты продукта. Итак, рассмотрим уязвимостей — и способы обойти соответствующие проверки. WArm-up Уязвимость присутствовала в сценарии, который отслеживал актив- ность пользователя на сайте: POST /online.php HTTP/1.1 Host: choo-choo.phdays.com Connection: keep-alive Content-Length: 24 Content-Type: application/json User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.48 Safari/537.36 {"timestamp":1432906707} Значения поля timestamp из JSON-данных в POST-запросе не валиди- ровались перед использованием в SQL-запросе: Warning: pg_query(): Query failed: ERROR: invalid input syntax for integer: "1432906707' " LINE 1: UPDATE activity SET timestamp = '1432906707'' ' WHERE id=1 ^ in /var/www/php/online.php> on line 8 {"ok":false} Обойти проверку можно было подменив Content-Type, например на text/xml, в результате чего POST-данные не обрабатывались как JSON (проверка была отключена). Warning: pg_query(): Query failed: ERROR: invalid input syntax for integer: "d2a5400fc306d25b6886612cd203a77e | 26.05 15:30 - Industry monopolist Choo Choo Roads wins a government contract for railroad construction" in /var/www/php/online. php on line 8 {"ok":false} xsd-валидация На сайте была форма для поиска билетов, который осуществлялся путем формирования XML и отправки запроса на бекенд. POST /tickets.php HTTP/1.1 Host: choo-choo.phdays.com Connection: keep-alive Content-Length: 220 Content-Type: text/xml Для XML-запроса использовалась XSD-схема: positive research 2016 92 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 02 04 06 08 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 Атрибут id, согласно схеме, должен иметь длину в 35 символов. Значение атрибута попадало в SQL-запрос без валидации. Для обхода требовалось сконструировать вектор, удовлетворяющий требовани- ям XSD-схемы. open redirecT Уязвимость была в параметре to сценария redirect.php. Флаг пере- давался в fragment-части URL, куда совершался редирект, т. е. он не отправлялся на серверную часть. Чтобы получить флаг, необходимо было отправить бота на сторонний сайт со страницей, которая долж- на была бы извлечь значение из location.hash и отправить его логгеру. Варианты обхода: http://choo-choo.phdays.com/redirect.php?to=phdays.com:asd@host.com http://choo-choo.phdays.com/redirect.php?to=http://ahack.ru%23. phdays.com/ http://choo-choo.phdays.com/redirect.php?to=http%3a//www.samincube. com%3f\..\\www.phdays.com xml exTernAl enTiTies inJecTion Сценарий, обрабатывающий XML-данные, был подвержен XXE. Для обхода требовалось использовать внешнюю сущность внутри parameter entity: "> %asd; %asd1; ]> Также был возможен обход с помощью кодировки UTF-16: cross siTe scripTing Уязвимость была заложена на странице поиска по сайту. Чтобы полу- чить флаг, требовалось отправить куки бота на свой сайт. Для обхода можно было использовать нестандартные атрибуты тэгов, которые обрабатываются библиотекой bootstrap-validator, позволяя выпол- нять JavaScript-код: http://choo-choo.phdays.com/index.php?search= Или так: http://choo-choo.phdays.com/index.php?search=<% http://choo-choo.phdays.com/index.php?search=<%00 результаты Как и в 2014 году, первое место заняла команда bushwhackers: георгий Носеевич, Андрей Петухов и Александр Раздобаров. Они решили все задания еще в первый день! Второе место занял Михаил Степанкин (ArtSploit), а третье — Эльдар Заитов (cococo). За время конкурса было заблокировано 271 390 запросов (в два раза больше, чем в прошлом году). Зарегистрировались 302 участника, но лишь 18 человек смогли добыть хотя бы один флаг. |