refactor: 优化控制台输出格式

- 去掉时间戳,保留[*][+]前缀
- Web输出合并WebTitle和WebFinger为一行
- 有指纹显示绿色[+],无指纹显示白色[*]
- 格式: code:xxx len:xxx title:xxx server:xxx [指纹]
- 服务探测格式: [Product:xxx ||Version:xxx] Banner:(xxx)
- 字段对齐,输出更清爽
This commit is contained in:
ZacharyZcR
2026-01-20 12:05:01 +08:00
parent e86dd1a231
commit 4ef21f3841
3 changed files with 48 additions and 31 deletions
+2 -3
View File
@@ -114,10 +114,9 @@ func (l *Logger) log(level LogLevel, content string) {
return return
} }
// 格式化消息 // 格式化消息:保留前缀,去掉时间戳
timeStr := l.formatElapsedTime(time.Since(l.startTime))
prefix := l.getLevelPrefix(level) prefix := l.getLevelPrefix(level)
logMsg := fmt.Sprintf("[%s] %s %s", timeStr, prefix, content) logMsg := fmt.Sprintf("%s %s", prefix, content)
// 输出消息 // 输出消息
l.outputMessage(level, logMsg) l.outputMessage(level, logMsg)
+24 -10
View File
@@ -311,23 +311,37 @@ func isResourceExhaustedError(err error) bool {
} }
// buildServiceLogMessage 构建服务识别的日志信息 // buildServiceLogMessage 构建服务识别的日志信息
// 格式: addr service banner (简洁单行,方便复制) // 格式: addr service [Product:xxx ||Version:xxx] Banner:(xxx)
func buildServiceLogMessage(addr string, serviceInfo *ServiceInfo, isWeb bool) string { func buildServiceLogMessage(addr string, serviceInfo *ServiceInfo, isWeb bool) string {
var parts []string var msg strings.Builder
parts = append(parts, addr) msg.WriteString(fmt.Sprintf("%-21s", addr))
if serviceInfo.Name != "unknown" { if serviceInfo.Name != "unknown" {
parts = append(parts, serviceInfo.Name) msg.WriteString(fmt.Sprintf(" %-8s", serviceInfo.Name))
} }
// Banner 优先,其次是版本信息 // 构建 [Product:xxx ||Version:xxx] 格式
if len(serviceInfo.Banner) > 0 && len(serviceInfo.Banner) < 100 { var info []string
parts = append(parts, strings.TrimSpace(serviceInfo.Banner)) if product, ok := serviceInfo.Extras["product"]; ok && product != "" {
} else if serviceInfo.Version != "" { info = append(info, fmt.Sprintf("Product:%s", product))
parts = append(parts, serviceInfo.Version) }
if serviceInfo.Version != "" {
info = append(info, fmt.Sprintf("Version:%s", serviceInfo.Version))
}
if len(info) > 0 {
msg.WriteString(fmt.Sprintf(" [%s]", strings.Join(info, " ||")))
} }
return strings.Join(parts, " ") // Banner 信息
if len(serviceInfo.Banner) > 0 {
banner := strings.TrimSpace(serviceInfo.Banner)
if len(banner) > 80 {
banner = banner[:80] + "..."
}
msg.WriteString(fmt.Sprintf(" Banner:(%s)", banner))
}
return msg.String()
} }
// scanSinglePort 扫描单个端口并进行服务识别(重构后的简洁版本) // scanSinglePort 扫描单个端口并进行服务识别(重构后的简洁版本)
+22 -18
View File
@@ -40,7 +40,7 @@ func NewWebTitlePlugin() *WebTitlePlugin {
// Scan 执行WebTitle扫描 // Scan 执行WebTitle扫描
func (p *WebTitlePlugin) Scan(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *WebScanResult { func (p *WebTitlePlugin) Scan(ctx context.Context, info *common.HostInfo, config *common.Config, state *common.State) *WebScanResult {
title, status, server, fingerprints, url, err := p.getWebTitle(ctx, info, config) title, status, length, server, fingerprints, url, err := p.getWebTitle(ctx, info, config)
if err != nil { if err != nil {
return &WebScanResult{ return &WebScanResult{
Success: false, Success: false,
@@ -48,21 +48,24 @@ func (p *WebTitlePlugin) Scan(ctx context.Context, info *common.HostInfo, config
} }
} }
msg := fmt.Sprintf("WebTitle %s", url) // 构建输出:URL code:状态码 len:长度 title:标题 server:服务器 [指纹]
if title != "" { titleDisplay := title
msg += fmt.Sprintf(" [%s]", title) if titleDisplay == "" {
} titleDisplay = "None"
if status != 0 {
msg += fmt.Sprintf(" %d", status)
} }
msg := fmt.Sprintf("%-30s code:%-3d len:%-5d title:%-20s", url, status, length, titleDisplay)
if server != "" { if server != "" {
msg += fmt.Sprintf(" %s", server) msg += fmt.Sprintf(" server:%s", server)
} }
// 基础信息用白色输出
common.LogInfo(msg)
// 指纹信息单独用绿色输出
if len(fingerprints) > 0 { if len(fingerprints) > 0 {
common.LogSuccess(fmt.Sprintf("WebFinger %s %v", url, fingerprints)) msg += fmt.Sprintf(" %v", fingerprints)
}
// 有指纹用绿色,无指纹用白色
if len(fingerprints) > 0 {
common.LogSuccess(msg)
} else {
common.LogInfo(msg)
} }
return &WebScanResult{ return &WebScanResult{
@@ -75,7 +78,7 @@ func (p *WebTitlePlugin) Scan(ctx context.Context, info *common.HostInfo, config
} }
} }
func (p *WebTitlePlugin) getWebTitle(ctx context.Context, info *common.HostInfo, config *common.Config) (string, int, string, []string, string, error) { func (p *WebTitlePlugin) getWebTitle(ctx context.Context, info *common.HostInfo, config *common.Config) (string, int, int, string, []string, string, error) {
// 智能协议检测 // 智能协议检测
protocol := p.detectProtocol(info, config) protocol := p.detectProtocol(info, config)
baseURL := fmt.Sprintf("%s://%s:%d", protocol, info.Host, info.Port) baseURL := fmt.Sprintf("%s://%s:%d", protocol, info.Host, info.Port)
@@ -90,7 +93,7 @@ func (p *WebTitlePlugin) getWebTitle(ctx context.Context, info *common.HostInfo,
req, err := http.NewRequestWithContext(ctx, "GET", baseURL, nil) req, err := http.NewRequestWithContext(ctx, "GET", baseURL, nil)
if err != nil { if err != nil {
return "", 0, "", nil, displayURL, err return "", 0, 0, "", nil, displayURL, err
} }
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
@@ -98,13 +101,14 @@ func (p *WebTitlePlugin) getWebTitle(ctx context.Context, info *common.HostInfo,
// 先使用不跟随重定向的Client获取原始响应 // 先使用不跟随重定向的Client获取原始响应
resp, err := lib.ClientNoRedirect.Do(req) resp, err := lib.ClientNoRedirect.Do(req)
if err != nil { if err != nil {
return "", 0, "", nil, displayURL, err return "", 0, 0, "", nil, displayURL, err
} }
body, err := io.ReadAll(resp.Body) body, err := io.ReadAll(resp.Body)
_ = resp.Body.Close() _ = resp.Body.Close()
if len(body) <= 0 && err != nil { contentLen := len(body)
return "", resp.StatusCode, resp.Header.Get("Server"), nil, displayURL, err if contentLen <= 0 && err != nil {
return "", resp.StatusCode, 0, resp.Header.Get("Server"), nil, displayURL, err
} }
// 收集用于指纹识别的响应数据 // 收集用于指纹识别的响应数据
@@ -157,7 +161,7 @@ func (p *WebTitlePlugin) getWebTitle(ctx context.Context, info *common.HostInfo,
// 执行指纹识别(合并原始响应和跳转后响应的指纹) // 执行指纹识别(合并原始响应和跳转后响应的指纹)
fingerprints := p.identifyFingerprintsMulti(info, baseURL, checkDataList, config) fingerprints := p.identifyFingerprintsMulti(info, baseURL, checkDataList, config)
return title, statusCode, server, fingerprints, displayURL, nil return title, statusCode, contentLen, server, fingerprints, displayURL, nil
} }
// resolveRedirectURL 解析重定向URL,处理相对路径 // resolveRedirectURL 解析重定向URL,处理相对路径