摘要 / 前言:
SQL 注入的“增删改查”四部曲至此来到了最后一部——Delete 注入。Delete 操作通常用于删除留言、订单或购物车商品。这类漏洞一旦被利用,轻则导致数据丢失(被恶意清空),重则像查询注入一样泄露敏感数据。本关演示了如何利用 Delete 注入进行破坏以及如何利用它获取数据库信息。
一、漏洞分析
点击留言板上的“删除”按钮,抓取 Burp 包:
- 请求方式: GET
- URL:
/vul/sqli/sqli_del.php?id=xx
源码逻辑推测:
后端大概率接收 id 参数后直接拼接到 DELETE 语句中:
$id = $_GET['id'];
// 注意:这里 id 可能是数字型,通常不需要单引号闭合,也可能加了引号
$query="delete from message where id={$_GET['id']}";
二、攻击方式 1:批量删除 (破坏型)
这是最简单的验证方式,也是造成拒绝服务攻击(DoS)的手段。
- Payload:
将id修改为id=1 or 1=1
(注意:在 URL 中空格需要编码为+或%20)GET /vul/sqli/sqli_del.php?id=74+or+1=1 - 效果:
SQL 变为delete from message where id=1 or 1=1。
因为条件恒真,数据库中的 所有留言被瞬间清空 。这在实战中属于高危操作,请在授权测试时 慎用。

三、攻击方式 2:报错注入 (窃取型)
如果目标不是搞破坏,而是获取管理员账号密码,我们依然可以使用报错注入。原理与 Insert/Update 注入完全一致:利用数据库解析 SQL 时的逻辑执行顺序。
前提: 必须在 URL 中进行编码(空格变 + 或 %20)。
1. 爆数据库名
- Payload:
sql id=1+and+updatexml(1,concat(0x7e,database(),0x7e),1) - 原理:
SQL 变为delete from message where id=1 and updatexml(...)。
数据库在筛选要删除哪一行时,先计算了and后面的updatexml,结果触发报错,将数据库名显示在页面上。

2. 爆表名 / 数据
- Payload:
sql id=1+and+updatexml(1,concat(0x7e,(select+group_concat(username)+from+member),0x7e),1) - 效果: 页面报错并显示用户名。

四、源码深度分析
if(isset($_GET['id'])){$id=$_GET['id'];
// 漏洞点:id 未经处理直接拼接
// 这是一个典型的数字型注入场景
$query="delete from member where id={$id}";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){header("location:sqli_del.php"); // 删除成功跳转
}else{$html.="<p> 删除失败, 请检查下数据库是否还活着 </p>"; // 失败(或报错)显示信息}
}
关键点:
- 数字型注入: 这里的
$id并没有被单引号包裹(id={$id}),所以不需要构造单引号闭合,直接接and或or即可。 - 报错回显: 虽然代码中没有显式打印
$result的错误信息,但在 Pikachu 的通用execute函数配置或 PHP 环境配置中,如果 SQL 执行出错(updatexml 报错),错误信息往往会直接打印在页面上。
五、总结与防御
Delete 注入的危害:
- 数据丢失: 攻击者可以轻易清空核心业务表。
- 信息泄露: 通过报错注入获取敏感数据。
防御方案:
- 权限控制: 确保删除接口只有经过验证的管理员或数据拥有者才能调用(但这防不住 SQL 注入,只能防越权)。
- 参数化查询(预编译): 永恒的解决方案。
php $stmt = $pdo->prepare('DELETE FROM member WHERE id = :id'); // 无论 id 传进来是什么(哪怕是 "1 or 1=1"),都只会被当做一个字符串或数字处理 $stmt->execute(['id' => $_GET['id']]);
正文完