Princípio de implementação de ataque cross-chain BNBChain com restauração de alta fidelidade - - O que significa que o invasor escolheu um bloco com uma altura de 110217401?
20 de outubro de 2022
Se passaram 10 dias desde o incidente do ataque da ponte cross-chain BNBChain, e existem muitas análises e discussões na Internet. Todos estão muito preocupados sobre o ocorrido e a reparação de vulnerabilidades.
No entanto, descobrimos que 99% dos desenvolvedores apenas compreendem que a vulnerabilidade é causada por uma vulnerabilidade no algoritmo de Hash do nó folha da árvore IAVL+ no SDK da Cosmos, mas não sabem como o invasor constrói a carga útil (dados de entrada) e o quão difícil é implementar um ataque como esse. Quão grande ele é, qual a razão para a escolha dessa altura de bloco (110217401) há muito tempo atrás?
Com esses problemas em mente, a SharkTeam restaurou o processo de mineração de vulnerabilidade do hacker e a lógica de construção da carga útil (payload) com alta fidelidade. Vamos descobrir!
1. Análise de transações
txHash: 0xebf83628ba893d35b496121fb8201666b8e09f3cbadf0e269162baa72efe3b8b
O contrato acessado é o contrato CrossChain na BNBChain, o endereço é 0x2000 e a função chamada e parâmetros são como a seguir:
Análise de parâmetro:
- Carga útil (payload): a carga útil (payload) é o pacote de informações da transação cross-chain, que inclui a função e os parâmetros para chamar a transferência BNB, com um comprimento de 147 bytes.
- Prova (proof): a prova da Merkle do pacote de transação cross-chain, incluindo o alcance de prova da árvore IVAL e a prova da árvore Merkle simples armazenada na MultiStore, com um comprimento de 999 bytes.
- Altura (height): altura do bloco, leia o appHash no bloco onde a altura da cadeia de origem da transação cross-chain é a altura, que é, na verdade, o appHash do bloco anterior, usado para verificar a simples prova da árvore Merkle armazenada na MultiStore.
- packageSequence: o número da sequência do pacote cross-chain, que é semelhante ao Nonce do bloco.
- channelId: a ID do canal cross-chain, indicando a cadeia de origem (source chain) e a cadeia de destino (target chain) da transação cross-chain. Aqui, channelId=2 indica uma transação de transferência cross-chain da cadeia BC para a cadeia BSC.
2. Análise de contrato
O contrato CrossChain é como o seguinte:
Nós dividimos a função handlePackage em 6 funções chave durante todo o processo de execução. Por sua vez, a lógica, os parâmetros e os valores retornados dessas 6 funções chave são analisados.
2.1. Função validateMerkleProof
A finalidade dessa função é verificar a prova Merkle. O nome da função e parâmetros são definidos como mostrado a seguir:
Os parâmetros passados são os seguintes:
{
“appHash”: “0x72cda827a83531ca0fd7ac917a6b65649719aab0836722caafe0603147a52318”,
“storeName”: “ibc”,
“key” (chave): “0x00000100380200000000010dd85c”,
“value” (valor): “0x000000000000000000000000000000000000000000000000000000000000000000f870a0424e4200000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000008ad3c21bcecceda100000094489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec94489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec846553f100”,
“proof” (prova): “0x0a8d020a066961766c3a76120e00000100380200000000010dd85c1af201f0010aed010a2b0802100318b091c73422200c10f902d266c238a4ca9e26fa9bc36483cd3ebee4e263012f5e7f40c22ee4d20a4d0801100218b091c7342220e4fd47bffd1c06e67edad92b2bf9ca63631978676288a2aa99f95c459436ef632a20da657c1ffb86c684eb3e265361ef0fa4f9dfa670b45f9f91c5eb6ad84b21a4d112001a370a0e0000010038020000000000000002122011056c6919f02d966991c10721684a8d1542e44003f9ffb47032c18995d4ac7f18b091c7341a340a0e00000100380200000000010dd85c12202c3a561458f8527b002b5ec3cab2d308662798d6245d4588a4e6a80ebdfe30ac18010ad4050a0a6d756c746973746f726512036962631ac005be050abb050a110a066f7261636c6512070a0508b891c7340a0f0a046d61696e12070a0508b891c7340a350a08736c617368696e6712290a2708b891c7341220c8ccf341e6e695e7e1cb0ce4bf347eea0cc16947d8b4e934ec400b57c59d6f860a380a0b61746f6d69635f7377617012290a2708b891c734122042d4ecc9468f71a70288a95d46564bfcaf2c9f811051dcc5593dbef152976b010a110a0662726964676512070a0508b891c7340a300a0364657812290a2708b891c73412201773be443c27f610 75cecdc050ce22eb4990c54679089e90afdc4e0e88182a230a2f0a02736312290a2708b891c7341220df7a0484b7244f76861b1642cfb7a61d923794bd2e076c8dbd05fc4ee29f3a670a330a06746f6b656e7312290a2708b891c734122064958c2f76fec1fa5d1828296e51264c259fa264f499724795a740f48fc4731b0a320a057374616b6512290a2708b891c734122015d2c302143bdf029d58fe381cc3b54cedf77ecb8834dfc5dc3e1555d68f19ab0a330a06706172616d7312290a2708b891c734122050abddcb7c115123a5a4247613ab39e6ba935a3d4f4b9123c4fedfa0895c040a0a300a0361636312290a2708b891c734122079fb5aecc4a9b87e56231103affa5e515a1bdf3d0366490a73e087980b7f1f260a0e0a0376616c12070a0508b891c7340a300a0369626312290a2708b891c7341220e09159530585455058cf1785f411ea44230f39334e6e0f6a3c54dbf069df2b620a300a03676f7612290a2708b891c7341220db85ddd37470983b14186e975a175dfb0bf301b43de685ced0aef18d28b4e0420a320a05706169727312290a2708b891c7341220a78b556bc9e73d86b4c63ceaf146db71b12ac80e4c10dd0ce6eb09c99b0c7cfe0a360a0974696d655f6c6f636b12290a2708b891c73412204775dbe01d41cab018c21ba5c2af94720e4d7119baf693670e70a4 0ba2a52143”
}
Os parâmetros acima são interpretados da seguinte forma:
(1) O appHash lê o AppHash com altura (height) chamando a função getAppHash no contrato TendermintLightClient. A função getAppHash é como a seguir:
A variável de estado lightClientConsensusStates é atualizada quando o repetidor Relayer da cross-chain chama a função syncTendermintHeader para sincronizar a informação de cabeçalho (header) de cada bloco, que armazena o appHash de cada bloco na cadeia BC.
O AppHash é um campo no cabeçalho (header) do bloco, que representa o valor do hash do estado do aplicativo depois que a execução do bloco anterior está completa.
O parâmetro appHash é o AppHash do bloco cuja altura da cadeia BC é 110217400 (a altura do parâmetro é 110217401) e seu valor é 0x72cda827a83531ca0fd7ac917a6b65649719aab0836722caafe0603147a52318.
(2) O parâmetro storeName=”ibc” é uma constante definida pelo contrato, que é convertida em hexadecimal para 0x696263.
(3) A chave do parâmetro é gerada pela chamada da função generateKey. O código é o seguinte:
O valor da chave do parâmetro é 14 bytes de comprimento e consiste em duas partes:
- Os primeiros 6 bytes são gerados pela ID channel, que é channelId, cujo valor é 0x000001003802 e contém, na ordem:
- Os últimos 8 bytes são o número de sequência do pacote packageSequence, que é 17684572=0x00000000010dd85c.
Portanto, aqui temos, chave=0x00000100380200000000010dd85c, comprimento=14=0x0e.
(4) O parâmetro payloadLocal é a carga útil (payload) na transação InputData, com um comprimento de 147 bytes.
(5) O parâmetro proofLocal é a prova (proof) na transação InputData, com um comprimento de 999 bytes.
O código de implementação da função validateMerkleProof é o seguinte:
Esta função chama o contrato com o endereço 0x65 para verificar a prova. Os parâmetros são os seguintes:
(1) input(entrada)=0x00000000000000000000000000000000000000000000000000000000000005086962630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000100380200000000010dd85c0000000000000000000000000000000000000000000000000000000000000093000000000000000000000000000000000000000000000000000000000000000000f870a0424e4200000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000008ad3c21bcecceda100000094489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec94489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec846553f10072cda827a83531ca0fd7ac917a6b65649719aab0836722caafe0603147a523180a8d020a066961766c3a76120e00000100380200000000010dd85c1af201f0010aed010a2b0802100318b091c73422200c10f902d266c238a4ca9e26fa9bc36483cd3ebee4e263012f5e7f40c22ee4d20a4d0801100218b091c7342220e4fd47bffd1c06e67edad92b2bf9ca63631978676288a2aa99f95c459436ef632a20da657c1ffb86c684eb3e265361ef0fa4f9dfa670b45f9f91c5eb6ad84b21a4d112001a370a0e00000100380200000 00000000002122011056c6919f02d966991c10721684a8d1542e44003f9ffb47032c18995d4ac7f18b091c7341a340a0e00000100380200000000010dd85c12202c3a561458f8527b002b5ec3cab2d308662798d6245d4588a4e6a80ebdfe30ac18010ad4050a0a6d756c746973746f726512036962631ac005be050abb050a110a066f7261636c6512070a0508b891c7340a0f0a046d61696e12070a0508b891c7340a350a08736c617368696e6712290a2708b891c7341220c8ccf341e6e695e7e1cb0ce4bf347eea0cc16947d8b4e934ec400b57c59d6f860a380a0b61746f6d69635f7377617012290a2708b891c734122042d4ecc9468f71a70288a95d46564bfcaf2c9f811051dcc5593dbef152976b010a110a0662726964676512070a0508b891c7340a300a0364657812290a2708b891c73412201773be443c27f61075cecdc050ce22eb4990c54679089e90afdc4e0e88182a230a2f0a02736312290a2708b891c7341220df7a0484b7244f76861b1642cfb7a61d923794bd2e076c8dbd05fc4ee29f3a670a330a06746f6b656e7312290a2708b891c734122064958c2f76fec1fa5d1828296e51264c259fa264f499724795a740f48fc4731b0a320a057374616b6512290a2708b891c734122015d2c302143bdf029d58fe381cc3b54cedf77ecb8834dfc5dc3e1555d68f19ab0a3 30a06706172616d7312290a2708b891c734122050abddcb7c115123a5a4247613ab39e6ba935a3d4f4b9123c4fedfa0895c040a0a300a0361636312290a2708b891c734122079fb5aecc4a9b87e56231103affa5e515a1bdf3d0366490a73e087980b7f1f260a0e0a0376616c12070a0508b891c7340a300a0369626312290a2708b891c7341220e09159530585455058cf1785f411ea44230f39334e6e0f6a3c54dbf069df2b620a300a03676f7612290a2708b891c7341220db85ddd37470983b14186e975a175dfb0bf301b43de685ced0aef18d28b4e0420a320a05706169727312290a2708b891c7341220a78b556bc9e73d86b4c63ceaf146db71b12ac80e4c10dd0ce6eb09c99b0c7cfe0a360a0974696d655f6c6f636b12290a2708b891c73412204775dbe01d41cab018c21ba5c2af94720e4d7119baf693670e70a40ba2a52143
(2) length=1260=0x508=32+1228
O comprimento (length) real da entrada é 1260 bytes, mas o comprimento real do parâmetro é 1228. A razão pelo qual o comprimento=1260 é porque o primeiro byte da entrada armazena o comprimento real do parâmetro 1228=0x508.
O resultado é enviado para “result” (resultado) e seu valor 0x01. Por fim, a verificação da prova é aprovada e “true” (verdadeiro) é retornado.
2.2. Função getSubmitter
Os remetentes (submitters) da variável de estado são atualizados quando o retransmissor Relayer da cross-chain chama a função syncTendermintHeader para sincronizar a informação do cabeçalho (header) de cada bloco. Seu valor é msg.sender, que é o endereço do repetidor Relayer: 0xb005741528b86f5952469d80a8614591e3c5b632.
2.3. Função decodePayloadHeader
payload=0x000000000000000000000000000000000000000000000000000000000000000000f870a0424e4200000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000008ad3c21bcecceda100000094489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec94489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec846553f100
Entre eles, incluindo:
- packageType=0x0, o comprimento é 1 byte;
- relayFee=0x0, o comprimento é 32 bytes.
- package=0xf870a0424e4200000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000008ad3c21bcecceda100000094489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec94489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec846553f100, o comprimento é 114 bytes.
2.4. Função handleSynPackage
O parâmetro aqui é como a seguir:
- channelId=0x02;
- msgBytes=0xf870a0424e4200000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000008ad3c21bcecceda100000094489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec94489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec846553f100.
Entre eles, a função handleTransferInSynPackage é a seguinte:
2.5. Função addReward
A funcionalidade desta função é distribuir recompensas ao retransmissor (relayer) após a conclusão do negócio da cross-chain.
3. Análise da cadeia pública
O contrato pré-compilado no endereço 0x65 é chamado ao validar a prova Merkle no contrato.
Examinamos o contrato pré-compilado em 0x65 na VM (Virtual Machine ou Máquina Virtual) da seguinte maneira:
A entrada de execução do contrato pré-compilado é a seguinte:
Análise do parâmetro:
- p: iavlMerkleProofValidate no endereço 0x65;
- entrada: a entrada aprovada pela função validateMerkleProof, o comprimento é 32+1228=1260 bytes, os primeiros 32 bytes são o comprimento do parâmetro real da entrada, que é 1228=0x508.
input(entrada)=0x00000000000000000000000000000000000000000000000000000000000005086962630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000100380200000000010dd85c0000000000000000000000000000000000000000000000000000000000000093000000000000000000000000000000000000000000000000000000000000000000f870a0424e4200000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000008ad3c21bcecceda100000094489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec94489a8756c18c0b8b24ec2a2b9ff3d4d447f79bec846553f10072cda827a83531ca0fd7ac917a6b65649719aab0836722caafe0603147a523180a8d020a066961766c3a76120e00000100380200000000010dd85c1af201f0010aed010a2b0802100318b091c73422200c10f902d266c238a4ca9e26fa9bc36483cd3ebee4e263012f5e7f40c22ee4d20a4d0801100218b091c7342220e4fd47bffd1c06e67edad92b2bf9ca63631978676288a2aa99f95c459436ef632a20da657c1ffb86c684eb3e265361ef0fa4f9dfa670b45f9f91c5eb6ad84b21a4d112001a370a0e0000010038020000000000000002122011056c6919f02d966991c10721684a8d1542e44003f9ffb47032c18995d4ac7f18b091c7341a340a0e00000100380200000000010dd85c12202c3a561458f8527b002b5ec3cab2d308662798d6245d4588a4e6a80ebdfe30ac18010ad4050a0a6d756c746973746f726512036962631ac005be050abb050a110a066f7261636c6512070a0508b891c7340a0f0a046d61696e12070a0508b891c7340a350a08736c617368696e6712290a2708b891c7341220c8ccf341e6e695e7e1cb0ce4bf347eea0cc16947d8b4e934ec400b57c59d6f860a380a0b61746f6d69635f7377617012290a2708b891c734122042d4ecc9468f71a70288a95d46564bfcaf2c9f811051dcc5593dbef152976b010a110a0662726964676512070a0508b891c7340a300a0364657812290a2708b891c73412201773be443c27f61075cecdc050ce22eb4990c54679089e90afdc4e0e88182a230a2f0a02736312290a2708b891c7341220df7a0484b7244f76861b1642cfb7a61d923794bd2e076c8dbd05fc4ee29f3a670a330a06746f6b656e7312290a2708b891c734122064958c2f76fec1fa5d1828296e51264c259fa264f499724795a740f48fc4731b0a320a057374616b6512290a2708b891c734122015d2c302143bdf029d58fe381cc3b54cedf77ecb8834dfc5dc3e1555d68f19ab0a330a06706172616d7312290a2708b891c734122050abddcb7c115123a5a4247613ab39e6ba935a3d4f4b9123c4fedfa0895c040a0a300a0361636312290a2708b891c734122079fb5aecc4a9b87e56231103affa5e515a1bdf3d0366490a73e087980b7f1f260a0e0a0376616c12070a0508b891c7340a300a0369626312290a2708b891c7341220e09159530585455058cf1785f411ea44230f39334e6e0f6a3c54dbf069df2b620a300a03676f7612290a2708b891c7341220db85ddd37470983b14186e975a175dfb0bf301b43de685ced0aef18d28b4e0420a320a05706169727312290a2708b891c7341220a78b556bc9e73d86b4c63ceaf146db71b12ac80e4c10dd0ce6eb09c99b0c7cfe0a360a0974696d655f6c6f636b12290a2708b891c73412204775dbe01d41cab018c21ba5c2af94720e4d7119baf693670e70a40ba2a52143
O método Executar (Run) da iavlMerkleProofValidate é o seguinte:
A estrutura kvmp analisada é a seguinte:
Em seguida, chame o método de validação de kvmp:
A estrutura de prt e kp é a seguinte:
Chame o método VerifyValue de prt:
A estrutura poz é a seguinte:
Poz contém 2 operações, nomeadas IAVLValueOp e MultiStoreOp.
Chame o método Verify da poz, do seguinte modo:
Chame o método Executar (Run) na operação. Existem 2 operações na poz, IAVLValueOp e MultiStoreOp. Portanto, os métodos Executar (Run) de IAVLValueOp e MultiStoreOp são chamados sucessivamente, isto é, para verificar a prova Merkle.
3.1. Verificação IVALValueOp
A primeira chamada é o método Run da IAVLValueOp, da seguinte maneira:
O parâmetro args (argumento) aqui tem apenas um elemento args[0], que é o parâmetro da carga útil (payload), com um comprimento de 147 bytes. O que é retornado é a rootHash na prova Merkle.
A operação (op) aqui é a seguinte:
O tipo de prova (proof) é RangeProof e a estrutura é definida da seguinte maneira:
Uma das Esquerda (Left) e Direita (Right) da estrutura proofInnerNode deve ser nula e a outra deve ser não nula.
Tome a seguinte árvore IAVL+ como um exemplo:
Descrição: letras representam os nós, números representam as chaves e existem 8 nós de folha em comuns.
De acordo com as características da árvore IAVL+, para qualquer nó intermediário, as condições são conhecidas:
node.key<=node.Right.key && node.key>=node.Left.key
Por exemplo, para a construção da RangeProof do nó J, o caminho da prova é como a seguir:
Quando Key=2 (nó J), PathToLeaf é {A, B, E}. Entre eles, Esquerda (Left) e Direta (Right) de cada nó são como a seguir:
lLeft=nulo, A.Right=C.key
lB.Left=D.key, B.Right=nulo
lE.Left=nulo, E,Right=K.key (E.Left é, na verdade, o nó J)
Aqui, o valor da prova (proof) é o seguinte:
Na prova (proof), LeftToPath tem 2 LeafToPaths, 0 InnerNodes e 2 Leaves. Também foi descoberto que Esquerda (Left) e Direita (Right) de LeftToPath[1] não são nulos. Além disso, após o cálculo, encontramos que LeftToPath[1].Right é, na verdade, leaves[1], que é a chave aprovada pelo parâmetro e o valor de Hash de toda a folha (leaf) é:
0xda657c1ffb86c684eb3e265361ef0fa4f9dfa670b45f9f91c5eb6ad84b21a4d1
Três métodos importantes são chamados no método Run:
(1) Método de alcance de prova ComputeRootHash (Range Proof’s ComputeRootHash method), que é calcular o rootHash da prova Merkle de acordo com a prova:
O método computeRootHash de pathWithLeaf é o seguinte:
Neste ponto, os valores de pin são os seguintes:
Em seguida, chame o método Hash de proofInnerNode, do seguinte modo:
O método Hash aqui é calcular o Hash do nó intermediário baseado em Esqueda (Left) e Direita (Right) do pin. De acordo com a introdução acima, um dos Esquerda e Direita devem ser nulos e o outro deve ser não nulo. Mas, no código real, quando Esquerda é não nulo, Direita não precisa ser nulo. Ou seja, o valor de Direita, nesse caso, não participa no cálculo do valor do Hash, portanto, não tem efeito no Hash.
O Hash aqui é, na verdade, calculado pelo pin.Left e leaves[0]. A Direita (Right) do pin deveria ser nulo, mas não é. Também por causa disso, o Hash calculado está correto.
A partir da prova completa, podemos construir a árvore IAVL+ correspondente, da seguinte maneira:
LeftPath[1].Right deveria ser nulo, mas é, na verdade, leaves[0]. O invasor o alterou para leaves[1]. Devido à vulnerabilidade de cálculo da função Hash, isso não afeta o cálculo do Hash.
Adicione o rootHash calculado ao campo rootHash da prova e retorne o rootHash.
(2) Método de verificação (Verify) de RangeProof
A função deste método é verificar se o campo rootHash da prova é calculado e definido na etapa anterior. Após a verificação for aprovada, o rootVerified da prova é definido como verdadeiro.
(3) Método VerifyItem de RangeProof
Este método é usado para verificar que a chave e a carga útil (payload) fornecidos no parâmetro estão nas folhas da prova, ou seja, o pacote cross-chain no parâmetro é o nó da folha da MerkleProof e seu ValueHash é o mesmo que o ValueHash do nó da folha correspondente na MerkleProof.
A IAVLValueOp verifica a MerkleProof do módulo, ou seja, a prova Merkle da raiz da árvore IAVL+ de um módulo de função específico (“ibc”) para o nó da folha de destino.
3.2. Verificação MultiStoreOp
De acordo com a ordem das operações (ops) na poz, após a conclusão da verificação IAVLValueOp, a verificação da MultiStoreOp será realizada.
Depois de executar o método Run da IAVLValueOp, seu valor de retorno é rootHash na prova IAVL. Portanto, a carga útil (payload) dos argumentos (args) se torna iavlRootHash neste ponto. A seguir, execute o método Run da MultiStore:
Aqui, as operações (op’s) são as seguintes:
Aqui está o método ComputeRootHash da prova da MultiStoreOp:
A estrutura de computação e o valor de retorno são appHash.
A respeito de si.Core.CommitID.Hash no código, onde si se refere ao módulo “ibc” em Proof.StoreInfos.
Então si.Core.CommitID.Hash é o valor da raiz da árvore IAVL+ do módulo “ibc”, ou seja, o iavlRootHash retornado na verificação IAVLValueOp.
Essa etapa verifica que o appHash implementa a prova de verificação Merkle da raiz da ávore IAVL+ do AppHash para um módulo funcional específico (“ibc”).
3.3. Resumo
As duas partes acima verificam, respectivamente, a prova Merkle da raiz da árvore IAVL+ de um módulo funcional específico para o nó da folha de destino (verificação IAVLValueOp) e a prova Merkle do AppHash para a raiz da árvore IAVL+ de um módulo funcional específico (verificação MultiStoreOp). Por fim, a prova fornecida pelo parâmetro é verificada e 0x01 é retornado, representando “verdadeiro”.
4. Resumo
A causa raiz do incidente de segurança é a vulnerabilidade no algoritmo Hash do nó da folha da árvore IAVL+ no SDK da Cosmos usado ao final da BNBChain. O invasor pode consultar completamente toda a árvore Merkle da blockchain e então usar a vulnerabilidade para adulterá-la e, em seguida, gerar uma RangeProof Merkle que pode aprovar a verificação, de modo a atingir o objetivo de forjar a prova.
A vulnerabilidade do nó da folha Hash não existe em condições específicas. Teoricamente, qualquer árvore IAVL+ pode forjar uma RangeProof Merkle. Ao forjar provas, quanto mais simples a árvore IAVL+, obviamente, mais fácil é forjar provas. Quanto mais folhas tiver na árvore IAVL+, mais complexa é a estrutura e mais difícil é forjar provas.
Neste incidente, o invasor escolheu um bloco com uma altura de 110217401 porque a estrutura da árvore IAVL+ correspondente a esse bloco é mais simples e é mais fácil de forjar provas. Essa é também a razão pela qual o invasor tem múltiplas transações com falha antes de uma transação bem-sucedida.
Sobre nós
Nossa visão é melhorar a segurança globalmente. Acreditamos que, ao construir essa barreira de segurança, podemos melhorar significativamente vidas ao redor do mundo. A SharkTeam é composta por membros com muitos anos de experiência em segurança cibernética e blockchain. Membros da equipe tem suas bases em Suzhou, Pequim (Beijing), Nanjing e Vale do Silício (Silicon Valley), competentes em teorias de blockchain subjacentes e contratos inteligentes, e fornecemos serviços abrangentes incluindo modelagem de ameaças, auditoria de contrato inteligente, resposta à emergência, etc. A SharkTeam estabeleceu cooperações estratégicas e de longo prazo com participantes importantes em muitas áreas do ecossistema blockchain, como Huobi Global, OKX, Polygon, Polkadot, ImToken, ChainIDE, etc.
Esse artigo foi escrito por SharkTeam e traduzido por Isabela Curado Nehme. Seu original pode ser lido aqui.
Latest comments (0)