![以欺骗者角度分析蜜罐合约 以欺骗者角度分析蜜罐合约]()
文章作者:pinging
1 前言
很久没有发布区块链的相关内容了,今天偶然间我点开了很久之前部署的一个蜜罐合约,借助比赛推出去之后发现收获了9个以太币hhhh(就是骗到的,当然这个是测试节点并不是真正的以太币)
效果还挺好的于是我就以欺骗者的角度来分析一下整个合约的代码,包括代码的设计思路以及上当的原因。最后我将该题目的wp放上以便爱好者学习。
2 题目分析
最初始部分是一个FatherOwned,该合约中有修饰函数onlyOwner用来判断调用合约方是否等于合约创建者。而该合约创建时会将owner赋初值。
之后为HoneyLock重头戏,该合约继承了标准代币合约StandardToken与父合约FatherOwned(这里为后面的蜜罐打下基础)。
该合约为一个简易的银行合约。HoneyLock函数的作用是初始化合约;之后为takeMoney。该函数使得新用户可以提取airDrop空投资金。
之后为lock()函数,用于判断存储时间是否大于一年。
为了让合约能修改owner,我们设置了useCode函数,该函数中需要传入一个猜测code,如果code == 设置好的guessCode,并且传入的msg.value大于初始的guessValue,那么就将owner设置为新的用户。
withdraw()中判断是否为owner,若为owner则可以将余额清零。
最后为CaptureTheFlag用于获取flag。
3 蜜罐分析
站在欺骗者角度,我们来分析一下本题目的技巧。为了达到蜜罐的作用,我们需要领用户自愿传入一定数量的代币。改题目中让用户参与合约的方法就是获取flag,而获取flag又需要满足两个条件:
而要满足上述两个条件需要我们调用空投函数takeMoney(),而调用之后又需要满足合约余额为0 。正常的操作需要等1年才可以提取,所以很多人会瞄准useCode函数,而该函数需要猜测guessCode与guessValue,对于很多专业队员来说,这种链上的信息可以从区块链上直接获取到,所以会想当然的调用,并传入一定数量代币。然而事情并没有那么简单。
许多人会认为调用了useCode(uint256 code)函数之后会改变owner = msg.sender,而忽略的一个重要的地方是onlyOwner是继承来的,所以这里onlyOwner改变的是FatherOwned的owner,然而获取flag的要求是需要HoneyLock合约的owner被修改,但是我们并没有修改HoneyLockowner的地方,所以这个方法永远不可能成功。所有的钱就只是白白扔进去。
简单解读一下该合约,该用户若想获得flag,那么他必须满足两个条件:
第一个为记录值必须为true第二个为余额必须为0.
但是该函数拥有修饰函数lock。
而该函数使得该余额需要存储1年才能进行转账,所以该方法跳过。
modifier onlyOwner{ if (msg.sender != owner) revert(); _; }。
这个函数看似能改变,当调用了之后会发现owner并不会改变。这是由于继承机制的问题。(蜜罐的精髓)
https://ethervm.io/decompile/ropsten/0xffd1e29ab7ea57836ce43c1089230fb29fd5b27e
既然上述的几种方法我们无法成功,那么我们需要通过逆向来查找是否有其他的函数了辅助我们进行。
其实在合约逆向后很容易能发现approve函数,而熟悉这个函数的用户都知道。ERC20中存在此类函数意味着拥有transferfrom类型的函数。
而我们并没有看到transferfrom函数。而逆向成为我们唯一的切入点,于是我们继续查看逆向合同:
这个函数中我们能看到需要传入四个参数,与地址相与操作意味着这是某个地址。
而if (arg2 > storage[keccak256(memory[0x00:0x40])]) { revert(memory[0x00:0x00]); }代表ERC20中的授权参数,我们从approve中能够看出该存储位置为0x03,此函数中的变量存储位置同样为0x03,所以为同一个参数。
即类似于:require(_value <= allowed[_from][msg.sender]);
而:if (storage[0x02] + msg.sender != arg3) { revert(memory[0x00:0x00]); }代表了0x02位置的参数+msg.sender需要 == arg3参数。
而位置0x02的参数可以通过如下方法进行查询,即为53231323。
所以我们需要传入 53231323+uint(msg.sender)。
这个时候就满足require (takeRecord[msg.sender] == true);。
传入参数:0x7083bcda08538cba3437d98ad01edfa73e2e2276,1000即赋予0x7083bcda08538cba3437d98ad01edfa73e2e2276代替账户转账1000的权利。
即授权成功。之后我们进行转账操作,调用attack函数:
结论
这是首次尝试使用蜜罐进行真实环境的尝试,在设计代码的时候是以欺骗者角度出发。为了让用户“上钩”我们必须给用户设计一个非常诱人的目标(这里是用CTF的flag),并非常明显的给用户一种提示,即需要满足什么条件。当用户拿到这个条件后会去代码中找达成条件的函数,而这些函数必须要非常明显并且易读。
对于熟悉攻击的人来说,这都是一些简单的技巧便能绕过。从而会让参与者觉得这个这个是合约的一个bug(内心窃喜?),当欢天喜地的去传入代币后会发现,完全不起作用??
而对于防守方来说,要知己知彼才能做到万无一失,所以要了解攻击者的想法才能做到很好的防御,这篇文章愿能提供一些思路。
联系/合作/投稿邮箱:[email protected]
![以欺骗者角度分析蜜罐合约 以欺骗者角度分析蜜罐合约]()
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
点赞
https://cn-sec.com/archives/116845.html
复制链接
复制链接
-
左青龙
- 微信扫一扫
-
-
右白虎
- 微信扫一扫
-
评论