Voltar aos artigos
Intermediate

Segurança de Canais IBC: Como Canais Desordenados Habilitam Ataques de Replay Entre Cadeias no Cosmos

O protocolo Inter-Blockchain Communication (IBC) é uma das peças de engenharia mais sofisticadas no espaço blockchain.

@0xrafasecFebruary 18, 2026decentralized_systems_security

Available in English

Share:

Segurança de Canais IBC: Como Canais Desordenados Habilitam Ataques de Replay Entre Cadeias no Cosmos

Legal & Ethical Disclaimer

This content is provided for EDUCATIONAL and AUTHORIZED SECURITY TESTING purposes only.

DO
  • Use these techniques on systems you own or have explicit written permission to test
  • Practice in authorized lab environments (VulnHub, HackTheBox, DVWA, etc.)
  • Follow responsible disclosure practices when finding vulnerabilities
  • Use knowledge for defensive security and authorized penetration testing
DO NOT
  • Access systems without explicit authorization
  • Use these techniques for malicious purposes
  • Deploy exploits against production systems you don't own
  • Share working exploits for unpatched vulnerabilities

Legal warning

Unauthorized access to computer systems is illegal in most jurisdictions (e.g. CFAA in the US, Computer Misuse Act in the UK). Violators may face criminal prosecution and civil liability. The author and publisher assume no liability for misuse of this information. By continuing, you agree to use this knowledge ethically and legally.

Hook & Contexto

O protocolo Inter-Blockchain Communication (IBC) é uma das peças de engenharia mais sofisticadas no espaço blockchain. Ele permite que cadeias soberanas troquem dados arbitrários com garantias criptográficas — um problema genuinamente difícil. Mas a solidez criptográfica na camada de transporte não se traduz automaticamente em segurança na camada de aplicação, e nenhum lugar essa tensão é mais visível do que na distinção entre canais ordenados e desordenados.

A maioria das aplicações IBC usa canais desordenados por padrão porque são operacionalmente tolerantes — pacotes podem chegar fora de ordem, retransmissores podem tentar novamente sem coordenação rígida, e a UX se sente mais suave. Essa conveniência operacional vem com um trade-off estrutural: canais desordenados não impõem números de sequência global no nível do canal. Em certos designs de aplicação, particularmente aqueles que rastreiam estado por pacote sem incorporar singularidade suficiente nos dados do pacote em si, isso cria uma janela para replay. Um pacote finalizado — aquele cuja confirmação já foi processada — pode às vezes ser reenviado por um retransmissor malicioso ou contraparte para desencadear uma segunda execução da lógica de negócio da cadeia receptora.

Este artigo disseca esse risco a partir dos primeiros princípios. Construiremos o modelo mental da hierarquia de confiança do IBC, mostraremos exatamente onde a lacuna de aplicação de sequência vive em canais desordenados, percorreremos um cenário de replay de prova de conceito envolvendo drenagem de fundos, e então mapearemos as mitigações que desenvolvedores de aplicações IBC seguras devem estar implementando hoje.


TL;DR

ConceitoPonto-Chave
Canais ordenadosImpõem sequência estrita de pacotes; replay é estruturalmente impossível
Canais desordenadosSem aplicação de sequência global; camada de aplicação deve se defender
Superfície de ataque de replayRetransmissor malicioso ou comprometido reenvia um pacote já confirmado
Causa raizLigação de nonce/sequência faltante nos dados do pacote da aplicação
Mitigação primáriaRastreamento de recebimento em nível de aplicação + poda de compromisso de pacote
Nível de riscoAlto quando combinado com lógica de transferência de fundos ou mutação de estado

Fundamentos & Teoria

O Modelo de Confiança do IBC

IBC não é uma ponte no sentido tradicional — é um protocolo para comunicação verificada entre cadeias. Sua segurança é derivada da verificação de cliente leve: a cadeia A mantém um cliente leve da cadeia B, e vice-versa. Cada pacote transmitido inclui um compromisso criptográfico que a cadeia receptora pode verificar contra um cabeçalho de bloco conhecido e confiável. Nenhuma terceira parte confiável é necessária; a confiança flui do consenso de cada cadeia participante.

A abstração de canal fica em cima dessa camada de transporte. Um canal é um pipe nomeado, versionado, ordenado ou desordenado entre dois módulos ligados a porta em duas cadeias. A propriedade de ordenação é definida na criação do canal durante o handshake de quatro etapas (ChanOpenInitChanOpenTryChanOpenAckChanOpenConfirm) e não pode ser alterada após a criação.

O que "Ordenado" Realmente Impõe

Em um canal ordenado, o módulo central do IBC rastreia um nextSequenceSend no lado do envio e um nextSequenceRecv no lado da recepção. Os pacotes devem ser entregues em sequência ascendente estrita. Se o pacote 5 chegar antes do pacote 4, o módulo IBC o rejeitará. Isso é imposto no nível do protocolo — não no nível da aplicação — e torna o replay trivialmente impossível: um pacote com sequência N pode apenas ser recebido uma vez, porque o contador de sequência esperado do receptor avança imediatamente para N+1.

O que "Desordenado" Realmente Garante (e Não Garante)

Canais desordenados substituem o contador de sequência global por um armazenamento de recebimento por pacote. Quando um pacote é recebido com sucesso, o módulo IBC escreve um recebimento em packetReceipt/{channelId}/{sequence}. Tentativas subsequentes de entrega para o mesmo pacote são rejeitadas se o recebimento existe.

Aqui está a nuance crítica: armazenamentos de recebimento de pacote são podados após o processamento da confirmação. Uma vez que a cadeia de envio escreve o compromisso de confirmação e o retransmissor a entrega de volta, o compromisso de pacote original no lado de envio é deletado. Dependendo do caminho de implementação e se a aplicação manipula adequadamente o recebimento, uma janela pode se abrir onde:

  1. O recebimento foi deletado ou nunca escrito (devido a um bug ou caminho não padrão).
  2. O compromisso de pacote foi apagado no lado de envio.
  3. O estado da aplicação da cadeia receptora foi mutado uma vez já.

Uma resubmissão nessa janela passaria pela verificação de recebimento do módulo IBC e re-entraria no manipulador OnRecvPacket da aplicação.


Onde Se Encaixa no Fluxo de Trabalho

Loading diagram…

Conceitos-Chave em Profundidade

1. Ciclo de Vida de Pacote e Onde os Recebimentos Vivem

Entender o ciclo de vida exato é essencial para identificar a superfície de ataque.

Loading diagram…

O recebimento na Cadeia B é o portão. Se for escrito corretamente e nunca podado antes que a confirmação seja totalmente processada, o replay é bloqueado no nível do módulo IBC. A vulnerabilidade emerge em casos extremos:

  • Módulos de aplicação que implementam lógica de recebimento customizada e esquecem de deixar o módulo IBC escrever o recebimento primeiro.
  • Cadeias executando versões não padrão do IBC onde a lógica de poda é agressiva.
  • Ambientes de teste usando o framework de teste Go IBC onde RecvPacket é chamado sem passar pelo caminho completo de commit/prova, o que pode silenciosamente pular escritas de recebimento.

2. O Cenário de Ataque de Replay: Passo a Passo

Considere uma aplicação de transferência de token entre cadeias simplificada executando sobre um canal desordenado onde o desenvolvedor da aplicação cometeu um erro sutil: eles armazenam quantidades recebidas apenas com chave (sender, denom) em vez de (sender, denom, sequence).

Configuração:

  • Cadeia A envia pacote com sequência 42: "transferir 1000 ATOM para endereço X na Cadeia B"
  • Retransmissor entrega o pacote. Cadeia B credita 1000 ATOM ao endereço X. Recebimento para seq 42 é escrito.
  • Retransmissor entrega a confirmação para Cadeia A. Cadeia A deleta seu compromisso.

Ataque: Um retransmissor malicioso agora constrói um MsgRecvPacket contendo os dados de pacote originais para sequência 42, pareado com uma prova Merkle válida de um bloco histórico na Cadeia A onde o compromisso ainda existia. Se o recebimento da Cadeia B para sequência 42 foi deletado (devido à poda agressiva ou um bug), o módulo IBC não encontrará um recebimento existente e chamará OnRecvPacket novamente. Cadeia B credita outros 1000 ATOM ao endereço X. O atacante efetivamente dobrou seus fundos.

Loading diagram…

3. Por Que o Framework de Teste Go IBC Pode Mascarar Isso

O pacote ibctesting em cosmos/ibc-go fornece helpers de caminho rápido como path.RelayPacket() que pulam o consenso real de Tendermint e geração de prova. Em um ambiente de teste, isso significa:

go
// Isso NÃO simula o caminho completo de escrita de recebimento
suite.coordinator.RelayAndAckPendingPackets(path)

Desenvolvedores que apenas testam com o framework podem nunca descobrir que seu manipulador OnRecvPacket é não idempotente, porque a infraestrutura de teste silenciosamente manipula deduplicação que a rede real não garante sob todas as condições. Sempre complemente testes de framework com testes de integração usando nós gaiad reais e hermes.

4. Construindo o PoC com hermes e gaiad

O fluxo de trabalho do PoC não requer explorar um bug de protocolo — é sobre explorar lacunas de lógica de aplicação através de caminhos de protocolo legítimos.

bash
# Inicie duas cadeias locais com ignite CLI
ignite chain serve --config chain_a.yml &
ignite chain serve --config chain_b.yml &

# Configure hermes para conectar ambas as cadeias
hermes config validate

# Crie um canal DESORDENADO entre as duas cadeias
hermes create channel \
  --a-chain chain-a \
  --b-chain chain-b \
  --a-port transfer \
  --b-port transfer \
  --channel-version ics20-1 \
  --order UNORDERED

# Envie um pacote e capture o hash de tx + altura de bloco
gaiad tx ibc-transfer transfer \
  channel-0 cosmos1<recipient> 1000uatom \
  --from attacker --chain-id chain-a

# Registre a altura de bloco H onde o compromisso existe
# Tente retransmissão com hermes (caminho normal)
hermes start

# Após confirmação, construa manualmente MsgRecvPacket
# com prova ancorada no bloco H (pré-confirmação)
# Envie via gaiad tx broadcast

O passo-chave é capturar o CommitmentProof na altura de bloco H antes do compromisso ser deletado. Esta é uma query de prova Merkle padrão:

bash
gaiad query ibc channel packet-commitment transfer channel-0 42 \
  --height <H> \
  --prove true \
  --chain-id chain-a

Se a camada de aplicação da cadeia receptora não verifica independentemente que este pacote já foi processado, a resubmissão tem sucesso.

5. Defesas de Nível de Aplicação

O mecanismo de recebimento do módulo IBC é a primeira linha de defesa, mas desenvolvedores de aplicação devem adicionar uma segunda linha:

a) Incorpore números de sequência nos dados do pacote. Cada pacote processado por OnRecvPacket deve incluir a sequência do canal na carga útil de nível de aplicação. O manipulador deve verificar se isso corresponde e registrá-lo em um mapa de sequência processada.

b) Implemente rastreamento de recebimento de nível de aplicação. Mantenha uma loja com chave (portId, channelId, sequence) → bool. Escreva nela no início de OnRecvPacket, antes de qualquer mutação de estado. Reverta se a chave já existir.

go
func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketData) error {
    // Guarda de idempotência de nível de aplicação
    if k.HasPacketProcessed(ctx, packet.DestinationPort, packet.DestinationChannel, packet.Sequence) {
        return sdkerrors.Wrap(types.ErrDuplicatePacket, "packet already processed")
    }
    k.SetPacketProcessed(ctx, packet.DestinationPort, packet.DestinationChannel, packet.Sequence)

    // ... resto da lógica de negócio
}

c) Use canais ordenados quando a ordem de entrega importa para semântica de aplicação. Se sua aplicação não pode tolerar replays e requer sequenciamento rigoroso, o custo de canais ordenados (bloqueio em pacotes faltantes) vale a garantia estrutural.


Alternativas & Comparação

AbordagemProteção de ReplayThroughputComplexidadeMelhor Para
Canais ordenados✅ Imposto por protocoloMais Baixo (bloqueio de head-of-line)Baixa (protocolo manipula)Transferências de alto valor, protocolos com estado
Desordenado + recebimentos de app✅ Imposto por aplicaçãoAltoMédioMensageria geral, transferências fungíveis
Desordenado + nonce em carga útil⚠️ Parcial (requer verificação correta)AltoMédio-AltoProtocolos customizados com dados de pacote único
Desordenado, sem defesa❌ Sem proteçãoAltoBaixa (inseguro)⚠️ Nunca em produção
Interceptação de middleware✅ Defesa em profundidadeDepende do middlewareAltoStacks requerendo garantias entre aspectos

Canais ordenados são a solução estruturalmente mais simples, mas impõem restrições de liveness — se um pacote é perdido, nenhum pacote subsequente pode ser entregue até que seja resolvido. Para aplicações de alto throughput como livros de ordem de DEX ou feeds de oráculo, isso é inaceitável.

Canais desordenados com recebimentos de nível de aplicação são o padrão de produção para transferências de token fungível do ICS-20. A implementação de referência em ibc-go faz isso corretamente; o risco emerge em módulos de aplicação customizados que implementam seu próprio OnRecvPacket sem auditar idempotência.

Middleware IBC (introduzido em ibc-go v3+) permite que lógica de proteção de replay seja fatorada em uma camada reutilizável que envolve módulos de aplicação, o que é arquiteturalmente elegante para projetistas de protocolo construindo em cima de IBC.


Conclusões & Leitura Adicional

Leitura Adicional & Referências

Achou este artigo interessante? Siga-me no X e no LinkedIn.