來(lái)源;http://bbs.ichunqiu.com/thread-9518-1-1.html?from=ch
作者:zusheng
時(shí)間:2016年8月3日 12:11:50
社區(qū):i春秋
前言
不管用什么語(yǔ)言編寫的Web應(yīng)用,它們都用一個(gè)共同點(diǎn),具有交互性并且多數(shù)是數(shù)據(jù)庫(kù)驅(qū)動(dòng)。在網(wǎng)絡(luò)中,數(shù)據(jù)庫(kù)驅(qū)動(dòng)的Web應(yīng)用隨處可見(jiàn),由此而存在的SQL注入是影響企業(yè)運(yùn)營(yíng)且最具破壞性的漏洞之一,這里我想問(wèn),我們真的了解SQL注入嗎?看完本篇文章希望能讓你更加深刻的認(rèn)識(shí)SQL注入。
目錄
第一節(jié) 注入攻擊原理及自己編寫注入點(diǎn)
1.1、什么是SQL?
1.2、什么是SQL注入?
1.3、SQL注入是怎么樣產(chǎn)生的?
1.4、編寫注入點(diǎn)
第二節(jié) 尋找及確認(rèn)SQL注入
2.1、推理測(cè)試法
2.2、and大法和or大法
2.3、加法和減法
正文
第一節(jié) 注入攻擊原理及自己編寫注入點(diǎn)
1.1、什么是SQL?
SQL 是一門 ANSI 的標(biāo)準(zhǔn)計(jì)算機(jī)語(yǔ)言,用來(lái)訪問(wèn)和操作數(shù)據(jù)庫(kù)系統(tǒng)。SQL 語(yǔ)句用于取回和更新數(shù)據(jù)庫(kù)中的數(shù)據(jù)。SQL 可與數(shù)據(jù)庫(kù)程序協(xié)同工作,比如 MS Access、DB2、Informix、MS SQL Server、Oracle、Sybase 以及其他數(shù)據(jù)庫(kù)系統(tǒng)。
1.2、什么是SQL注入?
看起來(lái)很復(fù)雜,其實(shí)很簡(jiǎn)單就能解釋,SQL注入就是一種通過(guò)操作輸入來(lái)修改后臺(tái)SQL語(yǔ)句達(dá)到代碼執(zhí)行進(jìn)行攻擊目的的技術(shù)。
1.3、SQL注入是怎么樣產(chǎn)生的?
構(gòu)造動(dòng)態(tài)字符串是一種編程技術(shù),它允許開發(fā)人員在運(yùn)行過(guò)程中動(dòng)態(tài)構(gòu)造SQL語(yǔ)句。開發(fā)人員可以使用動(dòng)態(tài)SQL來(lái)創(chuàng)建通用、靈活的應(yīng)用。動(dòng)態(tài)SQL語(yǔ)句是在執(zhí)行過(guò)程中構(gòu)造的,它根據(jù)不同的條件產(chǎn)生不同的SQL語(yǔ)句。當(dāng)開發(fā)人員在運(yùn)行過(guò)程中需要根據(jù)不同的查詢標(biāo)準(zhǔn)來(lái)決定提取什么字段(如SELECT語(yǔ)句),或者根據(jù)不同的條件來(lái)選擇不同的查詢表時(shí),動(dòng)態(tài)構(gòu)造SQL語(yǔ)句會(huì)非常有用。
在PHP中動(dòng)態(tài)構(gòu)造SQL語(yǔ)句字符串:
[PHP]純文本查看復(fù)制代碼
1
$query="SELECT * FROM users WHERE username = ".$_GET["ichunqiu"];
看上面代碼我們可以控制輸入?yún)?shù)ichunqiu,修改所要執(zhí)行SQL語(yǔ)句,達(dá)到攻擊的目的。
1.4、編寫注入點(diǎn)
為了照顧一下新人,這里先介紹一下涉及到的基礎(chǔ)知識(shí):
[SQL]純文本查看復(fù)制代碼
1
2
3SQLSELECT語(yǔ)法
SELECT列名稱FROM表名稱
符號(hào) * 取代列的名稱是選取所有列
[SQL]純文本查看復(fù)制代碼
1
2
3
4WHERE子句
如需有條件地從表中選取數(shù)據(jù),可將WHERE子句添加到SELECT語(yǔ)句。
語(yǔ)法
SELECT列名稱FROM表名稱WHERE列 運(yùn)算符 值
下面的運(yùn)算符可在 WHERE 子句中使用:
了解了以上基礎(chǔ)知識(shí)就讓我們來(lái)自己編寫注入點(diǎn)把。
第一步:我們使用if語(yǔ)句來(lái)先判斷一下變量是否初始化
[PHP]純文本查看復(fù)制代碼
1
2
3
4
5
if(isset($_GET["ichunqiu"])){
}
?>
第二步:在if語(yǔ)句里面,我們連接數(shù)據(jù)庫(kù)。在PHP中,這個(gè)任務(wù)通過(guò) mysql_connect() 函數(shù)完成。
[PHP]純文本查看復(fù)制代碼
1
2
3
4mysql_connect(servername,username,password);
servername??????? 可選。規(guī)定要連接的服務(wù)器。默認(rèn)是"localhost:3306"。
username??????? 可選。規(guī)定登錄所使用的用戶名。默認(rèn)值是擁有服務(wù)器進(jìn)程的用戶的名稱。
password??????? 可選。規(guī)定登錄所用的密碼。默認(rèn)是""。
第三步:連接成功后,我們需要選擇一個(gè)數(shù)據(jù)庫(kù)。
[PHP]純文本查看復(fù)制代碼
1
2
3mysql_select_db(database,connection)
database??????? 必需。規(guī)定要選擇的數(shù)據(jù)庫(kù)。
connection??????? 可選。規(guī)定 MySQL 連接。如果未指定,則使用上一個(gè)連接。
第四步:選擇完數(shù)據(jù)庫(kù),我們需要執(zhí)行一條 MySQL 查詢。
[PHP]純文本查看復(fù)制代碼
1
2
3mysql_query(query,connection)
query??????? 必需。規(guī)定要發(fā)送的 SQL 查詢。注釋:查詢字符串不應(yīng)以分號(hào)結(jié)束。
connection??????? 可選。規(guī)定 SQL 連接標(biāo)識(shí)符。如果未規(guī)定,則使用上一個(gè)打開的連接。
第五步:執(zhí)行完查詢,我們?cè)賹?duì)結(jié)果進(jìn)行處理
[AppleScript]純文本查看復(fù)制代碼
1
2
3
4
5
6
7mysql_fetch_array(data,array_type)
data可選。規(guī)定要使用的數(shù)據(jù)指針。該數(shù)據(jù)指針是 mysql_query()函數(shù)產(chǎn)生的結(jié)果。
array_type
可選。規(guī)定返回哪種結(jié)果??赡艿闹担?/p>
MYSQL_ASSOC-關(guān)聯(lián)數(shù)組
MYSQL_NUM-數(shù)字?jǐn)?shù)組
MYSQL_BOTH-默認(rèn)。同時(shí)產(chǎn)生關(guān)聯(lián)和數(shù)字?jǐn)?shù)組
題外話:我們使用echo將執(zhí)行的SQL語(yǔ)句輸出,方便我們查看后臺(tái)執(zhí)行了什么語(yǔ)句。
[PHP]純文本查看復(fù)制代碼
1
echo$querry
最終代碼如下:
[PHP]純文本查看復(fù)制代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26if(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"";
id
username
echo"";
".$result['id']."
".$result['username']."
echo"";
echo"";
mysql_close($con);
echo$querry;
}
?>
MySQL數(shù)據(jù)庫(kù)實(shí)驗(yàn)環(huán)境配置:
代碼層工作已經(jīng)做好,但是在數(shù)據(jù)庫(kù)里面,我們還沒(méi)有ichunqiu這個(gè)數(shù)據(jù)庫(kù)啊,接下來(lái)我就帶大家一步步創(chuàng)建數(shù)據(jù)庫(kù),創(chuàng)建表,創(chuàng)建列,插入數(shù)據(jù)。
第一步:創(chuàng)建數(shù)據(jù)庫(kù)
第二步:創(chuàng)建表users和列id,username,password
第三步:我們插入幾條數(shù)據(jù)
同樣的道理,大家多插幾條數(shù)據(jù)。到此我們整個(gè)任務(wù)就完成了。
最終成果如下:
第二節(jié) 尋找及確認(rèn)SQL注入
2.1、推理測(cè)試法
尋找SQL注入漏洞有一種很簡(jiǎn)單的方法,就是通過(guò)發(fā)送特殊的數(shù)據(jù)來(lái)觸發(fā)異常。
首先我們需要了解數(shù)據(jù)是通過(guò)什么方式進(jìn)行輸入,這里我總結(jié)了三個(gè):
GET請(qǐng)求:該請(qǐng)求在URL中發(fā)送參數(shù)。
POST請(qǐng)求:數(shù)據(jù)被包含在請(qǐng)求體中。
其他注入型數(shù)據(jù):HTTP請(qǐng)求的其他內(nèi)容也可能會(huì)觸發(fā)SQL注入漏洞。
了解完數(shù)據(jù)的輸入方式,我們接下來(lái)再學(xué)習(xí)數(shù)據(jù)庫(kù)錯(cuò)誤。這里我們以MySQL為例,其它的請(qǐng)大家自行學(xué)習(xí)咯。
我們現(xiàn)在參數(shù)后面加個(gè)單引號(hào),如下圖:
sql語(yǔ)句最終變?yōu)?/p>
[SQL]純文本查看復(fù)制代碼
1
select*fromuserswhereid = 1'
執(zhí)行失敗,所以mysql_query()函數(shù)會(huì)返回一個(gè)布爾值,在下行代碼中mysql_fetch_array($sql)將執(zhí)行失敗,并且PHP會(huì)顯示一條警告信息,告訴我們mysql_fetch_array()的第一個(gè)參數(shù)必須是個(gè)資源,而代碼在實(shí)際運(yùn)行中,給出的參數(shù)值卻是一個(gè)布爾值。
我們修改代碼在
[PHP]純文本查看復(fù)制代碼
1
2$sql= mysql_query($querry,$con);下一行加上
var_dump($sql);
可以發(fā)現(xiàn):
為了更好的了解MySQL錯(cuò)誤,我們?cè)?/p>
[PHP]純文本查看復(fù)制代碼
1
$sql= mysql_query($querry,$con);
加上
[PHP]純文本查看復(fù)制代碼
1
2
3
4if(!$sql)
{
die('
error:'.mysql_error().'
');}
這樣當(dāng)應(yīng)用捕獲到數(shù)據(jù)庫(kù)錯(cuò)誤且SQL查詢失敗時(shí),就會(huì)返回錯(cuò)誤信息:(我們?cè)趨?shù)中添加單引號(hào)返回的錯(cuò)誤信息)
[SQL]純文本查看復(fù)制代碼
1
error:You have an errorinyour SQL syntax;checkthe manual that correspondstoyour MySQL server versionfortherightsyntaxtouse near'''atline 1
然后借助這些錯(cuò)誤,我們這可以推斷應(yīng)該存在SQL注入。還有其他數(shù)據(jù)庫(kù)錯(cuò)誤信息,以及MySQL其他錯(cuò)誤信息,由于篇幅問(wèn)題就不一一講解了。
2.2、and大法和or大法
頁(yè)面不返回任何錯(cuò)誤信息,我們就可以借助本方法來(lái)推斷了,首先我們?cè)趨?shù)后面加上 and 1=1和and 1=2看看有什么不同
可以發(fā)現(xiàn)and 1=1 返回了數(shù)據(jù),而and 1=2沒(méi)有,這是由于1=1是一個(gè)為真的條件,前面的結(jié)果是true,true and true 所以沒(méi)有任何問(wèn)題,第二個(gè) 1=2 是個(gè)假條件, true and false還是false,所以并沒(méi)有數(shù)據(jù)返回。
好,講完and,我們自來(lái)看看 or ,or就是或者,兩個(gè)都為假,才會(huì)為假。我們先把id改為5,可以發(fā)現(xiàn)id=5是沒(méi)有數(shù)據(jù)的。
可以發(fā)現(xiàn)我們加上or 1=1就成功返回了數(shù)據(jù),這是因?yàn)?=1為真,不管前面是不是假,數(shù)據(jù)都會(huì)返回,這樣就把表里面數(shù)據(jù)全部返回,我們沒(méi)看見(jiàn),是因?yàn)榇a中并沒(méi)有迭代輸出。這樣,我們來(lái)修改一下代碼。
[PHP]純文本查看復(fù)制代碼
01
02
03
04
05
06
07
08
09
10
11
12echo"";
id
username
echo"";
//遍歷查詢結(jié)果
while($result= mysql_fetch_array($sql)) {
".$result[0] ."
".$result[1] ."
echo"";
}
然后你就可以發(fā)現(xiàn):
2.3、加法和減法
這里我們需要區(qū)分一下數(shù)字型和字符串型:
數(shù)字型:不需要使用單引號(hào)來(lái)表示
其他類型:使用單引號(hào)來(lái)表示
綜合上述,我們可以發(fā)現(xiàn)我們的例子是數(shù)字型的,這樣我們就可以使用加法和減法來(lái)判斷了。
加法,我們?cè)趨?shù)輸入1+1,看看返回的數(shù)據(jù)是不是id等于2的結(jié)果,這里注意一下+號(hào)在SQL語(yǔ)句是有特效含義的,所以我們要對(duì)其進(jìn)行url編碼,最后也就是%2b。
減法是同樣的道理,不過(guò)我們不需要對(duì)-號(hào)進(jìn)行url編碼了。
結(jié)束語(yǔ)
感謝大家的支持吧,在此我也總結(jié)一下前面自己的不足,由于篇幅很長(zhǎng),寬度是到位了,但是并沒(méi)有深入,也不算詳細(xì),所以本篇教程分為了三級(jí)即初級(jí)、中級(jí)、高級(jí)。六節(jié)來(lái)寫,既要深度也要寬度,當(dāng)然我也不是技術(shù)大牛,如文中有錯(cuò)誤請(qǐng)指出,我會(huì)加以改正,謝謝。
系列文章預(yù)告及導(dǎo)航
滲透攻防Web篇-SQL注入攻擊中級(jí)(狀態(tài):更新中)
第三節(jié) 利用SQL注入
第四節(jié) SQL盲注利用
滲透攻防Web篇-SQL注入攻擊高級(jí)(狀態(tài):更新中)
第五節(jié) 避開過(guò)濾方法總結(jié)
第六節(jié) 探討SQL注入防御技巧