Java代码审计Mybatis注入文件上传下载读取(非常详细!!)

目录

0x00 前言

0x01 Mybatis注入审计 - 若依(Ruoyi)后台管理系统 4.6.0

1、项目介绍与部署 - Ruoyi

2、若依 Ruoyi - Mybatis注入 - 代码审计

3、代审常搜词 - Java SQL 注入

0x02 文件上传漏洞审计 - Inxedu && Tmall

1、项目介绍与部署 - Inxedu && Tmall

2、Inxedu - 前台文件上传 - 代码审计

3、Tmall - 后台文件上传 - 代码审计

0x03 文件下载漏洞审计 - 若依(Ruoyi)后台管理系统 4.5.0

1、项目介绍与部署

2、若依 Ruoyi - 文件下载 - 代码审计

0x04 文件读取漏洞审计 - Oasys

1、项目介绍与部署

2、Oasys - 文件读取 - 代码审计

3、代审常搜词 - 文件上传&下载&读取


0x00 前言

希望和各位大佬一起学习,如果文章内容有错请多多指正,谢谢! 

个人博客链接:CH4SER的个人BLOG – Welcome To Ch4ser's Blog

0x01 Mybatis注入审计 - 若依(Ruoyi)后台管理系统 4.6.0

1、项目介绍与部署 - Ruoyi

若依(Ruoyi)是一个开源的后台管理系统,可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA。

版本:RuoYi-v4.6.0

项目部署:

  • 修改 application-druid.yml 中的数据库连接密码,在 application.yml 中可修改服务器默认端口(默认 80)
  • 创建名为 ry 的数据库,导入 quartz.sql、ry_20201214.sql 两个 SQL 文件执行(MySQL 版本推荐 5.7.26)
  • Maven clean && install,启动项目即可(注意 Project Structure SDK 版本最好为 1.8)
  • 默认管理员账号密码:admin/admin123

2、若依 Ruoyi - Mybatis注入 - 代码审计

2.1、明确项目框架及使用组件

首先要做的是明确项目的框架以及有没有用到 Mybatis 组件,当看到 controller、service、mapper 推测项目为 Spring 框架搭建

并且,在 External Libraries 看到项目有用到 Mybatis 和 Spring 相关组件,更加确定了我们的想法。

2.2、Mapper->Service->Controller->得到Mapping路由信息

我之前的文章提到 Mybatis 下的 SQL 注入有 3 种: order by 注入、搜索框 like 注入、in 之后多个参数的注入

总的来说,要找 Mybatis 注入点只需要全局搜索含有 ${ 的 Mapper 文件即可,全局搜索快捷键:Ctrl+Shift+F

选择跟进 SysDeptMapper.xml,很明显这里存在 in 的注入

来到 SysDeptMapper.xml,由 SQL 语句得知是与更新相关的操作,并且得知可控变量为 ${ancestors}。

Ctrl+左键点击 updateDeptStatus 跟进到 SysDeptMapper.java 可以看到该 Mapper 方法的声明,看到其传入了一个 SysDept 类。

Ctrl+左键点击 SysDept,跟进到该类得知其含有名为 ancestors 的成员变量,于是便知晓了 SysDeptMapper.xml 里可控变量 ${ancestors} 就是 SysDept 类的成员变量。

选中 updateDeptStatus - 右键 - Find Usages,在 Unclassified 下面定位到引用 updateDeptStatus 的文件,得知该文件为 SysDeptServiceImpl.java。

而 SysDeptServiceImpl.java 是一个 Service 层的文件,如果想要知道漏洞功能点的路由信息要到 Controller 层去找,所以还要继续跟进 updateParentDeptStatus(同样 Find Usages)

于是跟进到了 SysDeptServiceImpl.java,很明显这还是 Service 层的文件,同样的方法继续跟进。

最终跟进到了 SysDeptController.java,这才是我们需要的 Controller 层的文件,可以得知以下信息:

  • 该功能点为部门管理相关操作,由注释"保存"推测大概率为编辑功能
  • 结合上下代码,得知完整 Mapping 路由为:/system/dept/edit
  • 由 PostMapping 知,提交方式为 POST
  • 前端会传入一个 SysDept 类的对象 dept,得知注入点为 dept.ancestors,也就是在 POST 请求体里的 ancestors 字段写入 Payload

2.3、漏洞验证 - Ruoyi Mybatis 注入

因为该功能点提交方式为 POST,所以如果直接访问 /system/dept/edit 是不行的,这里根据之前得知的信息,我们可以定位到部门管理的编辑操作。

打开 Burp 抓包,填写好编辑的信息并提交,找到 URL 为 /system/dept/edit 的数据包,发送到 Repeater 模块。

发现 POST 请求体里没有 ancestors 字段,于是尝试将 POST 请求体替换为以下 POC。

POC:
DeptName=1&DeptId=100&ParentId=12&Status=0&OrderNum=1&ancestors=0)or(extractvalue(1,concat((select user()))));#

在 Response 里观察到 @localhost,说明确实存在注入,漏洞验证成功。

3、代审常搜词 - Java SQL 注入
Statement
createStatement
PrepareStatement
like '%${
in(${
in (${
select
update
insert
delete
${
order by
setObject(
setInt(
setString(
setSQLXML(
createQuery(
createSQLQuery(
createNativeQuery
.......

0x02 文件上传漏洞审计 - Inxedu && Tmall

1、项目介绍与部署 - Inxedu && Tmall

项目介绍:因酷时代 Inxedu 在线教育系统 V2.0.6 是一个开源的网校项目,Tmall 是一个模拟天猫购物的项目,在我之前的文章里有提到过(SpringBoot安全&Mybatis注入&Actuator泄露&Swagger自动化 – CH4SER的个人BLOG)

Inxedu V2.0.6 部署:

  • IDEA 打开 demo_inxedu_open,选择 Maven Project
  • 修改 project.properties 中的 username、password、host(数据库主机地址)
  • 导入 SQL 文件 demo_inxedu_v2_0_open.sql 执行(高版本 MySQL 会出错,我用的 MySQL 5.2.17)
  • Add Configurations - Tomcat Server - 选择 Local(Remote 应该也可以)
  • Tomcat 9.0.80 - Edit Configurations - Server - 修改 HTTP port 和 URL 为 82(默认),点击弹出来的 Fix 按钮
  • Tomcat 9.0.80 - Edit Configurations - Deployment - 设置 Application context 为 / (和配置文件里的项目路径保持一致)
  • Maven clean && install,启动项目即可(注意 Project Structure SDK 版本最好为 1.8)
  • 默认管理员账号密码:admin/111111,某普通学员账号 lmx193@162.com/123456

Tmall 部署:

  • 修改 application.properties 数据库连接配置(使用 MySQL 5.7.26)
  • 创建数据库 tmalldemodb,导入 SQL 文件 tmalldemodb.sql 执行
  • Maven clean && install,启动项目即可(注意 Project Structure SDK 版本最好为 1.8)
  • 默认管理员账号密码:admin/123456,某普通用户账号 MRJIANG/123456
  • 前台地址:http://localhost:8088/tmall
  • 后台地址:http://localhost:8088/tmall/admin

2、Inxedu - 前台文件上传 - 代码审计

2.1、审计思路:

寻找并测试文件上传功能点,抓包得到对应路由等信息,从而定位到功能实现的具体代码(代码溯源),然后审计其是否存在漏洞。

2.2、审计流程

登录学员账号 - 个人资料设置 - 个人头像,尝试上传头像同时 BurpSuite 抓包,得到上传头像路由信息为 "/image/gok4","fileType=jpg,gif,png,jpeg"

在项目代码中全局搜索 "/image/gok4" 或 "fileType=jpg,gif,png,jpeg",定位到的都是 jsp 或 js 文件,没有太大价值。

实际上这个项目是将处理文件上传的代码封装到了一个 Jar 包然后引用的,一般情况下如果碰到搜不到的情况,就去 pom.xml 里看看有没有声明依赖的 Jar 包,如下:

IDEA 自带反编译功能,能够将 Class 文件转换为 Java 文件,所以点进 Jar 包能看到 Java 代码

处理文件上传的代码一般放在 controller 里面,由此定位到 ImageUploadController.class

搜索路由 "/gok4",定位到处理文件上传的方法,具体代码如下:

该方法的逻辑如下:
1、检查上传文件的大小,如果超过4M,则返回错误信息。
2、根据fileType参数判断文件类型是否符合要求,如果文件类型不符合或者后缀为jsp,则返回错误信息。
3、根据上传文件的后缀和param参数,确定上传文件的保存路径。
4、创建保存文件的目录(如果目录不存在)。
5、将上传文件保存到指定的路径。
6、返回上传成功的响应信息,包括文件路径和状态码。
7、如果发生异常,记录错误日志,并返回上传失败的错误信息。

上图代码中,关键点为 if (fileType.contains(ext) && !"jsp".equals(ext)),即如果文件类型符合且后缀不为 JSP 才进行下一步的上传操作。
跟进 "ext",其来自于 FileUploadUtils.getSuffix(uploadfile.getOriginalFilename()),于是跟进 "getSuffix" 方法,其代码中没有过滤逻辑,只是简单获取后缀名。

跟进 "fileType" 对象,发现其来自于 Request 提交的变量 "fileType",也就是之前 BurpSuite 抓包发现的 "fileType=jpg,gif,png,jpeg"

将已知的信息串联起来,总结这段代码的判断逻辑为:文件后缀包含 jpg,gif,png,jpeg,且不为 jsp 即进行下一步上传操作。

2.3、漏洞利用

对于 "fileType" 显然是可以抓包修改的,所以得出漏洞利用的思路为:抓包修改 "fileType=jpg,gif,png,jpeg,jspx" ,上传 jspx 的 webshell 即可(我用的冰蝎自带的)

点击发包,在后续包中又观察到了上传的位置 http://127.0.0.1:82/images/upload/temp/20231219/1702990600563.jspx

冰蝎连接成功,如下:

3、Tmall - 后台文件上传 - 代码审计

3.1、审计思路

通过搜索 Java 文件操作常用函数,定位到功能点对应代码段,审计其是否存在漏洞(常规审计思路)

3.2、审计流程

搜索 "new file(" 关键字 - 定位到 controller 层文件 AccountController.java,从注释和路由信息("admin/uploadAdminHeadImage")推测该功能点大概率是在后台。

为了方便阅读,我重新加上了注释,如下:

跟进文件保存的路径:"filePath" <- "fileName" <- "extension" <- "originalFileName.substring" <- "file.getOriginalFileName" <- "@RequestParam MultipartFile file"

看来好像没有做过滤,怀疑是否重写了 new File() 将过滤加在里面,跟进之后发现是 Java 原生的,所以总的来说这段代码实质上就是没有任何过滤的。

问题来了,这个漏洞是后台的,如果只有普通用户权限,进不去后台,那么该如何利用呢?

这里我的思路是继续审计过滤器 filter 有无鉴权漏洞,所以定位到 AdminPermissionFilter.java,审计其核心方法 doFilter()。

为了方便阅读,我重新加上了注释,如下:

这里鉴权逻辑存在问题,只要 URI 含有 "/admin/login" 或 "/admin/account" 就放行了,显然是不合理的。

于是想到构造 URI 类似:/admin/login/../../tmall/admin/uploadAdminHeadImage

3.3、漏洞利用

首先用管理员账号登录后台测试,发现确实存在文件上传漏洞,成功上传 jsp 文件。

接下来注销管理员账号,再次发包,发现提示我们需要登录,无法上传。

根据代码的鉴权逻辑,构造 URI 类似:/admin/login/../../tmall/admin/uploadAdminHeadImage,重新发包,成功上传 webshell

这里有 JS 验证限制只能选择图片上传,随便绕一下即可。

冰蝎连接成功,如下:

0x03 文件下载漏洞审计 - 若依(Ruoyi)后台管理系统 4.5.0

1、项目介绍与部署

若依(Ruoyi)是一个开源的后台管理系统,可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA。

版本:RuoYi-v4.5.0(不用 4.6.0 版本的原因是修复了下述的文件下载漏洞)

项目部署:

  • 修改 application-druid.yml 中的数据库连接密码,在 application.yml 中可修改服务器默认端口(默认 80)
  • 创建名为 ry 的数据库,导入 quartz.sql、ry_20201214.sql 两个 SQL 文件执行(MySQL 版本推荐 5.7.26)
  • Maven clean && install,启动项目即可(注意 Project Structure SDK 版本最好为 1.8)
  • 默认管理员账号密码:admin/admin123

2、若依 Ruoyi - 文件下载 - 代码审计

2.1、审计思路

通过搜索 Java 文件操作常用函数,定位到功能点对应代码段,审计其是否存在漏洞(常规审计思路)

2.2、审计流程

全局搜索 "new FileInputStream(" ,定位到 FileUtils.java 的 writeBytes 方法,根据其代码得知是与文件输出相关的操作。

选中 writeBytes 方法 Find Usages,定位到 CommonController.java 的 resourceDownload 方法,其路由为 "/common/download/resource"

该方法调用 writeBytes 传入了 downloadPath, response.getOutputStream() 两个参数,即下载文件的路径、输出流对象,重点应该关注 "downloadPath" 是怎么来的。

跟踪得知,"downloadPath" 由 localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX) 拼接而成,

localPath 来自 Global.getProfile(),跟进 "getProfile" 得知其返回的是一个全局变量,将其调试打印输出得知为 "E:/xxxxxx/RuoYi-v4.5.0/files"(application.yml 里可以修改)

跟进 "substringAfter",其代码如下所示:(若字符串 str 和分隔符 separator 不为空,则截取分隔符之后的字符串返回)

现在问题来到了 StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX) 传入的两个参数:resource, Constants.RESOURCE_PREFIX

其中 "resource" 是 GET 请求传入的参数,而对于 "RESOURCE_PREFIX" ,跟进后发现其等于固定值 "/profile",如下所示:

由上图知 StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX) 实际上是截取分隔符 "/profile" 之后的 "resource" 字符串

所以 downloadPath 实际等于 "E:/xxxxxx/RuoYi-v4.5.0/files" + 经过处理后的 GET 请求传入的参数 resource 二者拼接而成,最后下载的文件也就是这个路径所对应的文件。

反观整个代码段,关键就在于有没有对 GET 请求传入的参数 resource 做过滤,显然这里并没有,如此一来便可以在 GET 请求传入的参数 resource 做手脚。

2.3、漏洞利用

尝试下载数据库配置文件 application-druid.yml,已知其路径为:E:/xxxxxx/RuoYi-v4.5.0/ruoyi-admin/src/main/resources/application-druid.yml

则需构造 resource = /profile/../ruoyi-admin/src/main/resources/application-druid.yml,经过 "/profile" 截取处理后,

此时 downloadPath = E:/xxxxxx/RuoYi-v4.5.0/files/../ruoyi-admin/src/main/resources/application-druid.yml(localPath + resource),才能下载到 application-druid.yml

构造 payload 如下:

/common/download/resource?resource=/profile/../ruoyi-admin/src/main/resources/application-druid.yml

成功拿下数据库配置文件 application-druid.yml,如下:

0x04 文件读取漏洞审计 - Oasys

1、项目介绍与部署

Oasys 是一个 OA 办公自动化系统,基于 Springboot 框架开发,使用 Maven 进行项目管理,前端采用freemarker模板引擎,集成 JPA、Mybatis 等框架。

项目部署:

  • 修改 application.properties 中的数据库连接密码和服务器默认端口(默认 8088)
  • 创建名为 oasys 的数据库,导入 oasys.sql SQL 文件执行(MySQL 版本推荐 5.7.26)
  • Maven clean && install,启动项目即可(注意 Project Structure SDK 版本最好为 1.8)
  • 默认账号密码:soli/123456

2、Oasys - 文件读取 - 代码审计

2.1、审计思路

通过搜索 Java 文件操作常用函数,定位到功能点对应代码段,审计其是否存在漏洞(常规审计思路)

2.2、审计流程

全局搜索 "new FileInputStream(" ,定位到 UserpanelController.java 的 image 方法,结合前后代码得到路由为 "/image/**"

着重关注 IOUtils.readFully(input, data),该代码为读取文件内容,其中 "input" 参数为所要读取的文件(FileInputStream 流),而 "data" 参数是为之分配的内存空间。

继续跟进 "input",由于 FileInputStream input = new FileInputStream(f.getPath()),所以跟进到 File f = new File(rootpath, path)

跟进参数 "rootpath",发现其在 application.properties 里声明为固定值:"E:/xxxxxx/oa_system-master/src/main/resources/static/images"

跟进参数 "path",发现其等于 "startpath" 将字符串 "/image" 替换为空之后的字符串,而 "startpath" 则来自 Request 请求的 URI

所以 File f = new File(rootpath, path) 返回的其实是 "E:/xxxxxx/oa_system-master/src/main/resources/static/images" + 经处理后的 URI 二者拼接成的文件路径对应的文件,这样一来 f.getPath() 返回的自然也是这个路径。

反观整个代码段,关键就在于有没有对 URI 做过滤,显然这里并没有,如此一来便可以在 Request 请求的 URI 做手脚。

2.3、漏洞利用

考虑读取数据库配置文件 application.properties,已知其绝对路径为:E:\xxxxxx\oa_system-master\src\main\resources\application.properties

最终构造 Payload 如下:(但不知道为啥没读取到,有无大佬告诉一下?)

/image//image..//image../application.properties

3、代审常搜词 - 文件上传&下载&读取
new File(
String path
String fileName
new FileInputStream(
new FileOutputStream(
new FileReader
response.setContentType("application/octet-stream;
file.delete();
FileUtils.
new ZipEntity(
file.getName(
.unzip(
.mkdirs(
stream.write(
save2File(
fos、fis.close()
MultipartFile(
file.getOriginalFilename(
IOUtil
FileUtil
download
fileName
filePath
write
getFile
getPath
getWriter
上传 // 搜注释
下载 // 搜注释
........

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

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

相关文章

Java智慧工地源码 SAAS智慧工地源码 智慧工地管理可视化平台源码 带移动APP

一、系统主要功能介绍 系统功能介绍&#xff1a; 【项目人员管理】 1. 项目管理&#xff1a;项目名称、施工单位名称、项目地址、项目地址、总造价、总面积、施工准可证、开工日期、计划竣工日期、项目状态等。 2. 人员信息管理&#xff1a;支持身份证及人脸信息采集&#…

MyBatis:动态 SQL 标签

MyBatis 动态 SQL 标签if 标签where 标签trim 标签choose 、when 、otherwise 标签foreach 标签附 动态 SQL 标签 MyBatis 动态 SQL 标签&#xff0c;是一组预定义的标签&#xff0c;用于构建动态的 SQL 语句&#xff0c;允许在 SQL 语句中使用条件、循环和迭代等逻辑。通过使…

利用Matplotlib画简单的线形图

实验题目&#xff1a;简单的线形图 实验目的&#xff1a;利用Matplotlib画简单的线形图 实验环境&#xff1a;海豚大数据和人工智能实验室&#xff0c;使用的Python库 名称 版本 简介 numpy 1.16.0 线性代数 Pandas 0.25.0 数据分析 Matplotlib 3.1.0 数据可视化 …

备份至关重要!如何解决iCloud的上次备份无法完成的问题

将iPhone和iPad备份到iCloud对于在设备发生故障或丢失时确保数据安全至关重要。但iOS用户有时会收到一条令人不安的消息&#xff0c;“上次备份无法完成。”下面我们来看看可能导致此问题的原因&#xff0c;如何解决此问题&#xff0c;并使你的iCloud备份再次顺利运行。 这些故…

技术分享-Jenkins

持续集成及Jenkins介绍 软件开发生命周期叫SDLC&#xff08;Software Development Life Cycle&#xff09;&#xff0c;集合了计划、开发、测试、部署过程。 在平常的开发过程中&#xff0c; 需要频繁地&#xff08;一天多次&#xff09;将代码集成到主干&#xff0c;这个叫持…

闭包 闭包理解 闭包的应用实例

闭包 形成闭包的条件&#xff1a;一个函数访问外部的变量就形成了闭包 用闭包的好处&#xff1a; (1)可以通过闭包函数形成独立实例的变量 (2)不会造成全局污染 代码调试&#xff0c;演示闭包形成过程 <script> //函数内部访问外部的变量&#xff0c;就形成了闭包functi…

Leetcode 406 根据身高重建队列

题意理解&#xff1a; people [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]] 给定一个二维数组&#xff0c;&#xff08;h,k&#xff09;h表示此人身高&#xff0c;k表示前面有几个人比他高。 我们按照每个人的h,k两个维度的需求给每个人排在合适的位置。 如&#xff1a; [5,0][7,0]…

深入浅出堆排序: 高效算法背后的原理与性能

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》 《高效算法》 ⛺️生活的理想&#xff0c;就是为了理想的生活! &#x1f4cb; 前言 &#x1f308;堆排序一个基于二叉堆数据结构的排序算法&#xff0c;其稳定性和排序效率在八大排序中也…

ctfshow sql 195-200

195 堆叠注入 十六进制 if(preg_match(/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\|\"|select|union|or|and|\x26|\x7c|file|into/i, $username)){$ret[msg]用户名非法;die(json_encode($ret));}可以看到没被过滤&#xff0c;select 空格 被过滤了&#xff0c;可…

制造行业定制软件解决方案——工业信息采集平台

摘要&#xff1a;针对目前企业在线检测数据信号种类繁多&#xff0c;缺乏统一监控人员和及时处置措施等问题。蓝鹏测控开发针对企业工业生产的在线数据的集中采集分析平台&#xff0c;通过该工业信息采集平台可将企业日常各种仪表设备能够得到数据进行集中分析处理存储&#xf…

VM——计算流程执行耗时

1、计算同一个流程内的耗时&#xff0c;可以直接用“耗时统计”模块&#xff1b; 2、计算多个流程的运行耗时&#xff0c;需要使用“脚本”&#xff0c;利用C#函数计算耗时 首先&#xff0c;记录起始时间&#xff0c;保存到string类型的全局变量中&#xff0c; curTmStr Dat…

C++之深拷贝和浅拷贝

目录 浅拷贝 深拷贝 赋值运算符重载的深拷贝 在学习C类和对象时我们学习了浅拷贝&#xff0c;本期我们将再次回顾浅拷贝并为大家讲述深拷贝的概念。 浅拷贝 在学习类和对象时我们学习了拷贝构造函数的概念&#xff0c;而且我们也知道&#xff0c;因为拷贝构造函数属于类的默…

Go后端开发 -- 环境搭建

Go后端开发 – 环境搭建 文章目录 Go后端开发 -- 环境搭建一、环境配置二、IDE的选择三、使用go mod构建项目1.初始化项目2.添加依赖项3.运行项目 四、环境报错1.VS Code中gopls报错 一、环境配置 Go官网下载地址&#xff1a;https://golang.org/dl/ https://go.dev/dl/ Go官方…

JavaWeb笔记之前端开发JQuery

一、引言 1.1 概述 jQuery是一个快速、简洁的JavaScript代码库。jQuery设计的宗旨是“Write Less&#xff0c;Do More”&#xff0c;即倡导写更少的代码&#xff0c;做更多的事情。它封装JavaScript常用的功能代码&#xff0c;提供一种简便的 JavaScript操作方式&#xff0c…

麒麟V10 ARM 离线生成RabbitMQ docker镜像并上传Harbor私有仓库

第一步在外网主机执行&#xff1a; docker pull arm64v8/rabbitmq:3.8.9-management 将下载的镜像打包给离线主机集群使用 在指定目录下执行打包命令&#xff1a; 执行&#xff1a; docker save -o rabbitmq_arm3.8.9.tar arm64v8/rabbitmq:3.8.9-management 如果懒得打包…

国产低成本Wi-Fi SoC解决方案芯片ESP8266与ESP8285对比差异

目录 ESP8266与ESP8285对比差异微信号&#xff1a;dnsj5343ESP8285简介ESP8285 主要特性Wi-Fi特性射频模块CPU特性硬件软件 ES8285 8266通用开发板 ESP8266与ESP8285对比差异 ESP8285相当于在ESP8266基础上多加了1/2MB Flash&#xff0c; ESP8285与ESP8266同用一套SDK&#xf…

落叶归根:递归思想在二叉树叶子节点类问题中的妙用

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》 《高效算法》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 一、递归的介绍二、递归算法的妙用2.1 二叉树结点个数2.2 二叉树叶子结点个数2.3 二叉树第k层结点个数2.4 二叉树…

基于比较的排序算法总结(java实现版)

目录 什么是基于比较的排序算法 什么是排序算法的稳定性 基础排序算法的稳定性 插入排序法 希尔排序法 冒泡排序法 总结 高级算法的稳定性 快速排序法 堆排序法 归并排序法 总结 注意 什么是基于比较的排序算法 基于比较的排序算法定义&#xff1a;之所以能给元素…

安装gnvm,nodejs,npm使用方法

安装gnvm,nodejs,npm使用方法 一、安装gnvm gnvm.exe下载地址&#xff1a; https://download.csdn.net/download/hsg77/88651752 http://ksria.com/gnvm/#download 二、配置gnvm环境变量 新建目录&#xff0c;如&#xff1a;d:/nodejs 并把gnvm.exe存储到此目录 并把d:/node…

【MATLAB第85期】基于MATLAB的2023年智能进化算法/元启发式算法合集(持续更新)

【MATLAB第85期】基于MATLAB的2023年智能进化算法/元启发式算法合集&#xff08;持续更新&#xff09; 1.海象进化算法&#xff08;Walrus Optimization Algorithm&#xff09; 作者&#xff1a;Pavel Trojovsk and Mohammad Dehghani 2.暴龙优化算法&#xff08;Tyrannosa…