
蜜罐是传统安全领域中的一个概念,通常指安全人员设置一些陷阱(比较明显的漏洞),让攻击者自己掉入我们设置好的陷阱中,以便安全人员分析攻击者的作恶手法。
蜜罐合约(HoneyPots Contract)也是类似的概念,但对象变了,一般指合约开发者设置了看似容易获利的合约逻辑,但其实是陷阱,普通用户观察合约,发现有利可图,便与蜜罐合约交互,结果发现交互的资产无法被自己提出。
蜜罐合约在中文圈子有时也称为貔貅合约,本文将简单讨论一下,我看见的几种逻辑陷阱型蜜罐合约。
比较多项目会在transfer函数(转账相关)中实现一些业务逻辑,蜜罐合约可能在transfer函数中加入一些强行限制用户交易的逻辑,从而实现截取用户资产的效果。
这类合约,我称为逻辑陷阱型蜜罐合约,是比较好识别的一类,主要关注其交易相关的逻辑在合约实现上是否透明以及是否有限制则可,这里介绍三个逻辑陷阱型蜜罐合约:
黑名单蜜罐合约
可变合约构成的蜜罐合约
限时限卖的蜜罐合约
我们看到BSC上一个叫Moco合约:https://bscscan.com/address/0x9d4bDdd642529a588f910Aad405C07e066A908Cf#code
Moco合约继承了ERC20,即是一个代币合约,看到合约中的_transfer函数,部分代码如下:
function _transfer(address sender, address recipient, uint256 amount) private returns (bool) {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
require(!_isbclisted[recipient] && !_isbclisted[sender], "bclisted address");
// ...
在用户进行交易时,会调用_transfer函数,它有3个require做条件判断,主要看到第三个,判断sender与recipient都不在黑名单内,才能进行交易。
根据_isbclisted进行搜索,可以发现addBot函数实现了将用户地址加入黑名单的操作。
function addBot(address recipient) internal {
if (!_isbclisted[recipient]) _isbclisted[recipient] = true;
}
那什么地方调用了addBot函数呢?搜索一下,发现还是在_transfer函数中,相关代码如下:
if(sender == uniswapPair) {
if (block.number <= launchedBlock + killblock) {
addBot(recipient);
}
}
如果当前区块数小于launchedBlock + killblock,那么当前recipient会被加入黑名单,而launchedBlock与killblock这两个变量是被合约创建者控制的。
简而言之,合约创建者可以通过对launchedBlock与killblock的控制,将部分区块中发生交易的recipient地址加入黑名单,这样recipient后续就无法从Moco中转出代币了。
这便是典型的黑名单蜜罐,通常出现在土狗项目中,用于杀抢土狗机器人的。
很多土狗项目上线时,会进行拉盘操作,对普通用户而言,会发现土狗项目涨的很快,从而被利润吸引,参与到土狗的交互中,部分开发者也会发现这个土狗项目早期拉盘的特点,就开发了机器人,在开盘后立刻买入,然后等土狗项目方拉盘时,快速卖出,从而获得稳定的利润。
随后,项目方很快也发现土狗机器人的存在,这便进入了一个对抗过程,比如当前这种黑名单逻辑,因为土狗机器人交易速度很快,会抢到比较前的区块完成买入交易,一个土狗项目开盘后,可能会涌入大量机器人交易,通过黑名单的逻辑,就可以将机器人地址加入黑名单,直接让机器人损失本金。
我们看到BSC上,一个名叫SpaceXOver的合约:https://bscscan.com/address/0x60899ea0c86048eb5d8a7a2cf395c7cc58a9023a#code
先看transfer函数,代码如下:
function transfer(address to, uint256 amount) public returns (bool) {
Acc(Acc_address).acc_Transfer(msg.sender, to, amount);
emit Transfer(msg.sender, to, amount);
return true;
}
transfer函数中,真正进行转账交易的逻辑没有在当前合约实现,而是通过Acc合约中的acc_transfer去做的,有猫腻。
翻看一下当前合约,发现Acc合约是在部署时设置了该合约的地址,即当前合约没有Acc合约的逻辑,相关代码如下:
constructor(address _acc) public {
totalSupply_ = 8000000*10**18;
deployer = msg.sender;
// 设置 Acc 合约地址
Acc_address = _acc;
Acc(Acc_address).acc_setup(address(this), totalSupply_);
}
我们可以通过解析input data的形式,来获得部署SpaceXOver合约时,Acc合约的具体地址。
先尝试用bscscan提供的Decode Input Data
发现解析不出来,这里吐槽一下,感觉很多合约的input data都无法通过这种方式解析,不知道为何不去优化一下,对于开源合约,获得abi后,input data还是很好解析的。
这里,我们使用web3-input-decoder这个库来解析一下,先安装一下。
pip install web3-input-decoder
然后保存一下SpaceXOver合约的ABI用于解析input data,相关代码如下:
import json
from web3_input_decoder import decode_constructor, decode_function
# SpaceXOver的ABI JSON
p = '1.json'
with open(p, 'r', encoding='UTF-8') as f:
abi = f.read()
abiJson = json.loads(abi)
result = decode_constructor(abiJson, "0x6080604...(input data复制过来则可)")
print(result)
结果如下:
访问acc合约地址,发现这个地址下的合约是闭源的,无法看到合约代码,猫腻很大,因为我们不知道其交易时的具体逻辑是怎么样的,很有可能就是一个蜜罐合约,只可进,不可出。
我们看到BSC上名叫SW的合约:https://bscscan.com/address/0xa7d0741813d2ff189b172f68c1ce3f0aa101bd22#code
SW合约的中定义了多个mapping(address => uint256)类型的变量,通过这些变量来记录转账的值。
看到_transfer函数,有限制交易时间与限制交易金额比例的逻辑,相关代码如下:
// 限制交易时间
if(block.timestamp<_limitTime){
dayBuy[to]=dayBuy[to].add(amount);
require(dayBuy[to]<=300*10**18 ,"limit time max 300");
}
require(_isTrade ,"limit trade2 ");
// 限制交易金额比例,最多只能交易 90% 的金额
require(balanceOf(from).mul(90).div(100)>amount,"selle max 90%");
takeFee = true;
除了逻辑陷阱型蜜罐,还有其他类型的蜜罐合约,阅读【The Art of The Scam: Demystifying Honeypots in Ethereum Smart Contracts】论文可知还有如下几种类型的蜜罐合约:
| 级别 | 技巧 |
|---|---|
| Ethereum Virtual Machine(以太坊虚拟机级别) | Balance Disorder(平衡紊乱) |
| Solidity编译器级别 | Inheritance Disorder(继承障碍) |
| Skip Empty String Literal(跳过空字符串字面值) | |
| Type Deduction Overflow(类别除法溢出) | |
| Uninitialised Struct(未初始化结构) | |
| 以太扫描区块链探索器(Etherscan) | Hidden State Update(隐藏状态更新) |
| Hidden Transfer(隐藏交易) | |
| Straw Man Contract(稻草人合同) |
因为论文中讨论的比较细致且我自身没有进行复现验证,所以本文就不多讨论。
值得一提的是Skip Empty String Literal与Type Deduction Overflow已在高版本的Solidity中fix了,如果你用0.8.0以上版本的Solidity不会有这两个问题,其他的,需要自行验证一下。
相关参考:
【米斯特姚】的Youtube频道(https://www.youtube.com/watch?v=SAzZ61cvvn8)
【The Art of The Scam: Demystifying Honeypots in Ethereum Smart Contracts】论文(https://www.arxiv-vanity.com/papers/1902.06976/)
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
前面一篇关于智能合约翻译文讲到了,是一种计算机程序,既然是程序,那就可以使用程序语言去编写智能合约了。而若想玩区块链上的项目,大部分区块链项目都是开源的,能看得懂智能合约代码,或找出其中的漏洞,那么,学习Solidity这门高级的智能合约语言是有必要的,当然,这都得在公链``````以太坊上,毕竟国内的联盟链有些是不兼容Solidity。Solidity是一种面向对象的高级语言,用于实现智能合约。智能合约是管理以太坊状态下的账户行为的程序。Solidity是运行在以太坊(Ethereum)虚拟机(EVM)上,其语法受到了c++、python、javascript影响。Solidity是静态类型
文章目录一基础定义二创建逻辑卷2-1准备物理设备2-2创建物理卷2-3创建卷组2-4创建逻辑卷2-5创建文件系统并挂载文件三扩展卷组和缩减卷组3-1准备物理设备3-2创建物理卷3-3扩展卷组3-4查看卷组的详细信息以验证3-5缩减卷组四扩展逻辑卷4-1检查卷组是否有可用的空间4-2扩展逻辑卷4-3扩展文件系统五删除逻辑卷5-1备份数据5-2卸载文件系统5-3删除逻辑卷5-4删除卷组5-5删除物理卷六LVM逻辑卷缩容6-1缩容注意事项6-2标准缩容步骤一基础定义LVM,LogicalVolumeManger,逻辑卷管理,Linux磁盘分区管理的一种机制,建立在硬盘和分区上的一个逻辑层,提高磁盘分
我有一个PORO(普通旧Ruby对象)来处理一些业务逻辑。它接收一个ActiveRecord对象并对其进行分类。为了简单起见,以下面为例:classClassificatorSTATES={1=>"Positive",2=>"Neutral",3=>"Negative"}definitializer(item)@item=itemenddefnameSTATES.fetch(state_id)endprivatedefstate_idreturn1if@item.value>0return2if@item.value==0return3if@item.value但是,我还想根据这些st
在以下示例中,我无法理解Ruby运算符的优先级:x=1&&y=2由于&&的优先级高于=,我的理解是类似于+和*运算符:1+2*3+4解析为1+(2*3)+4它应该等于:x=(1&&y)=2但是,所有Ruby源代码(包括内部语法解析器Ripper)都将其解析为x=(1&&(y=2))为什么?编辑[08.01.2016]让我们关注一个子表达式:1&&y=2根据优先规则,我们应该尝试将其解析为:(1&&y)=2这没有意义,因为=需要特定的LHS(变量、常量、[]数组项等)。但是既然(1&&y)是一个正确的表达式,那么解析器应该如何处理呢?我试过咨询Ruby的parse.y,但它太像意大利面条
我正在尝试解决来自SevenLanguagesinSevenWeeks的一个简单的Ruby问题Printthecontentsofanarrayofsixteennumbers,fournumbersatatime,usingjusteach这是我想到的,可以用简单的方式完成还是改进它?a=(1..16).to_ai=0j=[]a.eachdo|item|i+=1j可以在一行中使用each_slicea.each_slice(4){|x|px} 最佳答案 Teja,你的解决方案没问题。由于您需要使用每一个,因此算法的复杂性将受限于数
我想做的是处理n个集合,而我在下面提供的代码正好处理4个集合。defshow_combinations@combos=[]['A','noA'].eachdo|a|['B','noB'].eachdo|b|['C','noC'].eachdo|c|['D','noD'].eachdo|d|@combos我如何重构以下代码来处理以下场景:鉴于我有一个大小为y的数组,其中包含大小为n的数组,我想返回所有组合。请务必注意,每个子数组中只能有一个项目出现在结果中。(如“已完成资料”不能同时出现在“未完成资料”的结果中)背景:用户可能有一些任务:例如,“完成配置文件”或“设置电子邮件”或其他任何
我正在使用searchkick库作为产品搜索的elasticsearch客户端。https://github.com/ankane/searchkick可以创建'OR'条件和'AND'条件;AND运算Product.search其中:{price:{lte:200},in_stock:true}或运算Product.search其中:{或:[[{in_stock:true},{backordered:true}]]}但我坚持使用searchkick创建多个“AND”“OR”条件。我需要类似的东西A或B或(C和D)或者我需要这样,A与B与(C或D)请指导我,如何实现这一目标谢谢
假设我有两个数组:a=[1,2,3]b=[1,2]我想对这两个数组执行一个逻辑操作,返回不在两个数组中的元素(即3)。谢谢! 最佳答案 Ruby中的数组可以非常方便地重载一些数学运算符和按位运算符。在a中但不在b中的元素a-b#[3]同时在a和b中的元素>a&b#[1,2]a或b中的元素a|b#[1,2,3]数组求和(串联)a+b#[1,2,3,1,2]你明白了。 关于Ruby逻辑运算符-一个但不是两个数组中的元素,我们在StackOverflow上找到一个类似的问题:
我在一个网站上工作,收集人们玩过的国际象棋比赛的结果。查看玩家的评分以及他们与对手的评分之间的差异,我绘制了一个图表,其中的点代表获胜(绿色)、平局(蓝色)和失败(红色)。根据这些信息,我还实现了逻辑回归算法来对获胜和获胜/平局的截止值进行分类。使用评级和差异作为我的两个特征,我得到了一个分类器,然后在图表上绘制了分类器改变其预测的边界。我的梯度下降、成本函数和sigmoid函数的代码如下。defgradient_descent()oldJ=0newJ=J()alpha=1.0#Learningraterun=0while(run0.001))thenrun-=20end#Do20mo