Обнаружил занятную вещь.
Если попытаться загрузить драйвер diskdump.sys или dumpata.sys из стандартного каталога с драйверами windows, то произойдет BSOD:
SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e)
This is a very common bugcheck. Usually the exception address pinpoints
the driver/function that caused the problem. Always note this address
as well as the link date of the driver/image that contains this address.
Arguments:
Arg1: c0000005, The exception code that was not handled
Arg2: 82645e85, The address that the exception occurred at
Arg3: 807df9f0, Exception Record Address
Arg4: 807df5d0, Context Record Address
Debugging Details:
------------------
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - <Unable to get error code text>
...
STACK_TEXT:
807dfab8 965f339f 0052005c 00000000 00010000 nt!memset+0x45
807dfad8 827cf2e6 8647c2b8 86688000 00000000 Diskdump!DriverEntry+0x1b
807dfcbc 827d2d98 00000001 00000000 807dfce4 nt!IopLoadDriver+0x7ed
807dfd00 82689a6b 8a692cd0 00000000 84491640 nt!IopLoadUnloadDriver+0x70
807dfd50 82814f9e 00000001 41adab71 00000000 nt!ExpWorkerThread+0x10d
807dfd90 826bd1f9 8268995e 00000001 00000000 nt!PspSystemThreadStartup+0x9e
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x19
Смотрим код:
Diskdump!DriverEntry:
965f3384 8bff mov edi,edi
965f3386 55 push ebp
965f3387 8bec mov ebp,esp
965f3389 53 push ebx
965f338a 56 push esi
965f338b 8b750c mov esi,dword ptr [ebp+0Ch]
965f338e 57 push edi
965f338f bf00000100 mov edi,10000h
965f3394 57 push edi
965f3395 6a00 push 0
965f3397 ff7608 push dword ptr [esi+8]
965f339a e805110000 call Diskdump!memset (965f44a4)
Итак, падение происходит из-за обнуления памяти размером 10000h по невалидному адресу. Адрес виден в стеке: 0052005c
То, что он невалиден понятно по его виду, это юзермодный адрес, а Driver Entry выполняется в контексте системного потока. Но можно и проверить:
kd> !pte 0052005c
VA 0052005c
PDE at C0600010 PTE at C0002900
contains 0000000000000000
not valid
Откуда берется невалидный адрес? Он приходит из второго аргумента DriverEntry. По документации там всегда валидная копия юникодной строки, представляющей из себя registry path:
5c 00 52 00 это \.R, первые 2 WCHAR от строки
\.R.E.G.I.S.T.R.Y.\.M.A.C.H.I.N.E.\.S.Y.S.T.E.M.\.C.o.n.t.r.o.l.S.e.t.0.0.1.\.s.e.r.v.i.c.e.s.\.D.i.s.k.d.u.m.p.
Теперь разберемся, почему драйвер diskdump.sys считает, что вторым агрументом придет какая-то структура, которую он должен заполнить, вместо registry path. После непродолжительных поисков находится виновник - драйвер crashdmp.sys, в который начиная с windows vista перекочевал из ядра весь код, связанный с крешдампами.
Драйвер crashdmp.sys загружает ядро в ф-ции IopLoadCrashdumpDriver(), где в качестве второго аргумента в DriverEntry приходит указатель на таблицу колбеков. К слову, crashdmp.sys также портит память со строкой registry path, но до BSOD'а дело не доходит, по причине слишком длинной строки registry path.
Далее, в CrashdmpLoadDumpStack грузятся остальные драйвера из стека драйверов, в которые также передается вторым параметром в DriverEntry структура, которую они заполняют своими ф-циями.
Собственно, разработчики windows не учли тот факт, что драйвера из стека crash dump i/o path можно загрузить как обычный драйвер. Никаких проверок для предотвращения их загрузки нет. Поэтому и возможен такой локальный DOS.
Данного рода баг существует как минимум на win7 и win8 как х86, так и х64.
Теперь посмотрим, возможна ли тут EoP (elevation of privilege).
.text:0001239F push dword ptr [esi+4Ch] ; size_t <= 00300074
.text:000123A2 lea ebx, [esi+0Ch]
.text:000123A5 push 0 ; int
.text:000123A7 push dword ptr [ebx] ; void * <= 00470045
.text:000123A9 call _memset
.text:000123AE push dword ptr [esi+4Ch] ; size_t <= 00300074
.text:000123B1 push 0 ; int
.text:000123B3 push dword ptr [esi+10h] ; void * <= 00530049
.text:000123B6 call _memset
.text:000123BB mov eax, [esi+8] <= 0052005c
.text:000123BE lea ecx, [eax+10h] <= 52006c
.text:000123C1 mov _DeviceExtension, ecx <= 52006c
.text:000123C7 and dword ptr [eax], 0
.text:000123CA mov dword ptr [eax+8], 2F0h
.text:000123D1 mov edx, _DeviceExtension
.text:000123D7 lea ecx, [eax+2F0h]
.text:000123DD mov [edx+18h], ecx
.text:000123E0 mov ecx, edi
...
.text:000123F0 mov eax, _DeviceExtension
.text:000123F5 mov eax, [eax+18h]
.text:000123F8 and dword ptr [eax], 0 <======== bingo!
_DeviceExtension контролируемая атакующим структура, поле [eax+18h] контролируется, можно записать туда ядерный адрес, и он будет обнулен.
Реализация атаки через обнуление произвольного нулевого адреса давно известна, причем не только ресерчерами, но и security командой windows, которая в win8 прикрыла выделение памяти по нулевому адресу.
Однако, напомню, что дело происходит в Driver Entry, которая выполняется в контексте системного потока. То есть даже на win7 нельзя будет проэксплуатировать уязвимость с обнулением dword'а по нулевому адресу.
Кроме того, по этой же причине ( системный поток ), также не получится и просто добраться до инструкции, обнуляющей нужный адрес. Потому как для успешного выполнения нескольких ф-ций memset нужно, чтобы требуемые адреса были валидны. А они будут валидными, только если научиться в контексте системного процесса каким-либо образом выделить память. Мне таких способов не известно, боюсь, их вообще не существует. Для драйвера dumpata.sys картина примерно такая же.
Таким образом, реализация EOP невозможна, только DOS.
Если попытаться загрузить драйвер diskdump.sys или dumpata.sys из стандартного каталога с драйверами windows, то произойдет BSOD:
SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e)
This is a very common bugcheck. Usually the exception address pinpoints
the driver/function that caused the problem. Always note this address
as well as the link date of the driver/image that contains this address.
Arguments:
Arg1: c0000005, The exception code that was not handled
Arg2: 82645e85, The address that the exception occurred at
Arg3: 807df9f0, Exception Record Address
Arg4: 807df5d0, Context Record Address
Debugging Details:
------------------
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - <Unable to get error code text>
...
STACK_TEXT:
807dfab8 965f339f 0052005c 00000000 00010000 nt!memset+0x45
807dfad8 827cf2e6 8647c2b8 86688000 00000000 Diskdump!DriverEntry+0x1b
807dfcbc 827d2d98 00000001 00000000 807dfce4 nt!IopLoadDriver+0x7ed
807dfd00 82689a6b 8a692cd0 00000000 84491640 nt!IopLoadUnloadDriver+0x70
807dfd50 82814f9e 00000001 41adab71 00000000 nt!ExpWorkerThread+0x10d
807dfd90 826bd1f9 8268995e 00000001 00000000 nt!PspSystemThreadStartup+0x9e
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x19
Смотрим код:
Diskdump!DriverEntry:
965f3384 8bff mov edi,edi
965f3386 55 push ebp
965f3387 8bec mov ebp,esp
965f3389 53 push ebx
965f338a 56 push esi
965f338b 8b750c mov esi,dword ptr [ebp+0Ch]
965f338e 57 push edi
965f338f bf00000100 mov edi,10000h
965f3394 57 push edi
965f3395 6a00 push 0
965f3397 ff7608 push dword ptr [esi+8]
965f339a e805110000 call Diskdump!memset (965f44a4)
Итак, падение происходит из-за обнуления памяти размером 10000h по невалидному адресу. Адрес виден в стеке: 0052005c
То, что он невалиден понятно по его виду, это юзермодный адрес, а Driver Entry выполняется в контексте системного потока. Но можно и проверить:
kd> !pte 0052005c
VA 0052005c
PDE at C0600010 PTE at C0002900
contains 0000000000000000
not valid
Откуда берется невалидный адрес? Он приходит из второго аргумента DriverEntry. По документации там всегда валидная копия юникодной строки, представляющей из себя registry path:
NTSTATUS DriverEntry( _In_ struct _DRIVER_OBJECT *DriverObject, _In_ PUNICODE_STRING RegistryPath )
Собственно, невалидный адрес и является частью этой юникодной строки:5c 00 52 00 это \.R, первые 2 WCHAR от строки
\.R.E.G.I.S.T.R.Y.\.M.A.C.H.I.N.E.\.S.Y.S.T.E.M.\.C.o.n.t.r.o.l.S.e.t.0.0.1.\.s.e.r.v.i.c.e.s.\.D.i.s.k.d.u.m.p.
Теперь разберемся, почему драйвер diskdump.sys считает, что вторым агрументом придет какая-то структура, которую он должен заполнить, вместо registry path. После непродолжительных поисков находится виновник - драйвер crashdmp.sys, в который начиная с windows vista перекочевал из ядра весь код, связанный с крешдампами.
Драйвер crashdmp.sys загружает ядро в ф-ции IopLoadCrashdumpDriver(), где в качестве второго аргумента в DriverEntry приходит указатель на таблицу колбеков. К слову, crashdmp.sys также портит память со строкой registry path, но до BSOD'а дело не доходит, по причине слишком длинной строки registry path.
Далее, в CrashdmpLoadDumpStack грузятся остальные драйвера из стека драйверов, в которые также передается вторым параметром в DriverEntry структура, которую они заполняют своими ф-циями.
Собственно, разработчики windows не учли тот факт, что драйвера из стека crash dump i/o path можно загрузить как обычный драйвер. Никаких проверок для предотвращения их загрузки нет. Поэтому и возможен такой локальный DOS.
Данного рода баг существует как минимум на win7 и win8 как х86, так и х64.
Теперь посмотрим, возможна ли тут EoP (elevation of privilege).
.text:0001239F push dword ptr [esi+4Ch] ; size_t <= 00300074
.text:000123A2 lea ebx, [esi+0Ch]
.text:000123A5 push 0 ; int
.text:000123A7 push dword ptr [ebx] ; void * <= 00470045
.text:000123A9 call _memset
.text:000123AE push dword ptr [esi+4Ch] ; size_t <= 00300074
.text:000123B1 push 0 ; int
.text:000123B3 push dword ptr [esi+10h] ; void * <= 00530049
.text:000123B6 call _memset
.text:000123BB mov eax, [esi+8] <= 0052005c
.text:000123BE lea ecx, [eax+10h] <= 52006c
.text:000123C1 mov _DeviceExtension, ecx <= 52006c
.text:000123C7 and dword ptr [eax], 0
.text:000123CA mov dword ptr [eax+8], 2F0h
.text:000123D1 mov edx, _DeviceExtension
.text:000123D7 lea ecx, [eax+2F0h]
.text:000123DD mov [edx+18h], ecx
.text:000123E0 mov ecx, edi
...
.text:000123F0 mov eax, _DeviceExtension
.text:000123F5 mov eax, [eax+18h]
.text:000123F8 and dword ptr [eax], 0 <======== bingo!
_DeviceExtension контролируемая атакующим структура, поле [eax+18h] контролируется, можно записать туда ядерный адрес, и он будет обнулен.
Реализация атаки через обнуление произвольного нулевого адреса давно известна, причем не только ресерчерами, но и security командой windows, которая в win8 прикрыла выделение памяти по нулевому адресу.
Однако, напомню, что дело происходит в Driver Entry, которая выполняется в контексте системного потока. То есть даже на win7 нельзя будет проэксплуатировать уязвимость с обнулением dword'а по нулевому адресу.
Кроме того, по этой же причине ( системный поток ), также не получится и просто добраться до инструкции, обнуляющей нужный адрес. Потому как для успешного выполнения нескольких ф-ций memset нужно, чтобы требуемые адреса были валидны. А они будут валидными, только если научиться в контексте системного процесса каким-либо образом выделить память. Мне таких способов не известно, боюсь, их вообще не существует. Для драйвера dumpata.sys картина примерно такая же.
Таким образом, реализация EOP невозможна, только DOS.
Пост в предисловие к твоей записи http://j00ru.vexillium.org/?p=1169
ОтветитьУдалитьХм, судя по дате, первооткрыватель бага j00ru, мой пост можно удалять =\
ОтветитьУдалитьУ тебя подробнее и на русском. Читатели обязательно будут =)
ОтветитьУдалить