Skip to content

Commit

Permalink
支持html、json格式任务导出
Browse files Browse the repository at this point in the history
  • Loading branch information
qiwentaidi committed Nov 14, 2024
1 parent 336b429 commit c18b3ff
Show file tree
Hide file tree
Showing 31 changed files with 1,145 additions and 416 deletions.
6 changes: 3 additions & 3 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ func (a *App) InitTycHeader(token string) {
info.InitHEAD(token)
}

func (a *App) SubsidiariesAndDomains(query string, subLevel, ratio int, searchDomain bool, machine string) []info.CompanyInfo {
func (a *App) SubsidiariesAndDomains(query string, subLevel, ratio int, searchDomain bool, machine string) []structs.CompanyInfo {
tkm := info.CheckKeyMap(a.ctx, query)
time.Sleep(time.Second)
result := info.SearchSubsidiary(a.ctx, tkm.CompanyName, tkm.CompanyId, ratio, false, searchDomain, machine)
Expand Down Expand Up @@ -297,7 +297,7 @@ func (a *App) SubsidiariesAndDomains(query string, subLevel, ratio int, searchDo
return result
}

func (a *App) WechatOfficial(query string) []info.WechatReulst {
func (a *App) WechatOfficial(query string) []structs.WechatReulst {
var companyId string
for _, tkm := range info.TycKeyMap {
if tkm.CompanyName == query {
Expand Down Expand Up @@ -499,7 +499,7 @@ func (a *App) NewWebScanner(options structs.WebscanOptions, proxy clients.Proxy)
}
id++
gologger.Info(a.ctx, fmt.Sprintf("vulnerability scanning %d/%d", id, count))
webscan.NewNucleiEngine(a.ctx, proxy, webscan.NucleiOption{
webscan.NewNucleiEngine(a.ctx, proxy, structs.NucleiOption{
URL: target,
Tags: util.RemoveDuplicates(tags),
TemplateFile: options.TemplateFiles,
Expand Down
42 changes: 19 additions & 23 deletions core/info/tianyancha.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,8 @@ func GetCompanyID(ctx context.Context, company string) (string, string) {
return company_id, company_name
}

type CompanyInfo struct {
CompanyName string
Holding string
Investment string // 投资比例
RegStatus string
Domains []string
CompanyId string
}

// 返回查询公司的名称和子公司的名称, isSecond 是否为二次查询
func SearchSubsidiary(ctx context.Context, companyName, companyId string, ratio int, isSecond bool, searchDomain bool, machine string) (Asset []CompanyInfo) {
func SearchSubsidiary(ctx context.Context, companyName, companyId string, ratio int, isSecond bool, searchDomain bool, machine string) (Asset []structs.CompanyInfo) {
data := make(map[string]interface{})
data["gid"] = companyId
data["pageSize"] = 100
Expand All @@ -161,7 +152,14 @@ func SearchSubsidiary(ctx context.Context, companyName, companyId string, ratio
gologger.Debug(ctx, err)
}
}
Asset = append(Asset, CompanyInfo{companyName, "本公司", "", qr.State, util.RemoveDuplicates(domains), companyId})
Asset = append(Asset, structs.CompanyInfo{
CompanyName: companyName,
Holding: "本公司",
Investment: "",
RegStatus: qr.State,
Domains: util.RemoveDuplicates(domains),
CompanyId: companyId,
})
}
for _, result := range qr.Data.Result {
gq, _ := strconv.Atoi(strings.TrimSuffix(result.Percent, "%"))
Expand All @@ -174,7 +172,14 @@ func SearchSubsidiary(ctx context.Context, companyName, companyId string, ratio
gologger.Debug(ctx, err)
}
}
Asset = append(Asset, CompanyInfo{result.Name, result.Percent, result.Amount, result.RegStatus, util.RemoveDuplicates(subsidiaryDomains), fmt.Sprint(result.ID)})
Asset = append(Asset, structs.CompanyInfo{
CompanyName: result.Name,
Holding: result.Percent,
Investment: result.Amount,
RegStatus: result.RegStatus,
Domains: util.RemoveDuplicates(subsidiaryDomains),
CompanyId: fmt.Sprint(result.ID),
})
}
}
return
Expand All @@ -199,17 +204,8 @@ type OfficialAccounts struct {
} `json:"data"`
}

type WechatReulst struct {
CompanyName string
WechatName string
WechatNums string
Logo string
Qrcode string
Introduction string
}

// 获取微信公众号信息
func WeChatOfficialAccounts(ctx context.Context, companyName, companyId string) (wr []WechatReulst) {
func WeChatOfficialAccounts(ctx context.Context, companyName, companyId string) (wr []structs.WechatReulst) {
_, b, err := clients.NewRequest("GET", "https://capi.tianyancha.com/cloud-business-state/wechat/list?graphId="+companyId+"&pageSize=1&pageNum=1", gethead, nil, 10, true, clients.DefaultClient())
if err != nil {
gologger.Error(ctx, err)
Expand All @@ -228,7 +224,7 @@ func WeChatOfficialAccounts(ctx context.Context, companyName, companyId string)
}
json.Unmarshal(b, &oa)
for _, result := range oa.Data.ResultList {
wr = append(wr, WechatReulst{
wr = append(wr, structs.WechatReulst{
CompanyName: companyName,
WechatNums: result.PublicNum,
WechatName: result.Title,
Expand Down
2 changes: 1 addition & 1 deletion core/waf/waf.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var (
"qianxin": {".360safedns.com", ".360cloudwaf.com", ".360wzb.com", ".qaxcloudwaf.com"},
"baiduyunjiasu": {".yunjiasu-cdn.net"},
"anquanbao": {".anquanbao.net", ".anquanbao.com"},
"aliyun": {"kunlun", "aliyunddos", "aliyunwaf", "aligaofang", "aliyundunwaf", ".yundunwaf2.com"},
"aliyun": {"kunlun", "aliyunddos", "aliyunwaf", "aligaofang", "aliyundunwaf", ".yundunwaf2.com", ".yundunwaf1.com"},
"xuanwudun": {".saaswaf.com", ".dbappwaf.cn"},
"yundun": {".hwwsdns.cn", ".yunduncname.com"},
"knownsec-ns": {".jiasule.net"},
Expand Down
30 changes: 7 additions & 23 deletions core/webscan/callnuclei.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"slack-wails/lib/clients"
"slack-wails/lib/gologger"
"slack-wails/lib/structs"
"strings"

nuclei "github.com/projectdiscovery/nuclei/v3/lib"
Expand All @@ -13,28 +14,7 @@ import (
"github.com/wailsapp/wails/v2/pkg/runtime"
)

type VulnerabilityInfo struct {
ID string
Name string
Description string
Reference string
Type string
Risk string
URL string
Request string
Response string
Extract string
}

type NucleiOption struct {
SkipNucleiWithoutTags bool // 如果没有扫描到指纹,是否需要扫描全漏洞还是直接跳过
URL string
Tags []string // 全漏洞扫描时,使用自定义标签
TemplateFile []string
TemplateFolders []string
}

func NewNucleiEngine(ctx context.Context, proxy clients.Proxy, o NucleiOption) {
func NewNucleiEngine(ctx context.Context, proxy clients.Proxy, o structs.NucleiOption) {
if o.SkipNucleiWithoutTags && len(o.Tags) == 0 {
gologger.Info(ctx, fmt.Sprintf("[nuclei] %s does not have tags, scan skipped", o.URL))
return
Expand Down Expand Up @@ -76,7 +56,7 @@ func NewNucleiEngine(ctx context.Context, proxy clients.Proxy, o NucleiOption) {
if event.Info.Reference != nil && !event.Info.Reference.IsEmpty() {
reference = strings.Join(event.Info.Reference.ToSlice(), ",")
}
runtime.EventsEmit(ctx, "nucleiResult", VulnerabilityInfo{
runtime.EventsEmit(ctx, "nucleiResult", structs.VulnerabilityInfo{
ID: event.TemplateID,
Name: event.Info.Name,
Description: event.Info.Description,
Expand Down Expand Up @@ -115,6 +95,10 @@ func showRequest(event *output.ResultEvent) string {

func showResponse(event *output.ResultEvent) string {
if event.Response != "" {
byteResponse := []byte(event.Response)
if len(byteResponse) > 1024*512 {
return string(byteResponse[:1024*512]) + " ..."
}
return event.Response
}
if event.Interaction != nil {
Expand Down
12 changes: 12 additions & 0 deletions core/webscan/honeypot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package webscan

import "strings"

func checkHoneypotWithHeaders(rawHeaders string) bool {
count := strings.Count(rawHeaders, "Set-Cookie")
return count > 5
}

func checkHoneypotWithFingerprintLength(length int) bool {
return length > 15
}
24 changes: 6 additions & 18 deletions core/webscan/infoscan.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,6 @@ type WebInfo struct {
Cert string // TLS证书
}

type InfoResult struct {
URL string
StatusCode int
Length int
Title string
Fingerprints []string
IsWAF bool
WAF string
Detect string
Screenshot string // 截图图片路径
}

type FingerScanner struct {
ctx context.Context
urls []*url.URL
Expand Down Expand Up @@ -108,7 +96,7 @@ func NewFingerScanner(ctx context.Context, proxy clients.Proxy, options structs.
func (s *FingerScanner) NewFingerScan() {
var wg sync.WaitGroup
single := make(chan struct{})
retChan := make(chan InfoResult, len(s.urls))
retChan := make(chan structs.InfoResult, len(s.urls))
go func() {
for pr := range retChan {
runtime.EventsEmit(s.ctx, "webFingerScan", pr)
Expand Down Expand Up @@ -144,7 +132,7 @@ func (s *FingerScanner) NewFingerScan() {
goto ContinueExecution
}
// 如果是正常的无法响应则直接返回
retChan <- InfoResult{
retChan <- structs.InfoResult{
URL: u.String(),
StatusCode: 0,
}
Expand Down Expand Up @@ -202,7 +190,7 @@ func (s *FingerScanner) NewFingerScan() {
fingerprints = append(fingerprints, "Fastjson")
}

if len(fingerprints) >= 20 {
if checkHoneypotWithHeaders(web.HeadeString) || checkHoneypotWithFingerprintLength(len(fingerprints)) {
fingerprints = []string{"疑似蜜罐"}
}

Expand All @@ -218,7 +206,7 @@ func (s *FingerScanner) NewFingerScan() {
s.basicURLWithFingerprint[u.String()] = append(s.basicURLWithFingerprint[u.String()], fingerprints...)
s.mutex.Unlock()

retChan <- InfoResult{
retChan <- structs.InfoResult{
URL: u.String(),
StatusCode: web.StatusCode,
Length: web.ContentLength,
Expand Down Expand Up @@ -266,7 +254,7 @@ func (s *FingerScanner) NewActiveFingerScan(rootPath bool) {
visited := make(map[string]bool) // 用于记录已访问的URL和路径组合

single := make(chan struct{})
retChan := make(chan InfoResult, len(s.urls))
retChan := make(chan structs.InfoResult, len(s.urls))
go func() {
for pr := range retChan {
runtime.EventsEmit(s.ctx, "webFingerScan", pr)
Expand Down Expand Up @@ -315,7 +303,7 @@ func (s *FingerScanner) NewActiveFingerScan(rootPath bool) {
s.basicURLWithFingerprint[fp.URL.String()] = append(s.basicURLWithFingerprint[fp.URL.String()], result...)
s.mutex.Unlock()

retChan <- InfoResult{
retChan <- structs.InfoResult{
URL: fullURL,
StatusCode: ti.StatusCode,
Length: ti.ContentLength,
Expand Down
55 changes: 44 additions & 11 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package main
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"os"
"slack-wails/core/portscan"
"slack-wails/core/webscan"
"slack-wails/lib/fileutil"
"slack-wails/lib/gologger"
"slack-wails/lib/report"
"slack-wails/lib/structs"
"slack-wails/lib/util"
"strings"
Expand Down Expand Up @@ -820,16 +822,21 @@ func (d *Database) DeleteScanTask(taskid string) bool {
return isSuccess
}

func (d *Database) SelectFingerscanResult(taskid string) []webscan.InfoResult {
func (d *Database) RenameScanTask(taskid, taskname string) bool {
updateStmt := "UPDATE scanTask SET task_name = ? WHERE task_id = ?"
return d.ExecSqlStatement(updateStmt, taskname, taskid)
}

func (d *Database) SelectFingerscanResult(taskid string) []structs.InfoResult {
rows, err := d.DB.Query("SELECT * FROM FingerprintInfo WHERE task_id = ?;", taskid)
if err != nil {
gologger.Debug(d.ctx, err)
return []webscan.InfoResult{}
return []structs.InfoResult{}
}
defer rows.Close()
var results []webscan.InfoResult
var results []structs.InfoResult
for rows.Next() {
var result webscan.InfoResult
var result structs.InfoResult
var fingerprintsStr string
var task_id string
err = rows.Scan(&task_id, &result.URL, &result.StatusCode, &result.Length, &result.Title, &result.Detect, &result.IsWAF, &result.WAF, &fingerprintsStr, &result.Screenshot)
Expand All @@ -851,15 +858,15 @@ func (d *Database) SelectFingerscanResult(taskid string) []webscan.InfoResult {
return results
}

func (d *Database) SelectPocscanResult(taskid string) []webscan.VulnerabilityInfo {
func (d *Database) SelectPocscanResult(taskid string) []structs.VulnerabilityInfo {
rows, err := d.DB.Query("SELECT * FROM VulnerabilityInfo WHERE task_id = ?", taskid)
if err != nil {
return []webscan.VulnerabilityInfo{}
return []structs.VulnerabilityInfo{}
}
defer rows.Close()
var results []webscan.VulnerabilityInfo
var results []structs.VulnerabilityInfo
for rows.Next() {
var result webscan.VulnerabilityInfo
var result structs.VulnerabilityInfo
var task_id string
err = rows.Scan(&task_id, &result.ID, &result.Name, &result.Type, &result.Risk, &result.URL, &result.Extract, &result.Request, &result.Response, &result.Description, &result.Reference)
if err != nil {
Expand All @@ -871,12 +878,12 @@ func (d *Database) SelectPocscanResult(taskid string) []webscan.VulnerabilityInf
return results
}

func (d *Database) InsertFingerscanResult(taskid string, result webscan.InfoResult) bool {
func (d *Database) InsertFingerscanResult(taskid string, result structs.InfoResult) bool {
insertStmt := "INSERT INTO FingerprintInfo (task_id, url, status, length, title, detect, is_waf, waf, fingerprints, screenshot) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
return d.ExecSqlStatement(insertStmt, taskid, result.URL, result.StatusCode, result.Length, result.Title, result.Detect, result.IsWAF, result.WAF, strings.Join(result.Fingerprints, ","), result.Screenshot)
}

func (d *Database) InsertPocscanResult(taskid string, result webscan.VulnerabilityInfo) bool {
func (d *Database) InsertPocscanResult(taskid string, result structs.VulnerabilityInfo) bool {
insertStmt := "INSERT INTO VulnerabilityInfo (task_id, template_id, vuln_name, protocol, severity, vuln_url, extract, request, response, description, reference) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
return d.ExecSqlStatement(insertStmt, taskid, result.ID, result.Name, result.Type, result.Risk, result.URL, result.Extract, result.Request, result.Response, result.Description, result.Reference)
}
Expand All @@ -885,3 +892,29 @@ func (d *Database) DeletePocscanResult(taskid, template_id, vuln_url string) boo
deleteStmt := "DELETE FROM VulnerabilityInfo WHERE task_id = ? AND template_id = ? AND vuln_url = ?"
return d.ExecSqlStatement(deleteStmt, taskid, template_id, vuln_url)
}

func (d *Database) ExportWebReportWithJson(reportpath string, task structs.TaskResult) bool {
fingerprintsResult := d.SelectFingerscanResult(task.TaskId)
pocsResult := d.SelectPocscanResult(task.TaskId)
result := structs.WebReport{
Targets: task.Targets,
Fingerprints: fingerprintsResult,
POCs: pocsResult,
}
return fileutil.SaveJsonWithFormat(d.ctx, reportpath, result)
}

func (d *Database) ReadWebReportWithJson(reportpath string) (result structs.WebReport, err error) {
data, err := os.ReadFile(reportpath)
if err != nil {
return
}
err = json.Unmarshal(data, &result)
return
}

func (d *Database) ExportWebReportWithHtml(reportpath, taskid string) bool {
fingerprintsResult := d.SelectFingerscanResult(taskid)
pocsResult := d.SelectPocscanResult(taskid)
return os.WriteFile(reportpath, []byte(report.GenerateReport(fingerprintsResult, pocsResult)), 0644) == nil
}
Loading

0 comments on commit c18b3ff

Please sign in to comment.