¡Bienvenido a la guía para principiantes de auditoría de contratos inteligentes! Una de las mejores maneras de comenzar con la auditoría de contratos inteligentes es saltar y observar algunos tipos comunes de vulnerabilidades en los contratos inteligentes.
Sería útil si ya tiene una comprensión básica del lenguaje de programación Solidity de Ethereum. Como veremos, algunos de los códigos escritos por los programadores de solidez de Noob.
Ataque de reingreso
Escenario del mundo real:
Imagina que tienes 50 chocolates. Tienes una hermanita traviesa a la que le has permitido quitarte solo 2 chocolates a la vez. Tampoco querrás darle más de 10 chocolates en un día, por temor a que tenga caries. Para garantizar esto, todas las noches cuentas cuántos chocolates te quedan. ¿Crees que esto funcionaría? ¿O serías hackeado por tu hermana pequeña?
Desafortunadamente, ¡no funcionará! Tu hermana se da cuenta de que no sabes cuántos chocolates tienes hasta que se hace de noche. ¡Así que al día siguiente, tu hermanita te visita 6 veces antes de la noche y toma 2 chocolates cada vez! Esto es lo que llamamos un ataque de Re-entrada.
Aquí está actualizando el conteo de chocolates que tiene en la noche en lugar de actualizar el conteo cada vez que su hermana le quita 2 chocolates. Esto es también lo que sucede con el contrato inteligente. El contrato inteligente asume un equilibrio particular mientras que el atacante está realmente ocupado retirando una cantidad de criptografía del contrato varias veces.
Ejemplo de código del mundo real:
Este código pertenece a un contrato inteligente llamado Sin Banco. Cualquiera puede retirar ether de un contrato no bancarizado siempre que los saldos del remitente del mensaje (es decir, la persona que llama de withdraw
función ) es mayor o igual a la cantidad solicitada para retirar.
function withdraw(uint _amount) { require(balances[msg.sender] >= _amount); msg.sender.call.value(_amount)(); balances[msg.sender] -= _amount;
}
Observe que hay una palabra clave de llamada que se usa para enviar la cantidad requerida de éter al msg.sender
. Un atacante puede explotar esto creando un contrato llamado Thief en el que llama a la función de retiro en un fallback()
función. A fallback()
La función en Solidity es una función especial que se ejecuta cuando se envía ether al contrato inteligente.
Esto significa que un atacante puede llame recursivamente a la función de retiro. Por lo tanto, antes de las actualizaciones del contrato inteligente, los saldos de msg.sender
en la última línea de código, el atacante ya ha retirado ether varias veces. Esto podría evitarse si los saldos se actualizan antes de usar la palabra clave call, siguiendo así un controles-efectos-interacciones patrón.
Repercusiones:
El primer ataque de reentrada sucedió en 2016 en una DAO (Organización Autónoma Descentralizada) que resultó en un pirateo de aproximadamente $ 50 millones. Para revertir este ataque, la comunidad de Ethereum dividió la cadena de bloques de Ethereum, lo que dio lugar a ETC (Ethereum Classic) y ETH (Ethereum).
Desbordamiento aritmético y subdesbordamiento
Escenario del mundo real:
Hagamos un juego de pensamientos. Consiste en hacer girar la rueda, y el ganador se decide en función del mayor número que sea capaz de obtener al girar la rueda. La rueda está marcada por todas partes desde 256 hasta -256.
Las reglas del juego son que el puntero de todos los jugadores se encuentra en 0 al comienzo de cada giro. Y un jugador puede girar solo en la dirección de los números negativos. ¿Cómo ganarás este juego?
Una buena estrategia para ganar este juego cada vez sería hacer girar la rueda con tanta potencia que la rueda gire hasta -256 y luego gire a 256 de una sola vez. Esto es posible porque 256 viene justo después de -256 en la rueda. Esto es lo que llamamos un subdesbordamiento aritmético. Y el desbordamiento aritmético es justo lo contrario de esto.
Ejemplo de código del mundo real:
An subdesbordamiento o desbordamiento ocurre cuando una operación aritmética alcanza su mínimo o máximo.
function withdraw(uint _amount) public { require(balances[msg.sender] - _amount > 0); address payable to = payable(msg.sender); to.transfer(_amount); balances[msg.sender] -= _amount;
}
El _amount
El parámetro de la función de retiro es un entero sin signo. El valor de la asignación de saldos (que es como un diccionario en python o un par clave-valor en C++ o Java) también es un número entero sin signo.
mapping(address => uint256) public balances
El extracto requerido verifica si los saldos de msg.sender
es positivo o no. Pero esta afirmación siempre será cierta aunque la cantidad sea mayor que los saldos de msg.sender
. Esto se debe a que tanto el balances
y _amount
Las variables son de tipo entero sin signo y su resultado aritmético (después del subdesbordamiento) también será un entero sin signo.
Y como recordará, un número entero sin signo siempre es positivo. ¡Esto significa que un atacante puede retirar una cantidad ilimitada de Ether del contrato inteligente! Puede encontrar un ejemplo detallado y un código de implementación para esta vulnerabilidad. esta página.
Otra cosa crucial a tener en cuenta aquí es que la operación aritmética entre, digamos, dos números enteros sin signo también es un número entero sin signo. ¡Puede ser peligroso si esto se pasa por alto en los contratos inteligentes, ya que puede provocar violaciones de seguridad no deseadas!
function votes(uint postId, uint upvote, uint downvotes) { if (upvote - downvote < 0) { deletePost(postId) }
}
Como habrás notado en el ejemplo anterior, la declaración if es bastante inútil ya que upvote - downvote
siempre va a ser positivo. Y la publicación se eliminará incluso si downvotes
es mayor que upvotes
. Para evitar este tipo de ataques, se recomienda utilizar una versión del compilador de Solidity superior a 0.8.0.
Repercusiones:
Una moneda llamada Moneda PoWH se lanzó en 2017. Aunque era un juego Ponzi, fue pirateado debido a un error de desbordamiento aritmético que resultó en una pérdida de aproximadamente 866 ETH o $ 950,000 en ese momento. Puedes leer sobre esto en detalle. esta página.
Debe leer: Lecciones del ataque a Tinyman, el DEX más grande de Algorand
Ataque de denegación de servicio
Escenario del mundo real:
Imagina que estás en una Universidad Tecnológica de Bitcoin. Todo parece estar bien excepto que hay una mesa de comedor común para todos. Y lamentablemente, hay pocas personas de otra clase que siempre logran ocupar la mesa del comedor antes que nadie de tu clase.
En el escenario práctico, niegan el servicio esencial a todos, lo que resulta en la pérdida de un tiempo precioso. Esto es lo que llamamos un 'ataque de denegación de servicio'.
Ejemplo de código del mundo real:
En el juego llamado rey de éter, cualquiera puede convertirse en rey. Pero la regla para convertirse en rey es que una persona debe depositar más éter que el rey actual. Esto se puede hacer llamando al claimThrone()
función del contrato Rey de Éter en el que la persona envía éter directamente al rey anterior y se convierte en el nuevo rey.
function claimThrone() external payable { require(msg.value > balance, "Need to pay more to become the king"); (bool sent, ) = king.call{value: balance}(""); require(sent, "Failed to send Ether"); balance = msg.value; king = msg.sender; }
Como habrás adivinado, este código es vulnerable a un ataque DoS, pero ¿cómo? Para esto, deberá comprender que hay dos tipos de direcciones en Ethereum: la primera es la dirección de un externo cuenta propia o simplemente la dirección de una billetera, y la segunda es la dirección del contrato. Ahora el éter se puede enviar desde cualquiera de estos tipos de direcciones.
Si este, ether es enviado por la dirección del contrato, entonces el contrato se convertirá en el rey. Pero supongamos que este nuevo contrato no tiene un fallback()
función que es necesaria si el contrato quiere aceptar ether. Luego, si llega una nueva persona y trata de llamar al claimThrone()
función, siempre fallará!
Note que esto también sucede en parte porque el claimThrone()
La función verifica explícitamente si la transferencia de ether fue exitosa o no en la segunda declaración requerida. Puede encontrar el código completo y realizar un ataque DoS en él esta página.
También es posible que un código sea vulnerable a un ataque DoS si el código tiene un bucle sobre una matriz de tamaños grandes. Esto sucede porque el límite de gas puede excederse en tales casos. Puedes leer sobre eso esta página.
Repercusiones:
Un juego llamado Gubernamental, que aparentemente era un esquema Ponzi, se quedó atascado con 1100 ether porque se necesitaba una gran cantidad de gas para procesar el pago.
Aleatoriedad insegura
Escenario del mundo real:
Había una vez un hombre llamado Hesky que siempre iba acompañado de su mono Pesky. Hesky realizó juegos de lotería y obtuvo buenas ganancias. Un día, Alice notó que Hesky miraba fijamente a su mono Pesky. Luego lo vio escribiendo algo en un papel y lo selló en un sobre. Curiosa, decidió investigar más a fondo.
Más tarde esa noche, Alice vio que el ganador de la lotería se decidió abriendo públicamente el sobre sellado. Después de observarlo durante unos días, Alice se dio cuenta de que Hesky decidía el número ganador de la lotería al observar los gestos de Pesky (por ejemplo, si el mono se rascaba la cabeza, Hesky anotaba 10). ¡Ahora Alice tenía la fórmula para ganar cada lotería y solo tenía que comprar el boleto de lotería con el número correcto!
Hesky había asumido que su forma "aleatoria" de decidir el ganador de la lotería nunca se puede descifrar, pero de hecho estaba equivocado.
Ejemplo de código del mundo real:
En este ejemplo, se genera un número aleatorio basado en el hash de la combinación del número de un bloque y su marca de tiempo del bloque. este hash luego se asigna a la variable de respuesta. Ahora, cualquiera que adivine este número (aparentemente) aleatorio, es recompensado con 1 éter. ¿Crees que esto es inhackeable?
function guess(uint _guess) public { uint answer = uint( keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp)) ); if (_guess == answer) { (bool sent, ) = msg.sender.call{value: 1 ether}(""); require(sent, "Failed to send Ether"); } }
¡No! Un atacante aún puede adivinar este número aleatorio simplemente copiando y pegando el código para generar el valor asignado a la variable de respuesta y pasar la misma variable de respuesta al guess()
¡función!
guessTheRandomNumber.guess(answer);
Puedes encontrar el código completo esta página. Para evitar este ataque, se recomienda utilizar una función aleatoria verificable como la Eslabón de cadena VRF.
Repercusiones:
Se perdieron alrededor de 400 ETH debido a un ataque a la Lotería de miles de millones inteligentes contrato. Sorprendentemente, incluso la lotería de contratos en sí era un esquema Ponzi (¡ay!).
Manipulación del tiempo
Escenario del mundo real:
Satoshi le encanta comer galletas. Le encantan todos los tipos de galletas que hace su madre. Pero su madre es muy estricta y siente que comer demasiadas galletas no es bueno para él. Así que su madre tiene la regla de que solo recibirá las galletas a las 8 p. m.
Ese mismo día a las 7:45 pm, Satoshi corre hacia su madre y le pide galletas. Su madre pregunta: "¿Qué hora es?"
"¡Son las 8 en punto!" - el responde.
"Okey. Luego toma las galletas de mi armario.
¡Y así, Satoshi pudo manipular el tiempo con éxito por 15 minutos para poder obtener sus galletas! ¡Qué tipo hambriento de galletas!
Ejemplo de código del mundo real:
La marca de tiempo de un bloque puede ser manipulada por aproximadamente 15 segundos por un minero. De esta forma, un minero puede establecer un sello de tiempo favorable e incluir su transacción en ese mismo bloque que mina. La función play()
pertenece a un contrato de Juego llamado G-Dot.
function play() public { require(now > 1640392200 && neverPlayed == true); neverPlayed = false; msg.sender.transfer(1500 ether);
}
Este contrato recompensa con 1500 ether al jugador que sea el primero en llamar a la función de reproducción. Pero como puede ver, la función de reproducción solo se puede llamar si ahora o block.timestamp de la transacción que contiene la llamada a la play()
función, es mayor que la época tiempo 1640392200.
Un minero puede manipular fácilmente esta marca de tiempo e incluir su transacción de llamar al play()
función en el mismo bloque tal que él mismo es el primer jugador. ¡De esta manera se garantiza que el minero ganará el juego!
Repercusiones:
El block.timestamp se usó para generar números aleatorios en el Gubernamental y por lo tanto era vulnerable a los ataques de manipulación del tiempo.
Comuníquese con QuillAudits
QuillAudits es una plataforma segura de auditorías de contratos inteligentes diseñada por QuillHash
Tecnologías.
Es una plataforma de auditoría que analiza y verifica rigurosamente los contratos inteligentes para verificar las vulnerabilidades de seguridad a través de una revisión manual efectiva con herramientas de análisis estático y dinámico, analizadores de gas y asimiladores. Además, el proceso de auditoría también incluye pruebas unitarias extensas, así como análisis estructural.
Realizamos auditorías de contratos inteligentes y pruebas de penetración para encontrar potencial
vulnerabilidades de seguridad que podrían dañar la integridad de la plataforma.
Si necesita ayuda en la auditoría de contratos inteligentes, no dude en comunicarse con nuestros expertos aquí!
Para estar al día con nuestro trabajo, únase a nuestra comunidad: -
Twitter | Etiqueta LinkedIn | Facebook | Telegram
El puesto Guía para principiantes de auditoría de contratos inteligentes: Parte 1 apareció por primera vez en Blog de Quillhash.
Fuente: https://blog.quillhash.com/2022/01/19/beginners-guide-to-smart-contract-auditing-part-1/
- "
- &
- 000
- 2016
- 7
- Sobre
- Mi Cuenta
- dirección
- Todos
- ya haya utilizado
- Aunque
- análisis
- auditoría
- autónomo
- Comienzo
- MEJOR
- Bitcoin
- blockchain
- Error
- comprar
- llamar al
- cases
- Cheques
- clásico
- código
- Monedas
- combinación
- Algunos
- vibrante e inclusiva
- contiene
- contrato
- contratos
- galletas
- podría
- Creamos
- cripto
- Current
- DAO
- día
- Descentralizado
- Denegación de servicio
- detalle
- Dex
- DE INSCRIPCIÓN
- pasan fácilmente
- comer
- ETH
- Éter
- Etereum
- Etereum blockchain
- Etereum Classic
- ejemplo
- Explotar
- en fin
- Nombre
- Gratuito
- función
- juego
- Juegos
- GAS
- generar
- GitHub
- va
- candidato
- guía
- corte
- hacks
- hachís
- cabeza
- esta página
- Cómo
- HTTPS
- investigar
- IT
- Java
- únete
- saltar
- King
- idioma
- large
- línea
- Etiqueta LinkedIn
- Largo
- mirando
- lotería
- hombre
- millones
- madre
- números
- organización
- Papel
- Patrón de Costura
- Pagar
- Personas
- pieza
- plataforma
- Jugar
- jugador
- Ponzi
- Esquema Ponzi
- industria
- Programador
- Programación
- público
- marcha atrás
- una estrategia SEO para aparecer en las búsquedas de Google.
- Recompensas
- reglas
- Satoshi
- EN LINEA
- set
- inteligente
- contrato inteligente
- Contratos Inteligentes
- So
- solidez
- algo
- Girar
- dividido
- fundó
- Posicionamiento
- Estrategia
- exitosos
- Con éxito
- tecnología
- pruebas
- A través de esta formación, el personal docente y administrativo de escuelas y universidades estará preparado para manejar los recursos disponibles que derivan de la diversidad cultural de sus estudiantes. Además, un mejor y mayor entendimiento sobre estas diferencias y similitudes culturales permitirá alcanzar los objetivos de inclusión previstos.
- equipo
- transaccional
- no bancarizado
- universidad
- Actualizaciones
- propuesta de
- Vulnerabilidades
- vulnerabilidad
- Vulnerable
- Billetera
- ¿
- Sistemas de
- QUIENES
- ganar
- Actividades:
- la escritura