智能合约安全审计入门篇 —— Contract Size Check

慢雾科技
企业专栏
热度: 3653

本文讲解如何通过 Contract Size Check 判断调用者身份。

​By:小白

背景概述

第一期文章中我们提过防止重入攻击的多种方式,其中一种是通过检查调用者身份并禁止合约调用来防止重入攻击。这期文章我们就来了解如何通过 Contract Size Check 判断调用者身份。

前置知识

众所周知,合约是由代码编写的,所以部署后的合约地址肯定有相应的字节码,而 EOA 地址是没有字节码的,所以我们只需要检查调用者地址是否有字节码就可以判断调用者是否为合约。这里需要使用 Solidity 内联汇编中的 extcodesize() 函数。下面我们还是通过实例来看看这个函数的实际效果。

代码示例

首先,我们用一个代码示例来了解 extcodesize() 的作用:

智能合约安全审计入门篇 —— Contract Size Check

我们在 Remix 上部署后,调用 Size() 并传入 Deployer 的 EOA 地址(0x787···cabaB),发现返回 0。

智能合约安全审计入门篇 —— Contract Size Check

我们再次调用 Size() 并传入合约自身地址(0xC58···905F2),返回 348。

智能合约安全审计入门篇 —— Contract Size Check

综上可知,当 account 为 EOA 地址时,extcodesize() 会返回 0 ,当 account 为合约地址时,extcodesize() 会返回合约部署后的字节码大小。到这里,相信大家不难想到可以通过调用 extcodesize() 并看其返回值是否为 0 来判断该地址是 EOA 还是部署后的合约。诶,漏洞就这么写出来了。

漏洞示例

智能合约安全审计入门篇 —— Contract Size Check

漏洞分析

可以看到,isContract() 判断 account 字节码是否为 0 并返回 bool 类型的值。protected() 则会根据 isContract() 的返回值来修改 pwned 的状态。但是这里忽略了一个点,即合约部署时,constructor 函数中的代码逻辑会跟随部署合约的交易一起发送给矿工打包上链。由于此时合约部署的操作还没有完成,所以合约地址还没有存入相应的字节码,这时在 consturctor 函数中调用 extcodesize() 检查合约地址的字节码就会返回 0 。下面我们来看正常调用的情况下会返回什么:

智能合约安全审计入门篇 —— Contract Size Check

调用 pwn() 并将合约地址 0x058···4c899 传入会被 revert,这里说明合约部署后调用 protected() 会无法通过 require(!isContract(msg.sender) 检查。

智能合约安全审计入门篇 —— Contract Size Check

攻击合约

下面我们将调用逻辑放在 constructor 函数中再次尝试:

智能合约安全审计入门篇 —— Contract Size Check

部署 Hack 合约时传入 0xbd7···9EFB3 合约地址,发现成功绕过了 require(!isContract(msg.sender) 检查,而且成功修改了 pwned 的状态。

智能合约安全审计入门篇 —— Contract Size Check

修复建议

作为开发者

使用 extcodesize() 判断地址是否为 EOA 地址并不准确,在实际开发中最稳妥的判断调用者身份的方式还是通过 tx.origin 来判断。类似下面这样:

智能合约安全审计入门篇 —— Contract Size Check

由于 tx.origin 只可能是 EOA 地址,我们只需要判断上层调用者的 msg.sender 是否与 tx.origin 为同一地址就可以。以刚刚的漏洞代码为例,我们只需要稍加修改就可以修复漏洞。

智能合约安全审计入门篇 —— Contract Size Check

此时部署下面这个 Hack 合约再进行攻击,就会被 revert 并返回 "no contract allowed"。

智能合约安全审计入门篇 —— Contract Size Check

智能合约安全审计入门篇 —— Contract Size Check

作为审计者

在审计过程中,如果遇到限制合约地址调用的逻辑,应当结合实际业务逻辑判断该检查是否严谨以及是否存在被绕过的可能。

声明:本文为入驻“火星财经 专栏”作者作品,不代表火星财经官方立场。
转载请联系网页底部:内容合作栏目,邮件进行授权。授权后转载时请注明出处、作者和本文链接。未经许可擅自转载本站文章,将追究相关法律责任,侵权必究。
提示:投资有风险,入市须谨慎,本资讯不作为投资理财建议。
本内容旨在传递行业动态,不构成投资建议或承诺。