2.HTTP頭注入


重新認識被人遺忘的HTTP頭注入

前言

注入類漏洞經久不衰,多年保持在owasp Top 10的首位。今天就聊聊那些被人遺忘的http頭注入。用簡單的實際代碼進行演示,讓每個人更深刻的去認識該漏洞。

HOST注入

在以往http1.0中並沒有host字段,但是在http1.1中增加了host字段,並且http協議在本質也是要建立tcp連接,而建立連接的同時必須知道對方的ip和端口,然后才能發送數據。既然已經建立了連接,那host字段到底起着什么樣的的作用?

 Host頭域指定請求資源的Intenet主機和端口號,必須表示請求url的原始服務器或網關的是比如www.test.commail.test.com兩個域名IP相同,由同一台服務器支持,服務器可以根據host域,分別提供不同的服務,在客戶端看來是兩個完全不同的站點。

Host頭實驗總結:在http 1.1中不能缺失host字段,如果缺失, 服務器返回400 bad request,http1.1中不能缺失host字段,但host字段可以是空值。

0×01 密碼重置的中毒

 相信大家忘記密碼時,使用郵箱找回密碼並不陌生。看上去貌似能可靠只能發送到你綁的郵箱去重置密碼。並且使用你自己獨特的密鑰令牌才能重置成功。但是好多cms和實際場景為了獲取網站的域名拼接秘鑰令牌的方式將連接發送到你的郵箱。但是往往獲取正確的域名並不是十分的不容易, 然而用一個固定的URI來作為域名會有各種麻煩。所以一般程序員會采用(java)request.getHeader(“Host”); (php)$_SERVER['HTTP_HOST']的方式來獲取域名。

上面所述的兩種獲取域名的方法並不可靠。都可以人為的去控制。導致當域名和令牌拼接時,攻擊者通過篡改hsot值生成釣魚連接,當受害者點擊時,受害者的秘鑰令牌將會直接發送到攻擊者的服務器上。使其受害者的密碼被攻擊者篡改。

文字看上去比較繞的話,我在本地用代碼將此處的業務場景進行了復現。

public class FindPass extends HttpServlet{
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)  {

    //此處真實場景的話,是根據輸入的賬號去查對應的郵箱。就不繁瑣的構造了。 

        String email =request.getParameter("email");

   //此處獲取了host頭中的host字段,此值可以被攻擊者篡改

        String Host =request.getHeader("Host");
        int max=200000000;
        int min=100000000;
        Random random = new Random();

      //生成隨機的秘鑰令牌

        int randomNubmer = random.nextInt(max-min) + min;
        String content= "用戶您好:<br>現在給您發送郵件的XX銀行系統,您的賬戶"+email+"申請找回密碼!<br>" +
                "只需在提交請求后的三天之內,通過點擊下面的鏈接重置您的密碼:<br>"+
                "http://"+Host+"?id="+randomNubmer;

      //此處用Host拼接了秘鑰名牌
  
        try {

      //調用發信接口

            SendEmail.send(email, content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(email+Host);
    }

 

 }

提交找回密碼表單,篡改其中的host頭值。

image.png

當用戶收到密碼重置郵件后,發現是釣魚者的網址,且秘鑰令牌也已參數id的形式傳給給攻擊者,此時攻擊者可以直接使用受害者的令牌進行密碼重置。

image.png

0×02 XSS

有些網站會根據HTTP_HOST字段來進行加載css樣式表。如果要為固定的話,當域名發生改變時,那么站內所有的css即將失效。而且修改的時候也將的十分頭疼,因為每個頁面都會引用大量的公共資源。如下是我重構的場景重現:

<?php
echo<<<EOT
測試host攻擊<br>
cccccccc
<head>
<link rel="stylesheet" type="text/css" href="http://{$_SERVER['HTTP_HOST']}?id=111111" />
</head>
EOT;
echo $_SERVER["HTTP_HOST"];
?>

 

 

image.png

image.png

image.png

image.png

0×03 web緩存中毒

簡單描述:

Web緩存服務器的應用模式主要是正向代理反向代理。正向代理(Proxy)模式是代理網絡用戶訪問internet,客戶端將本來要直接發送到internet上源服務器的連接請求發送給代理服務器處理。正向代理的目的是加速用戶在使用瀏覽器訪問Internet時的請求響應時間,並提高廣域網線路的利用率。正向代理瀏覽器無需和該站點建立聯系,只訪問到Web緩存即可。通過正向代理,大大提高了后續用戶的訪問速度,使他們無需再穿越Internet,只要從本地Web緩存就可以獲取所需要的信息,避免了帶寬問題,同時可以大量減少重復請求在網絡上的傳輸,從而降低網絡流量,節省資費。

思路:

 Apache接收到一個帶有非法host header的請求,它會將此請求轉發給在 httpd.conf 里定義的第一個虛擬主機。因此,Apache很有可能將帶有任意host header的請求轉發給應用。

場景:

一般的緩存服務器都會識別hsot,所以一般直接替換host字段會被攔截。。Varnish辨別第一個host Apache識別所有請求的host, Nginx則只是看最后一個請求。此時就可以通以下方式

GET / HTTP/1.1 Host: test.com Host: exp.com 

來繞過緩存服務器的檢查。

0x04WordPressPHPMailer結合導致命令執行

 

 

漏洞描述:

 獨立研究人員Dawid Golunski發現該漏洞—遠程攻擊者利用該漏洞,可實現遠程任意代碼在web服務器上執行,並使web應用陷入威脅中。攻擊者主要在常見的web表單如意見反悔表單、注冊表單中 ,郵件密碼重置表單等使用發送的組建時利用此漏洞。

POC展示:

主要是利用host注入惡意命令導致遠任意代碼執行
Host : target(any -froot@localhost -be ${run{${substr{0}{1}{$spool_directory}}usr${substr{0}{1}{$spool_directory}}bin${substr{0}{1}{$spool_directory}}touch${substr{10}{1}{$tod_log}}${substr{0}{1}{$spool_directory}}tmp${substr{0}{1}{$spool_directory}}manning.test}} null)

 

下面針對這個做個簡要分析,網上很多文章已經對此作了詳細分析,我在此就不做詳細分析了。

if ( !isset( $from_email ) ) {

//此處會獲取SERVER_NAME字段拼接到$from_email變量上且SERVER_NAME可被攻擊者控制

        $sitename = strtolower( $_SERVER['SERVER_NAME'] );
        if ( substr( $sitename, 0, 4 ) == 'www.' ) {
            $sitename = substr( $sitename, 4 );
        }

        $from_email = 'wordpress@' . $sitename;
    }

private function mailPassthru($to, $subject, $body, $header, $params)
    {
        //Check overloading of mail function to avoid double-encoding
        if (ini_get('mbstring.func_overload') & 1) {
            $subject = $this->secureHeader($subject);
        } else {
            $subject = $this->encodeHeader($this->secureHeader($subject));
        }
        if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
            $result = @mail($to, $subject, $body, $header);
        } else {

//最終$params參數被@mail調用后會觸發CVE-2016-10033 phpmailer命令執行漏洞執行遠程命令。

            $result = @mail($to, $subject, $body, $header, $params);
        }
        return $result;
    }

 

 

X-Forwarded-For注入:

大家有沒有見過這樣一種場景,當你對用戶網站進行的爆破或者sql注入的時候,為了防止你影響服務器的正常工作,會限制你訪問,當你再次訪問時,會提示你的由於你的訪問頻過快或者您的請求有攻擊行為,限制訪問幾個小時內不能登陸,並且重定向到一個錯誤友好提示頁面。

由此可以發起聯想?http是無狀態連接,而且自己也清空了COOKIE信息,服務器是怎么還是自己的?

首先當你有攻擊行為的時候,服務器一般會把惡意用戶的ip存入數據庫。當每次用戶請求的時候(以java語言為例),服務器通過request.getRemoteAddr()這個方法來獲取請求者的ip。於是想到這個ip我們自己到底能不能偽造?答案是否定的。因為經過測試request.getRemoteAddr並不會回從數據包的請求頭去獲取ip字段的Value。所以推測ip地址是ip包中的soure來的,當我們發送http請求時是否可以更新soure ip來繞過限制呢,這個可以有!,但是你將不會收到對方的響應,因為在正常的TCP/IP通信中,偽造數據包來源 IP會讓發送出去的數據包返回到偽造的IP上,無法實現正常的通信。這樣我們也就失去的繞過的意義。

request.getRemoteAddr方法我們沒辦法偽造,是不是我們就無法利用這個點了呢?

結合實際一般程序員是不會通過request.getRemoteAddr方法來獲取ip的,這個方法雖然獲取的ip比較准確,暫無辦法繞過。但實際場景中往往服務器前面會有一個代理服務器和均衡負載服務器。當使用request.getRemoteAddr方法時,獲取的只是代理服務器的ip並不能獲取請求者的真實ip。這時候一些程序員為了實現獲取真實ip會采取如下方法。

public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (ip != null) {
            if (ip.indexOf(',') > 0) {
                ip = ip.split(",")[0];
            }
        } else {
            ip = "0.0.0.0";
        }
        return ip;
    }

 

 

image.png

image.png

X-Forwarded-For通過這個字段我們可以控制繞過ip的限制,但是當我們去繞過ip限制的時候ip會帶入數據庫去查詢,這點我們是不是可以嘗試一下sql注入。

將數據包寫入文件,通過 sqlmap.py  -r  “filePath”

 

 

image.png

通過sqlmap拋出的信息,可以看到存在sql注入的點是X-Forwarded-For字段,並且爆出了mysql的版本信息和腳本語言的信息。

User-Agent注入

 

 

User-Agent、Content-Type等只要是http包中存在的都可以進行篡改。在這再說下User-Agent的頭注入和Content-Type的頭注入,其他的就不詳細贅述。基本原理大同小異。最后會進行總結。

一般使用user-Agent,有兩種場景一是記錄訪問者的信息,如什么瀏覽器、操作系統版本等。二是獲取客戶的user-Agent,根據你提供的信息來給你推送不同的網頁。如果你手機手機訪問那么返回你的頁面將是小型的web界面,還有各種瀏覽器的特性,推送相兼容的頁面。此時已經進行的數據庫的入庫和查詢操作,如果沒對此做過濾那么漏洞就產生了。

Content-Type注入又一個遠程命令執行

Content-Type看見這個字段相信大家都不陌生,瞬間就會想起一個很可怕的漏洞。S2-045的遠程命令執行。當Jkarta解析文件上傳請求包不當,當攻擊者使用惡意的Content-Type,會導致上傳發生異常。從而導致Str2框架對Content-Type的內容進行ongl的解析導致命令執行。這個漏洞雖然要涉及Jkarta插件,而arta插件ommons-fileupload和commons-io包,但是這是Str2的默認插件。也就是說基本所有開發使用到上傳都會導入這兩個依賴包。最重要的是這個漏洞不需要真正的上傳只需進行模擬上傳即可,甚至可以是GET請求。具體的詳細代碼就不跟大家分析了,要不估計還比我這篇文章還長。有興趣的可以到我的博客或者網上搜索那些大佬的分析。

總結

歸根結底,http頭攻擊漏洞的產生就是因為服務器使用了不受信任的http頭字段對某個業務進行的操作。而http頭都是我們可以惡意篡改的。具體產生什么漏洞,就看你把這個不受信任的字段,拿去做什么樣的業務操作。在平常滲透的時候,可以思考程序員們會拿着這些參數去干什么,從而更有方向的去滲透。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM