安全性: 为低严重程度的 DoS 报告请求私有通道
Security Report — Unbounded HTTP response-body read in gobuster (memory-exhaustion DoS)
| -- | -- Project | gobuster (GitHub.com/OJ/gobuster) Version reviewed | v3.8.2 Commit | c77583fbb8824058d74d38240896eff610683c8e (2026-01-13) Component | libgobuster/http.go → HTTPClient.Request() Class | CWE-400 Uncontrolled Resource Consumption / CWE-770 Allocation of Resources Without Limits Impact | Denial of service (memory exhaustion) of the gobuster process Attacker | The scan target (a malicious or compromised host the operator points gobuster at) Proposed severity | Low (client-side CLI, operator-chosen target — see "Impact & honest severity")vhost is the realistic attack surface: the operator points gobuster at a URL they are testing, and the server operating at that URL fully controls the response. In vhost mode the impact is amplified in two ways:
- During
PreRun, the default-vhost body and a random-vhost body are each read in full and retained for the entire scan asv.normalBody/v.abnormalBody(gobustervhost.go:108,124). - Every word then issues another
ReturnBody: truerequest (:173), and gobuster runs many worker threads concurrently, so peak allocation scales with the thread count.
s3/gcs additionally pass the unbounded body straight into xml.Unmarshal /
json.Unmarshal (GCS into a map[string]interface{}), which roughly doubles the
transient footprint and adds a parser-side amplification vector.
Root cause
The response body is untrusted input controlled by the scan target, but it is read
without any upper bound. http.Client.Timeout limits how long the read may run, but
within that window a fast server can deliver an amount of data limited only by
throughput — which then all lands in a single []byte.
Proof of concept
The following faithfully reproduces the exact vulnerable pattern (io.ReadAll on a
target-controlled body under a gobuster-style 10 s client timeout) and contrasts it
with the proposed fix. It does not require building gobuster itself.
// malicious server streams an oversized body; victim mirrors libgobuster/http.go
func vulnerableRead(body io.Reader) (int, float64) {
b, _ := io.ReadAll(body) // current gobuster behaviour
return len(b), heapMiB()
}
func fixedRead(body io.Reader, max int64) (int, float64) {
b, _ := io.ReadAll(io.LimitReader(body, max)) // proposed fix
return len(b), heapMiB()
}
Measured results (Go 1.22, loopback, single request, 10 s client timeout):
Simulated malicious target streams: 500 MiB
baseline heap: 0.1 MiB
[VULNERABLE io.ReadAll] buffered 500 MiB
…内容来源: OJ/gobuster