代码审计-文件上传

GinTvT 发布于 2024-12-10 31 次阅读 安全学习 预计阅读时间: 5 分钟


脚本语言/解释型语言

可以上传webshell并运行

一次编译到处运行

python无法从路由到web shell,不能直接通过python对上传的文件解析和执行

java针对中间件分析,有的中间件解析jsp则可以上传webshell

./net同Java,从经验看,.net搭建的网站可直接上传aspxwebshell

编译型语⾔ (golang)

没有办法上传webshell,但是在某些情况下可以通过上传+其他利⽤来进⾏rce

web容器(服务器)web程序(应用)
apachediscuz
weblogicwordpress
tomcatjoomla
jetty
nginx

python web框架:flask/django

flask不能动态解析py文件,在内存里不会指引你走向路由

PHP文件上传分析

<?php
header("Content-type: text/html;charset=utf-8");
error_reporting(0);

// 设置上传目录
define("UPLOAD_PATH", dirname(__FILE__) . "/upload/");
//上传根目录位置
define("UPLOAD_URL_PATH", str_replace($_SERVER['DOCUMENT_ROOT'], "", UPLOAD_PATH));

$is_upload = false;//跟踪文件上传的状态

if (!file_exists(UPLOAD_PATH)) {
    mkdir(UPLOAD_PATH, 0755);
}

if (!empty($_POST['submit'])) {
    if (!$_FILES['file']['size']) //检查是否选择了文件进行上传{
        echo "<script>alert('请添加上传文件')</script>";
    } else {
        $name = basename($_FILES['file']['name']);
        if (move_uploaded_file($_FILES['file']['tmp_name'], UPLOAD_PATH . $name)) {
            $is_upload = true;
        } else {
            echo "<script>alert('上传失败')</script>";
        }
    }
}
?>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>

</head>

<body>
    <h1>文件上传</h1>

    <?php if ($is_upload): ?>
        <p>上传成功!文件路径:<a href="<?php echo UPLOAD_URL_PATH . $name; ?>"><?php echo htmlspecialchars($name); ?></a></p>

    <?php endif; ?>
    <form action="" method="post" enctype="multipart/form-data">
        <input type="file" name="file">
        <input type="submit" name="submit" value="上传">
    </form>

</body>

</html>

用户提交数据到服务器的过程

决定文件是否能够写入的是后端代码路由

案例分析

压缩文件处理

在tar包中,可以利用特殊字符进行路径穿越

../../../a/b/c

进行命令拼接后

/tmp/temp/../../../a/b/c -->最终解压到/c文件夹

关注在解压过程中对文件名有没有处理

def extract(tar_path, target_path):
 try:
 tar = tarfile.open(tar_path, "r:gz")
 file_names = tar.getnames()
 for file_name in file_names:
 tar.extract(file_name, target_path)
 tar.close()
 except Exception, e:
 raise Exception, e

在这段python中,如果file_name为../../../etc/passwd这种,这个文件名会被提取到/etc/passwd这个目录,他是直接对目录进行的拼接

以go语言解压库的这个版本为例

在这里也是直接做了一个拼接的操作,类似的效果会是这样

在修复的时候过滤了../与/符号,但是在Windows的情况下

可以替换成..\来规避修复

恶意tar包制作

创建一个文件

然后打包正常tar包

在010Editor打开tar包

013472是8进制的checksum,也是我们需要修改的基址

小脚本需要修改这个值为你的checksum,八进制是以0o开头所以要加上

计算得出基址为13700

137472替换为13700

更改后如下

更改完成,恶意tar包校验正确

任意写入的利用

1.webshell,主要是web路径,还需要配合web容器

2.ssh公钥写入,主要需要运行web容器的用户有ssh登录的权限,ssh还要开放外连

3.计划任务,写入目录 /var/spool/cron/或/etc/crontab/

路径穿越

var byte[] content	//文件内容
var string filename		//上传的filename字段内容
var string dst		//dit为存储路径
dst = upload_dir + filename //upload_dir为预设目录,与文件名直接拼接
os.open(dst).write(content)	//os.open表示创建或者或打开目录并将内容content写入

1.写入bash公钥

2.反弹shell

3.程序覆盖,覆盖掉web应用的可执行程序,然后用DDOS等方式重启服务器

在Linux下用supervisord守护,如果程序挂掉也会自动重启

4.配置文件覆盖

5.动态执行

6.构造恶意升级包(重点)

1.本地公钥证书加密tar包

2.服务端用私钥解密tar包,升级

名词解释:公钥,公开的加密密钥,用于加密数据,私钥,保密的解密密钥,用于解密数据,公钥加密后,只有对应的私钥才能解密,

tar包突破校验

服务端肯定需要存放私钥,私钥一般是个文件,可以通过文件覆盖将私钥替换掉,用公钥证书给我们tar包签名,在上传的时候,服务器会帮我们完成解密,执行bash的操作

此作者没有提供个人介绍。
最后更新于 2025-04-23