viernes, diciembre 02, 2022

Resolución del Reto de "Pentesting SmartContracts: From Web 2.0 to Web3" de #NavajaNegra

Hace unos días comentábamos en el blog la experiencia de haber realizado el taller en Navaja Negra (en su décima edición). Tras dar el taller queríamos proponer un reto a los asistentes para ver lo que se había dado. Para ello, desplegamos un contrato en la testnet de Goerli, con el que los alumnos podrían interactuar.  Hoy os voy a contar en qué consiste el reto y cómo se resuelve.

Figura 1: Figura 1: Resolución del Reto de "Pentesting SmartContracts:
From Web 2.0 to Web3" de #NavajaNegra

Al principio uno puede pensar que la gente no hará el reto, pero no hay nada mejor que el reto como base del aprendizaje, del probarse a uno mismo y es que cada vez aumenta más la metodología de aprendizaje basada en el reto. Es algo interesante y que cada vez vemos más en muchas formaciones. El profesor te enseña algo, pero tú luego tienes que enfrentarte a ciertos escenarios (con máquinas virtuales, con entornos de Docker o, directamente, contra una VPN dónde tienes una serie de máquinas que hay que "hackear"). 

Pentesting SmartContracts: From Web 2.0 to Web3

En el mundo de los SmartContracts podemos decir que un reto en el que hay que “hackear” un SmartContract es una forma de probar al alumno y ver si ha cogido los conceptos. El reto tenía “un poco de todo”. Realmente el objetivo del reto era ir consiguiendo una serie de tokens (de un token que habíamos generado con el nombre tokenNN). Si el alumno conseguía 3 tokens podía solicitar que se le “mintease” un NFT para el recuerdo del taller. Solo los tres primeros, los 3 más rápidos resolviéndolo, tendrían premio. El NFT tenía asociada una imagen “conmemorativa” del taller.

Figura 2: Libro dedicado a "Bitcoin: La tecnología Blockchain y su investigación"
de Yaiza Rubio y Félix Brezo

Vamos a empezar el resultado: los 3 NFTs fueron “minteados” por lo que los alumnos lo hicieron rápido, quitándonos el miedo de “esto no lo va a querer hacer nadie”. Además, sabemos que más de uno lo intentó y consiguió después de que nuestro SmartContractmintease” los 3 NFTs, por lo que no tuvieron premio, pero consiguieron más que eso, aprendieron.

Las pruebas del reto

Tenemos 3 contratos, los cuales explicamos a continuación:
  • Contrato TokenNN: implementa un token ERC20 y nos servirá para ir dándote un token por cada reto que consigas pasar. Recuerda que había que conseguir 3 tokens para poder optar al NFT.
  • Contrato NFT_NN: implementa un token ERC721 y nos sirve para poder “mintear” o acuñar el NFT para los ganadores. Solo se iban a generar 3 NFTs.
  • Contrato TallerNN: simula el propio taller en sí, más adelante hablaremos del contrato y sus funciones. El objetivo para el alumno era apuntarse al taller, entender un poco la lógica del contrato (el código fuente lo proporcionábamos) y poder conseguir pasar los diferentes retos que existían dentro del propio contrato.
El contrato TallerNN tiene las siguientes funciones:

Figura 3: Funciones del SmartContract TallerNN

El alumno debe “pagar” por apuntarse al taller (de ahí el color rojo en el botón “apuntarse”). Existe un mecanismo de destrucción del contrato (que solo puede ejecutar el propietario, a través del botón “close”). El alumno puede desapuntarse del taller y luego vemos que hay una serie de botones que empiezan por “get_token_*”.
  • Get_token_one: Esta es la primera prueba. La más sencilla. Para enseñar a interactuar con un contrato, en el momento que el alumno ejecuta dicha función obtiene su primer token de tipo TokenNN. Así de fácil.
Figura 4: Función get_token_one

Lógicamente, el propietario del contrato tiene una serie de tokens en su poder que irá repartiendo entre los alumnos que van superando las pruebas.

Reto 2 (get_token_two): Integer Overflow

Durante el taller se habló de diferentes vulnerabilidades, y en un punto concreto sobre el Integer Overflow y cómo afecta a los SmartContracts generados con Solidity. Hasta la versión 0.8 del compilador no se validaban los límites de los enteros y debía ser chequeado por el programador (con el riesgo que esto supone). El contrato se compiló con la versión 0.6.2 según el propio pragma del contrato. Por lo que este reto va de Integer Overflow.

+
Figura 5: Función get_token_two

Se debía enviar un número que provocase que ese número + 1 fuera igual a 0, teniendo en cuenta que era un uint8 (es decir, entero sin signo). El uint8 es un tipo de datos de Solidity para fijar enteros de hasta 8 bits, por lo que si le pasamos un 255 y le sumamos 1 habrá un overflow y daremos la vuelta “al marcador”. Consiguiendo el segundo token.

Reto 3 (get_token_three)

El tercer reto está orientado al uso del tx.origin (el cual como medida de autorización es un punto débil en la seguridad). Si miramos el código de get_token_three vemos que en la función debemos pasar un código (0 o 1) para ir por alguna de estas dos ramas. Si se estudia lo que hace cada rama, veremos que ninguna se ejecutará completamente, si la lanzamos directamente desde un usuario. ¿Cómo es esto?

Figura 6: Función get_token_three

Si introducimos 0 como código pasaremos por 3 requires. El primero verifica que el alumno está apuntado al taller. El segundo verifica que tienes ya los dos tokens (o las dos pruebas primeras hechas) y el tercer require verifica que el msg.sender (el que invoca la función) es igual a la dirección del propio contrato TallerNN. Esto último, invocándolo el usuario nunca va a suceder.

Si introducimos 1 como código pasamos por 3 requires también. Los dos primeros iguales a los anteriores. El tercero comprueba que tx.origin (el origen de la petición) sea igual a la dirección del contrato. De nuevo, si esta función es invocada por el alumno no podrá lograrse nunca.

Entonces, ¿qué ocurre? ¿No se puede superar el tercer reto? Revisándolo el código del contrato, vemos que hay una función que se llama auth_control y que realiza por nosotros la petición a la función get_token_three

Figura 7: Función auth_control

Eligiendo el 0 o 1 como código y pasándoselo a auth_control se puede conseguir que el contrato invoque a get_token_three y si vamos por la rama de msg.sender se validará que es el contrato el que invoca, por lo que se validará con su propia dirección de contrato pasando el reto y obteniendo nosotros el tercer token (siempre que pongamos bien la dirección nuestra en auth_control). Fijaos que el token.transfer se hace a tx.origin (que es el alumno, ya que es el que invocó a auth_control).

El NFT

Una vez que se conseguían los 3 tokens (se puede verificar en el contrato con la función “get_tokens”) podemos solicitar el NFT. Primero nos validamos como “winner” para que el contrato nos registre y nos asigne una de las tres posiciones disponibles. En caso afirmativo, podemos llamar a “give_me_NFT” y conseguir nuestro token. A continuación, os dejamos algunos ejemplos de lo que podía conseguirse.

Figura 8: Wallet con NFTs

Fue muy interesante ver cómo los asistentes al taller querían participar en el reto. Fuimos buenos y os dimos el código fuente, ya que facilitaba mucho el realizar los diferentes retos (fue en caja blanca). 

Figura 9: El NFT del Winner


Quizá hubiera sido muy interesante hacerlo en caja gris o caja negra y tener que vérselas con un bytecode y empezar a hacer ingeniería inversa para detectar algunas cosas. El objetivo del taller es que la gente aprenda y conozca las bases para poder crecer en este campo de la seguridad en Web3. Seguiremos haciendo este tipo de cosas.

Más artículos de Web3, Blockchain & SmartContracts
Saludos,

Autor: Pablo González Pérez (@pablogonzalezpe), escritor de los libros "Metasploit para Pentesters", "Hacking con Metasploit: Advanced Pentesting" "Hacking Windows", "Ethical Hacking", "Got Root",  “Pentesting con Powershell” y de "Empire: Hacking Avanzado en el Red Team", Microsoft MVP en Seguridad y Security Researcher en el equipo de "Ideas Locas" de la unidad CDCO de Telefónica.  Para consultas puedes usar el Buzón Público para contactar con Pablo González

Contactar con Pablo González


No hay comentarios:

Publicar un comentario