文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载CREATE2是 EIP-1014 引入的以太坊合约创建操作码它用0xff address salt keccak256(init_code)的确定性哈希取代了依赖nonce的CREATE地址推导使合约地址变得完全可控、可预先计算。在 CTF 区块链题目中这一特性最常见的利用方式是保持init_code不变、让构造函数返回的运行时字节码可变从而在同一个地址上先后部署字节码完全不同的合约绕过各类基于地址或字节码的校验。阅读本篇后你将掌握CREATE与CREATE2的地址推导原理、二者差异、地址预计算脚本以及 2019 Balsn CTF Creativity 题目的完整 Solidity PoC 复现思路。背景为何 CREATE2 会在以太坊与 CTF 中被关注在 CTF-Wiki 的区块链板块中以太坊Ethereum安全是占比最高、也是最常出现的主题见 区块链介绍。智能合约代码一旦上链便难以篡改因此合约部署地址的生成规则直接决定了攻击者能在多大程度上预测或重放合约。以太坊虚拟机EVM为开发者提供了两种创建合约的操作码CREATE最传统的合约创建方式地址由创建者地址与账户nonce决定CREATE2在君士坦丁堡Constantinople硬分叉中引入的新操作码地址由创建者地址、盐值salt与创建代码init_code共同决定完全不再依赖nonce。两者都输出一个新合约的地址但CREATE2让地址生成具有确定性 可预计算的能力这正是其衍生出大量攻击技巧的根源。CREATE 的地址推导nonce 驱动的确定性在理解CREATE2之前需要先理解旧的CREATE操作码。无论使用外部账户EOA部署还是由合约通过CREATE创建子合约新合约的地址都由创建者的账户地址以及该账户的nonce共同决定。以太坊中每个账户都维护着一个nonce字段Ethereum Basics 将其定义为已执行交易总数用来标示该账户发出的交易数量对外部账户而言每发送一笔交易nonce就会1对合约账户而言每通过CREATE创建一个子合约nonce就会1。新合约地址的计算公式为keccak256(rlp.encode(address, nonce))[12:]即将创建者地址与当前nonce做 RLP 编码取keccak256哈希结果的后 20 字节160 位作为新合约地址。由于nonce会随交易或子合约创建次数而递增同一账户两次创建合约得到的地址必然不同而且地址无法在创建之前被精确预知至少不直观。这种不可控性正是CREATE2要解决的痛点。CREATE2 的地址推导EIP-1014 的确定性公式CREATE2摒弃了对nonce的依赖改为对以下三个参数做哈希运算参数含义可控性address合约创建者的地址部署方部署方确定可控salt由调用方显式传入的 32 字节混淆值完全可控init_code合约的创建代码用于部署合约的字节码可控是整个技巧的关键其地址计算公式为keccak256(0xff address salt keccak256(init_code))[12:]公式中0xff是一个固定的单字节前缀用于与CREATE的地址空间以及普通交易地址推导作区分随后拼接创建者地址、salt再拼接init_code本身的keccak256哈希最终对整个结果再取一次keccak256并截取低 160 位后 20 字节作为新合约地址。一个容易忽略的关键细节init_code 与运行时字节码计算地址时使用的最后一个参数并非合约最终存储的运行时字节码runtime code而是创建代码init code。创建代码是用来创建合约的那段代码它在合约创建交易执行期间运行执行完毕后通过RETURN0xf3返回一段数据这段数据才是写入链上的运行时字节码参见 Ethereum Opcodes 中RETURN的语义return memory[offset:offsetlength]。这一细节带来了极具攻击性的推论只要init_code保持不变无论构造函数最终返回什么运行时字节码计算出的地址都完全一致。于是攻击者可以控制构造函数返回任意字节码同时保持init_code固定从而在同一个地址上反复部署、覆盖出完全不同行为的合约。CREATE2允许合约在部署后被重新更改的特性天然存在潜在安全问题这也是 EIP-1014 社区讨论Potential Security Implications of CREATE2所关注的重点。在 CTF 中该技巧通常被用作在同一地址部署不同合约以绕过不同校验的通用手段。实战案例2019 Balsn CTF Creativity 的 CREATE2 巧用下面以 2019 Balsn CTF 的 Creativity 题目基于其官方 Write-up 提供的 PoC为例完整演示如何借助CREATE2在同一个地址上先后部署两个完全不同的合约。核心 PoCDeployer 与 Dumper 两个合约PoC 使用 Solidity^0.5.10包含两个合约Deployer负责执行CREATE2部署Dumper则充当始终不变的init_code它唯一的职责就是在构造函数阶段把调用者传入的任意字节码倾倒return出来作为最终部署的运行时字节码。pragma solidity ^0.5.10; contract Deployer { bytes public deployBytecode; address public deployedAddr; function deploy(bytes memory code) public { deployBytecode code; address a; // Compile Dumper to get this bytecode bytes memory dumperBytecode hex6080604052348015600f57600080fd5b50600033905060608173ffffffffffffffffffffffffffffffffffffffff166331d191666040518163ffffffff1660e01b815260040160006040518083038186803b158015605c57600080fd5b505afa158015606f573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052506020811015609857600080fd5b81019080805164010000000081111560af57600080fd5b8281019050602081018481111560c457600080fd5b815185600182028301116401000000008211171560e057600080fd5b50509291905050509050805160208201f3fe; assembly { a : create2(callvalue, add(0x20, dumperBytecode), mload(dumperBytecode), 0x9453) } deployedAddr a; } } contract Dumper { constructor() public { Deployer dp Deployer(msg.sender); bytes memory bytecode dp.deployBytecode(); assembly { return (add(bytecode, 0x20), mload(bytecode)) } } }逐段拆解这个 PoC 的攻击链路deploy(code)是唯一的对外入口调用方把希望部署的任意合约字节码作为code参数传入。Deployer先将code存入公共状态变量deployBytecode后面Dumper会读取它再通过内联汇编执行CREATE2。init_code恒定dumperBytecode硬编码了编译后的Dumper合约字节码也就是说无论传入什么codeCREATE2使用的init_code始终是同一段字节码salt固定为0x9453部署方地址固定为Deployer合约地址。三者不变 ⇒ 计算出的目标地址不变。Dumper构造函数偷梁换柱Dumper的构造函数在创建阶段执行它会拿到msg.sender即Deployer合约调用deployBytecode()读出刚才传入的code然后用内联汇编的return(add(bytecode, 0x20), mload(bytecode))把这整段code作为运行时字节码返回给 EVM。需要注意汇编参数的内存布局mload(bytecode)读取的是bytecode指针处的长度字段add(bytecode, 0x20)则跳过长度字段指向数据区起始位置二者恰好构成RETURN所需的(offset, length)参数——这也与 Ethereum Opcodes 中RETURN的栈语义完全一致。效果同一个地址任意合约对调用者而言效果是惊人的每次调用deploy(code)实际参与地址计算的init_code都是同一个dumperBytecode加上固定的部署方地址与salt因此deploy(code)部署出来的合约最终总是落在同一个地址上而该地址上最终存储的运行时字节码则是本次调用传入的code。也就是说第一次deploy(codeA)→ 地址 X 上部署的是codeA第二次deploy(codeB)→地址 X 上部署的变成了codeB无论传入什么合约代码都能精确投递到同一个地址。这正好实现了本文开头所说的在同一次 CTF 挑战中用同一个地址绕过不同校验的攻击模式题目校验某地址上的合约行为时攻击者可以先在该地址部署满足校验 A 的合约再重新部署满足校验 B 的合约。地址预计算getAddress 函数由于CREATE2的地址完全确定攻击者在部署前就能算出目标地址。题目给出的已知条件是Deployer合约地址为0x99Ed0b4646a5F4Ee0877B8341E9629e4BF30c281配合固定的dumperBytecode与salt可以预先算出实际部署合约的地址为0x4315DBef1aC19251d54b075d29Bcc4E81F1e3C73。地址预计算的 Solidity 实现如下其计算逻辑与keccak256(0xff address salt keccak256(init_code))[12:]一一对应function getAddress(address addr, bytes memory bytecode, uint salt) public view returns (address) { bytes32 hash keccak256( abi.encodePacked( bytes1(0xff), addr, salt, keccak256(bytecode) ) ); // NOTE: cast last 20 bytes of hash to address return address(uint160(uint256(hash))); }实现细节解读abi.encodePacked将0xff、创建者地址、salt与keccak256(init_code)紧凑拼接保证不引入任何填充字节与 EVM 内部计算逻辑完全一致bytes1(0xff)对应公式中的固定前缀最后通过uint160(uint256(hash))截取哈希的低 20 字节并转换为address类型。实际复现时可以先用getAddress验证预计算地址0x4315DBef1aC19251d54b075d29Bcc4E81F1e3C73再分别在deploy中传入两段不同的字节码观察同一地址上先后部署出两个不同合约。部署过程实测截图下面的两张图来自本题的复现过程直观展示了同一个地址上先后部署两个不同合约的完整链路。两张图中部署方DEPLOYER地址均为0x99Ed0b4646a5F4Ee0877B8341E9629e4BF30c281但传入的待部署字节码参数不同第一张为0x33ff第二张为完整合约字节码两次部署计算出的合约地址却都是0x4315DBef1aC19251d54b075d29Bcc4E81F1e3C73——这正是CREATE2地址确定性在实战中的直接体现。实战中的攻击套路与防御视角为什么攻击者偏爱 CREATE2从 CTF 出题与解题两个角度看CREATE2的核心价值在于地址可预计算部署前即可获知目标地址便于配合其他合约预先设置白名单、授权等依赖地址的逻辑地址可复用同一地址可以承载完全不同的代码逻辑从而绕过地址 A 已经存在/不可修改之类的假设init_code与运行时字节码解耦只要控制好构造函数返回的数据就能让地址计算与最终代码脱钩。对应的防御注意事项合约逻辑中若把某地址上已部署的代码视为不可变信任根需要意识到该地址可能被CREATE2重新部署出恶意代码即所谓的合约可以自我替换风险审计中应特别关注项目方是否使用了固定salt 可变init_code的模式以及构造函数是否会返回来自外部输入的字节码在编写依赖合约地址做权限控制的系统时应显式验证部署方身份与部署时间而不是只依赖地址本身。相关 CTF 题目下列题目均与CREATE2技巧相关适合作为练习题目附件可参考 CTF-Wiki 的 challenges 仓库赛事题目名称Balsn 2019CreativityQWB 2020EasyAssembly其中 Balsn 2019 Creativity 正是上文 PoC 的出处QWB 2020 EasyAssembly 则将CREATE2与汇编/字节码构造技巧结合进一步考验对 EVM 执行细节的把控。参考EIP-1014: Skinny CREATE2CREATE2操作码的正式规范定义了地址计算公式与引入背景充分利用 CREATE2社区对CREATE2各类用法的系统梳理Balsn CTF 2019 - Creativity本题的官方 Write-up 与 PoC 原始出处。如需回顾相关基础知识可继续阅读 Ethereum Basics账户、nonce、交易与合约创建机制以及 Ethereum OpcodesRETURN、CALL等关键指令的栈语义。赞分享文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载相关推荐Envoy 静态配置详解用 static_resources 搭建一个可运行的 HTTP 反向代理Envoy 静态配置详解用 static_resources 搭建一个可运行的 HTTP 反向代理 本文以 Envoy 官方快速上手指南中的「静态配置」文档为文档网络安全教程WTF Solidity 极简入门25. CREATE2 操作码——在合约部署前预计算合约地址WTF Solidity 极简入门25. CREATE2 操作码——在合约部署前预计算合约地址 CREATE2 操作码允许开发者在不实际部署合约的情况下通过示例工程区块链教程Wasp 邮件功能中的 Dummy Provider仅限开发使用的邮件发送器与生产构建限制Wasp 邮件功能中的 Dummy Provider仅限开发使用的邮件发送器与生产构建限制 在 Wasp一个面向全栈 Web 应用的声明式框架中 ema文档网络安全教程上一篇推荐开源项目Zulip Mobile - 跨平台的高效聊天客户端下一篇nginx-rtmp-win32性能优化提升Windows平台流媒体服务效率创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
ISTA 2A运输包装测试:从随机振动到跌落冲击的完整执行指南 简介:国际安全运输协会(ISTA)发布的ISTA 2A-2011(2012)是一项面向包装工程师、物流质量与运输安全人员的包装产品测试标准,专门用于评估150磅(68kg)以下单个包装产品在运输过程中的可靠性与稳定性。该标准结… · 2026/9/25 7:47:30
双向可编程交流电源深度评测:能量回馈与谐波叠加实战解析 在实验室里把一台三相30kVA的DH18600系列双向可编程交流电源从开箱到满载回馈完整跑了一整天,包括谐波叠加、电压骤降、防孤岛测试等十几个场景,这边把过程和结果整理成一篇简评。双向可编程交流电源这几年在新能源测试领域几乎成了标配,但真… · 2026/9/25 7:47:24
Docling实战:PDF版面分析与表格结构恢复指南 我真正开始认真留意 Docling,是在一个被 PDF 折磨的下午。当时我从一批审计报告里抽表格,报告是双栏排版,页眉页脚还带着公司公告,常用的解析库给我返回了一段连顺序都不对的纯文本,表格里的数字和左侧标题完全错位&am… · 2026/9/25 7:47:24
人工智能数学基础:习题答案+源代码如何帮你彻底弄懂公式 简介:一份聚焦人工智能数学基础的资源包,由唐宇迪编著,面向AI学生与从业者,帮助逐项补齐线性代数、概率统计、微积分、最优化、图论、离散数学与动态规划等核心数学短板,通过习题与代码将理论落到实践。压缩包整体约6.… · 2026/9/25 8:20:28
HDMI信号传输原理:从TMDS编码到音频PCM打包的FPGA实现 HDMI 这玩意儿现在满大街都是,电视、显示器、机顶盒、笔记本、游戏机,甚至树莓派和 FPGA 开发板上都标配。但真要问一句“HDMI 到底是怎么把画面和声音从一根线送过去的”,能说清楚的人并不多。我当初调 FPGA 的 HDMI 输出时,对着… · 2026/9/25 8:20:22
8G显存本地部署minimaxh3:ComfyUI剪枝版+加速LoRA实战 1. 为什么要在8G显存上折腾minimaxh3本地部署先把结论摆在前面:8G显存跑minimaxh3,能跑,但绝对不是“点一下按钮就出片”的体验。我前后折腾了差不多两周,从最初的直接爆显存,到后来能把一段5秒的480P视频稳定生成出来… · 2026/9/25 8:20:16
物联网健康监测系统设计:从树莓派网关到多传感器报警闭环 简介:一套面向物联网开发者和嵌入式学习者的健康监测系统设计资料,围绕树莓派网关、加速度计、音频与视频监测、Web端应用等核心模块展开,覆盖从硬件数据采集、传感器信号处理到云端传输与远程管理的完整链路,可支撑课程设计、项目… · 2026/9/25 8:20:16
Atlas 300V 24G部署YOLO实战:从硬件认知到推理调优全流程 最近后台私信里问得最多的一个东西,就是Atlas 300V 24G。问来问去其实就两句话:这卡到底是不是运算加速卡?能不能用来部署YOLO?我的回答一直很直接:能,而且就是干这个的。Atlas 300V 24G是华为昇腾阵营里一… · 2026/9/25 8:20:16
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37