## 漏洞概述 / Summary 在 libhv 的 HTTP 反向代理实现中,`HttpService::GetProxyUrl()` 通过直接拼接配置的后端 URL 字符串与剥离前缀后的客户端请求路径来构造代理目标 URL: ```cpp url = iter->second + (path + iter->first.length()); ``` 当反向代理后端 URL 配置为不含尾部 `/` 的 authority 形式(如 `service.Proxy("/api/", "http://127.0.0.1:18081")`)时,未认证攻击者可发送以 `@` 开头的子路径请求(例如 `GET /api/@169.254.169.254:80/latest/meta-data/`)。拼接后的 URL 变为 `http://127.0.0.1:18081@169.254.169.254:80/latest/meta-data/`。随后 `HUrl::parse()` 将 `@` 之前的 `127.0.0.1:18081` 解析为 URL 的 `userinfo` 字段,而将攻击者控制的 `169.254.169.254:80` 解析为真正的目标 `host` 与 `port`。 此外,`HttpHandler::connectProxy()` 仅在 `forward_proxy`(正向代理)模式下检查 `service->IsTrustProxy(url.host.c_str())`,对 `reverse_proxy`(反向代理)不做任何目标主机一致性校验,导致反向代理服务器直接向攻击者指定的任意内网或外部 `host:port` 发起 HTTP 请求并返回响应内容。 ## 2. 漏洞成因与源码分析 / Root Cause & Vulnerable Code 源码位置 1:[`[http/server/HttpService.cpp#L195-L204](https://github.com/ithewei/libhv/blob/060a4b6c0cf8ae252741d0a58976376eac02e8c5/http/server/HttpService.cpp#L195-L204)`](https://github.com/ithewei/libhv/blob/060a4b6c0cf8ae252741d0a58976376eac02e8c5/http/server/HttpService.cpp#L195-L204) ```cpp std::string HttpService::GetProxyUrl(const char* path) { std::string url; for (auto iter = proxies.begin(); iter != proxies.end(); ++iter) { if (hv_strstartswith(path, iter->first.c_str())) { // 直接进行字符串拼接,未保证路径分隔符 '/',也未校验拼接后解析出的 host 是否改变 url = iter->second + (path + iter->first.length()); break; } } return url; } ``` 源码位置 2:[`[http/server/HttpHandler.cpp#L1163-L1171](https://github.com/ithewei/libhv/blob/060a4b6c0cf8ae252741d0a58976376eac02e8c5/http/server/HttpHandler.cpp#L1163-L1171)`](https://github.com/ithewei/libhv/blob/060a4b6c0cf8ae252741d0a58976376eac02e8c5/http/server/HttpHandler.cpp#L1163-L1171) ```cpp int HttpHandler::connectProxy(const std::string& raw_url) { HUrl url; if (!url.parse(raw_url)) { return SendHttpStatusResponse(HTTP_STATUS_BAD_REQUEST); } if (forward_proxy && !service->IsTrustProxy(url.host.c_str())) { // 反向代理跳过主机校验 hlogw("[%s:%d] Forbidden to proxy %s", ip, port, url.host.c_str()); return SendHttpStatusResponse(HTTP_STATUS_FORBIDDEN); } ``` ## 影响范围与危害评估 / Impact **确认影响**:未认证远程攻击者可将 libhv 反向代理作为跳板,向云环境元数据服务、内网未授权 HTTP 管理服务或任意内部端口发起全回显 SSRF 请求。 ## 修复建议 / Remediation 1. 在 `HttpService::Proxy()` 注册或 `GetProxyUrl()` 拼接时,若配置的目标 URL 路径为空且不以 `/` 结尾,自动补齐 `/`;并确保拼接的子路径始终以 `/` 开头。 2. 在 `HttpService::GetProxyUrl()` 或 `HttpHandler::connectProxy()` 中解析拼接前后的 `HUrl`,强制校验最终请求的 `url.host` 与 `url.port` 必须与反向代理配置的目标 `host` 和 `port` 完全一致。
Activity