具体漏洞httpoxy详情可以先参考在https://httpoxy.org/
CGI是外部应用程序(CGI程序)与Web服务器之间的接口标准,是在CGI程序和Web服务器之间传递信息的过程。CGI规范允许Web服务器执行外部程序,并将它们的输出发送给Web浏览器,CGI将Web的一组简单的静态超媒体文档变成一个完整的新的交互式媒体。
⑴ 通过Internet把用户请求送到服务器
⑵ 服务器接收用户请求并交给CGI程序处理
⑶ CGI程序把处理结果传送给服务器
⑷ 服务器把结果送回到用户
Web 服务器和CGI交互,CGI 是独立的程序,为了方便web服务器和CGI的交互,web服务器获得http参数后fork子进程,部分参数通过设置环境变量于CGI交互。
RFC 3875 规范里定义了一些交互的环境变量的名称,而针对HTTP传递的头,通常web服务器设置成HTTP_HeaderName环境变量进行交互
在这个漏洞中,将PROXY 设置成了CGI的环境变量HTTP_PROXY
CGI代码本身如果是获取HTTP_PROXY环境变量用于获取资源的代理,或者运行的第三方的组件也使用这个环境变量作为代理,这样黑客可以通过设置http 请求中的PROXY, 控制CGI 里的环境变量HTTP_PROXY
在3中已经提到了服务器和CGI的交互方式,主要以起子进程交互的方式,对java来说可以使用Runtime.getRuntime().exec()的方式,通过perl 来执行.cgi
在执行cgi的时候也可以添加额外的参数,可以作为perl执行的参数命令
常见的可以通过请求的url的参数进行传递
http://www.test.com/cgi?parameter |
而针对后面parameter,可以直接通过命令拼接的方式进行运行
perl test.cgi parameter
java 示例 Runtime.getRuntime().exec(“perl test.cgi parameter”); |
在3中提到的环境变量于CGI交互,比如在http请求中的头,默认以HTTP_ heade大写=value的格式设置环境变量
例子:以前面的PROXY为例
PROXY:www.test.com
Java 示例
Runtime.getRuntime().exec(“perl test.cgi parameter”, new String[]{“HTTP_PROXY=www.test.com”}); |
通常GET请求可以通过querystring 或者header来传递值和cgi交互,但是如果是post呢?
对post 的参数为了避免覆盖header, 所以不使用HTTP_前缀的方式设置环境变量,而是通过流的方式传递
获取子进程的输入流 Process proc= Runtime.getRuntime().exec(“perl test.cgi parameter”, new String[]{“HTTP_PROXY=www.test.com”}); OutputStream stdin = proc.getOutputStream(); 获取web的post的流 InputStream stdout =request.getInputStream();
将stdout.read的内容复制到strout中 byte[] buf = new byte[4*1024]; int numRead; while ( (numRead = stdout.read(buf) ) >= 0) { stdin.write(buf, 0, numRead); }
|
这样cgi获取的是urlencoder的parameterName = parameterValue¶meterName = parameterValue 的内容
InputStream cgiOutput = proc.getInputStream(); OutputStream out = response.getOutputStream(); byte[] buf = new byte[4*1024]; int numRead; while ( (numRead = cgiOutput.read(buf) ) >= 0) { out.write(buf, 0, numRead); }
|
如果CGI里返回的标准http协议的话,可以直接用流对拷输出
考虑到HTTP_PROXY 环境变量很多组件里已经使用的默认的环境变量参数,主要防御方式以过滤http头proxy,因为proxy并不是一个标准的http 头
写个 filter 过滤器
public class PoxyFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request; HttpServletResponse res = (HttpServletResponse)response; String poxy = req.getHeader("proxy"); if (poxy == null) { chain.doFilter(request, response); } else { ………… } } } |