jueves, 30 de octubre de 2008

Novell NetWare Client nicm.sys Local Privilege Escalation Vulnerability

Hola!,

Hoy queria hablar un poco acerca de esta vulnerabilidad que aunque es vieja, resulta muy trivial:

http://labs.idefense.com/intelligence/vulnerabilities/display.php?id=637

Todo el problema esta en el driver ncim.sys que no valida los datos que le pasamos en el input buffer desde user mode.

Desensamblando un poco el codigo en IDA, ubicamos primero el IOCTL Manager:

[...]
push edi
mov dword ptr [esi+38h], offset sub_16E16
mov dword ptr [esi+80h], offset sub_16E16
mov dword ptr [esi+40h], offset sub_16E16
mov dword ptr [esi+70h], offset ioctl_manager
mov dword ptr [esi+78h], offset sub_16E16
push DeviceObject ; DeviceObject
[...]

Lo primero que hace es verificar que el IOCTL es del tipo METHOD_NEITHER:

[...]
mov edi, [ebp+Irp]
push edi
call sub_16BE2
mov [ebp+var_28], al
mov esi, [edi+60h]
mov [ebp+var_2C], esi
mov eax, [esi+0Ch] ; IOCTL
sub eax, 143B63h ; METHOD_NEITHER
jz loc_16D74 ; input_buffer
[...]

En caso de que lo sea, comprueba que el INPUT_BUFFER no sea 0:

[...]
loc_16D74: ; input_buffer
mov eax, [esi+10h]
test eax, eax
jz short loc_16DD5
[...]
y luego, guarda el addrs del INPUT_BUFFER en el stack:

[...]
lea ecx, [eax+10h]
mov [ebp+var_40], ecx
[...]

Como vemos, es INPUT_BUFFER+10h.

Luego, continua haciendo un par de cosas pero nunca mas toca esa variable del stack hasta aqui:

[...]
mov eax, [ebp+var_40]
mov eax, [eax]
mov ecx, [eax]
push eax
call dword ptr [ecx+8]
jmp short loc_16DCC
[...]

Como vemos, primero saca INPUT_BUFFER+10h del stack, luego saca el primer DWORD de lo apuntando por INPUT_BUFFER+10h y posteriormente, vuelve a sacar el contenido de lo apuntado por el contenido de INPUT_BUFFER+10h y termina llamando al contenido de ese pujntero + 8; en ese momento logramos ejecutar nuestro codigo en ring0 desde user. El INPUT_BUFFER lo manejamos nosotros y por ende tambien su contenido.

Pero para llegar hasta aqui, debemos de bypassear dos comprobaciones.

La primero de ellas es esta:

[...]
call NicmCreateInstance
mov ebx, eax
mov ecx, ebx
mov eax, 0C0000000h
and ecx, eax
cmp ecx, eax
jz short loc_16DC7
[...]

En donde si EAX y ECX son ambos iguales nos iremos fuera del IOCTL manager pero en caso de que sean diferentes, pues estaremos un poco mas cerca de la parte vulnerable. Hay que decir que el valor de EAX depende de la llamada a NicmCreateInstance() a la cual se le pasan varios parametros controlados por nosotros:

[...]
mov [ebp+var_40], ecx
push ecx ; inbuffer_addr+10h
push offset dword_10568 ; constants_array
push 0 ; NULL
push eax ; input_buffer_addrs
call NicmCreateInstance
[...]

El siguiente trozo de codigo es la ultima comprobacion que debemos de pasar para poder estar en la parte vulnerable:

[...]
call sub_1716A
mov eax, [ebp+var_40]
push dword ptr [eax]
call sub_16FD2
mov ecx, eax
mov eax, 0C0000000h
and ecx, eax
cmp ecx, eax
jnz short loc_16DCC
[...]

Aqui, ECX y EAX deben de ser diferentes para que el JNZ nos lleve a la parte vulnerable. Notese que el parametro pasado al segundo call (call sub_16FD2) es un valor que nosotros controlamos y es el contenido de INPUT_BUFFER+10h.

Si logramos hacer todo eso, entonces estaremos ejecutando codigo en ring0 desde una cuenta con pocos privilegios ya que el symlink: \\..\nicm esta abierto para todo el mundo :)

Si alguien quiere el .idb de IDA ya sabe donde encontrarme.

Saludos.

2 comentarios:

Yibam desde MAdrid dijo...

Muy bueno, pero no entiendo como sabes que es METHOD_NEITHER. Podrias aclararlo ...

Gracias por adelantado ..

Un fuerte abrazo y sigue asi ...

Anónimo dijo...

http://www.osronline.com/article.cfm?article=229

Hay un articulo que explica toda la teoria para llegar a eso, cuando lo encuentre lo posteo!.