• httpoxy 漏洞预警及修复方案


    影响范围

    PHP、Go、Python等开启CGI(Client)模式的脚本语言

    Language环境依赖HTTP Client
    PHP php-fpmmod_php Guzzle 4+Artax
    Python wsgiref.handlers.CGIHandlertwisted.web.twcgi.CGIScript requests
    Go net/http/cgi net/http

    漏洞原理

    在CGI(RFC 3875)的模式的时候,server 会把请求中的 Header, 加上 HTTP_ 前缀, 注册为环境变量,且重名变量会被覆盖污染,若该变量被脚本调用,即可利用,该漏洞在15年前在LWP中已被发现并修复http://www.nntp.perl.org/group/perl.libwww/2001/03/msg2249.html。

    如控制 HTTPHOST 进行 URL 跳转,或者直接控制 HTTP_PROXY 让流量到代理服务器中转,将 HTTP 控制进入环境变量进行shellshock攻击等,所以,所有 HTTP_ 开头的环境变量在CGI模式下都是不可信不安全的。

    利用过程如图所示:

    可通过

    ngrep -q -i -d any -W byline 'proxy' 'dst port 80'

    捕获扫描

    <?php
    $http_proxy = getenv("HTTP_PROXY");
    if ($http_proxy) {
        $context = array(
            'http' => array(
                'proxy' => $http_proxy,
                'request_fulluri' => true,
            ),
    
        );
        $s_context = stream_context_create($context);
    } else {
        $s_context = NULL;
    }
    $ret = file_get_contents("http://www.chaitin.cn/", false, $s_context);

    PoC

    curl "http://target" -H "Proxy: test env"

    利用条件

    • 后端信任接收的 Header
    • 污染控制的变量被脚本调用
    • 开启CGI(Client)模式
    • 服务器能对外通信

    修复方案

    最为有效的方式就是在脚本调用变量之前及时阻断或者限制内部调用时的可信变量

    Nginx

    在配置中加入

    fastcgi_param HTTP_PROXY "";

    Apache

    根据官方建议patchhttps://www.apache.org/security/asf-httpoxy-response.txt

    IIS

    运行 appcmd set config /section:requestfiltering /+requestlimits.headerLimits.[header='proxy',sizelimit='0'] 来阻止恶意代理被调用

    如果要清理header,可以使用如下规则

    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Erase HTTP_PROXY" patternSyntax="Wildcard">
                    <match url="*.*" />
                    <serverVariables>
                        <set name="HTTP_PROXY" value="" />
                    </serverVariables>
                    <action type="None" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>

    参考来源

    https://httpoxy.org/

    https://www.symfony.fi/entry/httpoxy-vulnerability-hits-php-installations-using-fastcgi-and-php-fpm-and-hhvm

    附其他语言测试用例

    bash

    #!/bin/bash
    
    export http_proxy=$HTTP_PROXY
    `curl http://www.chaitin.cn`

    python

    #!/usr/bin/python
    
    import requests
    import os
    import sys
    from wsgiref.handlers import CGIHandler
    
    if sys.version_info < (3,):
        def b(x):
            return x
    else:
        import codecs
    
        def b(x):
            return codecs.latin_1_encode(x)[0]
    
    def application(environ, start_response):
        status = '200 OK'
    
        r = requests.get("http://www.chaitin.cn/")
    
        output = """
        Made internal subrequest to http://www.chaitin.cn/ and got:
          os.environ[HTTP_PROXY]: %(proxy)s
          os.getenv('HTTP_PROXY'): %(getenv-proxy)s
          wsgi Proxy header: %(wsgi-env-proxy)s
          status code: %(status)d
          text: %(text)s
        """ % {
            'proxy': os.environ['HTTP_PROXY'] if 'HTTP_PROXY' in os.environ else 'none',
            'getenv-proxy': os.getenv('HTTP_PROXY', 'none'),
            'wsgi-env-proxy': environ['HTTP_PROXY'] if 'HTTP_PROXY' in environ else 'none',
            'status': r.status_code,
            'text': r.text
        }
    
        response_headers = [('Content-type', 'text/plain'),
                            ('Content-Length', str(len(b(output))))]
    
        start_response(status, response_headers)
    
        return [b(output)]
    
    if __name__ == '__main__':
        CGIHandler().run(application)

    Go

    package main
    
    import (
        "fmt"
        "io"
        "log"
        "net/http"
        "net/http/cgi"
    )
    
    func main() {
        if err := cgi.Serve(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            header := w.Header()
            header.Set("Content-Type", "text/plain; charset=utf-8")
    
            response, err := http.Get("http://www.chaitin.cn/")
    
            if err != nil {
                log.Fatal(err)
            } else {
                defer response.Body.Close()
    
                fmt.Fprint(w, "Response body from internal subrequest:")
                _, err := io.Copy(w, response.Body)
                fmt.Fprintln(w, "")
    
                if err != nil {
                    log.Fatal(err)
                }
            }
    
            fmt.Fprintln(w, "Method:", r.Method)
            fmt.Fprintln(w, "URL:", r.URL.String())
    
            query := r.URL.Query()
            for k := range query {
                fmt.Fprintln(w, "Query", k+":", query.Get(k))
            }
    
            r.ParseForm()
            form := r.Form
            for k := range form {
                fmt.Fprintln(w, "Form", k+":", form.Get(k))
            }
            post := r.PostForm
            for k := range post {
                fmt.Fprintln(w, "PostForm", k+":", post.Get(k))
            }
    
            fmt.Fprintln(w, "RemoteAddr:", r.RemoteAddr)
    
            if referer := r.Referer(); len(referer) > 0 {
                fmt.Fprintln(w, "Referer:", referer)
            }
    
            if ua := r.UserAgent(); len(ua) > 0 {
                fmt.Fprintln(w, "UserAgent:", ua)
            }
    
            for _, cookie := range r.Cookies() {
                fmt.Fprintln(w, "Cookie", cookie.Name+":", cookie.Value, cookie.Path, cookie.Domain, cookie.RawExpires)
            }
        })); err != nil {
            fmt.Println(err)
        }
    }


    http://www.tuicool.com/articles/Brmm6zm
  • 相关阅读:
    Linux 配置gitee
    Linux C errno出错处理
    Linux C进程时间:墙上时钟时间,用户CPU时间,系统CPU时钟时间
    编译错误: 对‘aio_read’未定义的引用
    Linux 异步IO(AIO)
    Linux getaddrinfo获得本机ip地址为何127.0.1.1?
    Linux 文件截断的几种方式
    如何创建守护进程?
    守护进程, 协同进程, 僵尸进程, 孤儿进程概念理解
    对线程安全, 可重入函数, 异步安全的理解
  • 原文地址:https://www.cnblogs.com/chunguang/p/5687885.html
Copyright © 2020-2023  润新知