WTF Academy: wtf.academy

WTF Solidity 合约安全: S08. 绕过合约检查
我最近在重新学solidity,巩固一下细节,也写一个“WTF Solidity极简入门”,供小白们使用(编程大佬可以另找教程),每周更新1-3讲。 推特:@0xAA_Science|@WTFAcademy_ 社区:Discord|微信群|官网 wtf.academy 所有代码和教程开源在github: github.com/AmazingAng/WTFSolidity这一讲,我们将介绍绕过合约长度检查,并介绍预防的方法。绕过合约检查很多 freemint 的项目为了限制科学家(程序员)会用到 isContract() 方法,希望将调用者 msg.sender 限制为外部账户(EOA),而非合约。这个函数利用 extcodesize 获取该地址所存储的 bytecode 长度(runtime),若大于0,则判断为合约,否则就是EOA(用户)。 // 利用 extcodesize 检查是否为合约 function isContract(address account) public view returns (bool) { // extcodesize > 0 的地址一定是合约...

WTF Solidity 合约安全: S09. 拒绝服务
我最近在重新学solidity,巩固一下细节,也写一个“WTF Solidity极简入门”,供小白们使用(编程大佬可以另找教程),每周更新1-3讲。 推特:@0xAA_Science|@WTFAcademy_ 社区:Discord|微信群|官网 wtf.academy 所有代码和教程开源在github: github.com/AmazingAng/WTFSolidity这一讲,我们将介绍智能合约的拒绝服务(Denial of Service, DoS)漏洞,并介绍预防的方法。NFT项目 Akutar 曾因为 DoS 漏洞损失 11,539 ETH,当时价值 3400 万美元。DoS在 Web2 中,拒绝服务攻击(DoS)是指通过向服务器发送大量垃圾信息或干扰信息的方式,导致服务器无法向正常用户提供服务的现象。而在 Web3,它指的是利用漏洞使得智能合约无法正常提供服务。 在2022年4月,一个很火的 NFT 项目名为 Akutar,他们使用荷兰拍卖进行公开发行,筹集了 11,539.5 ETH,非常成功。之前持有他们社区Pass的参与者会得到 0.5 ETH的退款,但是他们处理...

WTF Solidity 合约安全 S06. 签名重放
我最近在重新学solidity,巩固一下细节,也写一个“WTF Solidity极简入门”,供小白们使用(编程大佬可以另找教程),每周更新1-3讲。 推特:@0xAA_Science|@WTFAcademy_ 社区:Discord|微信群|官网 wtf.academy 所有代码和教程开源在github: github.com/AmazingAng/WTFSolidity这一讲,我们将介绍智能合约的签名重放(Signature Replay)攻击和预防方法,它曾间接导致了著名做市商 Wintermute 被盗2000万枚 $OP。签名重放上学的时候,老师经常会让家长签字,有时候家长很忙,我就会很“贴心”照着以前的签字抄一遍。某种意义上来说,这就是签名重放。 在区块链中,数字签名可以用于识别数据签名者和验证数据完整性。发送交易时,用户使用私钥签名交易,使得其他人可以验证交易是由相应账户发出的。智能合约也能利用 ECDSA 算法验证用户将在链下创建的签名,然后执行铸造或转账等逻辑。更多关于数字签名的介绍请见WTF Solidity第37讲:数字签名。 数字签名一般有两种常见的重放攻击...

WTF Solidity 合约安全: S08. 绕过合约检查
我最近在重新学solidity,巩固一下细节,也写一个“WTF Solidity极简入门”,供小白们使用(编程大佬可以另找教程),每周更新1-3讲。 推特:@0xAA_Science|@WTFAcademy_ 社区:Discord|微信群|官网 wtf.academy 所有代码和教程开源在github: github.com/AmazingAng/WTFSolidity这一讲,我们将介绍绕过合约长度检查,并介绍预防的方法。绕过合约检查很多 freemint 的项目为了限制科学家(程序员)会用到 isContract() 方法,希望将调用者 msg.sender 限制为外部账户(EOA),而非合约。这个函数利用 extcodesize 获取该地址所存储的 bytecode 长度(runtime),若大于0,则判断为合约,否则就是EOA(用户)。 // 利用 extcodesize 检查是否为合约 function isContract(address account) public view returns (bool) { // extcodesize > 0 的地址一定是合约...

WTF Solidity 合约安全: S09. 拒绝服务
我最近在重新学solidity,巩固一下细节,也写一个“WTF Solidity极简入门”,供小白们使用(编程大佬可以另找教程),每周更新1-3讲。 推特:@0xAA_Science|@WTFAcademy_ 社区:Discord|微信群|官网 wtf.academy 所有代码和教程开源在github: github.com/AmazingAng/WTFSolidity这一讲,我们将介绍智能合约的拒绝服务(Denial of Service, DoS)漏洞,并介绍预防的方法。NFT项目 Akutar 曾因为 DoS 漏洞损失 11,539 ETH,当时价值 3400 万美元。DoS在 Web2 中,拒绝服务攻击(DoS)是指通过向服务器发送大量垃圾信息或干扰信息的方式,导致服务器无法向正常用户提供服务的现象。而在 Web3,它指的是利用漏洞使得智能合约无法正常提供服务。 在2022年4月,一个很火的 NFT 项目名为 Akutar,他们使用荷兰拍卖进行公开发行,筹集了 11,539.5 ETH,非常成功。之前持有他们社区Pass的参与者会得到 0.5 ETH的退款,但是他们处理...

WTF Solidity 合约安全 S06. 签名重放
我最近在重新学solidity,巩固一下细节,也写一个“WTF Solidity极简入门”,供小白们使用(编程大佬可以另找教程),每周更新1-3讲。 推特:@0xAA_Science|@WTFAcademy_ 社区:Discord|微信群|官网 wtf.academy 所有代码和教程开源在github: github.com/AmazingAng/WTFSolidity这一讲,我们将介绍智能合约的签名重放(Signature Replay)攻击和预防方法,它曾间接导致了著名做市商 Wintermute 被盗2000万枚 $OP。签名重放上学的时候,老师经常会让家长签字,有时候家长很忙,我就会很“贴心”照着以前的签字抄一遍。某种意义上来说,这就是签名重放。 在区块链中,数字签名可以用于识别数据签名者和验证数据完整性。发送交易时,用户使用私钥签名交易,使得其他人可以验证交易是由相应账户发出的。智能合约也能利用 ECDSA 算法验证用户将在链下创建的签名,然后执行铸造或转账等逻辑。更多关于数字签名的介绍请见WTF Solidity第37讲:数字签名。 数字签名一般有两种常见的重放攻击...
WTF Academy: wtf.academy

Subscribe to 0xAA

Subscribe to 0xAA
Share Dialog
Share Dialog
>100 subscribers
>100 subscribers


我最近在重新学solidity,巩固一下细节,也写一个“WTF Solidity极简入门”,供小白们使用(编程大佬可以另找教程),每周更新1-3讲。
所有代码和教程开源在github: github.com/AmazingAng/WTFSolidity
这一讲,我们将介绍选择器碰撞攻击,它是导致跨链桥 Poly Network 被黑的原因之一。在2021年8月,Poly Network在ETH,BSC,和Polygon上的跨链桥合约被盗,损失高达6.11亿美元。这是2021年最大的区块链黑客事件,也是历史被盗金额榜单上第2名,仅次于 Ronin 桥黑客事件。
以太坊智能合约中,函数选择器是函数签名 "<function name>(<function input types>)" 的哈希值的前4个字节(8位十六进制)。当用户调用合约的函数时,calldata的前4字节就是目标函数的选择器,决定了调用哪个函数。如果你不了解它,可以阅读WTF Solidity极简教程第29讲:函数选择器。
由于函数选择器只有4字节,非常短,很容易被碰撞出来:即我们很容易找到两个不同的函数,但是他们有着相同的函数选择器。比如transferFrom(address,address,uint256)和gasprice_bit_ether(int128)有着相同的选择器:0x23b872dd。当然你也可以写个脚本暴力破解。

大家可以用这两个网站来查同一个选择器对应的不同函数:
你也可以使用下面的Power Clash工具进行暴力破解:
PowerClash: https://github.com/AmazingAng/power-clash
相比之下,钱包的公钥有256字节,被碰撞出来的概率几乎为0,非常安全。
以太坊的人得罪了天神,天神震怒。天后赫拉为了惩罚以太坊的人,在以太坊的峭崖上降下一个名叫斯芬克斯的人面狮身的女妖。她向每一个路过悬崖的以太坊用户提出一个谜语:“什么东西在早晨用四只脚走路,中午两只脚走路,晚间三只脚走路,在一切生物中这是唯一的用不同数目的脚走路的生物。脚最多的时候,正是速度和力量最小的时候。”对于这个奥妙费解的谜语,凡猜中者即可活命,凡猜不中者一律被吃掉。过路的人全被斯芬克斯吃了,以太坊用户陷入恐惧之中。斯芬克斯用选择器0x10cd2dc7来验证答案是否正确。
有一天上午,俄狄浦斯路过此地,会见了女妖,并猜中了这神秘奥妙之谜。他说:“这是"function men()"啊!在生命的早晨,他是个孩子,用两条腿和两只手爬行;到了生命的中午,他变成壮年,只用两条腿走路;到了生命的傍晚,他年老体衰,必须借助拐杖走路,所以被称为三只脚。”谜语被猜中后,俄狄浦斯得以生还。
那一天下午,0xAA路过此地,会见了女妖,并猜中了这神秘奥妙之谜。他说:“这是"fucntion peopleLduohW(uint256)"啊!在生命的早晨,他是个孩子,用两条腿和两只手爬行;到了生命的中午,他变成壮年,只用两条腿走路;到了生命的傍晚,他年老体衰,必须借助拐杖走路,所以被称为三只脚。”谜语再次被猜中后,斯芬克斯气急败坏,脚下一打滑就从巍峨的峭崖上掉下去摔死了。

下面我们来看一下有漏洞的合约例子。SelectorClash合约有1个状态变量 solved,初始化为false,攻击者需要将它改为true。合约主要有2个函数,函数名沿用自 Poly Network 漏洞合约。
putCurEpochConPubKeyBytes() :攻击者调用这个函数后,就可以将solved改为true,完成攻击。但是这个函数检查msg.sender == address(this),因此调用者必须为合约本身,我们需要看下其他函数。
executeCrossChainTx() :通过它可以调用合约内的函数,但是函数参数的类型和目标函数不太一样:目标函数的参数为(bytes),而这里调用的函数参数为(bytes,bytes,uint64)。
contract SelectorClash {
bool public solved; // 攻击是否成功
// 攻击者需要调用这个函数,但是调用者 msg.sender 必须是本合约。
function putCurEpochConPubKeyBytes(bytes memory _bytes) public {
require(msg.sender == address(this), "Not Owner");
solved = true;
}
// 有漏洞,攻击者可以通过改变 _method 变量碰撞函数选择器,调用目标函数并完成攻击。
function executeCrossChainTx(bytes memory _method, bytes memory _bytes, bytes memory _bytes1, uint64 _num) public returns(bool success){
(success, ) = address(this).call(abi.encodePacked(bytes4(keccak256(abi.encodePacked(_method, "(bytes,bytes,uint64)"))), abi.encode(_bytes, _bytes1, _num)));
}
}
我们的目标是利用executeCrossChainTx()函数调用合约中的putCurEpochConPubKeyBytes(),目标函数的选择器为:0x41973cd9。观察到executeCrossChainTx()中是利用_method参数和"(bytes,bytes,uint64)"作为函数签名计算的选择器。因此,我们只需要选择恰当的_method,让这里算出的选择器等于0x41973cd9,通过选择器碰撞调用目标函数。
Poly Network黑客事件中,黑客碰撞出的_method为 f1121318093,即f1121318093(bytes,bytes,uint64)的哈希前4位也是0x41973cd9,可以成功的调用函数。接下来我们要做的就是将0x41973cd9转换为bytes类型:0x6631313231333138303933,然后作为参数输入到executeCrossChainTx()中。executeCrossChainTx()函数另3个参数不重要,都填 0x 就可以。
部署SelectorClash合约。
调用executeCrossChainTx(),参数填0x6631313231333138303933,0x,0x,0x,发起攻击。
查看solved变量的值,被修改为ture,攻击成功。
这一讲,我们介绍了选择器碰撞攻击,它是导致跨链桥 Poly Network 被黑 6.1 亿美金的的原因之一。这个攻击告诉了我们:
函数选择器很容易被碰撞,即使改变参数类型,依然能构造出具有相同选择器的函数。
管理好合约函数的权限,确保拥有特殊权限的合约的函数不能被用户调用。
我最近在重新学solidity,巩固一下细节,也写一个“WTF Solidity极简入门”,供小白们使用(编程大佬可以另找教程),每周更新1-3讲。
所有代码和教程开源在github: github.com/AmazingAng/WTFSolidity
这一讲,我们将介绍选择器碰撞攻击,它是导致跨链桥 Poly Network 被黑的原因之一。在2021年8月,Poly Network在ETH,BSC,和Polygon上的跨链桥合约被盗,损失高达6.11亿美元。这是2021年最大的区块链黑客事件,也是历史被盗金额榜单上第2名,仅次于 Ronin 桥黑客事件。
以太坊智能合约中,函数选择器是函数签名 "<function name>(<function input types>)" 的哈希值的前4个字节(8位十六进制)。当用户调用合约的函数时,calldata的前4字节就是目标函数的选择器,决定了调用哪个函数。如果你不了解它,可以阅读WTF Solidity极简教程第29讲:函数选择器。
由于函数选择器只有4字节,非常短,很容易被碰撞出来:即我们很容易找到两个不同的函数,但是他们有着相同的函数选择器。比如transferFrom(address,address,uint256)和gasprice_bit_ether(int128)有着相同的选择器:0x23b872dd。当然你也可以写个脚本暴力破解。

大家可以用这两个网站来查同一个选择器对应的不同函数:
你也可以使用下面的Power Clash工具进行暴力破解:
PowerClash: https://github.com/AmazingAng/power-clash
相比之下,钱包的公钥有256字节,被碰撞出来的概率几乎为0,非常安全。
以太坊的人得罪了天神,天神震怒。天后赫拉为了惩罚以太坊的人,在以太坊的峭崖上降下一个名叫斯芬克斯的人面狮身的女妖。她向每一个路过悬崖的以太坊用户提出一个谜语:“什么东西在早晨用四只脚走路,中午两只脚走路,晚间三只脚走路,在一切生物中这是唯一的用不同数目的脚走路的生物。脚最多的时候,正是速度和力量最小的时候。”对于这个奥妙费解的谜语,凡猜中者即可活命,凡猜不中者一律被吃掉。过路的人全被斯芬克斯吃了,以太坊用户陷入恐惧之中。斯芬克斯用选择器0x10cd2dc7来验证答案是否正确。
有一天上午,俄狄浦斯路过此地,会见了女妖,并猜中了这神秘奥妙之谜。他说:“这是"function men()"啊!在生命的早晨,他是个孩子,用两条腿和两只手爬行;到了生命的中午,他变成壮年,只用两条腿走路;到了生命的傍晚,他年老体衰,必须借助拐杖走路,所以被称为三只脚。”谜语被猜中后,俄狄浦斯得以生还。
那一天下午,0xAA路过此地,会见了女妖,并猜中了这神秘奥妙之谜。他说:“这是"fucntion peopleLduohW(uint256)"啊!在生命的早晨,他是个孩子,用两条腿和两只手爬行;到了生命的中午,他变成壮年,只用两条腿走路;到了生命的傍晚,他年老体衰,必须借助拐杖走路,所以被称为三只脚。”谜语再次被猜中后,斯芬克斯气急败坏,脚下一打滑就从巍峨的峭崖上掉下去摔死了。

下面我们来看一下有漏洞的合约例子。SelectorClash合约有1个状态变量 solved,初始化为false,攻击者需要将它改为true。合约主要有2个函数,函数名沿用自 Poly Network 漏洞合约。
putCurEpochConPubKeyBytes() :攻击者调用这个函数后,就可以将solved改为true,完成攻击。但是这个函数检查msg.sender == address(this),因此调用者必须为合约本身,我们需要看下其他函数。
executeCrossChainTx() :通过它可以调用合约内的函数,但是函数参数的类型和目标函数不太一样:目标函数的参数为(bytes),而这里调用的函数参数为(bytes,bytes,uint64)。
contract SelectorClash {
bool public solved; // 攻击是否成功
// 攻击者需要调用这个函数,但是调用者 msg.sender 必须是本合约。
function putCurEpochConPubKeyBytes(bytes memory _bytes) public {
require(msg.sender == address(this), "Not Owner");
solved = true;
}
// 有漏洞,攻击者可以通过改变 _method 变量碰撞函数选择器,调用目标函数并完成攻击。
function executeCrossChainTx(bytes memory _method, bytes memory _bytes, bytes memory _bytes1, uint64 _num) public returns(bool success){
(success, ) = address(this).call(abi.encodePacked(bytes4(keccak256(abi.encodePacked(_method, "(bytes,bytes,uint64)"))), abi.encode(_bytes, _bytes1, _num)));
}
}
我们的目标是利用executeCrossChainTx()函数调用合约中的putCurEpochConPubKeyBytes(),目标函数的选择器为:0x41973cd9。观察到executeCrossChainTx()中是利用_method参数和"(bytes,bytes,uint64)"作为函数签名计算的选择器。因此,我们只需要选择恰当的_method,让这里算出的选择器等于0x41973cd9,通过选择器碰撞调用目标函数。
Poly Network黑客事件中,黑客碰撞出的_method为 f1121318093,即f1121318093(bytes,bytes,uint64)的哈希前4位也是0x41973cd9,可以成功的调用函数。接下来我们要做的就是将0x41973cd9转换为bytes类型:0x6631313231333138303933,然后作为参数输入到executeCrossChainTx()中。executeCrossChainTx()函数另3个参数不重要,都填 0x 就可以。
部署SelectorClash合约。
调用executeCrossChainTx(),参数填0x6631313231333138303933,0x,0x,0x,发起攻击。
查看solved变量的值,被修改为ture,攻击成功。
这一讲,我们介绍了选择器碰撞攻击,它是导致跨链桥 Poly Network 被黑 6.1 亿美金的的原因之一。这个攻击告诉了我们:
函数选择器很容易被碰撞,即使改变参数类型,依然能构造出具有相同选择器的函数。
管理好合约函数的权限,确保拥有特殊权限的合约的函数不能被用户调用。
No activity yet