{"id":255,"date":"2025-10-06T19:21:24","date_gmt":"2025-10-06T19:21:24","guid":{"rendered":"https:\/\/fikresekhel.com\/blog\/?p=255"},"modified":"2025-10-06T19:21:24","modified_gmt":"2025-10-06T19:21:24","slug":"smart-contract-hacking-function-visibility","status":"publish","type":"post","link":"https:\/\/fikresekhel.com\/blog\/forensic\/smart-contract-hacking-function-visibility\/","title":{"rendered":"Smart Contract Hacking \u2014 Function Visibility"},"content":{"rendered":"\n<p>Visibilidade de fun\u00e7\u00f5es \u00e9 uma das fontes mais comuns de vulnerabilidades em contratos Solidity. Vamos explicar o que \u00e9, por que importa, exemplos pr\u00e1ticos de explora\u00e7\u00e3o e como consertar. Vamos incluir c\u00f3digo vulner\u00e1vel e a vers\u00e3o corrigida, checklist para auditoria e ferramentas\/testes recomendados.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Conceito R\u00e1pido:<\/strong>\n<ul class=\"wp-block-list\">\n<li>EM Solidity, visibilidade define quem pode chamar uma fun\u00e7\u00e3o ou acessar uma vari\u00e1vel. As principais visibilidades s\u00e3o:\n<ul class=\"wp-block-list\">\n<li><em>public:<\/em> qualquer endere\u00e7o (externo) e outros contratos podem chamar; tamb\u00e9m gera uatomaticamente um getter para vari\u00e1veis p\u00fablicas.<\/li>\n\n\n\n<li><em>external:<\/em> s\u00f3 pode ser chamada de fora do contrato (por transa\u00e7\u00e3o ou chamada externa); mais barata que <em>public<\/em> em alguns casos.<\/li>\n\n\n\n<li><em>internal: <\/em>s\u00f3 pode ser chamada dentro do contrato e por contratos que herdam (como <em>protected<\/em>).<\/li>\n\n\n\n<li><em>private: <\/em>s\u00f3 pode ser chamada dentro do contrato onde foi definida (n\u00e3o \u00e9 vis\u00edvel para contratos filhos).<\/li>\n\n\n\n<li>Al\u00e9m disso, <em>view\/pure<\/em> indicam que n\u00e3o alteram estado, mas n\u00e3o s\u00e3o visibilidade.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Probla comum: deixar fun\u00e7\u00e3o que deveria ser <em>private\/internal <\/em>como <em>public\/external<\/em> &#8211; qualquer um pode cham\u00e1-la e manipular o estado do contrato.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Exemplos pr\u00e1ticos de vulnerabilidades e explora\u00e7\u00f5es:<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>Exemplo 1 &#8211; inicializados p\u00fablico (reentr\u00e2ncia de propriedade)<\/strong><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>\n\/\/ Vulner\u00e1vel: initialize \u00e9 public e pode ser re-executado\npragma solidity ^0.8.19;\n\ncontract Vault {\n    address public owner;\n    uint256 public balance;\n\n    function initialize(address _owner) public {\n        owner = _owner;\n    }\n\n    function deposit() public payable {\n        balance += msg.value;\n    }\n\n    function withdraw(uint256 amount) public {\n        require(msg.sender == owner, \"not owner\");\n        payable(owner).transfer(amount);\n        balance -= amount;\n    }\n}\n<\/code><\/pre>\n\n\n\n<p><strong>Explora\u00e7\u00e3o: <\/strong>Se <em>initialize<\/em> for esquecida e <em>owner <\/em> est\u00e1 0x0, um atacante chama <em>initialize(attacker)<\/em> e se torna dono &#8211; pode sacar tudo.<\/p>\n\n\n\n<p><strong>Corre\u00e7\u00e3o: <\/strong>tornar constructor\/initializer <em>internal<\/em> ou proteger com um <em>initialized <\/em>flag \/ <em>onlyOwner<\/em>. Para proxys, usar initializer do OpenZeppelin.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Exemplo 2- fun\u00e7\u00e3o administrativa p\u00fablica<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Vulner\u00e1vel: setFee \u00e9 public, qualquer um muda taxa para 100%\npragma solidity ^0.8.19;\n\ncontract Marketplace {\n    address public admin;\n    uint256 public feePercent;\n\n    constructor() {\n        admin = msg.sender;\n    }\n\n    function setFee(uint256 _fee) public {\n        feePercent = _fee;\n    }\n}\n<\/code><\/pre>\n\n\n\n<p><strong>Explora\u00e7\u00e3o: <\/strong>qualquer pessoa chama <em>setFee(1000)<\/em> e quebra economia do contrao.<\/p>\n\n\n\n<p><strong>Corre\u00e7\u00e3o: <\/strong>adicionar <em>onlyAdmin<\/em> modifier e <em>private \/ internal<\/em> quando apropriado.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Exemplo 3 &#8211; fun\u00e7\u00e3o <em>private<\/em> pretendida mas <em>public <\/em>por engano<\/strong><\/p>\n\n\n\n<p>&#8216;As vezes o desenvolvedor cria uma fun\u00e7\u00e3o auxiliar e esquece de marcar visibilitiy:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function _transferInternal(address from, address to, uint256 amount) public {\n    \/\/ deveria ser internal\/private\n    \/\/ ...\n}\n<\/code><\/pre>\n\n\n\n<p><strong>Explora\u00e7\u00e3o: <\/strong>chamam essa fun\u00e7\u00e3o diretamente com par\u00e2metros forjados (bypass de checks).<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Exemplo 4 &#8211; getters acidentais para vari\u00e1veis sens\u00edveis<\/strong><\/p>\n\n\n\n<p>Vari\u00e1vel marcada <em>public <\/em>cria um getter p\u00fablico automaticamente. N\u00e3o fa\u00e7a isso para dados sens\u00edveis (por exemplo, mapping de limites secretos).<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>3) C\u00f3digo vulner\u00e1vel completo e ver~so corrigida<\/strong><\/p>\n\n\n\n<p>Vulner\u00e1vel &#8211; contrato simples com v\u00e1rias falhas de visibilidade:<\/p>\n\n\n\n<p>pragma solidity ^0.8.19;<\/p>\n\n\n\n<p>contract BadToken {<br>mapping(address =&gt; uint256) public balances;<br>address public owner;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>constructor() {\n    owner = msg.sender;\n}\n\n\/\/ deveria ser internal\nfunction mint(address to, uint256 amount) public {\n    balances&#91;to] += amount;\n}\n\n\/\/ deveria ser onlyOwner\nfunction setOwner(address _owner) public {\n    owner = _owner;\n}\n\n\/\/ erroneamente public (bypass poss\u00edvel)\nfunction _deduct(address from, uint256 amount) public {\n    balances&#91;from] -= amount;\n}<\/code><\/pre>\n\n\n\n<p>}<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Corrigido &#8211; visibilidades + controle de acesso<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ SPDX-License-Identifier: MIT\npragma solidity ^0.8.19;\n\nimport \"@openzeppelin\/contracts\/access\/Ownable.sol\";\n\ncontract GoodToken is Ownable {\n    mapping(address => uint256) private balances;\n\n    \/\/ mint s\u00f3 o dono pode chamar\n    function mint(address to, uint256 amount) external onlyOwner {\n        balances&#91;to] += amount;\n    }\n\n    \/\/ getter expl\u00edcito, se quiser expor saldo\n    function balanceOf(address account) external view returns (uint256) {\n        return balances&#91;account];\n    }\n\n    \/\/ internal helper, n\u00e3o exposto\n    function _deduct(address from, uint256 amount) internal {\n        require(balances&#91;from] >= amount, \"insufficient\");\n        balances&#91;from] -= amount;\n    }\n}\n<\/code><\/pre>\n\n\n\n<p><strong>Principais mudan\u00e7as<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>mint -> external onlyOwner<\/em><\/li>\n\n\n\n<li><em>balances -> private + balanceOf<\/em> para controle<\/li>\n\n\n\n<li>helpers marcados <em>internal<\/em><\/li>\n\n\n\n<li>uso de <em>Ownable <\/em>para acesso administrativo<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>4) Boas pr\u00e1ticas e recomneda\u00e7\u00f5es (quick checklist)<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Sempre declarar visibilidade <em>(public | external | internal | private)<\/em>. N\u00e3o deixe em branco (o compilador pode inferir, mas seja expl\u00edcito).<\/li>\n\n\n\n<li>Fun\u00e7\u00f5es administrativas: <em>onlyOwner \/ onlyRole <\/em>(use OpenZeppelin <em>Ownable \/ AccessControl).<\/em><\/li>\n\n\n\n<li>Helpers (utilit\u00e1rias que n\u00e3o devem ser chamadas externamente): marque <em>internal<\/em> ou <em>private.<\/em><\/li>\n\n\n\n<li>Construtores ; inicializadores:\n<ul class=\"wp-block-list\">\n<li>Para contratos normais, use <em>constructor() <\/em>(n\u00e3o p\u00fablico).<\/li>\n\n\n\n<li>Para proxies, use padr\u00f5es<em>initializer <\/em>(OpenZeppelin) e implemente flag <em>initialized<\/em> para prevenir re-inicializa\u00e7\u00e3o.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Evite vari\u00e1veis <em>public<\/em> para dados sens\u00edveis &#8211; <em>public <\/em> gera getters autom\u00e1ticos.<\/li>\n\n\n\n<li>Use <em>external <\/em>para fun\u00e7\u00f5es que s\u00f3 ser\u00e3o chamadas externamente (mais gas-econ\u00f4mico para calldata).<\/li>\n\n\n\n<li>Use <em>view\/pure <\/em>quando aplic\u00e1vel &#8211; melhora clareza.<\/li>\n\n\n\n<li>Revis\u00e3o de visibilidade em cada fun\u00e7\u00e3o durante auditoria &#8211; fa\u00e7a checklist linha-a-linha.<\/li>\n\n\n\n<li>Teste de fuzz \/ unit tests para chamadas externas inesperadas.<\/li>\n\n\n\n<li>Minimize superf\u00edcie de ataque &#8211; fun\u00e7\u00f5es que mudam estado e n\u00e3o precisam ser p\u00fablicas devem ser privadas\/internal.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>5) Ferramentas * testes recomendados<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Statis analysis:<\/strong> Slither, Solhint, MythX, Security. *Pode testar nossa ferramenta que esta em desenvolvimento, falar com consultor agora!<\/li>\n\n\n\n<li><strong>Fuzzing\/property testing: <\/strong>Echidna, Fooundry \/ <em>forge test.<\/em><\/li>\n\n\n\n<li><strong>Unit tests: <\/strong>Hardhat \/ Foundry \/ Truffle &#8211; escrever testes que tentem chamar fun\u00e7\u00f5es privadas via ABI (simular chamadas externas0.<\/li>\n\n\n\n<li><strong>Review manual: <\/strong>checar explicitamente cada fun\u00e7\u00e3o: &#8220;quem precisa chamar isso?&#8221; -> escolher visibility.<\/li>\n\n\n\n<li><strong>Upgrade \/ Proxy patterns: <\/strong>Verificar <em>initialize <\/em> e prote\u00e7\u00f5es para evitar <em>re-initialization.<\/em><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>6) Exemplos de verifica\u00e7\u00e3o r\u00e1pida manual (mini-checklist para cada fun\u00e7\u00e3o)<\/strong><\/p>\n\n\n\n<p>Para cada fun\u00e7\u00e3o no contrato:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Quem deve chamar? <\/strong>(usu\u00e1rio, dono, outro contrato, \u00f3 internamente).<\/li>\n\n\n\n<li><strong>Precisa ser p\u00fablica\/external? <\/strong>Se n\u00e3o -> <em>internal\/private<\/em>.<\/li>\n\n\n\n<li><strong>Muda estado? <\/strong>Se sim, considerar checks <em>onlyOwner \/ <\/em>reentr\u00e2ncia.<\/li>\n\n\n\n<li><strong>\u00c9 helper? <\/strong>Se sim, marque <em><span style=\"text-decoration: underline;\">internal.<\/span><\/em><\/li>\n\n\n\n<li><strong>Tem fallback logic? <\/strong>Verifique <em>receive() \/ fallback() <\/em>visibilidade e comportamento.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>7) Casos reais de ataques relacionados a visibilidade (reumo r\u00e1pido)<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Re-initializa\u00e7\u00e3o de contratos de proxy:<\/strong> contrato  n\u00e3o protegido permitiu que atacante chamasse <em>initialize.<\/em><\/li>\n\n\n\n<li><strong>SetOwner p\u00fablico: <\/strong>atacante muda administrador e rouba fundos.<\/li>\n\n\n\n<li><strong>Fun\u00e7oes auxiliares p\u00fablicas: <\/strong>permitem manipular balances internamente e quebrar invariantes.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>8) Resumo enxuto (pr\u00e1tico)<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Erro mais comum:<\/strong> esquecer de marcar visibilidade ou marcar <em>public<\/em> quando n\u00e3o deveria.<\/li>\n\n\n\n<li><strong>Regra de ouro: <\/strong>fun\u00e7\u00f5es n\u00e3o necess\u00e1rias externamente -> <em>private\/internal<\/em>. Fun\u00e7\u00f5es administrativas -> <em>external + onlyOwner \/ <\/em>ACL.<\/li>\n\n\n\n<li><strong>Proteja inicializadores (especialmente em proxys).<\/strong><\/li>\n\n\n\n<li><strong>Use ferramentas e crie testes que tentem chamar APIs inesperadas.<\/strong><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Visibilidade de fun\u00e7\u00f5es \u00e9 uma das fontes mais [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":256,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[34,33,8,4,16,11],"tags":[],"class_list":["post-255","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blockchain","category-cryptography","category-cybersecurity","category-forensic","category-fraud-protection","category-incident-response"],"_links":{"self":[{"href":"https:\/\/fikresekhel.com\/blog\/wp-json\/wp\/v2\/posts\/255","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fikresekhel.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fikresekhel.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fikresekhel.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fikresekhel.com\/blog\/wp-json\/wp\/v2\/comments?post=255"}],"version-history":[{"count":1,"href":"https:\/\/fikresekhel.com\/blog\/wp-json\/wp\/v2\/posts\/255\/revisions"}],"predecessor-version":[{"id":257,"href":"https:\/\/fikresekhel.com\/blog\/wp-json\/wp\/v2\/posts\/255\/revisions\/257"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fikresekhel.com\/blog\/wp-json\/wp\/v2\/media\/256"}],"wp:attachment":[{"href":"https:\/\/fikresekhel.com\/blog\/wp-json\/wp\/v2\/media?parent=255"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fikresekhel.com\/blog\/wp-json\/wp\/v2\/categories?post=255"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fikresekhel.com\/blog\/wp-json\/wp\/v2\/tags?post=255"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}