poc yaml go pprof leak漏洞复现
Poc yaml 和 go pprof 组合起来能挖出什么?漏洞一个内存泄漏的洞,而且复现过程比想象的复现更拧巴。别急着看结论,漏洞先跟着走一遍。复现 目标是漏洞一个用 Go 写的内部 API 服务,开了 pprof 的复现 HTTP 端口,但没做鉴权。漏洞这本身不算新鲜,复现真正的漏洞问题在于,某个接口的复现响应体没被正确关闭。你猜怎么着?漏洞pprof 的 heap profile 能把这个泄漏直接钉死在屏幕上。 我写了个 poc yaml,复现逻辑不复杂:先请求一次目标接口,漏洞记录内存基线,复现再连续打 200 次同样的漏洞请求,最后拉一次 pprof heap 输出。关键点在于,yaml 里不能用简单的 复现环境是 Docker 里跑的一个瘦身容器,内存限制 512M。第一次跑,我盯着终端等结果,结果 200 次请求后,heap profile 显示 打开 profile 文件,用 这不是什么高深漏洞,纯粹是 resource leak 的经典案例。可为什么值得写?因为 poc yaml 的写法有讲究。如果你用常见的 我试过三种变体。第一种是直接忽略响应体,只读 header,泄漏最明显。第二种是读完 body 但没关闭,泄漏速度慢一半。第三种是正确关闭,但服务端主动断开连接,这种反而触发不了漏洞——因为 Go 的 transport 层会主动清理死连接。 复现完,我给开发提了个建议:别只盯着 pprof 的 CPU 和 goroutine,heap 的 最后说个细节,这个漏洞在压测工具 wrk 和 ab 下根本测不出来,因为它们每个请求都新建连接。只有用 keep-alive 的持续连接才能触发。所以别迷信常规压测结果,特定场景下的泄漏得靠特定姿势去捅。requests 循环,得用 generate 脚本块,因为你需要动态比对两次 profile 的差值。inuse_space 从 80M 跳到了 310M。增长曲线不是线性的,是阶梯状的——每 50 次请求后内存会突然拔高一段,然后平缓,再拔高。这说明泄漏点不是每次请求都触发,而是跟内部某个缓存失效策略有关。go tool pprof 分析,定位到 net/http.(*persistConn).readLoop 和 writeLoop 的 goroutine 数量异常。普通情况下这两个 goroutine 应该在请求结束后退出,但这里堆积了 47 个没回收的。原因找到了——服务端在响应头里设置了 Connection: keep-alive,但客户端(也就是 poc 脚本)没有正确读取 body 到 EOF,导致连接永远处于半开状态。http.Get 模式,Go 的默认 client 会自动复用连接,反而掩盖了问题。必须手动设置 DisableKeepAlives: true 或者限制 body 读取长度,才能让泄漏暴露出来。alloc_objects 计数更能反映这类问题。另外,poc yaml 里最好加一个 threshold 断言,比如内存增长超过 200% 就判定为 vulnerable,不然人工看 profile 输出太费劲。
-
上一篇
-
下一篇