This commit is contained in:
jhin
2022-05-31 16:08:05 +08:00
commit e57fad1815
12 changed files with 773 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/rsasZipToExcel.iml" filepath="$PROJECT_DIR$/.idea/rsasZipToExcel.iml" />
</modules>
</component>
</project>

9
.idea/rsasZipToExcel.iml generated Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

41
cmd/cmd.go Normal file
View File

@@ -0,0 +1,41 @@
package cmd
import (
"flag"
"rsasZipToExcel/pkg"
)
func Runner() {
//命令行
var zipFile, outputFilename string
flag.StringVar(&zipFile, "z", "", "-z 包含漏洞的zip文件")
flag.StringVar(&outputFilename, "o", "", "-o 输出的文件名")
flag.Parse()
//拆分excel
if outputFilename == "" {
outputFilename = "output"
}
//解析zip
err := pkg.MergeRsasVulnToExcel(zipFile, outputFilename)
if err != nil {
print(err.Error())
}
//匹配excel
//合并输出
}
//同比上个月漏洞情况
//初始化rsas
//初始化yb
//读取配置 yaml
//定时扫描
//触发发送?

27
go.mod Normal file
View File

@@ -0,0 +1,27 @@
module rsasZipToExcel
go 1.17
require (
github.com/antchfx/htmlquery v1.2.4
github.com/schollz/progressbar/v3 v3.8.6
github.com/xuri/excelize/v2 v2.6.0
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3
)
require (
github.com/antchfx/xpath v1.2.0 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8 // indirect
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 // indirect
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
)

67
go.sum Normal file
View File

@@ -0,0 +1,67 @@
github.com/antchfx/htmlquery v1.2.4 h1:qLteofCMe/KGovBI6SQgmou2QNyedFUW+pE+BpeZ494=
github.com/antchfx/htmlquery v1.2.4/go.mod h1:2xO6iu3EVWs7R2JYqBbp8YzG50gj/ofqs5/0VZoDZLc=
github.com/antchfx/xpath v1.2.0 h1:mbwv7co+x0RwgeGAOHdrKy89GvHaGvxxBtPK0uF9Zr8=
github.com/antchfx/xpath v1.2.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o=
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/schollz/progressbar/v3 v3.8.6 h1:QruMUdzZ1TbEP++S1m73OqRJk20ON11m6Wqv4EoGg8c=
github.com/schollz/progressbar/v3 v3.8.6/go.mod h1:W5IEwbJecncFGBvuEh4A7HT1nZZ6WNIL2i3qbnI0WKY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8 h1:3X7aE0iLKJ5j+tz58BpvIZkXNV7Yq4jC93Z/rbN2Fxk=
github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.6.0 h1:m/aXAzSAqxgt74Nfd+sNzpzVKhTGl7+S9nbG4A57mF4=
github.com/xuri/excelize/v2 v2.6.0/go.mod h1:Q1YetlHesXEKwGFfeJn7PfEZz2IvHb6wdOeYjBxVcVs=
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 h1:OAmKAfT06//esDdpi/DZ8Qsdt4+M5+ltca05dA5bG2M=
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 h1:iU7T1X1J6yxDr0rda54sWGkHgOp5XJrqm79gcNlC2VM=
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c=
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

7
main.go Normal file
View File

@@ -0,0 +1,7 @@
package main
import "rsasZipToExcel/cmd"
func main() {
cmd.Runner()
}

507
pkg/rsas.go Normal file
View File

@@ -0,0 +1,507 @@
package pkg
import (
"archive/zip"
"errors"
"fmt"
"github.com/antchfx/htmlquery"
"github.com/schollz/progressbar/v3"
"github.com/xuri/excelize/v2"
"golang.org/x/net/html"
"io"
"regexp"
"strconv"
"strings"
)
func RsasInit() *RsasScanner {
return &RsasScanner{}
}
func (RsasScanner *RsasScanner) AnalyseZip(zipFile string) bool {
//var filenames []string
print("解析zip: " + zipFile)
r, err := zip.OpenReader(zipFile)
if err != nil {
return false
}
defer r.Close()
var htmlAllVulnInfos []HtmlAllVulnInfo
for _, f := range r.File {
//println(f.Name)
re := regexp.MustCompile(`host/.*?.html`)
htmlFilename := re.FindAllString(f.Name, -1)
if len(htmlFilename) >= 1 {
htmlContent := GetHtmlContent(f)
if htmlContent != "" {
htmlAllVulnInfo := QueryHtmlInfo(htmlContent)
//for _, vuln := range htmlAllVulnInfo.HtmlVulnInfos {
// fmt.Printf(vuln.Solution)
//}
htmlAllVulnInfos = append(htmlAllVulnInfos, htmlAllVulnInfo)
}
}
}
for _, eachHtmlVuln := range htmlAllVulnInfos {
for _, eachVuln := range eachHtmlVuln.HtmlVulnInfos {
RsasScanner.AllVulnInfos = append(RsasScanner.AllVulnInfos, eachVuln)
}
}
return true
}
func MergeRsasVulnToExcel(zipFile string, outputFilename string) error {
//print("执行中")
if zipFile == "" {
return errors.New("请输入压缩文件文件名, -h 弹出帮助菜单")
}
rsas := RsasInit()
rsas.AnalyseZip(zipFile)
rsas.GenerateXlsx(outputFilename)
//fmt.Printf("%v", rsas.AllVulnInfos)
return nil
}
func GetHtmlContent(filename *zip.File) string {
//println("打印..")
htmlContent, err := filename.Open()
if err != nil {
println("解析html有问题")
}
//io流转string
if b, err := io.ReadAll(htmlContent); err == nil {
return string(b)
}
return ""
}
func QueryHtmlInfo(content string) (htmlAllVulnInfo HtmlAllVulnInfo) {
//var htmlAllVulnInfo HtmlAllVulnInfo
doc, err := htmlquery.Parse(strings.NewReader(content))
if err != nil {
println(err)
}
//println(htmlquery.InnerText(ip)) //ip
ip := htmlquery.FindOne(doc, "//*[@id=\"content\"]/div[2]/table[2]/tbody/tr/td[1]/table/tbody/tr[1]/td")
if strings.Contains(content, "非常安全0分") {
println(htmlquery.InnerText(ip) + " 无漏洞")
} else {
vulnDetail := htmlquery.FindOne(doc, "//*[@id=\"vuln_list\"]/tbody")
//ip := htmlquery.FindOne(doc, "//*[@id=\"content\"]/div[2]/table[2]/tbody/tr/td[1]/table/tbody/tr[1]/td")
nodes := htmlquery.Find(vulnDetail, "//tr")
htmlAllVulnInfo = FindVulnDetails(nodes, ip)
//htmlVulnInfo.IpAddress = htmlquery.InnerText(ip)
//htmlAllVulnInfo.HtmlVulnInfos = append(htmlAllVulnInfo.HtmlVulnInfos, htmlVulnInfo)
vulnSolutionNode := htmlquery.FindOne(doc, "//*[@id=\"vul_detail\"]/table")
solutionVulnInfos := FindVulnSolution(vulnSolutionNode)
for _, solutionVulnInfo := range solutionVulnInfos {
for i, htmlVulnInfo := range htmlAllVulnInfo.HtmlVulnInfos {
if htmlVulnInfo.VulnInfos == solutionVulnInfo.VulnInfos {
//println("找到解决方法:" + htmlVulnInfo.VulnInfos)
htmlAllVulnInfo.HtmlVulnInfos[i].Solution = solutionVulnInfo.Solution
htmlAllVulnInfo.HtmlVulnInfos[i].CVENumber = solutionVulnInfo.CVENumber
htmlAllVulnInfo.HtmlVulnInfos[i].Details = solutionVulnInfo.Details
htmlAllVulnInfo.HtmlVulnInfos[i].RiskLevel = solutionVulnInfo.RiskLevel
}
}
}
}
return htmlAllVulnInfo
}
func FindVulnDetails(nodes []*html.Node, ip *html.Node) HtmlAllVulnInfo {
var htmlAllVulnInfo HtmlAllVulnInfo
var htmlVulnInfo HtmlVulnInfo
filterFirstLine := false
for _, node := range nodes {
if !filterFirstLine {
filterFirstLine = true
continue
}
td := htmlquery.Find(node, "//td")
htmlVulnInfo.IpAddress = htmlquery.InnerText(ip)
htmlVulnInfo.Port = htmlquery.InnerText(td[0])
htmlVulnInfo.Protocol = htmlquery.InnerText(td[1])
htmlVulnInfo.Service = htmlquery.InnerText(td[2])
if JudgeMutiVulnName(td[3]) {
vulnInfos := AddMutiVulnName(td[3], htmlVulnInfo)
for _, vulnInfo := range vulnInfos {
htmlAllVulnInfo.HtmlVulnInfos = append(htmlAllVulnInfo.HtmlVulnInfos, vulnInfo)
}
} else {
htmlVulnInfo.VulnInfos = htmlquery.InnerText(htmlquery.FindOne(td[3], "//span"))
htmlVulnInfo.VulnInfos = strings.Replace(htmlVulnInfo.VulnInfos, "\r", "", -1)
htmlVulnInfo.VulnInfos = strings.Replace(htmlVulnInfo.VulnInfos, "\n", "", -1)
htmlVulnInfo.VulnInfos = strings.Replace(htmlVulnInfo.VulnInfos, " ", "", -1)
versionDiv, _ := htmlquery.QueryAll(td[3], "//div/div")
if len(versionDiv) == 0 {
htmlVulnInfo.ServiceDetail = ""
} else {
//println("端口" + htmlVulnInfo.Port)
//println(len(versionDiv))
htmlVulnInfo.ServiceDetail = TrimString(htmlquery.InnerText(versionDiv[0]))
//println("单漏洞版本号: " + htmlVulnInfo.ServiceDetail)
}
htmlVulnInfo.ServiceDetail = TrimString(htmlVulnInfo.ServiceDetail)
htmlAllVulnInfo.HtmlVulnInfos = append(htmlAllVulnInfo.HtmlVulnInfos, htmlVulnInfo)
}
//for _, n := range td {
//
// //text := strings.Replace(htmlquery.InnerText(n), "\r", "", -1)
// //text = strings.Replace(text, "\n", "", -1)
// //text = strings.Replace(text, " ", "", -1)
// println(text)
//}
}
return htmlAllVulnInfo
}
func JudgeMutiVulnName(td *html.Node) bool {
span := htmlquery.Find(td, "//span")
if len(span) > 1 {
return true
}
return false
}
func AddMutiVulnName(td *html.Node, vulnInfo HtmlVulnInfo) (vulnInfos []HtmlVulnInfo) {
spans := htmlquery.Find(td, "//span")
for i, span := range spans {
eachVulnInfo := HtmlVulnInfo{
IpAddress: vulnInfo.IpAddress,
Port: vulnInfo.Port,
Service: vulnInfo.Service,
Protocol: vulnInfo.Protocol,
}
//println("端口" + vulnInfo.Port)
versionDiv, _ := htmlquery.QueryAll(td, "//ul/li["+strconv.Itoa(i+1)+"]/div/div") ///html/body/div/div[4]/div[4]/div[2]/table/tbody/tr[8]/td[4]/ul/li[1]/div/div
if len(versionDiv) == 0 {
eachVulnInfo.ServiceDetail = ""
} else {
eachVulnInfo.ServiceDetail = TrimString(htmlquery.InnerText(versionDiv[0]))
//eachVulnInfo.ServiceDetail = htmlquery.SelectAttr(versionDiv, "class")
//println("多漏洞 版本号:" + eachVulnInfo.ServiceDetail)
}
eachVulnInfo.VulnInfos = htmlquery.InnerText(span)
eachVulnInfo.VulnInfos = strings.Replace(eachVulnInfo.VulnInfos, "\r", "", -1)
eachVulnInfo.VulnInfos = strings.Replace(eachVulnInfo.VulnInfos, "\n", "", -1)
eachVulnInfo.VulnInfos = strings.Replace(eachVulnInfo.VulnInfos, " ", "", -1)
vulnInfos = append(vulnInfos, eachVulnInfo)
}
return
}
//先提取所有漏洞修复,再根据漏洞名称分配至每个漏洞内。
func FindVulnSolution(vulnSolutionNode *html.Node) (solutionVulninfos []HtmlVulnInfo) {
var count int
var solutionVulnInfo HtmlVulnInfo
nodes := htmlquery.Find(vulnSolutionNode, "//tr")
for _, node := range nodes {
//匹配修复表格中漏洞名称
trClass := htmlquery.SelectAttr(node, "data-id")
if trClass != "" {
vulnName := htmlquery.InnerText(htmlquery.FindOne(node, "//td//span"))
vulnName = strings.Replace(vulnName, "\r", "", -1)
vulnName = strings.Replace(vulnName, "\n", "", -1)
vulnName = strings.Replace(vulnName, " ", "", -1)
solutionVulnInfo.VulnInfos = vulnName
//println(vulnName)
//漏洞等级
spanClass := htmlquery.FindOne(node, "//span")
className := htmlquery.SelectAttr(spanClass, "class")
if className != "" {
className = strings.Split(className, "_")[2]
solutionVulnInfo.RiskLevel = GetChineseRiskLevel(className)
//println(solutionVulnInfo.RiskLevel)
}
count += 1
}
trsolutionClass := htmlquery.SelectAttr(node, "class")
if trsolutionClass == "solution" || trsolutionClass == "solution hide" {
trsolutionTable := htmlquery.FindOne(node, "//table")
GetSolutionInfo(trsolutionTable, &solutionVulnInfo)
count += 1
}
if count == 2 {
count = 0
solutionVulninfos = append(solutionVulninfos, solutionVulnInfo)
solutionVulnInfo = HtmlVulnInfo{}
}
}
return
}
func GetChineseRiskLevel(level string) (chineseLevel string) {
if level == "low" {
return "低"
}
if level == "middle" {
return "中"
}
if level == "high" {
return "高"
}
return "未定级"
}
func GetSolutionInfo(htmlTable *html.Node, solutionVulnInfo *HtmlVulnInfo) {
tr := htmlquery.Find(htmlTable, "//tr")
for _, line := range tr {
th := htmlquery.FindOne(line, "//th")
if htmlquery.InnerText(th) == "详细描述" {
td := htmlquery.FindOne(line, "//td")
text := htmlquery.InnerText(td)
text = strings.Replace(text, "\r", "", -1)
text = strings.Replace(text, "\n", "", -1)
text = strings.Replace(text, " ", "", -1)
solutionVulnInfo.Details = text
}
if htmlquery.InnerText(th) == "解决办法" {
td := htmlquery.FindOne(line, "//td")
text := htmlquery.InnerText(td)
text = strings.Replace(text, "\r", "", -1)
text = strings.Replace(text, "\n", "", -1)
text = strings.Replace(text, " ", "", -1)
solutionVulnInfo.Solution = text
}
if htmlquery.InnerText(th) == "CVE编号" {
td := htmlquery.FindOne(line, "//td")
text := htmlquery.InnerText(td)
text = strings.Replace(text, "\r", "", -1)
text = strings.Replace(text, "\n", "", -1)
text = strings.Replace(text, " ", "", -1)
solutionVulnInfo.CVENumber = text
}
}
if solutionVulnInfo.CVENumber == "" {
solutionVulnInfo.CVENumber = "无cve编号"
}
}
func (RsasScanner RsasScanner) GenerateXlsx(output string) {
filename := output + ".xlsx"
line := len(RsasScanner.AllVulnInfos)
bar := progressbar.Default(int64(line))
excel := excelize.NewFile()
excel.NewSheet("主机漏洞清单")
excel.SetSheetRow("主机漏洞清单", "A1", &[]string{"序号", "漏洞名称", "风险等级", "漏洞描述", "整改建议", "IP地址", "端口", "协议", "服务", "漏洞CVE编号", "版本"})
for i, infos := range RsasScanner.AllVulnInfos {
bar.Add(1)
axis := fmt.Sprintf("A%d", i+2)
err := excel.SetSheetRow("主机漏洞清单", axis, &[]interface{}{
i + 1,
infos.VulnInfos,
infos.RiskLevel,
infos.Details,
infos.Solution,
infos.IpAddress,
infos.Port,
infos.Protocol,
infos.Service,
infos.CVENumber,
infos.ServiceDetail,
})
if err != nil {
println(err)
}
}
excel.DeleteSheet("Sheet1")
err := excel.SaveAs(filename)
if err != nil {
println(err.Error())
} else {
println("保存为:" + filename + ".xlsx")
}
}
//
////检查是否有漏报情况
//func CheckVulnHasAssetInfo() {}
//
////根据基线规则匹配是否排除漏洞 true 为满足基线
//func JudgeWithBaseLine(vulnWithAsset VulnInfoWithAssetInfo) (bool, string) {
//
// if JudgeNginx(vulnWithAsset) {
// return true, "nginx版本为 " + vulnWithAsset.HtmlVulnInfo.ServiceDetail + " ,符合基线要求,暂不处理"
// }
// if JudgeTomcat(vulnWithAsset) {
// return true, "tomcat版本为 " + vulnWithAsset.HtmlVulnInfo.ServiceDetail + " ,符合基线要求,暂不处理"
// }
// if JudgeSql(vulnWithAsset) {
// return true, vulnWithAsset.HtmlVulnInfo.VulnInfos + " 为数据库漏洞,暂不处理"
// }
// if JudgeRedis(vulnWithAsset) {
// return true, "redis版本为 " + vulnWithAsset.HtmlVulnInfo.ServiceDetail + " ,符合基线要求,暂不处理"
// }
// if JudgeRabbitMQ(vulnWithAsset) {
// return true, "RabbitMQ版本为 " + vulnWithAsset.HtmlVulnInfo.ServiceDetail + " ,符合基线要求,暂不处理"
// }
// if JudgeOpenSSL(vulnWithAsset) {
// return true, vulnWithAsset.HtmlVulnInfo.VulnInfos + " 为openssl漏洞,暂不处理"
// }
//
// if JudgeTls(vulnWithAsset) {
// return true, vulnWithAsset.HtmlVulnInfo.VulnInfos + " 为ssl/tls漏洞,暂不处理"
// }
// return false, ""
//}
//
////检查ng基线 true为符合基线
//func JudgeNginx(vulnWithAsset VulnInfoWithAssetInfo) bool {
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
// if strings.Contains(vulnBanner, "nginx/") {
// ngBanner := strings.Replace(vulnBanner, "nginx/", "", 1)
// ngbaseInt, err := strconv.Atoi(strings.Replace(nginxVersion, ".", "", -1))
// if err != nil {
// println("nginx基线常量有问题: " + nginxVersion)
// return false
// }
// ngBannerInt, err := strconv.Atoi(strings.Replace(ngBanner, ".", "", -1))
// if err != nil {
// println("nginx版本获取有问题漏洞名称:" + vulnWithAsset.HtmlVulnInfo.VulnInfos + " ip: " + vulnWithAsset.HtmlVulnInfo.IpAddress + "ng信息: " + vulnWithAsset.HtmlVulnInfo.ServiceDetail)
// return false
// }
// ngBannerIntPrefix, err := strconv.Atoi(strings.Split(ngBanner, ".")[0] + strings.Split(ngBanner, ".")[1])
// ngBaseIntPrefix, err := strconv.Atoi(strings.Split(nginxVersion, ".")[0] + strings.Split(nginxVersion, ".")[1])
// if ngBannerInt >= ngbaseInt && ngBannerIntPrefix >= ngBaseIntPrefix {
// return true
// }
// }
//
// return false
//}
//
//func JudgeTomcat(vulnWithAsset VulnInfoWithAssetInfo) bool {
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
// if strings.Contains(vulnBanner, "tomcat/") {
// tomcatBanner := strings.Replace(vulnBanner, "tomcat/", "", 1)
// tomcatBanner = strings.Replace(tomcatBanner, ".tar", "", 1)
// tomcatBanner = strings.Replace(tomcatBanner, " ", "", -1)
// tomcatBaseInt, err := strconv.Atoi(strings.Replace(tomcatVersion, ".", "", -1))
// if err != nil {
// println("tomcat版本常量有问题: " + tomcatVersion)
// return false
// }
// tomcatBannerInt, err := strconv.Atoi(strings.Replace(tomcatBanner, ".", "", -1))
// if err != nil {
// println("tomcat版本获取有问题漏洞名称:" + vulnWithAsset.HtmlVulnInfo.VulnInfos + " ip: " + vulnWithAsset.HtmlVulnInfo.IpAddress + "ng信息: " + vulnWithAsset.HtmlVulnInfo.ServiceDetail)
// return false
// }
// tomcatBannerIntPrefix, err := strconv.Atoi(strings.Split(tomcatBanner, ".")[0] + strings.Split(tomcatBanner, ".")[1])
// tomcatBaseIntPrefix, err := strconv.Atoi(strings.Split(tomcatVersion, ".")[0] + strings.Split(tomcatVersion, ".")[1])
// if tomcatBannerInt >= tomcatBaseInt && tomcatBannerIntPrefix >= tomcatBaseIntPrefix {
// return true
// }
// }
// return false
//}
//
////数据库类型匹配到就不修复
//func JudgeSql(vulnWithAsset VulnInfoWithAssetInfo) bool {
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
// if strings.Contains(vulnBanner, "mysql/") {
// return true
// }
// if strings.Contains(vulnBanner, "mariadb/") {
// return true
// }
// if strings.Contains(vulnBanner, "mongodb/") {
// return true
// }
//
// return false
//}
//
//func JudgeRedis(vulnWithAsset VulnInfoWithAssetInfo) bool {
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
// if strings.Contains(vulnBanner, "redis/") {
// redisBanner := strings.Replace(vulnBanner, "redis/", "", 1)
// redisBaseInt, err := strconv.Atoi(strings.Replace(redisVersion, ".", "", -1))
// if err != nil {
// println("redis版本常量有问题: " + redisVersion)
// return false
// }
// redisBannerInt, err := strconv.Atoi(strings.Replace(redisBanner, ".", "", -1))
// if err != nil {
// println("redis版本获取有问题漏洞名称:" + vulnWithAsset.HtmlVulnInfo.VulnInfos + " ip: " + vulnWithAsset.HtmlVulnInfo.IpAddress + "ng信息: " + vulnWithAsset.HtmlVulnInfo.ServiceDetail)
// return false
// }
// redisBannerIntPrefix, err := strconv.Atoi(strings.Split(redisBanner, ".")[0] + strings.Split(redisBanner, ".")[1])
// redisBaseIntPrefix, err := strconv.Atoi(strings.Split(redisVersion, ".")[0] + strings.Split(redisVersion, ".")[1])
// if redisBannerInt >= redisBaseInt && redisBannerIntPrefix >= redisBaseIntPrefix {
// return true
// }
// }
// return false
//
//}
//
//func JudgeRabbitMQ(vulnWithAsset VulnInfoWithAssetInfo) bool {
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
// if strings.Contains(vulnBanner, "rabbitmq/") {
// rabbitmqBanner := strings.Replace(vulnBanner, "rabbitmq/", "", 1)
// rabbitmqBaseInt, err := strconv.Atoi(strings.Replace(RabbitMQ, ".", "", -1))
// if err != nil {
// println("RabbitMQ版本常量有问题: " + RabbitMQ)
// return false
// }
// rabbitmqBannerInt, err := strconv.Atoi(strings.Replace(rabbitmqBanner, ".", "", -1))
// if err != nil {
// println("RabbitMQ版本获取有问题漏洞名称:" + vulnWithAsset.HtmlVulnInfo.VulnInfos + " ip: " + vulnWithAsset.HtmlVulnInfo.IpAddress + "ng信息: " + vulnWithAsset.HtmlVulnInfo.ServiceDetail)
// return false
// }
// rabbitmqBannerIntPrefix, err := strconv.Atoi(strings.Split(rabbitmqBanner, ".")[0] + strings.Split(rabbitmqBanner, ".")[1])
// rabbitmqBaseIntPrefix, err := strconv.Atoi(strings.Split(RabbitMQ, ".")[0] + strings.Split(RabbitMQ, ".")[1])
// if rabbitmqBannerInt >= rabbitmqBaseInt && rabbitmqBannerIntPrefix >= rabbitmqBaseIntPrefix {
// return true
// }
// }
// return false
//
//}
//
//func JudgeOpenSSL(vulnWithAsset VulnInfoWithAssetInfo) bool {
// vulnBanner := strings.ToLower(vulnWithAsset.HtmlVulnInfo.ServiceDetail)
// if strings.Contains(vulnBanner, "openssl/") && strings.Contains(strings.ToLower(vulnWithAsset.HtmlVulnInfo.VulnInfos), "openssl") {
// return true
// }
// return false
//}
//
//func JudgeTls(vulnWithAsset VulnInfoWithAssetInfo) bool {
// vulnName := strings.ToLower(vulnWithAsset.HtmlVulnInfo.VulnInfos)
// if strings.Contains(vulnName, "ssl/tls") || strings.Contains(vulnName, "tlsclient") {
// return true
// }
// return false
//}

55
pkg/structs.go Normal file
View File

@@ -0,0 +1,55 @@
package pkg
type RsasScanner struct {
Account string
Password string
AllVulnInfos []HtmlVulnInfo
//AssetInfos []AssetInfo
//AssetExcel string
//ZipResult string
//VulnExcel string
//OldVulnExcel string
//OutputFileName string
}
type HtmlAllVulnInfo struct {
HtmlVulnInfos []HtmlVulnInfo
}
type VulnInfoWithAssetInfo struct {
HtmlVulnInfo HtmlVulnInfo
//AssetInfos AssetInfo
}
//type AssetInfo struct {
// productLine string
// DPlMNumber string
// IpAddress string
// Mail string
// AppName string
// ManagerName string
// DevEnvironment string
// Ascription string
//}
type HtmlVulnInfo struct {
IpAddress string
Port string
Protocol string
Service string
VulnInfos string
RiskLevel string
Details string
Solution string
CVENumber string
ServiceDetail string
Record string
}
const nginxVersion = `1.18.0`
const tomcatVersion = `9.0.40`
const IIS = `10`
const mysql = `5.7.31`
const redisVersion = `6.0.8`
const dotNet = `4.8`
const RabbitMQ = `3.8.2`

32
pkg/utils.go Normal file
View File

@@ -0,0 +1,32 @@
package pkg
import (
"regexp"
"strings"
)
func writeToExcel() {}
func CheckRegexString(regString string, htmlContent string) (finding string) {
re := regexp.MustCompile(regString)
finding = re.FindString(htmlContent)
return
}
func CheckColumnKey(columnName []string, m map[string]int, key string) string {
if value, ok := m[key]; ok {
//return utils.StringstripToSemicolon(columnName[value])
return columnName[value]
} else {
return ""
}
}
func TrimString(s string) string {
s = strings.Replace(s, "\r", "", -1)
s = strings.Replace(s, "\n", "", -1)
s = strings.Replace(s, " ", "", -1)
return s
}

6
readme.md Normal file
View File

@@ -0,0 +1,6 @@
绿盟扫描器报告转excel
./main -h
./rsasExcel -z xxx.zip -o t1