惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
A
About on SuperTechFans
博客园 - Franky
Engineering at Meta
Engineering at Meta
Recent Announcements
Recent Announcements
云风的 BLOG
云风的 BLOG
B
Blog
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
U
Unit 42
Martin Fowler
Martin Fowler
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
博客园 - 叶小钗
Vercel News
Vercel News
Apple Machine Learning Research
Apple Machine Learning Research
The Cloudflare Blog
Last Week in AI
Last Week in AI
腾讯CDC
Microsoft Azure Blog
Microsoft Azure Blog
爱范儿
爱范儿
V
V2EX
G
Google Developers Blog

高金的博客

人机协作逆向:用 AI + Frida 打通微信 4.1.8 macOS 数据库密钥提取 情绪价值与求真:如何平衡与应对? friend_tech 第一笔交易只能买 1 个key? friend_tech 套利到底有多卷 无公网ip,无服务器实现内网穿透 植物挖矿 浏览器环境检测 加密、编码相关知识汇总 使用tensorflow识别验证码 POW与反爬虫 appium 安卓无法点击搜索框解决办法 知乎直播弹幕抓取与解析 知乎直播套利分析 1000刀+的羊毛在等你 如何创建一个完全匿名的EOS、ETH账号 如何通过技术手段证明"我"没有去过武汉 XUNTA 季度报告 玩游戏不如CX,JUSTGAME邀请分析(内附元数据) 如何在conflux上部署合约 程序员找对象聚合平台-xunta.today
EOS 1.8 bidname的漏洞分析
Gao JIn · 2019-11-24 · via 高金的博客

背景

因为最近EIDOS挖矿很火,所以会特别关注EOS CPU的使用情况

一觉醒来看到 eosio的cpu的使用率变高,这肯定不正常,应该是有人利用eosio的cpu来挖EIDOS

bidname 源代码分析

bidname的逻辑大概说一下

就是a先竞拍某个名字,b如果也想要这个名字的话,需要出大于a价格的10%

然后系统会把a的钱退给他

源码在: https://github.com/EOSIO/eosio.contracts/blob/v1.8.0/contracts/eosio.system/src/name_bidding.cpp#L53

竞拍成功后的给上一个人退钱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
eosio::transaction t;
t.actions.emplace_back( permission_level{get_self(), active_permission},
get_self(), "bidrefund"_n,
std::make_tuple( current->high_bidder, newname )
);
t.delay_sec = 0;
uint128_t deferred_id = (uint128_t(newname.value) << 64) | current->high_bidder.value;
eosio::cancel_deferred( deferred_id );
t.send( deferred_id, bidder );

bids.modify( current, bidder, [&]( auto& b ) {
b.high_bidder = bidder;
b.high_bid = bid.amount;
b.last_bid_time = current_time_point();
});
}

可以看到当竞拍成功后,会发起一个延时交易,调用自己的bidrefund方法, bidrefund是给上一个人退钱

注意这边的的发起人是 get_self(),也就是eosio自己,所以这个延时交易的cpu 由eosio这个账号付

科普一下: 延时交易的cpu由谁付,主要看签名的人是谁

bidrefund 方法

1
2
3
4
5
6
7
8
9
void system_contract::bidrefund( const name& bidder, const name& newname ) {
bid_refund_table refunds_table(get_self(), newname.value);
auto it = refunds_table.find( bidder.value );
check( it != refunds_table.end(), "refund not found" );

token::transfer_action transfer_act{ token_account, { {names_account, active_permission}, {bidder, active_permission} } };
transfer_act.send( names_account, bidder, asset(it->amount), std::string("refund bid on name ")+(name{newname}).to_string() );
refunds_table.erase( it );
}

bidrefund 方法就是给上一个人打EOS

发起人是 eosio.names,接收人是上一个参与拍卖的人

如何利用漏洞

因为上面有给前一个参与拍卖的人打EOS,其实是可以挂一个钩子

就是我可以写一个方法,接收某个人给我打代币的通知,然后我做某些事情

代码示例

官方文档关于on_notify在eosioon_notifyvalid-eosio-account-namevalid-eosio-action-name

1
2
3
4
5
6
7
8
9

[[eosio::on_notify("eosio.token::transfer")]]
void run(name from, name to, asset quantity, std::string memo)
{
if (from == name("eosio.names"))
{

}
}

利用漏洞的整个流程

所以整个逻辑是这样

eosio 发起 bidrefund -> 向前一个人转账 -> 接收通知后挖矿

由于 “向前一个人转账、接收通知后挖矿” 都是内部交易,所以整个cpu都是由 执行bidrefund 方法的人买单,也就是eosio买单

那么只要 我弄两个号,一起去拍某个名字,这样就可以一直挖矿了

如何更高效的利用漏洞

成本分析

  1. 拍一个新的名字,ram由发起人付
  2. 因为每次拍卖的费用需要最少比上次多10%,所以两个人一直互相拍的话,最后停止的时候会损耗10%的EOS

ram费用和收入相比,基本上可以忽略不计

最后损耗10%的话,只要我控制上限就好了…(也就是每次从0.0001 EOS开始,到0.01 EOS我就换一个名字继续拍)

让程序永远的跑下去

有两种方法

  1. 线下版

两个合约都设置好上限,然后线下新增名字拍卖

  1. 合约版

生成新的名字也在合约内

合约完全自动执行(一次触发

整个逻辑如下图

当A收到eosio.names发来的eos,先执行挖矿

再判断是否大于0.01EOS

不大于的话,直接金额加10%拍卖一次(这样,另一个合约就会收到eosio.names的转账通知)

大于的话,先生成新的可用的name

然后先本合约参与拍卖0.0001EOS的,并让另一个合约拍卖0.0002EOS的

这样整个流程就完成了

只要先线下一次性拍100个,那就相当于100并发

会永远的执行拍卖下去,而且CPU只要刚开始触发的100次。。。

自动生成可用的name

  1. 需要名字没有被注册过

is_account 就可以做到

1
2
3
if (!is_account(name(newname))){

}
  1. 名字没有被拍卖过
1
2
3
4
5
6
name_bid_table bids("eosio"_n, "eosio"_n.value);
auto current = bids.find(name(newname).value);
if (current == bids.end())
{
return newname;
}

漏洞修复

可以看到cpu由之前的get_self() 改成了 current->high_bidder

也就是由之前的eosio 改成了上一个人参与拍卖的人。。。

所以后面就无法继续利用了


本文作者:高金
本文地址https://igaojin.me/2019/11/24/EOS-1-8-bidname的漏洞分析/
版权声明:转载请注明出处!

推荐文章