SQL注入--二次注入

一.基本概念

二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。

二.注入原理

二次注入的原理:在第一次进行数据库插入数据的时候,仅仅只是使用了 addslashes​ 或者是借助 get_magic_quotes_gpc​对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身还是脏数据。

在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入。

三.注入过程

  1. 先构造语句(此语句含有被转义字符的语句,如mysql_escape_string、mysql_real_escape_string 转义)
  2. 将我们构造的恶意语句存入数据库(被转义的语句)
  3. 第二次构造语句(结合前面已被存入数据库的语句构造。因为系统没有对已存入的数据做检查,成功注入)​

四.靶场示例

靶场:sqli-labs less 24

1.查看初始的users​表
  • 发现表中 admin 用户的密码为 admin
2.注册用户
  • 主要代码 login_create.php​ 如下:

    • if (isset($_POST['submit']))
      {
      # Validating the user input........
      //$username= $_POST['username'] ;
      	$username=mysql_escape_string($_POST['username']) ;
      	$pass=mysql_escape_string($_POST['password']);
      	$re_pass=mysql_escape_string($_POST['re_password']);
      	// 对注册账号时输入的数据进行转义
      	echo "<font size='3' color='#FFFF00'>";
      	$sql = "select count(*) from users where
      	username='$username'";
      	$res = mysql_query($sql) or die('You tried tobe smart, Try harder!!!! :( ');
      	$row = mysql_fetch_row($res);
      //print_r($row);
      if (!$row[0]== 0)
      {
      ?>
      <script>alert("The username Alreadyexists, Please choose a different username ")
      </script>;
      	<?php
      	header('refresh:1, url=new_user.php');
      	}
      	else
      	{
      		if ($pass==$re_pass)
      		{
      			# Building up the query........
      			$sql = "insert into users (
      			username, password) values(\"$username\",\"$pass\")";
      			mysql_query($sql) or die('Error Creating your user account, : '.mysql_error());
      
      

      可以在该php文件末尾添加一句代码,在网页中打印出创建的用户名。

      ​echo "Hint: you input is: ".$username ."<br>";​

  • 注册一个名为 admin'# ,密码为 123456 的用户

3.修改用户密码

我们先查看一下此时的 users 表,发现多了一个用户admin'# ,而不是刚刚网页打印出来的 admin\'# ,这是因为创建用户的代码只是在单引号前加了一个 \ ,使得在执行的时候
单引号被认为是字符串里的一个字符,而不是被当成 sql 语句中的单引号。

  • 使用 admin'# 用户登录​

  • 修改 admin'# 用户的密码


  • 再次查看 users 表,发现用户 admin'# 的密码并没有修改,而是用户 admin 的密码被修改了。

原因

  • 介绍:在网站设计时,虽然过滤了注册的信息,把特殊字符进行了转义,但是在从数据库调用从外部保存下来的数据时,并没有进行过滤,使得 admin'# 被代入到 sql 语句执行,执行了这段 payload,达到了修改用户 admin 的密码的目的。

  • 具体代码:

    #原语句
    UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
    
    #插入 payload 后的语句
    UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass'
    #此时 'admin' 后的语句被注释
    
    #真正的生效的语句
    UPDATE users SET PASSWORD='$pass' where username='admin'
    #从而达到了修改用户 admin 密码的目的
    
### SQL 二次注入的原理 SQL 二次注入是一种特殊的 SQL 注入攻击形式,其核心在于恶意数据被存储在数据库中,并在后续操作中未经过充分验证或过滤而被执行。具体来说,这种攻击发生的原因可能是应用系统在初次接收到用户输入时已经对其进行了安全性处理,但当这些已存储的数据再次参与动态 SQL 查询构建时,未能重新对其进行防护[^2]。 #### 攻击过程描述 1. **初始输入阶段**:攻击者向目标系统提交含有恶意 SQL 片段的内容。此时,该内容可能会经历初步的安全检测(如转义特殊字符),随后存入数据库。 2. **后续利用阶段**:当程序从数据库提取之前保存的恶意数据并将其嵌套至新的 SQL 查询语句中时,如果缺乏必要的清理机制,则可能导致原始恶意代码得以执行,从而实现对系统的非法访问或者破坏行为[^3]。 --- ### 防御方法 针对上述提到的 SQL 二次注入风险,可以从以下几个方面着手加强防范: #### 数据校验与清洗 - 对于任何来源于外部环境的信息,在写入持久化层前都应实施严格的格式校验以及敏感符号替换工作; - 即使某些字段看似无害也需要谨慎对待,因为它们有可能在未来某个时刻成为潜在威胁源的一部分[^1]。 #### 参数化查询技术的应用 采用预编译好的参数占位符方式来代替传统的字符串拼接法构造SQL指令是非常有效的手段之一 。这种方法能够确保即使存在危险成分也不会影响最终形成的合法命令结构 ,因为它会自动把所有传进去 的变量当作纯文本看待而不是可解析语法单元 : ```java PreparedStatement pstmt = connection.prepareStatement("SELECT * FROM users WHERE username=? AND password=?"); pstmt.setString(1, userInputName); pstmt.setString(2, userInputPassword); ResultSet rs = pstmt.executeQuery(); ``` 以上例子展示了如何通过 Java 中 PreparedStatement 类型对象来进行安全可靠的数据库交互操作 。 #### 输出编码控制 除了重视前端收集来的资料之外 , 还要特别留意那些由内部生成却又要反馈给用户的项目 . 如果有必要的话 可考虑运用 HTML 实体转换等功能 来阻止可能出现跨站点脚本 (XSS) 或其他类型的漏洞传播路径 同样适用于防止二次 sql injection 发生的情况 下面给出 python flask 框架下的简单示范 : ```python from markupsafe import escape @app.route('/search') def search(): query = request.args.get('q', '') safe_query = escape(query) # Escape potentially harmful characters. results = db.execute(f"SELECT * FROM entries WHERE title LIKE '%{safe_query}%'").fetchall() return render_template('results.html', results=results) ``` 这里借助 `markupsafe` 库里的 `escape()` 函数实现了基本层面的文字序列保护作用 . #### 定期审计日志审查制度建立 最后一点建议便是养成良好习惯定期查看服务器端产生的各类记录文件寻找异常模式迹象以便及时发现隐患所在 并采取相应补救措施减少损失扩大可能性的同时提高整体网络安全水平 [^3]. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值