跳转至

文件上传

JavaScript WebShell

话不多说,直接上题(BugKu CTF)

打开网页啥也没有

查看源代码发现注释

访问是一个文件上传

前面试了各种过滤方法

要使用 HTML 标签定义 PHP 一句话木马,最后保存为图片文件,任意均可

上传文件回显路径

访问路径可以看到命令被执行了

上传一句话木马

使用中国蚁剑连接

成功拿到 flag

.user.ini 解析绕过

话不多说,直接上题(BUUCTF)

打开页面考察文件上传

.user.ini 文件是一个配置文件,并且是可以由用户自定义的

php.ini 不一样的是,.user.ini 可以被动态加载,只需要等待一段时间就会刷新了

BurpSuite 抓包修改 MIME 类型再上传

再上传同名的木马发现有过滤

修改木马后再上传

访问给出的目录路径下的 index.php 拿到 flag

Content-type 大小写混淆绕过

话不多说,直接上题(BugKu CTF)

打开网页正常的文件上传

strpos() 函数查找字符串在另一字符串中第一次出现的位置(区分大小写)

所以这里使用大小写混淆绕过

常规的 php 后缀被替换,换成 php4 可以

最后是修改 Content-Type 类型为图片即可

上传成功

使用蚁剑连接拿到 flag

php4 后缀绕过

话不多说,直接上题(BugKu CTF)

打开网页正常的文件上传

strpos() 函数查找字符串在另一字符串中第一次出现的位置(区分大小写)

所以这里使用大小写混淆绕过

常规的 php 后缀被替换,换成 php4 可以

最后是修改 Content-Type 类型为图片即可

上传成功

使用蚁剑连接拿到 flag

参数置空绕过

话不多说,直接上题(青少年 CTF 练习平台)

扫描目录发现有个 index.php.bak

<?php 
error_reporting(0);
$token = $_COOKIE['token'] ?? null;

if($token){
    extract($_GET);
    $token = base64_decode($token);
    $token = json_decode($token, true);


    $username = $token['username'];
    $password = $token['password'];
    $isLocal = false;

    if($_SERVER['REMOTE_ADDR'] == "127.0.0.1"){
        $isLocal = true;
    }

    if($isLocal){
        echo 'Welcome Back,' . $username . '!';
        if(file_exists('upload/' . $username . '/' . $token['filename'])){
            echo '<br>';
            echo '<img src="upload/' . $username . '/' . $token['filename'] .'" width="200">';
        } else {
            echo '请上传您高贵的头像。';
            $html = <<<EOD
            <form method="post" action="upload.php" enctype="multipart/form-data">
                <input type="file" name="file" id="file">
                <input type="submit" value="Upload">
            </form>
            EOD;
            echo $html;
        }
    } else {
        // echo "留个言吧";
        $html = <<<EOD
        <h1>留言板</h1>
        <label for="input-text">Enter some text:</label>
        <input type="text" id="input-text" placeholder="Type here...">
        <button onclick="displayInput()">Display</button>
        EOD;
        echo $html;
    }
} else {
    $html = <<<EOD
<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
</head>
<body>
    <h2>Login</h2>
    <form method="post" action="./login.php">
        <div>
            <label for="username">Username:</label>
            <input type="text" name="username" id="username" required>
        </div>
        <div>
            <label for="password">Password:</label>
            <input type="password" name="password" id="password" required>
        </div>
        <div>
            <input type="submit" value="Login">
        </div>
    </form>
</body>
</html>
EOD;
    echo $html;
}
?>

<script>
    function displayInput() {
      var inputText = document.getElementById("input-text").value;
      document.write(inputText)
    }
</script>

主要功能流程:

  1. 获取 Cookie 中的 token
$token = $_COOKIE['token'] ?? null;
  1. 解析 token 内容
$token = base64_decode($token);
$token = json_decode($token, true);
  1. 判断访问者是否为 127.0.0.1
if ($_SERVER['REMOTE_ADDR'] == "127.0.0.1")
  1. 本地用户功能

显示欢迎语;

检查头像文件是否存在;

若存在则展示头像;

若不存在则提示上传表单(提交到 upload.php

  1. 远程用户功能:

显示留言板(前端 HTML + JS 动态展示)

  1. 未登录用户

显示登录表单,提交至 login.php

extract($_GET) 工作原理:

<?php
extract($_GET);
echo "Hello, $name!";
?>

请求:

http://example.com/index.php?name=Alice

结果:

Hello, Alice!

变量污染攻击:

<?php
$token = "secure-token";
extract($_GET);
echo "Token is: $token";
?>

请求:

http://example.com/index.php?token=hacked

结果:

Token is: hacked

extract($GET); 存在变量覆盖,可以利用这个把 $SERVER['REMOTE_ADDR'] 覆盖成 127.0.0.1

?_SERVER[REMOTE_ADDR]=127.0.0.1

首先登录

然后污染找到文件上传点

上传成功后没有返回路径,在源码上可以看到这个

if(file_exists('upload/' . $username . '/' . $token['filename']))

猜测文件上传到 /upload/[username]/[filename],尝试发现是正确的

当存在 username 时,无论上传什么都不能被解析成 PHP 代码

username 置空,成功将文件上传到 upload 目录

token=eyJ1c2VybmFtZSI6IiIsInBhc3N3b3JkIjoiIn0=

Apache 多后缀解析漏洞

话不多说,直接上题(青少年 CTF 练习平台)

打开网页是直接给出了源码

<?php
header("Content-Type:text/html; charset=utf-8");
// 每5分钟会清除一次目录下上传的文件
require_once('pclzip.lib.php');

if(!$_FILES){

        echo '

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>文件上传章节练习题</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <style type="text/css">
        .login-box{
            margin-top: 100px;
            height: 500px;
            border: 1px solid #000;
        }
        body{
            background: white;
        }
        .btn1{
            width: 200px;
        }
        .d1{
            display: block;
            height: 400px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="login-box col-md-12">
        <form class="form-horizontal" method="post" enctype="multipart/form-data" >
            <h1>文件上传章节练习题</h1>
            <hr />
            <div class="form-group">
                <label class="col-sm-2 control-label">选择文件:</label>
                <div class="input-group col-sm-10">
                    <div >
                    <label for="">
                        <input type="file" name="file" />
                    </label>
                    </div>
                </div>
            </div>

        <div class="col-sm-8  text-right">
            <input type="submit" class="btn btn-success text-right btn1" />
        </div>
        </form>
        </div>
    </div>
</body>
</html>
';

    show_source(__FILE__);
}else{
    $file = $_FILES['file'];

    if(!$file){
        exit("请勿上传空文件");
    }
    $name = $file['name'];

    $dir = 'upload/';
    $ext = strtolower(substr(strrchr($name, '.'), 1));
    $path = $dir.$name;

    function check_dir($dir){
        $handle = opendir($dir);
        while(($f = readdir($handle)) !== false){
            if(!in_array($f, array('.', '..'))){
                if(is_dir($dir.$f)){
                    check_dir($dir.$f.'/');
                 }else{
                    $ext = strtolower(substr(strrchr($f, '.'), 1));
                    if(!in_array($ext, array('jpg', 'gif', 'png'))){
                        unlink($dir.$f);
                    }
                }

            }
        }
    }

    if(!is_dir($dir)){
        mkdir($dir);
    }

    $temp_dir = $dir.md5(time(). rand(1000,9999));
    if(!is_dir($temp_dir)){
        mkdir($temp_dir);
    }

    if(in_array($ext, array('zip', 'jpg', 'gif', 'png'))){
        if($ext == 'zip'){
            $archive = new PclZip($file['tmp_name']);
            foreach($archive->listContent() as $value){
                $filename = $value["filename"];
                if(preg_match('/\.php$/', $filename)){
                     exit("压缩包内不允许含有php文件!");
                 }
            }
            if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) {
                check_dir($dir);
                   exit("解压失败");
            }

            check_dir($dir);
            exit('上传成功!');
        }else{
            move_uploaded_file($file['tmp_name'], $temp_dir.'/'.$file['name']);
            check_dir($dir);
            exit('上传成功!');
        }
    }else{
        exit('仅允许上传zip、jpg、gif、png文件!');
    }
}

在上传时,使用白名单验证上传文件后缀

if(in_array($ext, array('zip', 'jpg', 'gif', 'png'))){

不过本上传点支持上传 zip 压缩包,且会将 zip 包解压到文件上传目录中,有可能会导致一些安全问题

if($ext == 'zip'){
            $archive = new PclZip($file['tmp_name']);
            foreach($archive->listContent() as $value){
                $filename = $value["filename"];
                if(preg_match('/\.php$/', $filename)){
                     exit("压缩包内不允许含有php文件!");
                 }
            }
            if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) {
                check_dir($dir);
                   exit("解压失败");
            }

            check_dir($dir);
            exit('上传成功!');
        }

首先会检测压缩包内是否含有 .php 文件,如果存在 .php 文件就直接退出解压流程

在解压完成后,会调用 check_dir() 方法再次检测解压出来的文件是否含有恶意文件

    function check_dir($dir){
        $handle = opendir($dir);
        while(($f = readdir($handle)) !== false){
            if(!in_array($f, array('.', '..'))){
                if(is_dir($dir.$f)){
                    check_dir($dir.$f.'/');
                 }else{
                    $ext = strtolower(substr(strrchr($f, '.'), 1));
                    if(!in_array($ext, array('jpg', 'gif', 'png'))){
                        unlink($dir.$f);
                    }
                }

            }
        }
    }

并且因为解压到的目录是一个随机生成的目录,目录名无法预测,与导致不能使用条件竞争方法

if(!is_dir($dir)){
        mkdir($dir);
    }

    $temp_dir = $dir.md5(time(). rand(1000,9999));
    if(!is_dir($temp_dir)){
        mkdir($temp_dir);
    }

首先来绕第一个过滤, 黑名单过滤了 php 文件,压缩包内不能含有 .php 文件,这里正则为 .php$ 限制了结尾

所以可以尝试 php3、php5、phtml 等绕过,不过服务端只配置了解析 php 文件,导致该类绕过不可用

根据 404 页面,发现使用的是 apache,很容易联想到 apache 的多后缀文件解析漏洞

这里选择上传一个 x.php.xxx 文件

通过 010editor 构造恶意压缩包,这里需要注意修改后的文件名长度与修改前一致,否则解压会报错

这里改为 /../../jason07.php.xxx

上传压缩包,访问 jason07.php.xxx,得到 flag

%00 截断绕过

话不多说,直接上题(CTFHUB)

%00 是 URL 编码中**空字节(null byte,\x00)**的表示方式

空字节在**C 语言等底层语言**中,常用作字符串的结束标志

例如,char filename[100] = "shell.php\x00.jpg"; 实际上等同于 shell.php\x00 之后的内容被忽略

%00 的使用是在路径上!

%00 的使用是在路径上!

%00 的使用是在路径上!

重要的话说三遍,如果在文件名上使用,就无法正常截断了

这个路径可能在 POST 数据包中,也可能在 URL 中

成功拿到 flag

双写后缀绕过

话不多说,直接上题(CTFHUB)

准备一个 *.pphphp 文件上传

后端会自动替换其中的 php 为空值,这样两边的 p + hp 自动合并成了 php

PNG 图片马绕过

话不多说,直接上题(PicoCTF)

上传木马回显必须包含 .png

修改文件名后发现回显文件头不对

直接在文件头前添加 PNG

上传成功

文件放在了 /uploads 目录下

文件名加 / 绕过

漏洞本质 Tomcat 配置了可写(readonly=false),导致我们可以往服务器写文件

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>0</param-value>
    </init-param>
    <init-param>
        <param-name>listings</param-name>
        <param-value>false</param-value>
    </init-param>
    <init-param>
        <param-name>readonly</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

虽然 Tomcat 对文件后缀有一定检测(不能直接写 JSP),但我们使用一些文件系统的特性(如 Linux下可用 /)来绕过了限制

Python WebShell

话不多说,直接上题(BugKu CTF)

打开网页是一个文件上传

这是 Python 的 Flask 框架,编写 Python 的木马

import os
os.system('cat /flag')

上传文件

代码被执行拿到 flag

Nginx 文件上传绕过(CVE-2013-4547)

这个漏洞的原理是,Nginx 错误地解析了请求的 URI,错误地获取到用户请求的文件名,导致出现权限绕过、代码执行等连带影响

location ~ \.php$ {
    include        fastcgi_params;

    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  /var/www/html$fastcgi_script_name;
    fastcgi_param  DOCUMENT_ROOT /var/www/html;
}

正常情况下(关闭 pathinfo 的情况下),只有 .php 后缀的文件才会被发送给 Fastcgi 解析

而存在 CVE-2013-4547 的情况下,我们请求 1.gif[0x20][0x00].php,这个 URI 可以匹配上正则 \.php$,可以进入这个 Location 块;但进入后,Nginx 却错误地认为请求的文件是 1.gif[0x20],就设置其为 SCRIPT_FILENAME 的值发送给Fastcgi

Fastcgi 根据 SCRIPT_FILENAME的值进行解析,最后造成了解析漏洞

上传反弹 Shell,先添加两个空格

将两个 20 的最后一个改为 00

上传成功

访问上传的文件

成功连接

JavaScript 加密绕过

话不多说,直接上题(BugKu CTF)

实战打网站

先去注册账号

然后登录

看到头像是一个上传点

上传图片试试

头像变了确认可以上传

再次上传打开 BurpSuite 抓包拦截

前端进行了 Base64 编码,同时设置了文件类型

修改类型为 PHP,上传 Base64 编码的一句话木马

打开中国蚁剑测试连接

拿到 flag

Content-type 图片绕过

话不多说,直接上题(BugKu CTF)

打开网页正常的文件上传

strpos() 函数查找字符串在另一字符串中第一次出现的位置(区分大小写)

所以这里使用大小写混淆绕过

常规的 php 后缀被替换,换成 php4 可以

最后是修改 Content-Type 类型为图片即可

上传成功

使用蚁剑连接拿到 flag

disable_functions 绕过

话不多说,直接上题(BugKu CTF)

加密混淆,这一步因为解密网站挂了就跳过

网上找的图

使用中国蚁剑远程连接

访问别的目录报错,应该设置了 disable_function() 函数

基于黑名单来实现对某些函数使用的限制

使用蚁剑的插件绕过,网不行的自己去 GitHub 上下插件

LD_PRELOAD 是一个可选的 Unix 环境变量, 包含一个或多个共享库或共享库的路径

它允许你定义在程序运行前优先加载的动态链接库,即我们可以自己生成一个动态链接库加载

以覆盖正常的函数库,也可以注入恶意程序,执行恶意命令

最后远程连接这个新木马就行了,密码一样的

phtml 后缀绕过

话不多说,直接上题(BUUCTF)

考察的是文件上传

上传正常的 PHP 改 MIME 都不行

尝试修改后缀为 php3、Php、phtml 等,发现 phtml 可以

GIF 文件头绕过

话不多说,直接上题(BUUCTF)

继上一节发现它过滤 < 及 ? 之后

可以使用第一节的 JavaScript WebShell 绕过

但还是被拦截了,要求是图片类型

添加一个 GIF 的文件头绕过

上传成功

扫描后台有个 upload 目录可以访问

打开蚁剑连接我们上传的文件

成功拿到 flag

JavaScript 验证绕过

话不多说,直接上题(BUUCTF)

与上一节方法一样,只不过多了一个前端 JS 验证

浏览器设置禁用 JS 就可以绕过

上传文件成功

拿到 flag

.htaccess 解析绕过

话不多说,直接上题(BUUCTF)

打开网页考察文件上传

利用 Apache 的 .htaccess 解析漏洞,将要上传的文件按 PHP 解析

上传时修改 MIME 类型为图片类

上传成功

接着上传木马文件(要与 .htaccess 中的保持一致)

打开中国蚁剑建立远程连接

成功拿到 flag

评论