二次注入

二次注入漏洞是一种在Web应用程序中广泛存在的安全漏洞形式。相对于一次注入漏洞而言,二次注入漏洞更难以被发现,但是它却具有与一次注入攻击漏洞相同的攻击威力。

什么是二次注入?

简单的说,二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入。
网站对我们输入的一些重要的关键字进行了转义,但是这些我们构造的语句已经写进了数据库,可以在没有被转义的地方使用
可能每一次注入都不构成漏洞,但是如果一起用就可能造成注入。

普通注入与二次注入:

普通注入  (1)在http后面构造语句,是立即直接生效的

                (2)一次注入很容易被扫描工具扫描到



二次注入   (1) 先构造语句(有被转义字符的语句)

                (2)我们构造的恶意语句存入数据库

                (3)第二次构造语句(结合前面已经存入数据库的语句,成功。因为系统没有对已经存入数据库的数据做检查)

                (4)二次注入更加难以被发现

二次注入的原理:

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

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

二次注入原理案列详解:

假如有一个网站管理员的用户名为:root 密码为:123456789 ,攻击者注册了一个账号 : root'-- 密码为:123因为账号当中有特殊字符,网站对于特殊字符进行了转义,一次注入在这就行不通了。虽然账号被转义了,但是他在数据库当中任然是以 root'-- 的方式被储存的。现在攻击者开始实施正真的攻击了,他开始对账号修改密码。普通网站修改密码的过程为:先判断用户是否存在------》确认用户以前的密码是否正确--------》获取要修改的密码---------》修改密码成功。 在数据库中 -- 表示注释的意思,后面的语句不会执行,而root后面的那个单引号又与前面的 ' 闭合,而原本后面的那个单引号因为是在 -- 之后,所以就被注释掉了,所以他修改的其实是 root 的密码。
下面就是一个例子
实例:
sqli-labs24
本关为二次排序注入的示范例。二次排序注入也成为存储型的注入,就是将可能导致sql注入的字符先存入到数据库中,当再次调用这个恶意构造的字符时,就可以出发sql注入。二次排序注入思路:

  1. 黑客通过构造数据的形式,在浏览器或者其他软件中提交HTTP数据报文请求到服务端进行处理,提交的数据报文请求中可能包含了黑客构造的SQL语句或者命令。

  2. 服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库中,保存的数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应。

  3. 黑客向服务端发送第二个与第一次不相同的请求数据信息。

  4. 服务端接收到黑客提交的第二个请求信息后,为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的SQL语句或者命令在服务端环境中执行。

  5. 服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功。

此例子中我们的步骤是注册一个admin'#的账号,接下来登录该帐号后进行修改密码。此时修改的就是admin的密码。

Sql语句变为UPDATE users SET passwd="New_Pass" WHERE username =' admin' # ' AND password=' ,也就是执行了UPDATE users SET passwd="New_Pass" WHERE username =' admin'
1.注册admin'#账号

image

2.注意此时的数据库中出现了admin'#的用户,同时admin的密码为admin

image

3.登录admin'#,并修改密码

image

4.这时并没有修改admin'#的密码,而是修改了admin的密码。原理上面已经提过

简单的二次注入案例

测试代码1:
sql2.php

<?php
    //include('con_nect.php'); //引入数据库配置文件
    $conn = mysqli_connect('127.0.0.1','root','');  
    mysqli_select_db($conn,'berlin'); 
    if (mysqli_connect_errno($conn)) 
{ 
    echo "连接 MySQL 失败: " . mysqli_connect_error(); 
} 
    $id=$_GET['id']; 
    $select_sql="SELECT * FROM article WHERE title='$id'";
    echo $select_sql;
    mysqli_query($conn,'set names utf8');
    $select_sqli_result=mysqli_query($conn,$select_sql);
   //  $date=mysqli_fetch_assoc($select_sqli_result);
    $date=mysqli_fetch_array($select_sqli_result);

 ?>
<!DOCTYPE html>
 <html>
   <head>
     <meta charset="utf-8">
     <title><?php echo $date['title']."啦啦啦啦啦啦"?></title>
   </head>
   <body>
      <h1><?php echo $date['title'] ;?></h1><br />
      作者: <?php echo $date['author']; ?><br/>
      时间: <?php echo date("Y-m-d H:i:s",$date['dateline']);?> <br />
      概述: <?php echo $date['description'];?><br />   
      正文: <?php echo $date['content']; ?>
   </body>
 </html>

测试代码2
sql22.php

  <!DOCTYPE html>
 <html>
   <head>
     <meta charset="utf-8">
     <title>sql22</title>
   </head>
   <body>
      <form action="sql22.php" method="post">
      主题title: <input type="text" name="title">
      <br/>
     作者author: <input type="text" name="author">
     <br/>
    概述description: <input type="text" name="description">
    <br/>
    正文content: <input type="text" name="content">
     <br/>
      <input type="submit" value="提交">
    </form>
   </body>
 </html>

<?php
   //include('con_nect.php');
   $conn = mysqli_connect('127.0.0.1','root','');  
   mysqli_select_db($conn,'berlin');
   mysqli_query($conn,"set names utf8"); 
   $title=addslashes($_POST['title']);  //addslashes 将预定义字符串转义
   $author=addslashes($_POST['author']);
   $description=addslashes($_POST['description']);
   $content=addslashes($_POST['content']);
   $dataline=time();
   if($title!=''&& $author!='')
   {$insert="INSERT INTO article(title,author,description,content,dateline) VALUES('$title','$author','$description','$content','$dataline')";

   if (mysqli_query($conn, $insert))
   {
    
    echo "新记录插入成功";
    } 
    else {
    echo "Error: " . $insert . "<br>" . mysqli_error($conn);
         }
       
   echo $insert;
   mysqli_query($conn,"set names utf8"); //设置编码
   if($result=mysqli_query($conn,$insert)){
     $num=mysqli_affected_rows($conn);
     echo $num;}
     }
     else {echo '插入失败';}
 ?>


代码1是显示页面,显示各个数据,代码2是添加页面,进行数据添加。
首先我们简单分析分析一下这两段代码。
测试代码1是一个内容显示页面,通过传入的id在数据库进行查询,然后在页面调用输出,我们可以看到传递的参数id并没有经过过滤,可以成为一个典型的字符串GET注入,但是我们今天要讨论的是二次注入,暂时不考虑这个注入。
测试代码2是一个添加页面,通过表单POST的数据执行INSERT语句插入数据,成功后返回数据库影响行数,而且这里的每一个参数都用addslashes函数进行了转义。
两段代码结合,我们可以发现一个典型的二次注入点,虽然文章添加页面中过滤的非常严格,但是addslashes有一个特点就是虽然参数在过滤后会添加 “\” 进行转义,但是“\”并不会插入到数据库中,再配合内容显示页面中的查询是通过id查询的,所以我们就可以利用这个构造一个二次注入。
在之前先看一下正常显示页面


图片.png

然后我们插入一条注入语句

添加post数据
id=0' union select 1,version(),database(),user(),4'
&author=111
&content=xxx

图片.png

可看到添加的id为sql注入语句,结果显示添加成功,可以看到图片中的结果是已经被转义,也意味着此语句没有任何作用,但已经被添加到数据库中,且储存在数据库中的值是不含转义字符的也就是原来post提交的数据
我们去数据库看一下


图片.png

确实数据库里的并没有转义,说明第一次构造成功了。
这时我们再回到显示页面查参数id,因为我们将注入语句通过id参数插入到数据库tilte列中。
查询 id=0' union select 1,version(),database(),user(),4'

图片.png

数据库用户,名字,版本都出来了

例子很简单,也很垃圾,意思大概就是这个意思。
二次注入防范方法:
解决SQL注入最推荐的方法还是预处理+数据绑定。
另一个防御的点就是 对输入一视同仁,无论输入来自用户还是存储,在进入到 SQL 查询前都对其进行过滤、转义。
对于二次注入这种小众的漏洞,一般没有专门针对的方案,只能从流程上进行优化,例如做代码审查的时候禁止开发用拼接的方式执行sql。
总结一下二次注入的精髓就是,第一次构造的语句只是为了第二次构造做的铺垫,第二次才是正真的攻击。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • 教主是我比较佩服的人,不但对技术非常痴迷,而且对于生活与姑娘的热爱也是有着同样痴迷的程度。 第一次见教主的时候,是...
    南山一梦阅读 266评论 0 2
  • 写在前面的话:每个孩子都很不同,而且我家也只有一个2.7岁的孩子,我只是一位爱学习爱总结的普通妈妈。因家有乖女,荣...
    慢慢来比较快__阅读 282评论 0 0
  • 都说福不双至,祸不单行,老天不会让你一直走运,而祸事却常常接二连三的到来。 那么为什么会祸不单行呢?这里面又一个机...
    梦也夏雪阅读 550评论 0 0