Um erro de poucos bytes: análise do ataque à Liquid Network

Um erro de poucos bytes: análise do ataque à Liquid Network

Uma vulnerabilidade no código da Liquid Network permitiu criar cerca de 3,998.5 L-BTC explorando uma falha no mecanismo de cache das verificações criptográficas.

9 de set. de 2026

Em 6 de setembro de 2026, a rede Liquid Network sofreu um ataque que explorou uma vulnerabilidade na base de código do Elements, usada para verificar transações confidenciais.

O problema surgiu da formação ambígua da chave de cache na verificação do rangeproof, a prova criptográfica que confirma que o valor oculto de uma transação é admissível. Por causa disso, dois conjuntos diferentes de dados de verificação podiam gerar a mesma entrada no cache.

Primeiro o atacante preparou transações especiais e preencheu o cache com elas e, em seguida, enviou uma transação maliciosa que aumentava o volume de ativos emitidos: ela reutilizou um resultado de verificação já armazenado e permitiu criar L-BTC não autorizados.

Depois disso, o atacante trocou esses ativos dentro da rede Liquid por bitcoins reais por meio do mecanismo de retirada de recursos para a rede principal do Bitcoin.

Contexto

Os bitcoins bloqueados em uma carteira Bitcoin específica, controlada pela federação Liquid, dão lastro aos L-BTC emitidos na Liquid. De acordo com o sistema de ancoragem previsto, um L-BTC deve corresponder a um BTC sob o controle da federação.

Em vez de publicar o valor, a transação pode conter um compromisso criptográfico de Pedersen. O próprio ativo também pode ser representado por um compromisso semelhante. Uma equação matemática específica confirma que os valores de entrada e de saída da transação estão equilibrados, enquanto o chamado rangeproof demonstra que cada valor oculto está dentro da faixa não negativa permitida.

Em particular, a verificação do rangeproof faz parte do mecanismo que deve garantir que o valor oculto é realmente correto e não pode ser usado para criar ativos acima da quantidade permitida. Ao mesmo tempo, a verificação efetiva da correção depende de vários elementos simultaneamente: o rangeproof, o compromisso pelo valor, o compromisso pelo ativo e o scriptPubKey.

O script é passado para secp256k1_rangeproof_verify como dados adicionais incluídos na verificação criptográfica. Uma prova válida para uma combinação (C, X, S) não se torna automaticamente válida para outra combinação.

Transações-chave

Data/horaTXIDDescrição
2026-09-06 13:52:10271147100a94f6337b6c3db39b30c92d5b97ed91597307b6f721f73a15187ec5Transação preparatória
2026-09-06 13:53:10f24a4b179b5cc7e88b25a763911f7cbdf2bf45d1d1b5ab611e94461cef0a183fA transação que criou volume adicional de L-BTC dentro da Liquid
2026-09-06 13:54:103875a6d6ed4af708e6fd90d1c5504dc014e52c7093a566987252006d6cf1146bA transação cria novas saídas confidenciais da Liquid controladas pelo atacante ou pela carteira seguinte
2026-09-06 14:00:10c6ea588ac26f5838b6acbb2a444a33b325bbfeb39bf16dfe27b47215ffd72267A transação cria novas saídas confidenciais da Liquid controladas pelo atacante ou pela carteira seguinte
2026-09-06 14:01:1046f117c990580501a5156937a8c8affda551a38b3c0b99d29eb8469ee6beb3d2Retirada da Liquid no valor de 2.65138358 L-BTC
2026-09-06 14:06:10ce4caece413cd9d444ce7ed9f54e5b328b3da5e4af301aff59a3571f76e988f2Retirada da Liquid no valor de 3,996.01834922 L-BTC
2026-09-06 14:28:5685d2ca15bea33a592e73ed40c6a5da887feecf1e77f58ec7f580e008416450433,996.01834922 BTC enviados para o endereço bc1ql4mfu6aundtkksxklfajs2h3t9nzcd6gyqjlte
2026-09-07 18:09:25a6d697a25266ce3c78774fd1d75f896b7af522ada209b0f6228ea497bc49a46d3,400 BTC devolvidos ao endereço bc1qdlld6antmv4xug242ed83q7k4rqw50cwfns38szx4qu2f4jwaxxsuhwxxr

Endereços-chave

EndereçoUso
ex1q7kgx4ptje7px48tn0nsmc6se5pngdp3smpqa2wEndereço do atacante na rede Liquid
bc1qgslsydz56d0ed6827hdemfmk5w2f6ldyc6wt7pDestinatário do pagamento da federação de 3,996.01834922 BTC
bc1ql4mfu6aundtkksxklfajs2h3t9nzcd6gyqjlteDestinatário do pagamento da federação de 2.65138358 BTC
bc1ql4mfu6aundtkksxklfajs2h3t9nzcd6gyqjlteEndereço do atacante para consolidar recursos e transmitir mensagens na blockchain
bc1qdlld6antmv4xug242ed83q7k4rqw50cwfns38szx4qu2f4jwaxxsuhwxxrCarteira Bitcoin da federação Liquid usada para a ancoragem e a retirada de recursos

1. Falsificação do cache de provas

Para a análise, foram obtidos e decompostos os dados brutos de serialização do Elements, e não apenas os campos exibidos por um explorador de blockchain. As saídas :0 das duas transações preparatórias coincidem por completo em ativo, compromisso pelo valor, nonce, script, surjection proof e rangeproof.

Usando deslocamentos que começam em zero e um limite superior que não é incluído na faixa, a partir dos 8,882 bytes da transação bruta foi decodificado o output_0 da transação 271147100a94f6337b6c3db39b30c92d5b97ed91597307b6f721f73a15187ec5, o que resultou nos seguintes dados:

a. C0 = 09d6c6150e95e576d288dcc890bf48518119c6f227ea1be6f9a932792dbee683f5

b. S0 = 6a|43|086f5d67160fc4b477954fb09ef321e5b589d7a07740a1a6df494ed2335b1d01d8|0a0a488 de4899d0ae757f6cf8368663184d164106111ed9eaecf510e35282ddc6d|6a.

i. 6a significa OP_RETURN. ii. 43 indica que em seguida devem ser colocados 67 bytes.

Esses 67 bytes têm deliberadamente a seguinte estrutura: um C1 de 33 bytes, um X de 33 bytes e um 6a de um byte. Assim, o script S0 = 6a43 || C1 || X || 6a, em que X = 0a0a488de4899d0ae757f6cf8368663184d164106111ed9eaecf510e35282ddc6d é o resultado da execução de secp256k1_generator_generate(L-BTC asset ID).

2. Preenchimento do cache no mempool ativo

Na conexão de um bloco valem regras de cache segundo as quais uma entrada existente é consumida, mas, se não houver entrada, uma nova não é armazenada. Por isso, a conexão do bloco 4,050,335 deveria ter removido a entrada de cache criada no momento em que as duas transações preparatórias visíveis foram aceitas pela primeira vez.

Consequentemente, para que a transação que criava L-BTC adicionais pudesse passar pela verificação após a conexão do bloco 4,050,335 e antes da verificação da saída incorreta, cada nó que aceitava a transação precisava de uma nova transação válida com a mesma sequência (P0, C0, X, S0).

O identificador dessa transação de preenchimento e seus bytes originais ainda não são conhecidos. Para encontrá-los podem ser necessários o arquivo debug.log de um dos functionaries, o mempool.dat vigente naquele momento, um registro da troca de dados entre nós ou uma cópia salva do estado do mempool.

3. Criação de L-BTC adicionais dentro da Liquid

A decodificação do output_1 da transação de inflação f24a4b179b5cc7e88b25a763911f7cbdf2bf45d1d1b5ab611e94461cef0a183f resultou nos seguintes dados:

a. C1 = 086f5d67160fc4b477954fb09ef321e5b589d7a07740a1a6df494ed2335b1d01d8.

São exatamente os primeiros 33 bytes dos dados transmitidos pelo script OP_RETURN da saída preparatória.

Vale notar que o rangeproof P1 é 68 bytes mais longo que o P0, e esses dados adicionais estão no final: 09d6c6150e95e576d288dcc890bf48518119c6f227ea1be6f9a932792dbee683f5

b. 0a0a488de4899d0ae757f6cf8368663184d164106111ed9eaecf510e35282ddc6d6a43, o que dá o C0 da transação preparatória: 09d6c6150e95e576d288dcc890bf48518119c6f227ea1be6f9a932792dbee683f5

e X = 0a0a488de4899d0ae757f6cf8368663184d164106111ed9eaecf510e35282ddc6d é o resultado da execução de secp256k1_generator_generate(L-BTC asset ID). A incorporação do gerador exato de L-BTC permitiu que os bytes do script da transação preparatória se alinhassem com o campo do gerador do ativo na transação atacante.

c. No conjunto

Transação preparatória válida: P0 || C0 || X || (6a43 || C1 || X || 6a)

Transação atacante inválida: (P0 || C0 || X || 6a43) || C1 || X || 6a

Ambas acabam se reduzindo ao mesmo fluxo de 4,301 bytes: P0 || C0 || X || 6a43 || C1 || X || 6a

4. Retirada dos recursos

Os L-BTC podem ser trocados de volta por BTC reais sob o controle da federação Liquid. A transação seguinte, 3875a6d6…f1146b, usou a saída f24…:0 da transação ligada ao ataque. Outras duas transações criaram saídas explícitas para retirar recursos para a rede principal do Bitcoin:

  • 46f117c9…eb3d2: 2.65138358 L-BTC
  • ce4caece…988f2: 3,996.01834922 L-BTC

A transação de Bitcoin 8db751a6…7b140, confirmada no bloco 965,783, pagou os dois valores exatos retirados em consequência do ataque.

Em que consistia a essência da vulnerabilidade?

O Elements mantém em cache os rangeproof verificados com sucesso para não executar duas vezes a mesma operação criptográfica custosa. Aqui importam duas construções.

Esse desenho não levava em conta o gerador do ativo nem o script, embora ambos os parâmetros influenciem a validade da prova. O commit c26d719 tentou vincular a entrada de cache a todo o contexto da verificação.

O patch com a implementação do cache

Transação preparatória válida: (P0, C0, X, 6a43 || C1 || X || 6a)

Transação atacante inválida: (P0 || C0 || X || 6a43, C1, X, 6a)

As saídas observadas da transação preparatória e da atacante não criam colisão quando é usada a chave mais antiga P || C. Seus dados de entrada para a chave antiga diferem tanto em comprimento quanto em conteúdo.

A construção do ataque, em contrapartida, corresponde exatamente à chave de quatro campos sem separadores introduzida por essa correção. Por isso, o fato de a transação ter passado com sucesso indica uma implementação semelhante à c26d719 combinada com um cache previamente preenchido. Ao mesmo tempo, as versões exatas dos binários implantados nos diferentes nós functionaries da Liquid não foram divulgadas publicamente.

Problema de sincronização: como o protocolo Verus perdeu $7.5M por causa das diferenças entre blockchains

A movimentação dos recursos

Endereço: bc1ql4mfu6aundtkksxklfajs2h3t9nzcd6gyqjlte.

#Ataque hacker
A Liquid Network foi hackeada por causa de um cache: o que aconteceu com 4,000 BTC?