Skip to content

Latest commit

 

History

History
147 lines (118 loc) · 4.17 KB

026.md

File metadata and controls

147 lines (118 loc) · 4.17 KB

Special Shamrock Giraffe

High

Attacker can use 1 single WrappedCreateValidator msg to prevent all other Validator creation.

Summary

WrappedCreateValidator does not enforce BLS private key is on curve. Attacker can abuse this and make all further Validator creation request in the epoch fail.

Root Cause

https://github.com/sherlock-audit/2024-12-babylon/blob/main/babylon/x/checkpointing/keeper/msg_server.go#L28 In \babylon\x\checkpointing\keeper\msg_server.go:L28

func (m msgServer) WrappedCreateValidator(goCtx context.Context, msg *types.MsgWrappedCreateValidator) (*types.MsgWrappedCreateValidatorResponse, error) {
	...
	// store BLS public key
	err = m.k.CreateRegistration(ctx, *msg.Key.Pubkey, valAddr)
	if err != nil {
		return nil, err
	}
	...
}
func (k Keeper) CreateRegistration(ctx context.Context, blsPubKey bls12381.PublicKey, valAddr sdk.ValAddress) error {
	return k.RegistrationState(ctx).CreateRegistration(blsPubKey, valAddr)
}
// CreateRegistration inserts the BLS key into the addr -> key and key -> addr storage
func (rs RegistrationState) CreateRegistration(key bls12381.PublicKey, valAddr sdk.ValAddress) error {
	blsPubKey, err := rs.GetBlsPubKey(valAddr)

	// we should disallow a validator to register with different BLS public keys
	if err == nil && !blsPubKey.Equal(key) {
		return types.ErrBlsKeyAlreadyExist.Wrapf("the validator has registered a BLS public key")
	}

	// we should disallow the same BLS public key is registered by different validators
	bkToAddrKey := types.BlsKeyToAddrKey(key)
	rawAddr := rs.blsKeysToAddr.Get(bkToAddrKey)
	addr := new(sdk.ValAddress)
	err = addr.Unmarshal(rawAddr)
	if err != nil {
		return err
	}
	if rawAddr != nil && !addr.Equals(valAddr) {
		return types.ErrBlsKeyAlreadyExist.Wrapf("same BLS public key is registered by another validator")
	}

	// save concrete BLS public key object
	blsPkKey := types.AddrToBlsKeyKey(valAddr)
	rs.addrToBlsKeys.Set(blsPkKey, key)
	rs.blsKeysToAddr.Set(bkToAddrKey, valAddr.Bytes())

	return nil
}

The BLS pubkey is not verified. This will allow malicious users to push an invalid pubkey, and later when the ABCI BeginBlocker execute the registeration, the check will fail and the whole process is DoSed.

func BeginBlocker(ctx context.Context, k keeper.Keeper) error {
	defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker)
	epoch := k.GetEpoch(ctx)
	if epoch.IsFirstBlock(ctx) {
		err := k.InitValidatorBLSSet(ctx)
		if err != nil {
			panic(fmt.Errorf("failed to store validator BLS set: %w", err))
		}
	}
	return nil
}
// InitValidatorBLSSet stores the validator set with BLS keys in the beginning of the current epoch
// This is called upon BeginBlock
func (k Keeper) InitValidatorBLSSet(ctx context.Context) error {
	...
	for i, val := range valset {
		blsPubkey, err := k.GetBlsPubKey(ctx, val.Addr)
		if err != nil {
			return fmt.Errorf("failed to get BLS public key of address %v: %w", val.Addr, err)
		}
		...
}
func (k Keeper) GetBlsPubKey(ctx context.Context, address sdk.ValAddress) (bls12381.PublicKey, error) {
	return k.RegistrationState(ctx).GetBlsPubKey(address)
}
// GetBlsPubKey retrieves BLS public key by validator's address
func (rs RegistrationState) GetBlsPubKey(addr sdk.ValAddress) (bls12381.PublicKey, error) {
	pkKey := types.AddrToBlsKeyKey(addr)
	rawBytes := rs.addrToBlsKeys.Get(pkKey)
	if rawBytes == nil {
		return nil, types.ErrBlsKeyDoesNotExist.Wrapf("BLS public key does not exist with address %s", addr)
	}
	pk := new(bls12381.PublicKey)
	err := pk.Unmarshal(rawBytes)

	return *pk, err
}
func (pk *PublicKey) Unmarshal(data []byte) error {
	if len(data) != PubKeySize {
		return errors.New("Invalid public key length")
	}

	*pk = data
	return nil
}

If attacker's BLS key is not PubKeySize long, the flow will just return.

Internal Pre-conditions

N/A

External Pre-conditions

N/A

Attack Path

  1. Attacker make a WrappedCreateValidator message with incorrect BLS pubkey length
  2. wait for BeginBlocker.

Impact

All validator request in the whole epoch will fail.

PoC

No response

Mitigation

Verify BLS pubkey length in WrappedCreateValidator