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().
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.
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.
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.
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.
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().
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.
- 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.
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.
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:
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 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.
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.
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
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
Más artículos de Web3, Blockchain & SmartContracts
- Blockchain & SmartContracts: Una serie para aprender
- BlockChain & SmartContrats: Primer SmartContract con Solidity
- Blockchain & SmartContracts: Cómo probar y desplegar un SmartContract en Ethereum
- WWW, Web 1.0, Web 2.0, Web 3.0, Web3 y ¿Web 4.0?
- Metaverso, multiverso y las tierras digitales en que vivimos en forma de avatar
- Los Fan Tokens vs. las Criptomonedas y los NFTs: Level 101
- Tokenomics: Las criptomonedas y las "Proof-of-work": Level 101
- Los NFTs y el registro mundial de los dueños de activos digitales en el Metaverso
- BitCoin: Blockchain y su investigación
- BlockChain & SmartContrats: El Internet descentralizado y el almacenamiento off-chain en IPFS
- Reentrancy Attack: Cómo te roban criptomonedas por un bug en tu SmartContract
- BlockChain & SmartContract: Bugs que pueden dejar tu SmartContrat "fuera de juego"
- Blockchain & SmartContracts: Patrones y buenas prácticas de seguridad
- Blockchain & SmartContracts: Herramientas de Auditoría de Seguridad de SmartContracts
- BlockChain & SmartContracts: Ataque de phishing a tx.origin y robo de criptomonedas
- BlockChain & SmartContracts: Ataques de Ice Phishing
- Blockchain & SmartContracts: Herramientas de análisis dinámico
- ZIION: Una distribución Linux para auditar SmartContracts (& BlockChain)
- Dominios Web3 en Etherenum Name Service y la trazabilizad de las transacciones Blockchain
- BlockChain & SmartContracts: Actualizar SmartContracts como los grandes protocolos
- Jumping level up (from) web2 (to) web3: Vulnerabilities & SCAMs - SmartContracts
- 20 millones (Euros) en Tokens de Optimism perdidos por no saber cómo funcionan los Wallets Multifirma
- BlockChain & SmartContracts: Cómo crear una DApp de la Web3 con Python (y Flask)
- Pentesting SmartContracts: From Web2.0 to Web3
- Tokenomics 101: Una explicación con gráficos
- Read-Only Reentrancy Attack: $220k robados y otros +$100M en riesgo
- Como utilizar ChatGPT para encontrar bugs en SmartContracts
- BlockChain & SmartContracts: Nuevas áreas profesionales relacionadas con la Web3
- Las voces de Satoshi: Un canal para estar al día en Web3, Blockchain, Criptos & IA
- BlockChain & SmartContracts: Nuevas áreas profesionales relacionadas con la Web3
- Bit2Me Academy: Una plataforma online para aprender de Web3, BitCoin, Tokenomics o Ethereum con cursos gratuitos
- Level_Up!: Una plataforma para aprender a hacer pentesting en Web3 (SmartContracts & BlockChain ) a través de retos hacking
- Level_Up!: Web3 Security WarGames para los amantes del Challenge Based Learning
- Level_up!: WriteUp del Reto Questions para comenzar el pentesting en la Web3
- Level_Up! Deny_to_me Challenge activado en la plataforma Level_up! de retos hacking Web3
- Level_Up!: WriteUp del Ownership Challenge para hacer pentesting en Web3
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