perf: 优化WebTitile.go的代码,添加注释,规范输出

This commit is contained in:
ZacharyZcR 2024-12-19 14:15:58 +08:00
parent d860eb63b3
commit 6a33a65c94

View File

@ -19,28 +19,39 @@ import (
"golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/encoding/simplifiedchinese"
) )
// WebTitle 获取Web标题并执行扫描
func WebTitle(info *Config.HostInfo) error { func WebTitle(info *Config.HostInfo) error {
// 如果是webpoc扫描模式直接执行WebScan
if Common.Scantype == "webpoc" { if Common.Scantype == "webpoc" {
WebScan.WebScan(info) WebScan.WebScan(info)
return nil return nil
} }
// 获取网站标题信息
err, CheckData := GOWebTitle(info) err, CheckData := GOWebTitle(info)
info.Infostr = WebScan.InfoCheck(info.Url, &CheckData) info.Infostr = WebScan.InfoCheck(info.Url, &CheckData)
//不扫描打印机,避免打纸
// 检查是否为打印机,避免意外打印
for _, v := range info.Infostr { for _, v := range info.Infostr {
if v == "打印机" { if v == "打印机" {
return nil return nil
} }
} }
// 根据配置决定是否执行漏洞扫描
if !Common.NoPoc && err == nil { if !Common.NoPoc && err == nil {
WebScan.WebScan(info) WebScan.WebScan(info)
} else { } else {
errlog := fmt.Sprintf("[-] webtitle %v %v", info.Url, err) errlog := fmt.Sprintf("[-] webtitle %v %v", info.Url, err)
Common.LogError(errlog) Common.LogError(errlog)
} }
return err return err
} }
// GOWebTitle 获取网站标题并处理URL
func GOWebTitle(info *Config.HostInfo) (err error, CheckData []WebScan.CheckDatas) { func GOWebTitle(info *Config.HostInfo) (err error, CheckData []WebScan.CheckDatas) {
// 如果URL未指定根据端口生成URL
if info.Url == "" { if info.Url == "" {
switch info.Ports { switch info.Ports {
case "80": case "80":
@ -53,6 +64,7 @@ func GOWebTitle(info *Config.HostInfo) (err error, CheckData []WebScan.CheckData
info.Url = fmt.Sprintf("%s://%s:%s", protocol, info.Host, info.Ports) info.Url = fmt.Sprintf("%s://%s:%s", protocol, info.Host, info.Ports)
} }
} else { } else {
// 处理未指定协议的URL
if !strings.Contains(info.Url, "://") { if !strings.Contains(info.Url, "://") {
host := strings.Split(info.Url, "/")[0] host := strings.Split(info.Url, "/")[0]
protocol := GetProtocol(host, Common.Timeout) protocol := GetProtocol(host, Common.Timeout)
@ -60,12 +72,13 @@ func GOWebTitle(info *Config.HostInfo) (err error, CheckData []WebScan.CheckData
} }
} }
// 第一次获取URL
err, result, CheckData := geturl(info, 1, CheckData) err, result, CheckData := geturl(info, 1, CheckData)
if err != nil && !strings.Contains(err.Error(), "EOF") { if err != nil && !strings.Contains(err.Error(), "EOF") {
return return
} }
//跳转 // 处理URL跳转
if strings.Contains(result, "://") { if strings.Contains(result, "://") {
info.Url = result info.Url = result
err, result, CheckData = geturl(info, 3, CheckData) err, result, CheckData = geturl(info, 3, CheckData)
@ -74,10 +87,12 @@ func GOWebTitle(info *Config.HostInfo) (err error, CheckData []WebScan.CheckData
} }
} }
// 处理HTTP到HTTPS的升级
if result == "https" && !strings.HasPrefix(info.Url, "https://") { if result == "https" && !strings.HasPrefix(info.Url, "https://") {
info.Url = strings.Replace(info.Url, "http://", "https://", 1) info.Url = strings.Replace(info.Url, "http://", "https://", 1)
err, result, CheckData = geturl(info, 1, CheckData) err, result, CheckData = geturl(info, 1, CheckData)
//有跳转
// 处理升级后的跳转
if strings.Contains(result, "://") { if strings.Contains(result, "://") {
info.Url = result info.Url = result
err, _, CheckData = geturl(info, 3, CheckData) err, _, CheckData = geturl(info, 3, CheckData)
@ -86,22 +101,28 @@ func GOWebTitle(info *Config.HostInfo) (err error, CheckData []WebScan.CheckData
} }
} }
} }
//是否访问图标
//err, _, CheckData = geturl(info, 2, CheckData)
if err != nil { if err != nil {
return return
} }
return return
} }
// geturl 获取URL响应内容和信息
// 参数:
// - info: 主机配置信息
// - flag: 请求类型标志(1:首次尝试 2:获取favicon 3:处理302跳转 4:处理400转https)
// - CheckData: 检查数据数组
//
// 返回:
// - error: 错误信息
// - string: 重定向URL或协议
// - []WebScan.CheckDatas: 更新后的检查数据
func geturl(info *Config.HostInfo, flag int, CheckData []WebScan.CheckDatas) (error, string, []WebScan.CheckDatas) { func geturl(info *Config.HostInfo, flag int, CheckData []WebScan.CheckDatas) (error, string, []WebScan.CheckDatas) {
//flag 1 first try // 处理目标URL
//flag 2 /favicon.ico
//flag 3 302
//flag 4 400 -> https
Url := info.Url Url := info.Url
if flag == 2 { if flag == 2 {
// 获取favicon.ico的URL
URL, err := url.Parse(Url) URL, err := url.Parse(Url)
if err == nil { if err == nil {
Url = fmt.Sprintf("%s://%s/favicon.ico", URL.Scheme, URL.Host) Url = fmt.Sprintf("%s://%s/favicon.ico", URL.Scheme, URL.Host)
@ -109,61 +130,77 @@ func geturl(info *Config.HostInfo, flag int, CheckData []WebScan.CheckDatas) (er
Url += "/favicon.ico" Url += "/favicon.ico"
} }
} }
// 创建HTTP请求
req, err := http.NewRequest("GET", Url, nil) req, err := http.NewRequest("GET", Url, nil)
if err != nil { if err != nil {
return err, "", CheckData return err, "", CheckData
} }
// 设置请求头
req.Header.Set("User-agent", Common.UserAgent) req.Header.Set("User-agent", Common.UserAgent)
req.Header.Set("Accept", Common.Accept) req.Header.Set("Accept", Common.Accept)
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9") req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
if Common.Cookie != "" { if Common.Cookie != "" {
req.Header.Set("Cookie", Common.Cookie) req.Header.Set("Cookie", Common.Cookie)
} }
//if Common.Pocinfo.Cookie != "" {
// req.Header.Set("Cookie", "rememberMe=1;"+Common.Pocinfo.Cookie)
//} else {
// req.Header.Set("Cookie", "rememberMe=1")
//}
req.Header.Set("Connection", "close") req.Header.Set("Connection", "close")
// 选择HTTP客户端
var client *http.Client var client *http.Client
if flag == 1 { if flag == 1 {
client = lib.ClientNoRedirect client = lib.ClientNoRedirect // 不跟随重定向
} else { } else {
client = lib.Client client = lib.Client // 跟随重定向
} }
// 发送请求
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return err, "https", CheckData return err, "https", CheckData
} }
defer resp.Body.Close() defer resp.Body.Close()
var title string
// 读取响应内容
body, err := getRespBody(resp) body, err := getRespBody(resp)
if err != nil { if err != nil {
return err, "https", CheckData return err, "https", CheckData
} }
// 保存检查数据
CheckData = append(CheckData, WebScan.CheckDatas{body, fmt.Sprintf("%s", resp.Header)}) CheckData = append(CheckData, WebScan.CheckDatas{body, fmt.Sprintf("%s", resp.Header)})
// 处理非favicon请求
var reurl string var reurl string
if flag != 2 { if flag != 2 {
// 处理编码
if !utf8.Valid(body) { if !utf8.Valid(body) {
body, _ = simplifiedchinese.GBK.NewDecoder().Bytes(body) body, _ = simplifiedchinese.GBK.NewDecoder().Bytes(body)
} }
title = gettitle(body)
// 获取页面信息
title := gettitle(body)
length := resp.Header.Get("Content-Length") length := resp.Header.Get("Content-Length")
if length == "" { if length == "" {
length = fmt.Sprintf("%v", len(body)) length = fmt.Sprintf("%v", len(body))
} }
// 处理重定向
redirURL, err1 := resp.Location() redirURL, err1 := resp.Location()
if err1 == nil { if err1 == nil {
reurl = redirURL.String() reurl = redirURL.String()
} }
result := fmt.Sprintf("[*] WebTitle %-25v code:%-3v len:%-6v title:%v", resp.Request.URL, resp.StatusCode, length, title)
// 输出结果
result := fmt.Sprintf("[*] 网站标题 %-25v 状态码:%-3v 长度:%-6v 标题:%v",
resp.Request.URL, resp.StatusCode, length, title)
if reurl != "" { if reurl != "" {
result += fmt.Sprintf(" 跳转url: %s", reurl) result += fmt.Sprintf(" 重定向地址: %s", reurl)
} }
Common.LogSuccess(result) Common.LogSuccess(result)
} }
// 返回结果
if reurl != "" { if reurl != "" {
return nil, reurl, CheckData return nil, reurl, CheckData
} }
@ -173,14 +210,19 @@ func geturl(info *Config.HostInfo, flag int, CheckData []WebScan.CheckDatas) (er
return nil, "", CheckData return nil, "", CheckData
} }
// getRespBody 读取HTTP响应体内容
func getRespBody(oResp *http.Response) ([]byte, error) { func getRespBody(oResp *http.Response) ([]byte, error) {
var body []byte var body []byte
// 处理gzip压缩的响应
if oResp.Header.Get("Content-Encoding") == "gzip" { if oResp.Header.Get("Content-Encoding") == "gzip" {
gr, err := gzip.NewReader(oResp.Body) gr, err := gzip.NewReader(oResp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer gr.Close() defer gr.Close()
// 循环读取解压内容
for { for {
buf := make([]byte, 1024) buf := make([]byte, 1024)
n, err := gr.Read(buf) n, err := gr.Read(buf)
@ -193,6 +235,7 @@ func getRespBody(oResp *http.Response) ([]byte, error) {
body = append(body, buf...) body = append(body, buf...)
} }
} else { } else {
// 直接读取未压缩的响应
raw, err := io.ReadAll(oResp.Body) raw, err := io.ReadAll(oResp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
@ -202,30 +245,41 @@ func getRespBody(oResp *http.Response) ([]byte, error) {
return body, nil return body, nil
} }
// gettitle 从HTML内容中提取网页标题
func gettitle(body []byte) (title string) { func gettitle(body []byte) (title string) {
// 使用正则表达式匹配title标签内容
re := regexp.MustCompile("(?ims)<title.*?>(.*?)</title>") re := regexp.MustCompile("(?ims)<title.*?>(.*?)</title>")
find := re.FindSubmatch(body) find := re.FindSubmatch(body)
if len(find) > 1 { if len(find) > 1 {
title = string(find[1]) title = string(find[1])
title = strings.TrimSpace(title)
title = strings.Replace(title, "\n", "", -1) // 清理标题内容
title = strings.Replace(title, "\r", "", -1) title = strings.TrimSpace(title) // 去除首尾空格
title = strings.Replace(title, "&nbsp;", " ", -1) title = strings.Replace(title, "\n", "", -1) // 去除换行
title = strings.Replace(title, "\r", "", -1) // 去除回车
title = strings.Replace(title, "&nbsp;", " ", -1) // 替换HTML空格
// 截断过长的标题
if len(title) > 100 { if len(title) > 100 {
title = title[:100] title = title[:100]
} }
// 处理空标题
if title == "" { if title == "" {
title = "\"\"" //空格 title = "\"\"" // 空标题显示为双引号
} }
} else { } else {
title = "None" //没有title title = "无标题" // 没有找到title标签
} }
return return
} }
// GetProtocol 检测目标主机的协议类型(HTTP/HTTPS)
func GetProtocol(host string, Timeout int64) (protocol string) { func GetProtocol(host string, Timeout int64) (protocol string) {
protocol = "http" protocol = "http"
//如果端口是80或443,跳过Protocol判断
// 根据标准端口快速判断协议
if strings.HasSuffix(host, ":80") || !strings.Contains(host, ":") { if strings.HasSuffix(host, ":80") || !strings.Contains(host, ":") {
return return
} else if strings.HasSuffix(host, ":443") { } else if strings.HasSuffix(host, ":443") {
@ -233,11 +287,19 @@ func GetProtocol(host string, Timeout int64) (protocol string) {
return return
} }
// 尝试建立TCP连接
socksconn, err := Common.WrapperTcpWithTimeout("tcp", host, time.Duration(Timeout)*time.Second) socksconn, err := Common.WrapperTcpWithTimeout("tcp", host, time.Duration(Timeout)*time.Second)
if err != nil { if err != nil {
return return
} }
conn := tls.Client(socksconn, &tls.Config{MinVersion: tls.VersionTLS10, InsecureSkipVerify: true})
// 尝试TLS握手
conn := tls.Client(socksconn, &tls.Config{
MinVersion: tls.VersionTLS10,
InsecureSkipVerify: true,
})
// 确保连接关闭
defer func() { defer func() {
if conn != nil { if conn != nil {
defer func() { defer func() {
@ -248,10 +310,15 @@ func GetProtocol(host string, Timeout int64) (protocol string) {
conn.Close() conn.Close()
} }
}() }()
// 设置连接超时
conn.SetDeadline(time.Now().Add(time.Duration(Timeout) * time.Second)) conn.SetDeadline(time.Now().Add(time.Duration(Timeout) * time.Second))
// 执行TLS握手
err = conn.Handshake() err = conn.Handshake()
if err == nil || strings.Contains(err.Error(), "handshake failure") { if err == nil || strings.Contains(err.Error(), "handshake failure") {
protocol = "https" protocol = "https"
} }
return protocol return protocol
} }