Содержание статьи
- 5. Повышение привилегий в ядре linux / Уязвимость в эмуляции 32-х системных вызовов в 64-х битных версиях ядра linux
- 4. Повышение привилегий в FreeBSD / Уязвимость в nfs_mount()
- 3. Повышение привилегий в ядре Windows
- 2. Исполнение кода в Internet Explorer — Операция Aurora
- 1. Уязвимость в обработке .lnk-файлов (ярлыков), или lnk апокалипсис
- Что нас ждёт в 2011-м?
Этот год выдался по-настоящему жарким на уязвимости, столько опубликованных нульдеев — аж глаза разбегаются! Мне было довольно сложно выделить пять самых-самых, но я постарался справиться с этой нелегкой задачей!
5. Повышение привилегий в ядре linux / Уязвимость в эмуляции 32-х системных вызовов в 64-х битных версиях ядра linux
Эта замечательная уязвимость берет свое начало в недалеком 2007-м году, и под нее составлен документ CVE-2007-4573. Обнаружил баг польский хакер под псевдонимом cliph, он же Wojciech Purczynski (интересно как это произносится?). Уязвимость примечательна тем, что ей подвержены исключительно 64-е версии ядра linux, так как ошибка закралась в механизм совместимости 32-х системных вызовов. Рассмотрим кусок кода (из arch/x86_64/ia32/ia32entry.S), отвечающий за трансляцию 32-х битных системных вызовов в 64-е:
sysenter_do_call:
cmpl $(IA32_NR_syscalls-1),%eax <---- проверка значение EAX
ja ia32_badsys
IA32_ARG_FIXUP 1
call *ia32_sys_call_table(,%rax,8) <----- а здесь уже используется RAX
Как видно из листинга, сначала значение в регистре eax сравнивается с длиной таблицы системных вызовов, и если значение попадает в диапазон, вызывается IA32_ARG_FIXUP макрос. Этот макрос используется для выравнивания аргументов 64-битной платформы к регистрам 32-битной. Но если присмотреться повнимательнее к коду sysenter_do_call, видно, что для проверки сначала используется регистр eax, а для системного вызова уже rax! Тем самым, загружая в верхние 32 бита значения, отличные от нулевого, инструкция call передаст управление далеко за пределами системной таблицы!
.macro IA32_ARG_FIXUP noebp=0
movl %edi,%r8d
.if noebp
.else
movl %ebp,%r9d
.endif
xchg %ecx,%esi
movl %ebx,%edi
movl %edx,%edx /* zero extension */
.endm
Запатчили данную уязвимость путем добавления нового макроса LOAD_ARGS:
+ .macro LOAD_ARGS32 offset
+ movl offset(%rsp),%r11d
+ movl offset+8(%rsp),%r10d
+ movl offset+16(%rsp),%r9d
+ movl offset+24(%rsp),%r8d
+ movl offset+40(%rsp),%ecx
+ movl offset+48(%rsp),%edx
+ movl offset+56(%rsp),%esi
+ movl offset+64(%rsp),%edi
+ movl offset+72(%rsp),%eax <---- это затрет нулями верхние байты rax
+ .endm
Однако в коммите за 24-е апреля 2008 года самую главную строчку удалили, тем самым заново внедрив уязвимость :).
- movl offset+72(%rsp),%eax
.endm
В 2010-м году известный хакер Ben Hawkes, просматривая исходники ядра, к своему удивлению, обнаружил отсутствие валидации регистра eax. Забавный эксплоит со встроенным трояном опубликовали блекхеты из некой андеграунд команды под названием Ac1dB1tch3z. Они передали теплые слова поздравлений Ben Hawkes'у ;).
- cmpl $(IA32_NR_syscalls-1),%eax
+ cmpq $(IA32_NR_syscalls-1),%rax <---- теперь используется rax вместо eax
4. Повышение привилегий в FreeBSD / Уязвимость в nfs_mount()
Эту уязвимость обнаружил греческий исследователь Patroklos Argyroudis, более известный как argp. Уязвимость кроется в функции nfs_mount, до которой можно добраться с помощью системных вызовов mount() и nmount(), и связана она с отсутствием проверки длины данных, которые пришли из пользовательского пространства. Кусок кода из sys/nfsclient/nfs_vfsops.c ветки 8.0:
* 1094 if (!has_fh_opt) {
* 1095 error = copyin((caddr_t)args.fh, (caddr_t)nfh, <----- файловый хэндл под полным контролем атакующего
* 1096 args.fhsize); <----- fhsize тоже
* 1097 if (error) {
* 1098 goto out;
* 1099 }
Для эксплуатации данной уязвимости атакующий должен иметь права для монтирования: за это отвечает опция vfs.usermount (должна быть не нулевого значения).
Простейший патч, добавляющий проверку для длины:
+ if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
+ vfs_mount_error(mp, "Bad file handle");
+ error = EINVAL;
+ goto out;
+ }
Релиз FreeBSD 8.0 внес несколько улучшений в систему безопасности, одно из которых — защита от эксплуатации переполнения стека, более известная как canary word. Во FreeBSD это называется stack-smashing protection. Суть защитного механизма достаточно проста. До выхода из процедуры посредством инструкции ret вызывается код, который сравнивает значение canary word на стеке с актуальным значением. Если они не равны — значит, стек переполнился и происходит либо завершение процесса (ring 3), либо паника ядра (ring 0). Из-за этого отличного механизма эксплуатировать данную уязвимость можно на 7-й ветке фряхи, а на 8-й можно довольствоваться лишь DoS'ом :(.
3. Повышение привилегий в ядре Windows
Эта уязвимость наделала много шума в январе! Я даже помню, что новость об этой уязвимости проскакивала на mail.ru с заглавием "Обнаружена уязвимость в Windows 17-летней давности!". Атаке подвержены все 32-битные системы Windows, начиная от NT 4.0 и заканчивая «семеркой»! Ошибка заложена в специальном костыле ядра Windows, для поддержки старых 16-битных приложений, — эта подсистема называется NTVDM (NT Virtual DOS Mode). Обнаружил и опубликовал эксплоит небезызвестный хакер Tavis Ormandy из компании Google. Примечательно, что невозможность использования уязвимости лежала на нескольких предположениях/аксиомах, вот они:
- Для установки VDM контекста требуется SeTcbPrivilege привилегия.
- Код в пользовательском адресном пространстве (Ring 3 код) не может устанавливать произвольные значения в регистр селектора сегмента кода.
- Код в пользовательском адресном пространстве не может сформировать trap frame.
И Tavis Ormandy с хакерской смекалкой обошел все эти предположения!
Первое предположение.Tavis реализовал следующую комбинацию. Для начала посылается запрос NTVMD-подсистеме, затем создается удаленный поток (посредством стандартной API функции CreateRemoteThread) в процессе csrss, который по умолчанию имеет данную привилегию.
Второе предположение.Регистр CPL (Current Privilege Level) обычно равен двум младшим байтам сегментных регистров cs и ss, однако есть исключение из этого правила, если процессор находится в режиме Virtual-8086. Реальный режим процессоров x86 использует сегментную схему адресации памяти, чтобы, используя 16 бит, иметь доступ к 20-му адресному пространству. Это достигается путем нехитрой формулы: (cs << 4) + (eip & 0xffff). Такая же формула используется для проецирования сегментированного адресного пространства в защищенное линейное адресное пространство в режиме Virtual-8086. Это развязывает руки атакующему, ведь так можно выставлять cs в любое значение!
Третье предположение.Возврат из режима ядра в пользовательский режим посредством инструкции iret — достаточно сложная операция. Достаточно взглянуть на данную инструкцию в документации от Intel — это 6 страниц микрокода, нагруженных IF-конструкциями. Возврат состоит из двух частей: Pre-commit и Post-commit. Одна исполняется с ядерными значениями сегментных селекторов, другая — со значением уже для ring 3. Используя контекст VDM, с помощью недокументированной функции NtVdmControl атакующий может создать фейковый контекст, что приведет к ошибке на pre-commit стадии и сформирует trap-frame.
2. Исполнение кода в Internet Explorer — Операция Aurora
Открывает список удаленных уязвимостей — баг в IE (CVE-2010-0249), который наиболее известен под названием Aurora. Публикация этой уязвимости реально насолила Microsoft'у, так как произошло это через несколько дней после выхода "вторника патчей". Суть уязвимости CVE-2010-0249 заключается в неправильной обработке памяти в библиотеке mshtml.dll. Если точнее, там остается "подвешенной" ссылка на объект — типичнейший представитель use-after-free. Атакующий, используя JavaScript, может получить доступ к этому участку памяти следующим образом:
- При помощи вызова document.CreateEventObject() осуществляется доступ к уязвимому объекту;
- После этого вызывается document.getElementById(), чтобы убить в памяти бажный объект, но движок JavaScript'a от мелкомягких все еще дает возможность получить доступ к освобожденной памяти, пока она не занята!
Эксплуатировать уязвимость удается благодаря доступу к памяти srcElement при помощи метода CEventObj::GenericGetElement из библиотеки mshtml.dll, которая пытается получить доступ к удаленному объекту при помощи функции CElement:: GetDocPtr.
В эксплоите это делается следующим кодом:
function ev1(evt)
{
event_obj = document.createEventObject(evt);
document.getElementById("sp1").innerHTML = "";
window.setInterval(ev2, 1);
}
function ev2()
{
var data, tmp;
data = "";
tmp = unescape("%u0a0a%u0a0a");
for (var i = 0 ; i < 4 ; i++)
data += tmp;
for (i = 0 ; i < obj.length ; i++ ) {
obj[i].data = data;
}
event_obj.srcElement;
}
<body>
<span id="sp1">
<img src="aurora.gif" onload="ev1(event)"> <----- Триггер уязвимости
</span>
</body>
К сожалению, публично доступный эксплоит не обходит ни DEP, ни уж тем более ASLR, хотя от коллег из антивирусных компаний слышал, что есть эксплоиты, обходящие DEP, но в публичных источниках они не появлялись. Первыми почувствовали на себе мощь эксплоита компания Google: по их словам, 12 января была атакована система Gmail. Атака велась предположительно из Китая — прям третья мировая в киберпространстве! Впрочем, многие исследователи думают, что это не попытка промышленного шпионажа, а лишь простая деятельность блекхетов, и Google просто случайно попала под раздачу :).
1. Уязвимость в обработке .lnk-файлов (ярлыков), или lnk апокалипсис
На мой взгляд, это не уязвимость — это бомба, и она, бесспорно, заслуживает первой строчки в top 5! Брешь была обнаружена в составе нашумевшего Stuxnet червя для заражения через USB-накопители. Спустя некоторое время в MetaSploit'e появилась версия эксплоита для удаленного вектора, использующая WebDAV протокол.
Интересно проследить хронологию событий:
- 17-е июня — Антивирусные аналитики из белорусской компании VirusBlokAda обнаружили две очень интересных "малвари", которые заражали полностью пропатченную Windows 7, если пользователь просмотрит содержимое USB-носителя с помощью стандартного проводника (Windows Explorer).
- 17-е июля — Microsoft признала наличие уязвимости и выпустила соответствующую advisory.
Мне удалось узнать (по своим приватным каналам ;)), что Microsoft реально игнорировала репорты от VirusBlokAda'ы до тех пор, пока VirusBlokAda не разослала информацию другим антивирусным компаниям. Тогда уже монстры антивирусной индустрии нажали на мелкомягких — и те наконец-то зачесались :).
Уязвимость не относится к уже приевшимся stack/heap overflow и т.д. — это потрясающая архитектурная уязвимость, заложенная агентами АНБ или кривыми руками программиста :). Ошибка кроется в процессе отображения ярлыков Control Panel, когда происходит их загрузка в память процессом Explorer.exe. Уязвимой является библиотека shell32.dll, в которой происходит некорректная обработка, что приводит к контролю параметра (путь к загружаемой библиотеке) функции LoadLibraryW. Так как это прямая загрузка зловредного кода в адресное пространство, то все защитные механизмы (DEP/ASLR/SEHOP) идут лесом!
Что нас ждёт в 2011-м?
То, насколько разнообразны и интересны были уязвимости в 2010 году, действительно впечатляет. Благодаря червю Stuxnet впервые серьезно заговорили о целевой атаке против SCADA систем, а распространение Aurora назвали не просто набившим оскомину словом «эпидемия», а почти по-военному — операцией :). Вообще, малварь в этом году подарила (если, конечно, так можно сказать) вкуснейшую подборку 0day уязвимостей. Вот даже сейчас, когда я пишу эти строки, в паблике появился эксплоит для повышения привилегий в Windows Vista, 2008, 7, и он опять же был использован в Stuxnet! Будем по-доброму надеяться, что и этот, уже 2011 год, будет таким же интересным для всех security-исследователей, а значит и для нас с тобой.