[XDCTF 2015]filemanager

发布时间:2024年01月02日

[XDCTF 2015]filemanager

我们打开题目,大概看了下存在文件上传功能,并且可以执行重命名和删除文件的操作

在这里插入图片描述

扫描目录发现有源码泄露

在这里插入图片描述

我们逐一分析

upload.php

<?php
require_once "common.inc.php";

if ($_FILES) {
	$file = $_FILES["upfile"];
	if ($file["error"] == UPLOAD_ERR_OK) {
		$name = basename($file["name"]);
		$path_parts = pathinfo($name);

		if (!in_array($path_parts["extension"], array("gif", "jpg", "png", "zip", "txt"))) {
			exit("error extension");
		}
		$path_parts["extension"] = "." . $path_parts["extension"];

		$name = $path_parts["filename"] . $path_parts["extension"];

		// $path_parts["filename"] = $db->quote($path_parts["filename"]);
		// Fix
		$path_parts['filename'] = addslashes($path_parts['filename']);

		$sql = "select * from `file` where `filename`='{$path_parts['filename']}' and `extension`='{$path_parts['extension']}'";

		$fetch = $db->query($sql);

		if ($fetch->num_rows > 0) {
			exit("file is exists");
		}

		if (move_uploaded_file($file["tmp_name"], UPLOAD_DIR . $name)) {

			$sql = "insert into `file` ( `filename`, `view`, `extension`) values( '{$path_parts['filename']}', 0, '{$path_parts['extension']}')";
			$re = $db->query($sql);
			if (!$re) {
				print_r($db->error);
				exit;
			}
			$url = "/" . UPLOAD_DIR . $name;
			echo "Your file is upload, url:
                <a href=\"{$url}\" target='_blank'>{$url}</a><br/>
                <a href=\"/\">go back</a>";
		} else {
			exit("upload error");
		}

	} else {
		print_r(error_get_last());
		exit;
	}
}

首先检查上传文件的文件拓展名是否在白名单中,然后使用addslashes()函数对文件名进行转义处理,进行sql语句查询,如果不存在。那么上传文件到/uploads/文件名,执行insert命令将文件名和拓展名插入该数据表file中

接着看common.inc.php

<?php
$DATABASE = array(

	"host" => "127.0.0.1",
	"username" => "root",
	"password" => "ayshbdfuybwayfgby",
	"dbname" => "xdctf",
);

$db = new mysqli($DATABASE['host'], $DATABASE['username'], $DATABASE['password'], $DATABASE['dbname']);
$req = array();

foreach (array($_GET, $_POST, $_COOKIE) as $global_var) {
	foreach ($global_var as $key => $value) {
		is_string($value) && $req[$key] = addslashes($value);
	}
}

define("UPLOAD_DIR", "upload/");

function redirect($location) {
	header("Location: {$location}");
	exit;
}

告诉我们数据库的信息,然后用foreach嵌套循环$_GET, $_POST, $_COOKIE参数是否为字符串,如果是则进行转义处理

然后看rename.php

<?php
require_once "common.inc.php";

if (isset($req['oldname']) && isset($req['newname'])) {
	$result = $db->query("select * from `file` where `filename`='{$req['oldname']}'");
	if ($result->num_rows > 0) {
		$result = $result->fetch_assoc();
	} else {
		exit("old file doesn't exists!");
	}

	if ($result) {

		$req['newname'] = basename($req['newname']);
		$re = $db->query("update `file` set `filename`='{$req['newname']}', `oldname`='{$result['filename']}' where `fid`={$result['fid']}");
		if (!$re) {
			print_r($db->error);
			exit;
		}
		$oldname = UPLOAD_DIR . $result["filename"] . $result["extension"];
		$newname = UPLOAD_DIR . $req["newname"] . $result["extension"];
		if (file_exists($oldname)) {
			rename($oldname, $newname);
		}
		$url = "/" . $newname;
		echo "Your file is rename, url:
                <a href=\"{$url}\" target='_blank'>{$url}</a><br/>
                <a href=\"/\">go back</a>";
	}
}
?>

如果请求中存在oldname和newname参数,那么连接数据库进行查询旧文件名是否存在,如果查到那么用update命令去更新该文件名,然后定义newname为/upload/新文件名.拓展名,echo新的文件上传路径

delete.php

<?php
require_once "common.inc.php";

if(isset($req['filename'])) {
    $result = $db->query("select * from `file` where `filename`='{$req['filename']}'");
    if ($result->num_rows>0){
        $result = $result->fetch_assoc();
    }

    $filename = UPLOAD_DIR . $result["filename"] . $result["extension"];
    if ($result && file_exists($filename)) {
        $db->query('delete from `file` where `fid`=' . $result["fid"]);
        unlink($filename);
        redirect("/");
    }
}
?>

就是查询文件是否存在,如果存在则执行delete命令删除文件

既然题目存在文件上传功能,那么我们的思路肯定就是如何传马,但是由于上传时有白名单,那么我们就无法解析php后缀的文件。

我们是否可以尝试将jpg后缀改为php后缀呢,我们重点看向rename.php的这段代码

if ($result) {
		$req['newname'] = basename($req['newname']);
		$re = $db->query("update `file` set `filename`='{$req['newname']}', `oldname`='{$result['filename']}' where `fid`={$result['fid']}");
		if (!$re) {
			print_r($db->error);
			exit;
		}
		$oldname = UPLOAD_DIR . $result["filename"] . $result["extension"];
		$newname = UPLOAD_DIR . $req["newname"] . $result["extension"];
		if (file_exists($oldname)) {
			rename($oldname, $newname);
		}
		$url = "/" . $newname;
		echo "Your file is rename, url:
                <a href=\"{$url}\" target='_blank'>{$url}</a><br/>
                <a href=\"/\">go back</a>";
	}

update命令涉及到参数newname以及从数据库中查找参数oldname值,而后面进行rename()的时候是文件名(不包括拓展名),并且后面拼接路径是从数据库中查找拓展名,那么是不是可以文件名为1.php,然后拓展名为空即可实现getshell

我们可以本地测试下如何利用update语句让拓展名为空

上传', extension=",filename='1.jpg.jpg后,存储在数据库中

在这里插入图片描述

如果我们更新文件名为1.jpg(也就是对文件名', extension='',filename='1.jpg),并且让extension为空

那么我们更新的时候拼接进去的是

update uploadfile set filename='1.jpg', oldname='', extension='',filename='1.jpg';

至于为什么选择在oldname注入,是因为文件上传的时候虽然做了转义但是文件名并不会发生改变,然后在rename的时候oldname是从数据库中找到,而我们在newname注入的话,会发生转义导致文件路径包含\

在这里插入图片描述

因此成功设置extension为空

在这里插入图片描述

然后我们要将文件名1.jpg修改为1.php,这里就需要绕过file_exists()

因为虽然找得到1.jpg的文件名,但是没有拓展名使得判断为错

if (file_exists($oldname)) {
		rename($oldname, $newname);
	}

解决办法就是再上传一个1.jpg的文件,和前面提到还是一样,这里的$oldname是从数据库中得到的,也就是说文件名1.jpg拼接上空拓展名就等于文件名1拼接上拓展名.jpg,这样就能查询到存在使其为真

回到题目,我们先上传', extension='',filename='1.jpg.jpg(别忘了是两个jpg)

在这里插入图片描述

然后oldname填', extension='',filename='1.jpg

在这里插入图片描述

这样经过拼接就可以实现让extension为空,然后上传最关键一步1.jpg

然后rename为1.php

在这里插入图片描述

得到flag

在这里插入图片描述

文章来源:https://blog.csdn.net/m0_73512445/article/details/135330970
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。