前言
不管用什么語言編寫的Web應用,它們都用一個共同點,具有交互性並且多數是數據庫驅動。在網絡中,數據庫驅動的Web應用隨處可見,由此而存在的SQL注入是影響企業運營且最具破壞性的漏洞之一,這里我想問,我們真的了解SQL注入嗎?看完本篇文章希望能讓你更加深刻的認識SQL注入。
目錄
第一節 注入攻擊原理及自己編寫注入點
- 1.1、什么是SQL?
- 1.2、什么是SQL注入?
- 1.3、SQL注入是怎么樣產生的?
- 1.4、編寫注入點
第二節 尋找及確認SQL注入
- 2.1、推理測試法
- 2.2、and大法和or大法
- 2.3、加法和減法
正文
- 第一節 注入攻擊原理及自己編寫注入點
1.1、什么是SQL?
SQL 是一門 ANSI 的標准計算機語言,用來訪問和操作數據庫系統。SQL 語句用於取回和更新數據庫中的數據。SQL 可與數據庫程序協同工作,比如 MS Access、DB2、Informix、MS SQL Server、Oracle、Sybase 以及其他數據庫系統。
1.2、什么是SQL注入?
看起來很復雜,其實很簡單就能解釋,SQL注入就是一種通過操作輸入來修改后台SQL語句達到代碼執行進行攻擊目的的技術。
1.3、SQL注入是怎么樣產生的?
構造動態字符串是一種編程技術,它允許開發人員在運行過程中動態構造SQL語句。開發人員可以使用動態SQL來創建通用、靈活的應用。動態SQL語句是在執行過程中構造的,它根據不同的條件產生不同的SQL語句。當開發人員在運行過程中需要根據不同的查詢標准來決定提取什么字段(如SELECT語句),或者根據不同的條件來選擇不同的查詢表時,動態構造SQL語句會非常有用。
在PHP中動態構造SQL語句字符串:
$query = "SELECT * FROM users WHERE username = ".$_GET["ichunqiu"];
看上面代碼我們可以控制輸入參數ichunqiu,修改所要執行SQL語句,達到攻擊的目的。
1.4、編寫注入點
為了照顧一下新人,這里先介紹一下涉及到的基礎知識:
SQL SELECT 語法
SELECT 列名稱 FROM 表名稱
符號 * 取代列的名稱是選取所有列
WHERE 子句
如需有條件地從表中選取數據,可將 WHERE 子句添加到 SELECT 語句。
語法
SELECT 列名稱 FROM 表名稱 WHERE 列 運算符 值
下面的運算符可在 WHERE 子句中使用:

了解了以上基礎知識就讓我們來自己編寫注入點把。
第一步:我們使用if語句來先判斷一下變量是否初始化
<?php if(isset($_GET["ichunqiu"])){ } ?>
第二步:在if語句里面,我們連接數據庫。在PHP中,這個任務通過 mysql_connect() 函數完成。
mysql_connect(servername,username,password); servername 可選。規定要連接的服務器。默認是 "localhost:3306"。 username 可選。規定登錄所使用的用戶名。默認值是擁有服務器進程的用戶的名稱。 password 可選。規定登錄所用的密碼。默認是 ""。
第三步:連接成功后,我們需要選擇一個數據庫。
mysql_select_db(database,connection) database 必需。規定要選擇的數據庫。 connection 可選。規定 MySQL 連接。如果未指定,則使用上一個連接。
第四步:選擇完數據庫,我們需要執行一條 MySQL 查詢。
mysql_query(query,connection) query 必需。規定要發送的 SQL 查詢。注釋:查詢字符串不應以分號結束。 connection 可選。規定 SQL 連接標識符。如果未規定,則使用上一個打開的連接。
第五步:執行完查詢,我們再對結果進行處理
mysql_fetch_array(data,array_type) data 可選。規定要使用的數據指針。該數據指針是 mysql_query() 函數產生的結果。 array_type 可選。規定返回哪種結果。可能的值: MYSQL_ASSOC - 關聯數組 MYSQL_NUM - 數字數組 MYSQL_BOTH - 默認。同時產生關聯和數字數組
題外話:我們使用echo將執行的SQL語句輸出,方便我們查看后台執行了什么語句。
echo $querry
最終代碼如下:
if(isset($_GET["id"])){ $con = mysql_connect("127.0.0.1:3306","root","root"); if (!$con) { die('Could not connect: ' . mysql_error()); } mysql_select_db("ichunqiu",$con); $querry = "select * from users where id = " . $_GET['id']; $sql = mysql_query($querry,$con); $result = mysql_fetch_array($sql); echo "<table class='itable' border='1' cellspacing='0' width='300px' height='150'>"; echo "<tr>"; echo "<td>id</td>"; echo "<td>username</td>"; echo "</tr>"; echo "<tr>"; echo "<td>".$result['id']."</td>"; echo "<td>".$result['username']."</td>"; echo "</tr>"; echo "</table>"; mysql_close($con); echo $querry; } ?>
MySQL數據庫實驗環境配置:
代碼層工作已經做好,但是在數據庫里面,我們還沒有ichunqiu這個數據庫啊,接下來我就帶大家一步步創建數據庫,創建表,創建列,插入數據。
第一步:創建數據庫

- 第二節 尋找及確認SQL注入
2.1、推理測試法
尋找SQL注入漏洞有一種很簡單的方法,就是通過發送特殊的數據來觸發異常。
首先我們需要了解數據是通過什么方式進行輸入,這里我總結了三個:
- GET請求:該請求在URL中發送參數。
- POST請求:數據被包含在請求體中。
- 其他注入型數據:HTTP請求的其他內容也可能會觸發SQL注入漏洞。
了解完數據的輸入方式,我們接下來再學習數據庫錯誤。這里我們以MySQL為例,其它的請大家自行學習咯。
我們現在參數后面加個單引號,如下圖:

sql語句最終變為
select * from users where id = 1'
執行失敗,所以mysql_query()函數會返回一個布爾值,在下行代碼中mysql_fetch_array($sql)將執行失敗,並且PHP會顯示一條警告信息,告訴我們mysql_fetch_array()的第一個參數必須是個資源,而代碼在實際運行中,給出的參數值卻是一個布爾值。
我們修改代碼在
$sql = mysql_query($querry,$con);下一行加上 var_dump($sql);
可以發現:

為了更好的了解MySQL錯誤,我們在
$sql = mysql_query($querry,$con);
加上
if(!$sql) { die('<p>error:'.mysql_error().'</p>'); }
這樣當應用捕獲到數據庫錯誤且SQL查詢失敗時,就會返回錯誤信息:(我們在參數中添加單引號返回的錯誤信息)
error:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1
然后借助這些錯誤,我們這可以推斷應該存在SQL注入。還有其他數據庫錯誤信息,以及MySQL其他錯誤信息,由於篇幅問題就不一一講解了。
2.2、and大法和or大法
頁面不返回任何錯誤信息,我們就可以借助本方法來推斷了,首先我們在參數后面加上 and 1=1和and 1=2看看有什么不同

可以發現and 1=1 返回了數據,而and 1=2沒有,這是由於1=1是一個為真的條件,前面的結果是true,true and true 所以沒有任何問題,第二個 1=2 是個假條件, true and false還是false,所以並沒有數據返回。
好,講完and,我們自來看看 or ,or就是或者,兩個都為假,才會為假。我們先把id改為5,可以發現id=5是沒有數據的。

可以發現我們加上or 1=1就成功返回了數據,這是因為1=1為真,不管前面是不是假,數據都會返回,這樣就把表里面數據全部返回,我們沒看見,是因為代碼中並沒有迭代輸出。這樣,我們來修改一下代碼。
echo "<table class='itable' border='1' cellspacing='0' width='300px' height='150'>"; echo "<tr>"; echo "<td>id</td>"; echo "<td>username</td>"; echo "</tr>"; //遍歷查詢結果 while ($result = mysql_fetch_array($sql)) { echo "<tr>"; echo "<td>" . $result[0] . "</td>"; echo "<td>" . $result[1] . "</td>"; echo "</tr>"; }
然后你就可以發現:

2.3、加法和減法
這里我們需要區分一下數字型和字符串型:
- 數字型:不需要使用單引號來表示
- 其他類型:使用單引號來表示
綜合上述,我們可以發現我們的例子是數字型的,這樣我們就可以使用加法和減法來判斷了。
加法,我們在參數輸入1+1,看看返回的數據是不是id等於2的結果,這里注意一下+號在SQL語句是有特效含義的,所以我們要對其進行url編碼,最后也就是%2b。

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

結束語
感謝大家的支持吧,在此我也總結一下前面自己的不足,由於篇幅很長,寬度是到位了,但是並沒有深入,也不算詳細,所以本篇教程分為了三級即初級、中級、高級。六節來寫,既要深度也要寬度,當然我也不是技術大牛,如文中有錯誤請指出,我會加以改正,謝謝。
文章首鏈:http://bbs.ichunqiu.com/thread-9518-1-1.html
感謝您的閱讀,如果您學到了,請點贊(碼字不易)!
歡迎熱心園友補充!
作者:zusheng
系列文章預告及導航
滲透攻防Web篇-SQL注入攻擊中級(狀態:更新中)
- 第三節 利用SQL注入
- 第四節 SQL盲注利用
滲透攻防Web篇-SQL注入攻擊高級(狀態:更新中)
- 第五節 避開過濾方法總結
- 第六節 探討SQL注入防御技巧
