DVWA-SQL Injection (Bind) SQL盲注
盲注同于union select
查询注入,盲注只能得到数据库回显的正确和错误,利用返回的正确和错误一个一个判断。
LOW
审计源码
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// 获取 id
$id = $_GET[ 'id' ];
// 定义存在为 false
$exists = false;
// 判断数据库类型
switch ($_DVWA['SQLI_DB']) {
// MYSQL数据库
case MYSQL:
// 数据库查询
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ); // Removed 'or die' to suppress mysql errors
// 定义存在还是 false
$exists = false;
// 判断数据库查询是否有结果
if ($result !== false) {
try {
// 获取返回结果中的函数
$exists = (mysqli_num_rows( $result ) > 0);
} catch(Exception $e) {
// 没有结果定义为 false
$exists = false;
}
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
break;
case SQLITE:
global $sqlite_db_connection;
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
try {
$results = $sqlite_db_connection->query($query);
$row = $results->fetchArray();
$exists = $row !== false;
} catch(Exception $e) {
$exists = false;
}
break;
}
// 判断数据库是否查询成功
if ($exists) {
// 查询成功
echo '<pre>User ID exists in the database.</pre>';
} else {
// 找不到用户
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// 插叙失败
echo '<pre>User ID is MISSING from the database.</pre>';
}
}
?>
根据查询结果,只返回了查询正确和错误两种结果,对传入的id
没有进行过滤,所以可以直接进行注入
通过观察在$id
左右加入了''
,所以这是一个字符型的注入
SQL盲注非常的繁琐
普通的注入为发现注入点 -> 判断注入类型 -> 获取当前数据库的名 -> 获取当前数据库中表明 -> 获取表中的字段名 -> 获取字段内容
盲注
1.判断注入类型 -> 2.获取当前数据库名:获取当前数据库的长度,获取当前数据库的第一个字符的ascii码值,获取当前数据库的第二个字符的ascii码值........ -> 3.获取当前数据库中的表名: 获取当前数据库中表的数量,获取第一个表名长度,获取第一个表名的第一个字符的ascii码值........ -> 4.获取第一个表中的字段名: 获取第一个表中字段的数量,获取第一个字段的长度,获第一个字段的第一个字符的ascii码值........ -> 5.依次类推
这里的绕过方法为1'#
,详细步骤可以到另一篇博客
Less-5 和 Less-6 SQL盲注
这里也可以写一个sql盲注的脚本,后续补出来
Medium
审计源码
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// 获取 id
$id = $_POST[ 'id' ];
$exists = false;
// 判断数据库类型
switch ($_DVWA['SQLI_DB']) {
// mysql数据库
case MYSQL:
// mysqli_real_escape_string 传入 id 进行实例化
$id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// 执行SQL语句
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ); // Removed 'or die' to suppress mysql errors
$exists = false;
// 判断是否成功执行 SQl 语句
if ($result !== false) {
try {
// 获取执行 SQL 返回的行数
$exists = (mysqli_num_rows( $result ) > 0); // The '@' character suppresses errors
} catch(Exception $e) {
$exists = false;
}
}
break;
case SQLITE:
global $sqlite_db_connection;
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
try {
$results = $sqlite_db_connection->query($query);
$row = $results->fetchArray();
$exists = $row !== false;
} catch(Exception $e) {
$exists = false;
}
break;
}
// 判断数据库查询是否返回结果
if ($exists) {
// 返回结果
echo '<pre>User ID exists in the database.</pre>';
} else {
// 没有返回结果
echo '<pre>User ID is MISSING from the database.</pre>';
}
}
?>
使用POST方式传参id
并使用mysqli_real_escape_string
进行了实例化操作,但是这题是数字型的SQL注入,所对我们注入没什么影响
不用使用闭合,使用hackbar
直接进行传参
payload:Submit=Submit&id=1 and length(database()) > 0 %23
判断当前数据库的长度是否大于 0
可以看到返回正确,这样一步结果就出来了
High
审计源码
<?php
if( isset( $_COOKIE[ 'id' ] ) ) {
// 获取传入的 id
$id = $_COOKIE[ 'id' ];
$exists = false;
// 判断数据库类型
switch ($_DVWA['SQLI_DB']) {
case MYSQL:
// 进行数据库查询,后面的和Low基本一致
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ); // Removed 'or die' to suppress mysql errors
$exists = false;
if ($result !== false) {
// Get results
try {
$exists = (mysqli_num_rows( $result ) > 0); // The '@' character suppresses errors
} catch(Exception $e) {
$exists = false;
}
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
break;
case SQLITE:
global $sqlite_db_connection;
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
try {
$results = $sqlite_db_connection->query($query);
$row = $results->fetchArray();
$exists = $row !== false;
} catch(Exception $e) {
$exists = false;
}
break;
}
if ($exists) {
// 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>';
}
}
?>
通过观察High
的源码,除了获取id的方式和LOW
级别不一样,其余都类似
使用1'#
依然可以绕过
Impossible
审计源码
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// 检查user_token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
$exists = false;
// 获取传入的id
$id = $_GET[ 'id' ];
// 查看 id 是否为数字
if(is_numeric( $id )) {
// 将 id 转换为字符串
$id = intval ($id);
// 判断数据库类型
switch ($_DVWA['SQLI_DB']) {
// mysql
case MYSQL:
// 使用 PDO 方法进行sql查询
$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();
$exists = $data->rowCount();
break;
case SQLITE:
global $sqlite_db_connection;
$stmt = $sqlite_db_connection->prepare('SELECT COUNT(first_name) AS numrows FROM users WHERE user_id = :id LIMIT 1;' );
$stmt->bindValue(':id',$id,SQLITE3_INTEGER);
$result = $stmt->execute();
$result->finalize();
if ($result !== false) {
// There is no way to get the number of rows returned
// This checks the number of columns (not rows) just
// as a precaution, but it won't stop someone dumping
// multiple rows and viewing them one at a time.
$num_columns = $result->numColumns();
if ($num_columns == 1) {
$row = $result->fetchArray();
$numrows = $row[ 'numrows' ];
$exists = ($numrows == 1);
}
}
break;
}
}
// Get results
if ($exists) {
// 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();
?>
后面大概的我也没有看,首先判断是否为数字,然后类型转换为字符串类型,之后又使用PDO方法方法SQL注入,和普通的SQL注入一样的防御方法