一行代码蒸发了¥6,447,277,680 人民币!

背景

今天有人在群里说,Beauty Chain 美蜜 代码里面有bug,已经有人利用该bug获得了 57,896,044,618,658,100,000,000,000,000,000,000,000,000,000,000,000,000,000,000.792003956564819968 个 BEC

那笔操作记录是 0xad89ff16fd1ebe3a0a7cf4ed282302c06626c1af33221ebe0d3a470aba4a660f

下面我来带大家看看,黑客是如何实现的!

我们可以看到执行的方法是 batchTransfer

那这个方法是干嘛的呢?(给指定的几个地址,发送相同数量的代币)

整体逻辑是

你传几个地址给我(receivers),然后再传给我你要给每个人多少代币(value)

然后你要发送的总金额 = 发送的人数* 发送的金额

然后 要求你当前的余额大于 发送的总金额

然后扣掉你发送的总金额

然后 给receivers 里面的每个人发送 指定的金额(value)

从逻辑上看,这边是没有任何问题的,你想给别人发送代币,那么你本身的余额一定要大于发送的总金额的!

但是这段代码却犯了一个很傻的错!

代码解释

这个方法会传入两个参数

_receivers 的值是个列表,里面有两个地址

0x0e823ffe018727585eaf5bc769fa80472f76c3d7

0xb4d30cac5124b46c2df0cf3e3e1be05f42119033

_value 的值是 8000000000000000000000000000000000000000000000000000000000000000

我们再查看代码(如下图)

我们一行一行的来解释

但是此时 _value 是16进制的,我们把他转成 10进制

(python 16进制转10进制)

可以看到 _value = 57896044618658097711785492504343953926634992332820282019728792003956564819968

那么amount = _value*2 = 115792089237316195423570985008687907853269984665640564039457584007913129639936

可以在查看上面看到 uint256取值范围最大为 115792089237316195423570985008687907853269984665640564039457584007913129639935

此时,amout已经超过了最大值,溢出 则 amount = 0

下一行代码 require(cnt > 0 && cnt <= 20); require 语句是表示该语句一定要是正确的,也就是 cnt 必须大于0 且 小于等于20

我们的cnt等于2,通过!

这句要求 value 大于0,我们的value是大于0 的 且,当前用户拥有的代币余额大于等于 amount,因为amount等于0,所以 就算你一个代币没有,也是满足的!

这句是当前用户的余额 – amount

当前amount 是0,所以当前用户代币的余额没有变动

这句是遍历 _receivers中的地址, 对每个地址做以下操作

_receivers中的地址的余额 = 原本余额+value

所以 _receivers 中地址的余额 则加了57896044618658097711785492504343953926634992332820282019728792003956564819968 个代币!!!

Transfer(msg.sender, _receivers[i], _value); } 这句则只是把赠送代币的记录存下来!!!

总结

就一个简单的溢出漏洞,导致BEC代币的市值接近归0

那么,开发者有没有考虑到溢出问题呢?

其实他考虑了,

可以看如上截图

除了amount的计算外, 其他的给用户转钱 都用了safeMath 的方法(sub,add)

那么 为啥就偏偏这一句没有用safeMath的方法呢。。。

这就要用写代码的人了。。。

啥是safeMath

safeMath 是为了计算安全 而写的一个library

我们看看他干了啥?为啥能保证计算安全.

如上面的乘法. 他在计算后,用assert 验证了下结果是否正确!

如果在上面计算 amount的时候,用了 mul的话, 则 c / a == b 也就是 验证 amount / cnt == _value

这句会执行报错的,因为 0 / cnt 不等于 _value

所以程序会报错!

也就不会发生溢出了…

那么 还有一个小问题,这里的 assert 好 require 好像是干的同一件事

都是为了验证 某条语句是否正确!

那么他俩有啥区别呢?

用了assert的话,则程序的gas limit 会消耗完毕

而require的话,则只是消耗掉当前执行的gas

总结

那么 我们如何避免这种问题呢?

我个人看法是

只要涉及到计算,一定要用safeMath

代码一定要测试!

代码一定要review!

必要时,要请专门做代码审计的公司来 测试代码

这件事后需要如何处理呢?

目前,该方法已经暂停了(还好可以暂停)所以看过文章的朋友 不要去测试了…

不过已经发生了的事情咋办呢?

我能想到的是,快照在漏洞之前,所有用户的余额情况

然后发行新的token,给之前的用户 发送等额的代币…

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容