☰
DVWA靶场——SQL Injection(SQL注入)
2026/10/10 21:45:51 网站建设 项目流程

SQL Injection(SQL注入),是指当应用程序没有对用户输入的数据进行充分的验证和过滤,攻击者就可以通过构造恶意的输入数据,将 SQL 语句插入到应用程序提交给数据库的查询中,从而改变查询的逻辑,获取敏感信息、篡改数据或者执行其他恶意操作。SQL注入漏洞的危害是巨大的,常常会导致整个数据库被“脱裤”,尽管如此,SQL注入仍是现在最常见的Web漏洞之一。

sql注入原理

参数可控,使用户可以绕过防护对后端内容进行操作。

参数包含危险语句使得对敏感文件进行操作。

(1)1’报错验证原理

正常:select * from users where id =1 正常查询

错误: select * from users where id =1’ 出现报错 同理 ‘1’’ 也会报错

如果出现报错则可能存在SQL注入

(2)1=1 与 1=2 验证(1=1为TURE 而 1=2 为FALSE)

select * from users where id = 1 and 1=1 正常查询 与了一个TURE

select * from users where id =1 and 1=2 查询为空(并不会报错) 与了一个FALSE

判断是否存在注入打点:

id = 1 and 1=1 --+

id = 1 and 1=2 --+

id = 1 or 1=1 --+

id = '1' or '1'='1'--+

id = "1" or "1"="1"--+

或 id = 1 and sleep(10) --+

"--+"是用于注释掉后面的代码,闭合我们的命令(明确一点,--+是URL中的注释符号,有时会因为编码问题过滤掉#)

SQL注入流程

拿到一个查询条件的web网页,一般需要对输入框做以下的事情

1.判断是否存在注入,注入是字符型还是数字型

2.猜解SQL查询语句中的字段数

3.确定显示的字段顺序

4.获取当前数据库

5.获取数据库中的表

6.获取表中的字段名

7.下载数据

low

首先抓个包,看到它是以GET模式提交数据包到后端的,这种模式下,URL中会带着id参数,类似与这种?id=1&Submit=Submit#

然后我们分别输入1,和1'点击submit,可以看到1时正常返回了数据,而1'报错了,这就说明存在SQL注入

再输入1' and '1'='1 和 1' and '1'='2,前者正常显示,后者无数据

这说明他是字符型注入(单引号闭合)

(1)我们输入1' or '1'='1点击submit

可以看到正常返回了所有数据

(2)使用二分法判断字段(order by 5,3,2),最终判断存在2个字段

1' order by 5 # 1' order by 3 # 1' order by 2 #

(3)显示报错位

1' union select 1,2 #

(4)查找库名

1' union select 1,database() #

源码分析
<?php if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input //获取ID字段 $id = $_REQUEST[ 'id' ]; // Check database //拼接SQL语句并查询 $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</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>"; } mysqli_close($GLOBALS["___mysqli_ston"]); } ?>

通过分析源码,我们发现其对用户输入全盘接受,没有过滤。攻击者可以闭合单引号,注入任意 SQL 代码。

并且数据库会将报错信息直接输出到页面

Medium

这个级别用的POST提交,我们看不到他URL中的信息

我们f12打开开发者工具,找到表单所在的位置,将其中value标签改为"1 or 1=1",再submit

可以看到给我们返回了所有数据,可以用同样的方法拼接其他SQL语言拿到我们需要的信息

这个关卡除了在开发中工具中注入,也可以直接抓包改变id参数进行注入,这里就不做演示了

High

<?php if( isset( $_SESSION [ 'id' ] ) ) { // Get input $id = $_SESSION[ 'id' ]; // Check database //【select * from tableName limit i,n 】 tableName : 为数据表; i : 为查询结果的索引值(默认从0开始); n : 为查询结果返回的数量 查询第一条数据 select * from student limit 1 查询第二条数据 select * from student limit 1,1 $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); } ?>

通过对源代码的分析,我们发现它相较于low级别,主要是通过会话(Session)控制,将输入和结果分步处理,增加了自动化盲注的复杂度

其中有这么一行代码,他的意思是即使or条件让所有用户记录都符合where条件,LIMIT 1也强制数据库只返回第一条记录。所以,你看到的永远只是user_id为1的用户信息,而不是所有数据。

SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;

所以我们需要用#注释掉后面的LIMIT 1

Impossible

<?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(); ?>


这段代码主要通过参数化查询(prepare+bindParam)将输入强制绑定为整数,从根本上防御SQL注入;同时辅以is_numeric()过滤数字、rowCount()==1限制单条返回、以及Anti-CSRF Token防御跨站请求伪造。常规注入手段完全无效,整体防御非常可靠。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询