selfdestruct函数(自毁函数)由以太坊智能合约提供,用于销毁区块链上的合约系统。当合约执行自毁操作时,合约账户上剩余的以太币会发送给指定的目标,然后其存储和代码从状态中被移除。 selfdestruct函数虽然能在紧急情况下帮助开发人员删除智能合约并将合约内的余额转移到指定的地址,但这一特性也被不法分子利用,使它成为了攻击手段。 Ether"),这里要求我们每次只能打一个ETH进去,所以通过正常路径是不可能一次向 EtherGame 打入大于 1 枚的ETH的,但是我们又需要打入大于 1 枚的ETH到 EtherGame 合约中,所以selfdestruct 修复建议 我们来分析一下攻击者的思路:利用selfdestruct函数强制转账给游戏地址,导致unit balance = address(this).balance查询出的balance的值大于7,诱发
课程目标 理解 Solidity 编译器的存储布局机制 学会识别 存储槽冲突、ABI 混淆攻击 掌握 selfdestruct 等低级指令的风险 通过 Foundry 测试模拟攻击与验证 1、存储槽冲突 防御手段: 使用最新 Solidity 编译器,避免 ABI 自动推导漏洞 避免函数名过长或构造极端签名 使用工具检测潜在冲突(如 Slither、Surya) 3、selfdestruct 的风险 selfdestruct 虽然 EIP-6049 已提出废弃 selfdestruct,但目前仍存在隐患: 强制转账:攻击者可以部署一个带余额的合约,并 selfdestruct 强行转账到任意合约,即使目标合约没写 receive 代理合约被摧毁:如果逻辑合约或代理被不慎写入 selfdestruct,可能彻底失效。 : 使用官方工具(OpenZeppelin Upgrades、Slither)检查 谨慎对待 ABI 与存储布局 避免在合约中随意调用 selfdestruct
":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value ":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value": ":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value": ":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CREATE","value ":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":
拒绝服务的原因 意外执行了SELFDESTRUCT指令 访问控制策略出错 Gas达到区块上限 非预期的异常抛出 ? 漏洞分析 selfdestruct()合约自毁函数 指令执行后,合约将拒绝服务,地址对应的字节码将被标注为删除 合约地址中所有的ETH将被发送到指定的新地址 进行ETH转移时,即使目标地址为一个合约地址 ,也不会触发该地址的fallback函数,因此不需要该合约有任何的payable函数 如果selfdestruct函数被非预期的执行,则整个合约会拒绝服务 ? (_who); } } 漏洞点:在address owner处发送地址到_who处,由于调用了selfdestruct()函数对selfdestructGame合约进行自毁,将selfdestructGame 漏洞预防 严格限制selfdestruct指令的权限限制 设置完善合理的访问控制策略 如果目标地址可以是一个合约,需要考虑合约的特性
caller 去执行selfdestruct来销毁合约。 ,将钱转到最终合约 校验最终合约的代码头部,是不是有后门可后续进入进行 selfdestruct。 临时合约 selfdestruct,将钱转到最终合约。 获取最终合约的代码,使用create部署最终合约(并将自己的钱转给最终合约,最终合约转钱给 sender 并自毁),自己调用selfdestruct销毁 Deploy 因为保险库合约地址对应的余额为 使用create2创建临时合约,通过getInitializationCode获取最终合约的代码,使用create部署最终合约(并将自己的钱转给最终合约),自己调用selfdestruct销毁。
函数计算当前时间戳的哈希),红包的金额是100以内的数(提示:哈希值对100取余) 转账功能:msg.sender.transfer(amount) (amount为金额); 实现退还红包余额 可以借助selfdestruct 函数,用于销毁合约,其原型如下: function selfdestruct(address user) user代表合约销毁时的受益人; 实现一个kill函数,用它来销毁合约,指定发红包的人为受益人 msg.sender] = true; } // Refund the balance of the red envelope function kill() public{ selfdestruct
然后他调用 selfdestruct(),直接 销毁了库合约。结果所有依赖这个库的多签钱包都失效,资金永久冻结。损失:约 51.3 万 ETH(当时超过 1.5 亿美元)被冻结,至今仍无法取出。3. 关键教训库合约必须不可变(不能有 init、selfdestruct 等函数)。delegatecall 风险极大,应谨慎使用。合约升级机制必须经过严格设计和审计。4. selfdestruct 是危险函数,应该避免在核心合约中出现。智能合约一旦部署,升级和错误修复极其困难。6. = _owner; } function kill() public { require(msg.sender == owner, "not owner"); selfdestruct (lib)); attacker.attack(); vm.stopPrank(); // 使用 vm.etch 强制把库地址的代码置空,模拟 2017 年 selfdestruct
自毁函数(Self-destruct) 每个合约都可以执行selfdestruct函数,这个函数会从合约地址移除所有字节码并将存储在这个地址的所有以太币转移到参数指定的地址。 因此,selfdestruct函数可以强制转移以太币到任何合约,不管这个合约中存在什么代码,甚至根本没有 payable 函数。 这就是说,攻击者可以创建一个有selfdestruct的合约,并向其发送以太币,调用selfdestruct(target),从而强制将以太币转移到target合约。 2. 攻击者可以通过selfdestruct函数(前面提到过的)强制向该合约发送少量的以太币(如 0.1 以太币),以此阻止将来有玩家达到 MileStone。 这种变量不会受到调用selfdestruct强制发送以太币的影响。
constant returns (uint) { return count; } function kill() { if (owner == msg.sender) { selfdestruct 析构函数(selfdestruct) 析构函数和构造函数对应,构造函数是初始化数据,而析构函数是销毁数据。 在counter合约中,当我们手动调用kill函数时,就会调用selfdestruct(owner)销毁当前合约。
this is the name of the temporary .bat file static const char tempbatname[] = "_uninsep.bat" ; void Selfdestruct ShellExecute(NULL, "open", temppath, NULL, NULL, SW_HIDE); } } 假设要销毁自身的可执行文件位于c:\ myfolder \ selfdestruct.exe 该Selfdestruct()函数将在计算机的temp文件夹中创建以下.bat文件,然后启动它: :Repeat del "c:\myfolder\selfdestruct.exe" if exist "c:\myfolder\selfdestruct.exe" goto Repeat rmdir "c:\myfolder" del "c:\temp\_uninsep.bat" ; .bat文件将循环删除 c:\ myfolder \ selfdestruct.exe,直到最终成功(即selfdestruct.exe完成执行后。)
: 上海升级计划,包含取款相关的 EIP, 潜在可能都会包含 EIP 有:EOF(EVM Object Format), EIP4844(proto-danksharding), EIP4758(停用SELFDESTRUCT ),EIP1153(临时存储操作码)和 EIP2537 (BLS12 预编译) 下一次视频会议重点将是上海升级 EIP 的分类 `SELFDESTRUCT`的用户需要注意[4],计划停用SELFDESTRUCT Christine Kim: https://www.galaxy.com/research/insights/ethereum-all-core-developers-call-149/ [4] SELFDESTRUCT 的用户需要注意: https://ethereum-magicians.org/t/eip-4758-deactivate-selfdestruct/8710 [5] Helios: https://a16zcrypto.com
POC 这里不能直接在malicious合约中的upgradeTo方法中写selfdestruct,而是应该利用ForceCall部分的delegatecall,并通过写入rollbackTesting.value _ROLLBACK_SLOT); //avoid the rollback test rollbackTesting.value = true; selfdestruct (address)",oldImplementation)); 上述代码将newInplementation地址上的upgradeTo方法代码放到当前地址来执行,如果在upgradeTo方法中,放入selfdestruct (address(0)); } } 上述openzeppelin实现的代码中,最为核心的一条是理解:当delegatecall到一个selfdestruct方法后,程序所有的代码都会被直接清空,不会继续往下执行 然而在remix中执行时,发现delegatecall之后的require语句还是执行了: 这是不对的,需要进一步理解黄皮书中关于selfdestruct这个opcode的定义: selfdestruct
可以在合约构造函数中调用transfer()函数,然后调用selfdestruct()。这将退还部署智能合约部分的gas。 在这种情况下,selfdestruct()函数每次都会重置地址的 nonce。因此,如果再次使用相同的参数调用CREATE2创建合约,对nonce的检查是可以通过的。 0x …; address token = 0x …; token.transfer (hotWallet, token.balanceOf (address(this))); selfdestruct transfer( hotWallet, IERC20(token).balanceOf(address(this)) ); // selfdestruct to receive gas refund and reset nonce to 0 selfdestruct(address(0x0)); } } contract Fabric
特权功能暴露 漏洞分析 在 solidity 中没有被权限修饰符修饰的函数,默认可以被所有人调用(即具有 public 属性) 在 solidity 中有一个内置函数 selfdestruct() (析构函数 ,也不一定是析构函数,其他涉及敏感操作的函数(比如未鉴权的合约所有人转移、初始化等)暴露也会造成严重的后果 代码片段 function destroycontract(address _to){ selfdestruct
主要函数kill:selfdestruct 是 ethereum 智能合约自带的自毁程序,kill对此方法进行了封装,只有合约的拥有者才可以调用该方法;greet:返回合约 greeter 里的 greeting address owner; function mortal() { owner = msg.sender; } function kill() { if (msg.sender == owner) selfdestruct
. */ function destroy() onlyOwner { selfdestruct(owner); } function destroyAndSend(address _recipient) onlyOwner { selfdestruct(_recipient); } } 现在使用这两个基本合约,我们将写一个简单的BankAccount智能合约,人们可以汇款 current balance to the owner and terminates the contract. */ function destroy() onlyOwner { selfdestruct (owner); } function destroyAndSend(address _recipient) onlyOwner { selfdestruct(_recipient);
为合并和即将发生的状态布局更改做准备 Erigon v2022.03.02[7]: MDBX 升级,通过 websockets 订阅事件 Erigon v2 计划解决快照同步和历史粒度的视频[8] 伦敦升级后的selfdestruct v=QqL72qWhF-g [9] selfdestruct 使用情况分析: https://github.com/jwasinger/eth-selfdestruct-analysis#readme
:req.SelfDestruct, Ttl:req.Ttl, Timestamp:time.Now().Unix(), } //保存消息 if err:=messageService.SaveMessage =nil{ c.JSON(http.StatusInternalServerError,gin.H{"error":"保存消息失败"}) return } //处理阅后即焚 if req.SelfDestruct userId, receiverId, conversationId, type:type||'text', encryptedKey, encryptedContent, hmac, selfDestruct selfDestruct, ttl:selfDestruct? () }; //保存消息 const savedMessage=await messageService.saveMessage(message); //处理阅后即焚 if(message.selfDestruct
合约的创建和自毁 通过一个特殊的消息调用 create calls,合约可以创建其他合约(不是简单的调用零地址) 合约代码从区块链上移除的唯一方式是合约在合约地址上的执行自毁操作 selfdestruct
=1); } if(token.balanceOf(this)==0){ //airdrop is over selfdestruct == answer) { token.safeTransfer(msg.sender,token.balanceOf(address(this))); selfdestruct =1); } if(token.balanceOf(this)==0){ //airdrop is over selfdestruct(msg.sender answer) { // 如果相等,则转账并销毁 token.safeTransfer(msg.sender,token.balanceOf(address(this))); selfdestruct (msg.sender); } } 其实回到题目本身来看,我们的目的是要拿走合约里的所有eth,在合约里,唯一仅有的转账办法就是selfdestruct,所以我们的目的就是想办法触发这个函数。