Hardening de binarios (IV) – VTV

En el post anterior de esta serie hablamos de cómo Google había incluido ASan en GCC para detectar errores de corrupción de memoria. Virtual-Table Verification (VTV) es otra opción de GCC (>4.9) desarrollada por Google para tratar de prevenir ataques que traten de corromper punteros de la vtable.

En C++ se implementa el polimorfismo del paradigma de la orientación a objetos mediante virtual tables, o vtables. Una vtable es una estructura de datos que guarda punteros a función  de métodos virtuales, cada instancia de una clase tendrá un puntero a una o varias vtables (en casos de herencia múltiple). Estas vtables se utilizan para resolver a qué método hay que llamar cuando un objeto quiere utilizar una función virtual.

De forma maliciosa, un atacante podría explotar un error de use-after-free para hacer hijacking de la vtable de un objeto, inyectando en heap (vía heap-spraying u otra técnica) una vtable maliciosa que llame a una función designada por el atacante en vez de que el programa haga un SIGSEGV. Ver el siguiente ejemplo como prueba de concepto:

class A {
public:
int virtual foo ()
{…}
};
class B : public A {
public:
int virtual foo ()
{…}
};
int main() {
B *p1 = new B();
B *p2 = p1;
p1->foo();
delete (p1);
p2->foo ();
return 0;
}

vtv-example

La protección de VTV hace que en tiempo de ejecución por cada  llamada a un método virtual el puntero por el cual se llega a la vtable no haya sido corrompido o modificado. De esta forma, el ataque anteriormente descrito sería frustrado.

Para utilizar VTV tenemos que compilar nuestro programa con las opciones fvtable-verify=std ó -fvtable-verify=preinit. La primera genera las estructuras necesarias para verificar los punteros de vtables después de que las bibliotecas compartidas hayan sido cargadas e inicializadas, mientras que la segunda las genera antes.

Si al tratar de compilar el linker salta con el error de que no encuentra libvtv, nuestra versión de GCC no ha sido compilada con la biblioteca de vtv, por lo que tendremos que re-compilar GCC (con paciencia, tarda ~30 mins con 8 cores), configurando previamente con –enable-vtable-verify.

VTV fue presentado en USENIX Security en 2014, el artículo, la presentación y las transparencias están disponibles para más información. Previamente, en la conferencia de GNU Cauldron de 2012 una de las autoras del artículo presentó el progreso de VTV con el ejemplo que hemos visto además de más detalles, para más información sobre ataques y defensas sobre vtables ver este artículo.

¿Es esto suficiente? Lo descubriremos en los siguientes posts.

Irene Díez
Acerca de
Investigadora de DT
Expertise: Operating systems, program analysis