
1. 項目概述為什么我們需要深入理解Tamper腳本如果你用過SQLMap大概率遇到過這種情況對著一個看起來有注入點的URL跑了大半天結果要么是“所有參數似乎都不注入”要么是payload發出去就石沉大海連個錯誤回顯都沒有。新手這時候可能就放棄了但老手會心一笑默默加上--tamper參數。Tamper腳本就是SQLMap這套自動化“大殺器”里的“特種兵”專門負責在payload送上前線之前對其進行偽裝、變形、編碼以繞過各種WAFWeb應用防火墻、IDS入侵檢測系統甚至是應用層自己寫的蹩腳過濾邏輯。很多人把Tamper腳本當成一個黑盒魔法只知道“這個站用space2comment能過”卻不知道背后的原理。這就像你只會按配方做菜卻不懂火候和調味一旦遇到新奇的防御手段立馬抓瞎。這篇指南的目的就是帶你從“會用”到“懂原理”再到能根據實際情況“自己改”甚至“自己寫”。我們將從最基礎的繞過場景開始拆解經典Tamper腳本的每一行代碼理解其設計思路最后探討如何組合使用乃至定制開發高級繞過腳本。無論你是安全測試人員、滲透測試學習者還是對Web安全防御機制感興趣的研究者掌握Tamper腳本的實戰精髓都能讓你對SQL注入攻防的理解提升一個維度。2. Tamper腳本核心原理與工作機制拆解2.1 SQLMap的Payload生成與處理流水線要理解Tamper首先得明白SQLMap是如何工作的。它不是簡單地把一堆預定義的payload扔出去。其內部有一個完整的引擎工作流程大致如下邏輯判斷與指紋識別SQLMap首先會發送一些無害的探測請求判斷參數是否動態、數據庫類型通過報錯信息、特有函數等并嘗試識別WAF。Payload庫選取根據數據庫類型MySQL, PostgreSQL, SQL Server, Oracle等和注入類型布爾盲注、時間盲注、報錯注入、聯合查詢等從龐大的內置payload庫中選取基礎模板。Payload渲染將模板中的占位符如[INFERENCE],[SLEEP],[COLUMN]替換為具體的邏輯如比較子句、延時函數、列名。Tamper處理這是關鍵一步。渲染后的原始payload會依次通過用戶指定的Tamper腳本如--tamper “space2comment,randomcase”。每個腳本都是一個Python函數接收原始payload返回修改后的payload。多個腳本按順序執行前一個的輸出是后一個的輸入。請求發送與結果分析處理后的payload被嵌入到HTTP請求中發送SQLMap再根據響應內容如頁面差異、時間延遲、報錯信息來判斷注入是否成功并提取數據。所以Tamper腳本的本質是一個Payload變形過濾器。它不關心注入邏輯只負責對payload的“外觀”進行手術使其能夠逃逸防御系統的檢測規則。2.2 常見過濾與繞過思路分類WAF和過濾邏輯千變萬化但核心思路無非幾種對應的Tamper腳本也圍繞這些思路展開關鍵字過濾直接攔截union,select,from,where,or,and等SQL關鍵字。繞過思路大小寫變形UnIoN、內聯注釋分割uni/**/on、編碼URL編碼、HTML實體、十六進制、等價替換||替代or、注釋混淆union/*random*/select。特殊字符過濾過濾空格、單引號、雙引號、等號、注釋符--、#等。繞過思路空格用/**/多行注釋、、%0a換行、%0d回車、%09制表符甚至多個空格替代。單引號用\轉義、%bf%27寬字節、chr(39)字符函數、0x27十六進制替代。等號用like、between...and...、0 and 2等邏輯替代。語義分析高級WAF會嘗試解析SQL語句結構攔截拼接后形成威脅的語句而不僅僅是匹配關鍵字。繞過思路通過注釋、換行、無效括號等方式破壞WAF的語法解析例如union(select(1),2)或union/*!50000select*/ 1,2。MySQL特有的內聯注釋/*!...*/在這里是神器因為MySQL會執行其中的內容而許多WAF會忽略或錯誤解析。簽名/正則匹配基于已知攻擊payload的特征庫進行匹配。繞過思路隨機化。在關鍵字中隨機插入注釋、改變大小寫、添加無關參數如version()變成version/*foo*/()使每次請求的payload簽名都不同繞過靜態規則庫。實操心得不要一上來就堆砌Tamper腳本。先用手工測試判斷過濾類型。例如在參數后分別添加、and 11、and 12、union select 1,2,3觀察響應差異。如果被攔截但and 11和and 12返回相同頁面說明可能只過濾了引號但沒過濾and和。這個初步判斷能極大縮小Tamper腳本的選擇范圍。3. 基礎Tamper腳本深度解析與實戰應用這一部分我們挑選幾個最常用、最具代表性的基礎腳本逐行分析其代碼理解其適用場景和局限性。3.1 space2comment.py空格的經典替身這是使用頻率最高的Tamper腳本之一。它的邏輯非常簡單將payload中的空格字符 替換為多行注釋/**/。#!/usr/bin/env python # 簡化后的核心邏輯 def tamper(payload, **kwargs): retVal payload if payload: retVal re.sub(r\s, /**/, payload) # 正則匹配所有空白字符包括空格、制表符、換行等 return retVal作用繞過對空格的過濾。許多簡單的WAF或代碼層過濾會直接str_replace( , )或正則匹配\sunion\s。實戰場景當你的union select被攔截但union/**/select能正常返回時就應該使用它。注意事項它替換所有空白字符。有時payload里可能有必要的換行符\n也會被替換這可能破壞某些特定上下文極少見。對于更嚴格的過濾/**/本身也可能被列入黑名單。此時需要嘗試其他替代品如space2plus.py用替換或space2hash.py用#加換行。3.2 randomcase.py隨機大小寫的迷惑術這個腳本通過隨機化關鍵字的大小寫來繞過基于大小寫敏感匹配的過濾規則。#!/usr/bin/env python import random def tamper(payload, **kwargs): def process(match): word match.group(word) return .join(random.choice((c.upper, c.lower))() for c in word) # 對每個字符隨機選擇大寫或小寫 retVal payload if payload: retVal re.sub(r(?i)\b[A-Z_]\b, process, retVal) # (?i)忽略大小寫匹配單詞邊界內的純字母/下劃線串 return retVal作用將SELECT可能變為SeLeCt、sELecT等使SELECT這個靜態簽名失效。實戰場景適用于那些采用簡單正則如/select/i進行過濾但沒有進行規范化統一轉小寫再比較的防御系統。注意事項它只影響“單詞”即被\b邊界包圍的字母串。所以version()中的version會被變形但括號不會。過度隨機化可能導致payload長度顯著增加雖然不明顯且每次請求的payload都不同這在某些需要穩定payload的盲注場景下可能不是最優選擇。重要如果目標系統如Oracle對SQL關鍵字大小寫敏感通常不但自定義解析器可能使用此腳本會導致語法錯誤。3.3 charencode.py 與 charunicodeencode.py編碼的藝術這兩個腳本都涉及編碼轉換但目的不同。charencode.py對payload中未編碼的字符進行一次URL編碼%xx格式。union select 1,2-%75%6e%69%6f%6e%20%73%65%6c%65%63%74%20%31%2c%32適用場景某些WAF只解碼一次URL或者對原始參數進行關鍵字檢查但對解碼后的內容檢查不嚴。通過手動編碼可以讓關鍵字“隱形”。注意它使用urllib.quote并設置safe%意味著%和不會被二次編碼避免破壞已編碼部分或參數分隔符。charunicodeencode.py將字符轉換為Unicode編碼形式%u0075%u006e...或\u0075\u006e...。union-%u0075%u006e%u0069%u006f%u006e適用場景主要針對一些ASP/ASP.NET環境它們可能支持這種Unicode表示法而WAF規則庫可能遺漏對此格式的檢查。在現代Web應用中效果有限。避坑指南使用編碼類Tamper時務必使用-v 3或更高參數運行SQLMap觀察最終發出的payload。你需要確認編碼后的payload在目標服務器的上下文中能被正確解碼。例如如果參數放在JSON body里URL編碼可能無效如果放在application/x-www-form-urlencoded的POST數據中URL編碼是標準操作通常有效。3.4 between.py 與 equaltolike.py操作符的“馬甲”這兩個腳本針對的是對比較操作符,,的過濾。between.py用BETWEEN ... AND ...語法替換和。id 1-id NOT BETWEEN 0 AND 1(邏輯等價id 1)id 1-id BETWEEN 1 AND 1原理BETWEEN是范圍查詢在語義上可以等價于比較操作但字符串形式完全不同能繞過簡單的操作符過濾。限制生成的SQL語句更復雜可能在某些非常簡化的SQL解析場景如某些ORM框架拼接的查詢中引發問題。equaltolike.py將等號替換為LIKE。id1-id LIKE 1原理在絕大多數數據庫中當比較數值或簡單字符串時和LIKE在沒有通配符的情況下功能是等價的。但LIKE這個關鍵字很少出現在注入攻擊的規則集中。注意如果比較的是字符串LIKE是大小寫不敏感的取決于數據庫配置而可能是大小寫敏感的這可能導致邏輯差異。但在注入探測中我們通常只關心“真”和“假”的頁面差異這種細微差別通常不影響布爾盲注。基礎腳本組合策略面對未知過濾一個安全的起步組合是--tamper “space2comment,randomcase”。先用space2comment解決空格問題再用randomcase擾亂關鍵字簽名。如果不行再考慮加入編碼類charencode或操作符替換類between腳本。記住--tamper參數的腳本順序就是處理順序。4. 高級繞過技巧腳本組合、定制與WAF對抗實戰當你用遍了內置腳本還是繞不過時就需要更高級的策略了。這包括理解WAF的工作原理、巧妙組合現有腳本以及最終手段——自己編寫Tamper腳本。4.1 針對特定WAF的腳本解析SQLMap內置了一些針對歷史版本或特定品牌WAF的腳本理解它們有助于舉一反三。modsecurityversioned.py / modsecurityzeroversioned.py這兩個是針對ModSecurity一個開源的WAF模塊的。核心技巧是利用MySQL內聯注釋。# modsecurityversioned.py 核心代碼片段 def tamper(payload, **kwargs): retVal payload if payload: postfix for comment in (#, --, /*): if comment in payload: postfix payload[payload.find(comment):] # 保留原注釋 payload payload[:payload.find(comment)] # 去掉原注釋 break # 在關鍵字前添加 /*!50000*/ retVal re.sub(r(?i)\b(union|select|insert|update|delete|drop|from|where)\b, r/*!50000\1*/, payload) retVal postfix return retVal/*!50000*/是MySQL的特性表示如果數據庫版本大于等于5.00.00就執行注釋內的代碼。對于WAF它可能被視為普通注釋而忽略但MySQL會正常解析其中的union、select等關鍵字。modsecurityzeroversioned.py使用/*!00000*/原理類似。實戰意義這教會我們利用數據庫特性尤其是MySQL的內聯注釋是繞過WAF語義分析的利器。bluecoat.py這個腳本做了兩件事1) 在SQL語句后添加隨機空白符2) 將替換為LIKE。它模擬了某些特定代理或WAF如BlueCoat SGOS的繞過模式。其價值在于展示了尾部填充的思路添加無關內容可以干擾某些基于固定長度或位置簽名的檢測。4.2 腳本組合的進階策略與順序考量Tamper腳本的順序至關重要因為前一個腳本的輸出是后一個腳本的輸入。錯誤示例--tamper “charencode,space2comment”你先對整個payload進行了URL編碼空格變成了%20。然后space2comment腳本尋找的是空格字符 找不到%20所以替換無效。最終payload里依然是%20而不是/**/。正確順序--tamper “space2comment,charencode”先把空格變成/**/然后再對整個字符串進行URL編碼/**/被編碼為%2f%2a%2a%2f。這樣既繞過了空格過濾又通過了可能的關鍵字檢查。一個針對較強過濾的通用組合思路結構破壞randomcomments.py- 在關鍵字之間插入隨機注釋破壞union select這樣的連續簽名。關鍵字變形randomcase.py或versionedkeywords.py- 改變關鍵字本身的形式。空格處理space2comment.py或space2plus.py- 處理剩余的空格。最終編碼charencode.py- 對整個payload進行一次“化妝”。你可以這樣使用--tamper “randomcomments,randomcase,space2comment,charencode”。使用-v 3觀察最終payload看是否符合預期。4.3 手把手編寫自定義Tamper腳本當內置腳本全部失效或者遇到非常獨特的過濾規則時自己寫Tamper腳本是終極解決方案。一個Tamper腳本就是一個Python文件放在SQLMap的tamper/目錄下即可被識別。編寫步驟與模板創建文件在tamper目錄下新建一個.py文件例如my_bypass.py。編寫函數文件必須包含一個名為tamper的函數。實現邏輯在函數內對payload字符串進行操作。添加依賴如果需要可以導入re正則、random等庫。下面是一個實戰案例假設目標網站過濾了select關鍵字但不過濾selselectect即采用簡單的str_replace(‘select’, ‘’)過濾我們可以用雙寫繞過。#!/usr/bin/env python Copyright (c) 2006-2024 sqlmap developers (http://sqlmap.org/) See the file LICENSE for copying permission import re from lib.core.enums import PRIORITY __priority__ PRIORITY.NORMAL # 定義腳本優先級NORMAL即可 def dependencies(): pass # 這里可以聲明依賴關系通常為空 def tamper(payload, **kwargs): 雙寫繞過簡單字符串替換過濾 例如select - selselectect替換后變成 select retVal payload if payload: # 定義要雙寫的關鍵字列表 keywords [select, union, from, where, or, and, insert, update, delete, drop, table] for keyword in keywords: # 使用正則忽略大小寫進行替換 # 注意替換模式是 ‘s’ - ‘selsect’‘e’-‘seleect’... 我們采用簡單方法在關鍵字中間插入自身 # 更健壯的做法將 ‘select’ 替換為 ‘sel’ ‘select’ ‘ect’ if keyword.lower() in payload.lower(): # 粗略檢查是否存在 # 構造雙寫后的字符串將 ‘select’ 變成 ‘sel’ ‘select’ ‘ect’ doubled keyword[:len(keyword)//2] keyword keyword[len(keyword)//2:] # 使用正則進行不區分大小寫的替換 retVal re.sub(r(?i)\b re.escape(keyword) r\b, doubled, retVal) return retVal代碼解析__priority__腳本執行的優先級。當多個腳本對同一部分進行修改時優先級高的后執行覆蓋前面的。一般保持NORMAL。dependencies()用于聲明此腳本運行所需的其他腳本通常不需要。tamper(payload, **kwargs)核心函數。payload是SQLMap傳來的原始payload字符串。我們返回修改后的字符串。邏輯遍歷預定義的關鍵字列表檢查payload中是否存在忽略大小寫。如果存在則將其替換為“雙寫”版本。例如select被替換為selselectect。當目標系統執行str_replace(‘select’, ‘’, $input)后中間的select被移除兩邊的sel和ect又拼接成了select從而繞過過濾。測試你的腳本將腳本放入tamper/目錄。使用SQLMap的-t參數指定一個臨時文件來觀察payload變化sqlmap -u “http://test.com?id1” –tamper “my_bypass” -v 3 –flush-session。查看輸出中[PAYLOAD]部分確認變形是否符合預期。在安全的測試環境如DVWA、SQLi-Labs中配置相應的過濾規則進行實戰測試。高級技巧利用kwargstamper函數接收**kwargs其中包含一些有用的上下文信息例如kwargs.get(‘headers’, {})可以獲取HTTP頭。你可以編寫根據Content-Type或User-Agent動態調整變形策略的智能腳本。例如當Content-Type為application/json時可能需要對payload進行JSON字符串轉義。5. 實戰問題排查與Tamper腳本調試技巧即使掌握了所有腳本實戰中依然會碰壁。本章節匯總了常見問題及其排查思路。5.1 常見失敗場景分析與解決思路問題現象可能原因排查步驟與解決方案使用Tamper后SQLMap報告“所有參數似乎都不注入”1. Tamper腳本破壞了payload語法。2. 變形后的payload觸發了更嚴格的WAF規則。3. 目標參數本身不存在注入點。1.使用-v 3或-v 4這是最重要的步驟。仔細觀察[PAYLOAD]和[HTTP請求]部分看最終發出的SQL語句是什么。它是否還是一條合法的SQL2.簡化Tamper先只用一個最基本的腳本如space2comment測試逐步增加。3.手動驗證將-v 3看到的payload手工復制到Burp Suite Repeater中發送觀察服務器響應。確認是WAF攔截返回403等還是SQL語法錯誤返回500或數據庫報錯。4.檢查腳本順序確保編碼類腳本在最后。注入能檢測到但無法提取數據如--dbs失敗1. 某些關鍵函數或語句被過濾如select,from,information_schema。2. Tamper腳本在數據提取階段未生效或生效方式不對。1.分階段測試分別測試布爾盲注(--techniqueB)、時間盲注(--techniqueT)、報錯注入(--techniqueE)。可能某種技術能繞過。2.使用--prefix和--suffix手動指定注入點前后綴有時可以繞過對特定上下文語法的過濾。3.檢查WAF識別使用--identify-waf更準確地識別WAF然后查找針對該WAF的特定Tamper或技巧。4.嘗試--level和--risk提高檢測等級(--level 3)和風險等級(--risk 3)SQLMap會使用更多、更“冒險”的payload和Tamper組合。同一個Tamper腳本有時成功有時失敗1. WAF可能有動態規則或學習模式。2. 腳本中使用了隨機化如randomcase導致某些變形恰好被規則命中。3. 服務器有速率限制或IP臨時封鎖。1.降低請求頻率使用--delay 1每秒1請求和--timeout 30。2.使用代理池通過--proxy或--proxy-file輪換IP。3.禁用隨機化如果懷疑是randomcase導致換用確定性的變形腳本如versionedkeywords。4.觀察WAF日志模式如果可能在測試環境分析WAF日志看它到底攔截了哪些特征。自定義腳本不生效1. 腳本未放在正確的tamper/目錄。2. 腳本語法錯誤。3. 函數名不是tamper或優先級__priority__設置有問題。4. SQLMap緩存了之前的測試結果。1.檢查路徑確保腳本在SQLMap根目錄的tamper/文件夾內。2.Python語法檢查在命令行運行python -m py_compile your_script.py檢查錯誤。3.使用--flush-session清除緩存強制SQLMap重新開始測試。4.在腳本開頭加print語句調試臨時在tamper函數第一行添加print(“My script is called with:”, payload)運行SQLMap時觀察控制臺輸出。5.2 高效調試與信息收集方法論必用參數-v 3這是調試Tamper的“眼睛”。它顯示每一個測試payload的變形前和變形后狀態。結合Burp Suite將SQLMap的代理設置為Burp (--proxyhttp://127.0.0.1:8080)。在Burp中觀察所有請求和響應。重點關注被WAF攔截返回403、419等狀態碼或有特定攔截頁面的請求。對比攔截請求和成功請求的payload差異能精準定位觸發規則的“壞字符”或“壞模式”。使用--test-filter如果你懷疑某個特定的payload類型如的比較被過濾可以用--test-filter只測試包含該字符的payload快速驗證。利用--string或--not-string在盲注中指定一個在真/假條件下會穩定出現在頁面中的字符串可以幫助SQLMap更準確地判斷減少因WAF干擾導致的誤判。離線分析模式使用-l參數從Burp Suite保存的日志文件中讀取目標可以避免頻繁觸發WAF的IP封鎖同時仔細分析每個請求。5.3 超越Tamper當腳本也無力時Tamper腳本主要處理payload本身。如果WAF的防御層次更高可能需要結合其他技巧HTTP參數污染HPP?id1id2不同的服務器端語言會以不同方式解析可能繞過參數檢查。SQLMap的-prefix和-suffix可以模擬。畸形HTTP請求修改Content-Type、使用GET傳遞POST數據、分塊傳輸編碼等。這需要修改SQLMap的lib/request/相關代碼或使用其他工具配合。資源限制繞過如果WAF有請求大小限制可以嘗試使用非常長的參數值或者將payload拆分到多個參數如Cookie、Header中。時序攻擊對于時間盲注精心設計SLEEP函數使其延遲時間不規則避開基于固定延時閾值的檢測。最終SQL注入與WAF的對抗是道高一尺魔高一丈的持續過程。Tamper腳本是自動化工具中的重要一環但真正的突破往往來自于對目標系統、數據庫特性、WAF規則乃至HTTP協議的深刻理解。保持學習手動測試分析流量你才能從腳本的使用者成長為繞過規則的創造者。