domingo, mayo 07, 2023

Level_Up!: WriteUp del Ownership Challenge para hacer pentesting en Web3

Desde que publicamos Level_Up! Nos pusimos la política de que cada mes publicaríamos un reto nuevo y un Writeup. En esta ocasión, en el mes de mayo, nos toca escribir el Writeup del reto level 2 denominado Ownership. Anteriormente, hemos publicado algunos writeups como el del reto Questions o cómo el del tutorial de introducción a la plataforma llamado Interact o el writeup del Reto Deny_To_Me. Hoy vamos a trabajar sobre un reto de dificultad 3 (de 5) y que ya no es un reto puro de introducción y requiere de saber leer mínimamente el contrato y requiere que, además, entendamos la interacción con las funciones y lo que nos piden los require()

Figura 1: Level_Up!: WriteUp del Ownership Challenge para hacer pentesting en Web3

Cuando accedemos a la página del reto en la plataforma de Level_Up! veremos que hay 5 pasos y varias pistas. Además, nos hacen énfasis en el modifier OnlyOwner. Este modifier nos permite crear restricciones a nivel de invocación de función. Muchas librerías lo importan al código, cuando hacemos uso de ellas, por ejemplo, las de OpenZeppelin. También se puede definir por el desarrollador como se puede ver en este contrato.

Figura 2: Modifier onlyOwner

El modifier OnlyOwner solamente aplica un require para comprobar que la función dónde se aplique es invocada por el Owner del contrato, el cual debería estar definido en el constructor del contrato (esto también puede verse en el código fuente del reto Ownership). En la imagen anterior, se puede ver el énfasis que tienen en enseñarnos el modifier y su código. Se entiende que el usuario debe aprender con la realización de los retos, por lo que es importante ir leyendo el paso a paso y viendo el código que nos van indicando.

Comenzando el reto

Una vez desplegamos el reto a través de la plataforma vamos a comenzar a ver las funciones que nos proporciona el reto Ownership. Podemos ver que el objetivo parece ser conseguir ser el Owner del contrato. Si revisamos en el código del contrato la función getFlag() podemos observar cómo tiene el modifier OnlyOwner, por lo que solo nos devolverá la Flag si somos el propietario del contrato.

Visto esto, debemos revisar las funciones que nos proporciona el contrato. Son muchas las vulnerabilidades que pueden existir, por lo que debemos ir leyendo cada función y entender lo que hace. Existen funciones como:
  • CambioPropiedad(): Esta función se encarga de cambiar la propiedad del contrato, siempre que se cumplan dos condiciones:
    • El usuario debe haber aportado una mínima cantidad de ethers (o wei’s).
    • El usuario debe acertar un número que se le pasa a la función como parámetro. El número, revisando el contrato no puede ser mayor de 9.
Lo curioso del reto es que para hacer el cambio de propiedad aparece el concepto de inflación. En el momento que el usuario envíe un número con la función CambioPropiedad y no acierte, su inflación crece. 

Figura 3: Funciones del SmartContract

La inflación de los usuarios empieza en 0, pero irá creciendo según estos fallen. Cuando se llama a CambioPropiedad se debe tener esto en cuenta.
  • ComprarPropiedad(): Esta función permite al usuario comprar la propiedad. “Solo” tiene que pagar más de 1000 ether (el reto no consiste en conseguir esa cantidad). Esto es una función barrera. En la plataforma de level_up! no llegaremos a esas cantidades.
  • darAlta(): Esta función permite pagar una mínima cantidad al usuario y que el contrato lo considere dado de alta. Revisando el código se puede ver que la cantidad es 0.000001 ether (el mínimo, si se abona más, mejor para el contrato).
  • darBaja(): Esta función devuelve los fondos a los usuarios y los da de baja del contrato.
  • miInflacion(): Devuelve el valor de la inflación que tiene un usuario (el que invoca la función).
  • miContribucion(): Devuelve el valor de la contribución que ha hecho un usuario cuando se ha dado de alta.
  • miPista(): Es una función que proporciona una pista. Esto es lo que devuelve: “Debes acertar el número de la propiedad. Entre 0 y 9”.
  • getFlag(): La función que nos devuelve la flag, solo cuando seamos propietarios del contrato.
Una vez que observamos todo esto, hemos leído el contrato y entendido lo que tenemos que lograr vamos a resolverlo. En primer lugar, entendemos que la primera restricción que tenemos que salvar es la de estar dados de alta. 

Figura 4: Envía de Wei con DarAlta

Para ello, a través del objeto “contract” invocamos a darAlta y le pasamos una cantidad de Wei suficiente. Se puede verificar el alta con la función miContribución().

Figura 5: Objeto miContribucion

Una vez tenemos el primer “check” listo, vamos a revisar la función de CambioPropiedad(). Como se puede ver, el primer requiere lo tenemos, pero nos faltará adivinar el número. Aquí solo podemos ir probando. Si acertamos a la primera no tendríamos inflación, pero si fallamos, tendremos que enviar una pequeña cantidad de ethers, la cual va incrementando. 

Figura 6: Función cambioPropiedad

Si jugamos bien, en el peor de los casos solo se incrementará 9 veces y la cantidad no será muy alta. La variable incremento, almacena el valor en Wei’s. Vamos a hacer la llamada a cambioPropiedad() para ver qué ocurre:

Figura 7: Llamada a cambioPropiedad()

Como se puede ver, si tenemos mucha suerte, en el primer intento conseguimos acertar el número (en este caso es 0, hay que tener en cuenta que es un número aleatorio que se introduce en el contrato en el despliegue de éste). En este caso, no ha habido que darle valor a la inflación, por lo que es el mejor de los casos. Cuando comprobamos la propiedad del contrato, éste ahora es propiedad nuestra. Se puede comprobar con el atributo player, que es la dirección con la que estamos conectados a la plataforma de Level_Up.

El caso medio o peor: solución

Ahora pensemos que no acertamos a la primera, que será lo más común. En la imagen, se puede ver cómo se intenta el cambio de propiedad, pero no se ha conseguido.  Se puede ver que el owner no ha cambiado y que la inflación de nuestro usuario ha crecido. El valor “0x5af3107a4000” es 100000000000000 Wei’s

Figura 8: El cambio de propiedad no se ha conseguido.

Debido a lo anterior, la siguiente llamada a cambioPropiedad debería ser con otro número e indicándole que abonamos esa cantidad de Wei’s. Pero en este segundo intento tampoco se ha acertado. Vemos que el Owner no ha cambiado y que la inflación aumenta. Ese valor hexadecimal vale: 200000000000000 Wei’s. Tendremos que ir aumentando el número hasta 9 o hasta que consigamos cambiar la propiedad y deberemos ir aumentando el valor de los Wei’s para cubrir con la inflación.

Figura 9: Segundo intento. 

Hay que tener en cuenta que desde que se ejecuta la función cambioPropiedad hasta que se crea el bloque con la información y hay el cambio de storage en el contrato pueden pasar unos segundos. Hay veces que puede ser interesante llamar a las funciones “contract.owner()” y “contract.miInflacion()” varias veces antes de pasar a la siguiente combinación de números.

Figura 10: Intento 8

Aquí se puede ver que el número era 8 y toda la inflación que hemos ido abonando, ya que no acertábamos con la combinación del número.

Somos owners

Ahora, ya somos owners por lo que podemos solicitar la flag. Hay que recordad que cada vez que se despliega un contrato, aunque sea del mismo reto, la flag cambia.

Figura 11: Flag conseguida

Ahora la validamos en la plataforma para que nos cuenten los puntos y finalicemos el reto.

Figura 12: Flag validada

Ya tenemos los puntos, ahora se pueden ver desde el panel de Player o, incluso, en el ScoreBoard.El reto es de dificultad 3 de 5, ya que tiene el aspecto de la inflación que se puede observar leyendo bien el código y entendiendo.

Figura 13: Scoreboard

No consiste solo con acertar el número aleatorio de 0 a 9, si no que hay que ir jugando con esos valores que van cambiando y que debemos ir abonando para poder conseguir el cambio de propiedad. Tiene sus detalles y puede costar un poco más si no tenemos fluidez con Solidity.

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

Y recuerda que si quieres aprender de estas tecnologías, tienes Bit2Me Academy, que es una plataforma online para aprender de Web3, BitCoin, Tokenomics o Ethereum con cursos gratuitos además del libro dedicado a "Bitcoin: La tecnología Blockchain y su investigación" de Yaiza Rubio y Félix Brezo que seguro que te ayudan a ponerte las pilas.

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

Figura 15: Contactar con Pablo González

No hay comentarios:

Publicar un comentario