🔬 调用无前端无合约的智能合约
题目
原始题目
题目解读
我们直接看题. 已知有一个Polygon链上的未开源的合约, 求找到其中一个函数, 将微信昵称传入并成功发送交易.
做题过程
我一开始想了好久也没想通, 卡在某一步了, 到最后做完才知道原来是自己之前挖了个坑.
肖越与会枫的解题视频录像
1. 找出函数 Signature
首先, 我们需要审题, 这是Polygon上的合约, 那么我们就去Polygonscan上来搜索这个合约. 找到第一笔成功交易.
我们可以观察出这个函数的名字非常奇怪. 叫Buy And Free2245... . 同时上面的另一条成功交易叫Elddhzr. 但在现有的信息下我们没法直接来通过函数的名字调用, 因为我们没有源码.
我们点进其中的一个交易, 去看其中的具体信息. 根据我们在网络上搜索到的闭源合约知识, 我们可以知道. 这些各种0当中的0x以及前八位是函数的签名.
这就更奇怪了, 一个函数的签名竟然会如此凑巧, 正好是00000000. 但是有了这个线索, 我们所能确定的范围更小了.
2. 找出可能的函数
我们有了0x00000000的函数签名后, 就需要用到以太坊签名数据库. 这里面记录了几十万个不同函数和方法的签名. 我们搜索0x00000000得到以下结果.
我们在其中看到了我们的熟人 BuyAndFree 函数.
回忆一下题目内容, 函数是只有一个参数, 参数是能够传微信昵称的. 微信昵称是字母数字字符的组合, 那么在其中就只能是传一个bytes参数的函数. 我们找到以下三个可疑的函数.
3. 逆向推出合约
再次回忆一下题目内容. 原始题目内, 我们成功触发的顺序就是我们报名的顺序, 而且我们所传入的参数是我们的微信昵称. 那么我们可以推断出合约源码内是有一个mapping来存储报名顺序以及微信昵称的. 其中报名的顺序肯定是一个数字, 那么就肯定是uint256, 微信昵称则是bytes.
那么我们可以推理出合约的具体内容可能可以是:
pragma experimental ABIEncoderV2;
pragma solidity ^0.6.0;
contract hack{
mapping (uint256=>bytes) c;
function abcei51243fdgjkh(bytes memory _a) public returns(bytes memory){
c[2] = _a;
return _a;
}
}
4. 运行猜出的合约
我们把合约内容放到remix里. 编译后选择 Injected Web3 环境, 在下方填入合约原始的地址. 点击 At Address.
我们成功得到了我们想要的那个函数!
5. 传入参数, 提交交易
不要忘记这个函数参数的类型是bytes, 我们没法直接把字符串填进去.
我们需要用到另一个工具, 将我们的昵称变成hex编码.
之后我们就可以直接把hex编码填入进去, 发起交易. (别忘了在前面加上0x)
支付手续费确认交易之后你就可以看到成功啦!
错误示范
一个很典型的错误示范就是尝试把字节码反编译出来. [反编译的工具]中不包含Polygon网络, 就算把字节码粘贴过去, 成功反编译出来之后也会是天书.
BONUS
在题目发出的一个星期前, 我正好在群里转了关于函数签名带0能省gas的聊天记录 (这里有个相关的文章推荐阅读). 当时崔棉大师评论了几句. 之后可能也是受这几篇文章的启发, 所以出了这道题, 把我难住这么好几天.
感谢会枫和肖越的解题!