f1ower's Blog

邪法面前,我亦无畏

PHP审计学习-HongCMS RCE复现

@天堂空气 这个点子王挖出的漏洞,感谢分享;

初学审计的我开始复现这个漏洞,版本是HongCMS3.0.0;


直接访问/index.php是不行的,还必须手动安装;

访问/intall/index.php进行图形化安装完成之后,按照指引对install目录进行删除;

使用刚才安装时候的账户和密码登录后台之后,在:系统->模板管理->模板文件列表功能中观察,有修改模板的功能;

我首先使用正常功能对其进行修改并进行操作并抓包分析:

image.png

新加了一行,然后保存更新,查看这个包:

image.png

根据这个功能分析是这样的:

  1. 页面是在/admin/index.php,然后调用的方法是template控制器里面的save()方法进行保存;

  2. 参数分析:file=文件名&dir=目录(这个目录好像只能指向Default目录)&fileconten=修改之后的文件内容;


直接跟到代码层去分析这个方法:

/admin/controllers/tmplate.php

//保存模板文件
    public function save(){
		$file = ForceStringFrom('file');
		$filepath = $this->temp_path . $this->current_dir . $file;

		if (is_writable($filepath)) {
			$filecontent = trim($_POST['filecontent']);
			if (get_magic_quotes_gpc()) {
				$filecontent = stripslashes($filecontent);
			}

			$fd = fopen($filepath, 'wb');
			fputs($fd,$filecontent);

			Success('template'. Iif($this->current_dir, '?dir=' . $this->current_dir));
		}else{
			$errors = '模板文件('.$file.')不可写! 请将其属性设置为: 777';
			Error($errors, '编辑模板错误');
		}
	}

这个save()方法直接通过http:Url/admin/index.php/template/save进行调用。

代码中的$file是通过ForceStringFrom函数进行收取。

image.png

而ForceStringFrom()和ForceString()直接收取$_POST[]中的参数与值,调用函数EscapeSql进行转义和过滤;

但是这也就证明了$file是我们可以控制的;

而通过控制$file,我们可以间接的控制$filepath:

$filepath = $this->temp_path . $this->current_dir . $file;

//public function __construct($path){
//		parent::__construct($path);
//
//		$this->temp_path = ROOT.'public/templates/';
//
//		$this->current_dir = ForceStringFrom('dir');
//
//		if(!$this->ajax) SubMenu('模板管理'); //根据父对象SAdmin的ajax成员变量, 判断是否为ajax动作
//	}
//
//这个类名叫c_template,继承自SAdmin,构造函数如上,如刚才我们那样传参:
//$this->temp_path = /public/templates/
//$this->current_dir = Default/
//$filepath = /public/templates/Default/[文件名]
//如果将$file构造成这样:../../../../shell.php应该就可以直接对其他目录的其他文件进行操作了。

这里我总结一下:

可以控制$file和$filepath两个变量了;

if (is_writable($filepath)) {
			$filecontent = trim($_POST['filecontent']);    //这里直接通过POST接受内容,去掉前面的空白内容。
			if (get_magic_quotes_gpc()) {
				$filecontent = stripslashes($filecontent);
			}

而在其后的if()语句中,$filecontent直接接受$_POST['filecontent']作为变量内容,这里我们又可以控制写入文件的内容了;

但是在上面的if()中有个is_writable()去验证我们上面的$filepath是否存在并且为可写的。

image.png

那么这里我们只能找一个已经在web程序目录中存在的php文件去覆写并获取shell了;

image.png

/models/user.php看上去没有什么实质性的用处,我试试去覆写他;

那么$filepath我们需要控制为:/public/templates/Default/../../../models/user.php;

image.png

然后:

image.png