diff --git a/README.md b/README.md index 09e01d5..7cea47f 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ | 11 | 主机操作系统识别 | √ | 基于ttl | | 12 | 组件识别 | √ | 目前常用200+ | | 13 | 自动扫描弱口令 | √ | rdp、ssh、redis、mysql、oracle、es、telnet、pgsql等 | -| 14 | web自动扫描xss | √ | 仅验证反射型 | +| 14 | web自动扫描xss | √ | | @@ -92,7 +92,7 @@ | 13 | 识别目录浏览 | √ | | | 14 | 识别敏感信息泄露 | √ | | | 15 | 识别文件下载 | √ | | -| 16 | xss扫描 | √ | 仅验证反射型 | +| 16 | xss扫描 | √ | | | 17 | 组件识别 | √ | 目前常用200+ | ## 子域名扫描现阶段支持功能 @@ -108,12 +108,14 @@ # 常用启动参数 ``` golin web (通过web方式启动,仅支持等保功能) -golin port -i 192.168.1.1/24 (扫描c段端口以及弱口令) +golin port -i 192.168.1.1/24 (扫描c段端口并扫描弱口令、xss、poc漏洞) +golin port -i 192.168.1.1/24 -c 1000 -t 1(仅扫描c段端口并设置并发数为1000,端口连接超时为1秒) golin port -i 192.168.1.1/24 --noping --nocrack --random(扫描c段端口但不探测存活不扫描弱口令,并且打乱主机顺序扫描) golin port -i 192.168.1.1/24 --noxss(扫描c段端口但禁用扫描xss) +golin port -i 192.168.1.1/24 --nopoc(扫描c段端口但禁用扫描poc) golin dirsearch -u https://test.com -f 字典.txt --code 200,404 (扫描状态码为200以及404的web目录) golin domain -u baidu.com --api (扫描子域名,并且调用fofa、RapidDNS的API) -golin [linux、mysql、oracle、sqlserver、redis、windows...] (按照3级等保要求核查各项安全配置) +golin [linux、mysql、oracle、sqlserver、redis、windows...] (按照3级等保要求核查各项安全配置生成html形式报告) golin update (检查是否可更新) ``` diff --git a/dirscan/StatusCode.go b/dirscan/StatusCode.go index 13626ea..50fd70f 100644 --- a/dirscan/StatusCode.go +++ b/dirscan/StatusCode.go @@ -103,7 +103,6 @@ func isStatusCodeOk(URL string) { } for k, v := range ContentType { - //fmt.Println(contype, k, v) if strings.Contains(contype, k) { yesurl.info = append(yesurl.info, v) } diff --git a/global/percent.go b/global/percent.go index 12ba9c1..b672d93 100644 --- a/global/percent.go +++ b/global/percent.go @@ -12,7 +12,7 @@ var ( ) // Percent 输出进度条 -func Percent(mu *sync.Mutex, succeCount, countall int) { +func Percent(mu *sync.Mutex, succeCount, countall uint32) { percent := (float64(succeCount) / float64(countall)) * 100.00 spinChar := rotateSpinner(mu) diff --git a/global/version.go b/global/version.go index 3918be2..3d379b7 100644 --- a/global/version.go +++ b/global/version.go @@ -1,7 +1,7 @@ package global const ( - Version = "v3.3.2" //当前版本号 - Releasenotes = "增加识别主机来源局域网/互联网,增加识别CVE-2022-22947漏洞检测,NPS内网穿透默认口令扫描,增加识别web组件数量,优化扫描进度条输出" //版本说明 - RepoUrl = "https://api.github.com/repos/selinuxg/Golin/releases/latest" //仓库最新版本 + Version = "v3.3.3" //当前版本号 + Releasenotes = "优化并发逻辑,扫描速度增加;增加扫描Druidun默认口令、swagger未授权访问漏洞" //版本说明 + RepoUrl = "https://api.github.com/repos/selinuxg/Golin/releases/latest" //仓库最新版本 ) diff --git a/poc/AuthDruidun.go b/poc/AuthDruidun.go new file mode 100644 index 0000000..127df3e --- /dev/null +++ b/poc/AuthDruidun.go @@ -0,0 +1,34 @@ +package poc + +import ( + "io" + "net/http" + "strings" +) + +func AuthDruidun(url string) { + url += "/druid/index.html" + req, _ := http.NewRequest("GET", url, nil) + resp, err := newRequest(req) + if err != nil { + return + } + defer resp.Body.Close() + + if resp.StatusCode == 200 { + bodyBytes, err2 := io.ReadAll(resp.Body) + if err2 != nil { + return + } + bodyString := string(bodyBytes) + if strings.Contains(bodyString, "Druid Stat Index") && + strings.Contains(bodyString, "DruidVersion") && + strings.Contains(bodyString, "DruidDrivers") { + flags := Flagcve{ + url: url, + cve: "Druid未授权访问", + } + echoFlag(flags) + } + } +} diff --git a/poc/AuthSwagger.go b/poc/AuthSwagger.go new file mode 100644 index 0000000..e676058 --- /dev/null +++ b/poc/AuthSwagger.go @@ -0,0 +1,63 @@ +package poc + +import ( + "io" + "net/http" + "strings" +) + +func AuthSwagger(url string) { + + paths := []string{ + "/swagger/ui/index", + "/swagger-ui.html", + "/api/swagger-ui.html", + "/service/swagger-ui.html", + "/web/swagger-ui.html", + "/swagger/swagger-ui.html", + "/actuator/swagger-ui.html", + "/libs/swagger-ui.html", + "/template/swagger-ui.html", + "/api_docs", + "/api/docs/", + "/api/index.html", + "/swagger/v1/swagger.yaml", + "/swagger/v1/swagger.json", + "/swagger.yaml", + "/swagger.json", + "/api-docs/swagger.yaml", + "/api-docs/swagger.json", + } + + for _, path := range paths { + req, _ := http.NewRequest("GET", url+path, nil) + resp, err := newRequest(req) + + if err != nil { + continue + } + defer resp.Body.Close() + + if resp.StatusCode == 200 { + bodyBytes, err2 := io.ReadAll(resp.Body) + if err2 != nil { + continue + } + bodyString := string(bodyBytes) + + if strings.Contains(bodyString, "Swagger UI") || + strings.Contains(bodyString, "swagger-ui.min.js") || + strings.Contains(bodyString, "swagger:") || + strings.Contains(bodyString, "Swagger 2.0") || + strings.Contains(bodyString, "\"swagger\":") { + flags := Flagcve{ + url: url + path, + cve: "swagger未授权访问", + } + echoFlag(flags) + //break + } + } + } + +} diff --git a/poc/Spring-CVE-2022-22947.go b/poc/Spring-CVE-2022-22947.go index 94b7e1c..dc77298 100644 --- a/poc/Spring-CVE-2022-22947.go +++ b/poc/Spring-CVE-2022-22947.go @@ -65,7 +65,7 @@ func CVE_2022_22947(url, cmd string) { flags := Flagcve{ url: url, cve: "CVE_2022_22947", - flag: flag, + flag: "执行命令结果:" + flag, } echoFlag(flags) } diff --git a/poc/client.go b/poc/client.go index 558307a..fb05967 100644 --- a/poc/client.go +++ b/poc/client.go @@ -1,14 +1,23 @@ package poc import ( + "crypto/tls" "net/http" "time" ) func newRequest(req *http.Request) (*http.Response, error) { + + transport := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }} + client := &http.Client{ - Timeout: time.Second * 3, + Transport: transport, + Timeout: time.Second * 3, } + resp, err := client.Do(req) return resp, err } diff --git a/poc/nps-default-password.go b/poc/nps-default-password.go index ae1f77d..1faa7e6 100644 --- a/poc/nps-default-password.go +++ b/poc/nps-default-password.go @@ -6,8 +6,8 @@ import ( "net/http" ) -// npc_default_passwd nps默认账号密码admin/123 -func nps_default_passwd(url string) { +// NPS_default_passwd nps默认账号密码admin/123 +func NPS_default_passwd(url string) { url += "/login/verify" var data = []byte(`username=admin&password=123`) req, err := http.NewRequest("POST", url, bytes.NewBuffer(data)) diff --git a/poc/run.go b/poc/run.go index 747b69e..116bac7 100644 --- a/poc/run.go +++ b/poc/run.go @@ -18,12 +18,21 @@ func CheckPoc(url, app string) { url = url[:len(url)-1] } + functions := []func(string){ + AuthDruidun, //Druid未授权访问 + AuthSwagger, //swagger未授权访问 + } + for _, function := range functions { + function(url) + } + + //以下是基于特征扫描 app = strings.ToLower(app) switch { case strings.Contains(app, "spring"): CVE_2022_22947(url, "pwd") //任意执行命令 case strings.Contains(app, "nps"): - nps_default_passwd(url) //默认用户密码 + NPS_default_passwd(url) //默认用户密码 } } @@ -32,7 +41,7 @@ func echoFlag(flag Flagcve) { fmt.Printf("\033[2K\r") // 擦除整行 fmt.Printf("\r| %-2s | %-15s | %-15s |%s\n", fmt.Sprintf("%s", color.RedString("%s", "✓")), - fmt.Sprintf("%s", color.RedString("发现漏洞_%s", flag.cve)), + fmt.Sprintf("%s", color.RedString("漏洞:%s", flag.cve)), fmt.Sprintf("%s", color.RedString(flag.url)), fmt.Sprintf("%s", color.RedString(flag.flag)), ) diff --git a/port/Protocol/web.go b/port/Protocol/web.go index 0bbb88d..c600052 100644 --- a/port/Protocol/web.go +++ b/port/Protocol/web.go @@ -16,13 +16,14 @@ import ( ) type webinfo struct { - url string - title string - app string - statuscode int - ContentType string - xss string - server string + url string //web地址 + title string //网站标题 + app string //识别到的组件 + statuscode int //状态码 + ContentType string //ContentType + xss string //是否存在xss漏洞 + server string //ContentType中的server + risk string //通过title与ContentType确认是否存在风险 } func IsWeb(host, port string, timeout int, xss, Poc bool) string { @@ -81,8 +82,14 @@ func IsWeb(host, port string, timeout int, xss, Poc bool) string { //poc扫描 if Poc { go poc.CheckPoc(info.url, info.app) + } + // 基于title确认是否url是目录浏览 + var risk []string + if strings.Contains(strings.ToLower(info.title), "index of") { + risk = append(risk, "目录浏览漏洞") } + info.risk = strings.Join(risk, ",") info.server = resp.Header.Get("Server") @@ -134,8 +141,12 @@ func CheckApp(body string, head map[string][]string, cookies []*http.Cookie) str func chekwebinfo(info webinfo) string { output := fmt.Sprintf("%-23s ", info.url) + if info.risk != "" { + output += color.RedString("%s", fmt.Sprintf("[%s]", info.risk)) + } + if info.xss != "" { - output += color.RedString("%s", fmt.Sprintf(" XSS:「%s」", info.xss)) + output += color.RedString("%s", fmt.Sprintf(" [XSS漏洞:%s]", info.xss)) } if info.app != "" { diff --git a/port/Protocol/web_RuleDatas.go b/port/Protocol/web_RuleDatas.go index eefa545..9b54870 100644 --- a/port/Protocol/web_RuleDatas.go +++ b/port/Protocol/web_RuleDatas.go @@ -15,7 +15,7 @@ var RuleDatas = []RuleData{ {"织梦内容管理系统", "body", "(织梦内容管理系统)"}, {"宝塔", "body", "(app.bt.cn/static/app.png|安全入口校验失败|入口校验失败|href=\"http://www.bt.cn/bbs|恭喜, 站点创建成功!)"}, {"启明防火墙", "body", "(/cgi-bin/webui?op=get_product_model)"}, - {"数据库「ElasticSearch」(未授权)", "body", `(?s)"name"\s*:\s*"[^"]*".*?"cluster_name"\s*:\s*"[^"]*".*?"cluster_uuid"\s*:\s*"[^"]*".*?"number"\s*:\s*"[^"]*"`}, + {"数据库|ElasticSearch[存在未授权漏洞]", "body", `(?s)"name"\s*:\s*"[^"]*".*?"cluster_name"\s*:\s*"[^"]*".*?"cluster_uuid"\s*:\s*"[^"]*".*?"number"\s*:\s*"[^"]*"`}, {"AList", "body", "(由 AList 驱动|alist_pic.js)"}, {"数据库「MongoDB」", "body", `(MongoDB)`}, {"ZABBIX-监控系统", "body", "(Zabbix SIA|omni: Zabbix|images/general/zabbix.ico|Zabbix SIA|zabbix-server: Zabbix)"}, diff --git a/port/crack/ftp.go b/port/crack/ftp.go index 6e83ec1..46f2130 100644 --- a/port/crack/ftp.go +++ b/port/crack/ftp.go @@ -4,10 +4,11 @@ import ( "context" "fmt" "github.com/jlaffaye/ftp" + "sync" "time" ) -func ftpcon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int) { +func ftpcon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) { defer func() { wg.Done() <-ch diff --git a/port/crack/mysql.go b/port/crack/mysql.go index aa139a7..d7eb958 100644 --- a/port/crack/mysql.go +++ b/port/crack/mysql.go @@ -6,9 +6,10 @@ import ( "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" + "sync" ) -func mySql(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int) { +func mySql(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) { defer func() { wg.Done() <-ch diff --git a/port/crack/oracle.go b/port/crack/oracle.go index 0ab6fcc..4ebc488 100644 --- a/port/crack/oracle.go +++ b/port/crack/oracle.go @@ -5,10 +5,11 @@ import ( "database/sql" "fmt" _ "github.com/sijms/go-ora/v2" + "sync" "time" ) -func oraclecon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int) { +func oraclecon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) { defer func() { wg.Done() <-ch diff --git a/port/crack/pgsql.go b/port/crack/pgsql.go index 6c06659..c63e8cc 100644 --- a/port/crack/pgsql.go +++ b/port/crack/pgsql.go @@ -6,13 +6,11 @@ import ( "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" + "sync" ) -func pgsql(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int) { - defer func() { - wg.Done() - <-ch - }() +func pgsql(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) { + defer done(ch, wg) select { case <-ctx.Done(): return diff --git a/port/crack/rdp.go b/port/crack/rdp.go index a83864f..18613e7 100644 --- a/port/crack/rdp.go +++ b/port/crack/rdp.go @@ -32,11 +32,8 @@ type Client struct { vnc *rfb.RFB } -func rdpcon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int) { - defer func() { - wg.Done() - <-ch - }() +func rdpcon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) { + defer done(ch, wg) select { case <-ctx.Done(): return diff --git a/port/crack/redis.go b/port/crack/redis.go index 1160bd8..3683403 100644 --- a/port/crack/redis.go +++ b/port/crack/redis.go @@ -4,12 +4,13 @@ import ( "context" "fmt" "github.com/go-redis/redis/v8" + "sync" "time" ) var ctx = context.Background() -func rediscon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int) { +func rediscon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) { defer func() { wg.Done() <-ch diff --git a/port/crack/run.go b/port/crack/run.go index ce59f45..8109d46 100644 --- a/port/crack/run.go +++ b/port/crack/run.go @@ -8,13 +8,8 @@ import ( "sync" ) -var ( - ch = make(chan struct{}, 100) - wg = sync.WaitGroup{} -) - // ConnectionFunc 定义一个函数类型 -type ConnectionFunc func(ctx context.Context, cancel context.CancelFunc, host, user, passwd string, newport, Timeout int) +type ConnectionFunc func(ctx context.Context, cancel context.CancelFunc, host, user, passwd string, newport, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) // connectionFuncs 创建一个映射,将字符串映射到对应的函数 var connectionFuncs = map[string]ConnectionFunc{ @@ -32,24 +27,20 @@ var connectionFuncs = map[string]ConnectionFunc{ } func Run(host, port string, Timeout, chanCount int, mode string) { - if chanCount < 300 { - chanCount = 300 - } - ch = make(chan struct{}, chanCount) + ch := make(chan struct{}, chanCount) + wg := sync.WaitGroup{} ctx, cancel := context.WithCancel(context.Background()) defer cancel() //确保所有的goroutine都已经退出 newport, _ := strconv.Atoi(port) for _, user := range Userlist(mode) { for _, passwd := range Passwdlist() { - ch <- struct{}{} - wg.Add(1) - fmt.Printf("\033[2K\r") // 擦除整行 fmt.Printf("\r%s", color.MagentaString("\r[...] 正在进行弱口令扫描 -> %s", fmt.Sprintf("%s://%s:%s?user=%s?passwd=%s", mode, host, port, user, passwd))) - + ch <- struct{}{} + wg.Add(1) if connFunc, ok := connectionFuncs[mode]; ok { - go connFunc(ctx, cancel, host, user, passwd, newport, Timeout) + go connFunc(ctx, cancel, host, user, passwd, newport, Timeout, ch, &wg) } else { wg.Done() <-ch @@ -62,7 +53,7 @@ func Run(host, port string, Timeout, chanCount int, mode string) { func end(host, user, passwd string, port int, mode string) { fmt.Printf("\033[2K\r") // 擦除整行 - fmt.Printf("\r| %-2s | %-15s | %-4d |%-6s|%-4s|%s \n", + fmt.Printf("\r| %-2s | %-15s | %-4d |%-6s|%-4s|%-50s \n", fmt.Sprintf("%s", color.GreenString("%s", "✓")), host, port, @@ -71,5 +62,8 @@ func end(host, user, passwd string, port int, mode string) { fmt.Sprintf("%s", color.RedString(fmt.Sprintf("%s %s", user, passwd))), ) fmt.Printf("\033[2K\r") // 擦除整行 - +} +func done(ch <-chan struct{}, wg *sync.WaitGroup) { + <-ch + wg.Done() } diff --git a/port/crack/smb.go b/port/crack/smb.go index 69838f3..236ddec 100644 --- a/port/crack/smb.go +++ b/port/crack/smb.go @@ -3,9 +3,10 @@ package crack import ( "context" "github.com/stacktitan/smb/smb" + "sync" ) -func smbcon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int) { +func smbcon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) { defer func() { wg.Done() <-ch diff --git a/port/crack/sqlserver.go b/port/crack/sqlserver.go index 31d1b79..1b30df1 100644 --- a/port/crack/sqlserver.go +++ b/port/crack/sqlserver.go @@ -6,9 +6,10 @@ import ( "gorm.io/driver/sqlserver" "gorm.io/gorm" "gorm.io/gorm/logger" + "sync" ) -func sqlservercon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int) { +func sqlservercon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) { defer func() { wg.Done() <-ch diff --git a/port/crack/ssh.go b/port/crack/ssh.go index 609dca7..fc387b5 100644 --- a/port/crack/ssh.go +++ b/port/crack/ssh.go @@ -4,10 +4,11 @@ import ( "context" "fmt" "golang.org/x/crypto/ssh" + "sync" "time" ) -func SSH(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int) { +func SSH(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) { defer func() { wg.Done() <-ch diff --git a/port/crack/telnet.go b/port/crack/telnet.go index 175eba5..f6ea56f 100644 --- a/port/crack/telnet.go +++ b/port/crack/telnet.go @@ -6,10 +6,11 @@ import ( "github.com/ziutek/telnet" "io" "strings" + "sync" "time" ) -func telnetcon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int) { +func telnetcon(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) { defer func() { wg.Done() <-ch diff --git a/port/crack/tomcat.go b/port/crack/tomcat.go index 63f47d1..0b0a85c 100644 --- a/port/crack/tomcat.go +++ b/port/crack/tomcat.go @@ -7,10 +7,11 @@ import ( "io" "net/http" "strings" + "sync" "time" ) -func tomcat(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int) { +func tomcat(ctx context.Context, cancel context.CancelFunc, ip, user, passwd string, port, timeout int, ch <-chan struct{}, wg *sync.WaitGroup) { defer func() { wg.Done() <-ch diff --git a/port/parsePort.go b/port/parsePort.go index 5dbeca5..579847b 100644 --- a/port/parsePort.go +++ b/port/parsePort.go @@ -58,6 +58,7 @@ var ( "21", // FTP "8888", "9999", + "9200", "9080", "8989", "808", @@ -100,8 +101,6 @@ var ( "3306", // MySQL (Alternate) "5432", // PostgreSQL (Alternate) "6378", // redis - "9200", //es - "9300", //es "5601", //kibana "1080", //sock "1194", //vpn diff --git a/port/protocol.go b/port/protocol.go index 3500e8e..b03abf4 100644 --- a/port/protocol.go +++ b/port/protocol.go @@ -39,7 +39,6 @@ var portProtocols = map[string]string{ "6000": "X11", "6443": "Kubernetes", "5672": "RabbitMq", - "9200": "数据库|ES", "27017": "数据库|MongoDB", } diff --git a/port/run.go b/port/run.go index 86d0555..f2b1ff6 100644 --- a/port/run.go +++ b/port/run.go @@ -22,8 +22,8 @@ var ( random bool //打乱顺序 save bool //是否保存 infolist []INFO //成功的主机列表 - allcount int //IP*PORT的总数量 - donecount int //线程技术的数量 + allcount uint32 //IP*PORT的总数量 + donecount uint32 //线程技术的数量 outputMux sync.Mutex userfile string //user字典路径 passwdfile string //passwd字典路径 @@ -56,9 +56,6 @@ func ParseFlags(cmd *cobra.Command, args []string) { ch = make(chan struct{}, chancount) Timeout, _ = cmd.Flags().GetInt("time") //超时等待时常 - if Timeout <= 0 { - Timeout = 3 - } nocrack, _ := cmd.Flags().GetBool("nocrack") //弱口令扫描 if nocrack { diff --git a/port/scanPort.go b/port/scanPort.go index aa54b4a..cdf153c 100644 --- a/port/scanPort.go +++ b/port/scanPort.go @@ -7,13 +7,14 @@ import ( "golin/port/crack" "net" "strings" + "sync/atomic" "time" ) func scanPort() { checkPing() - allcount = len(iplist) * len(portlist) + allcount = uint32(len(iplist) * len(portlist)) for _, ip := range iplist { for _, port := range portlist { @@ -24,7 +25,6 @@ func scanPort() { } wg.Wait() - time.Sleep(time.Second * 1) //等待1秒是为了正常显示进度条 fmt.Printf("\r+------------------------------+\n") fmt.Printf("[*] 存活主机:%v 存活端口:%v ssh:%v rdp:%v web服务:%v 数据库:%v \n", @@ -50,9 +50,7 @@ func IsPortOpen(host, port string) { defer func() { wg.Done() <-ch - outputMux.Lock() - donecount += 1 - outputMux.Unlock() + atomic.AddUint32(&donecount, 1) global.Percent(&outputMux, donecount, allcount) }() @@ -63,9 +61,8 @@ func IsPortOpen(host, port string) { } parseprotocol := parseProtocol(conn, host, port, Xss, Poc) //识别协议、xss、poc扫描 - - fmt.Print("\033[2K") // 擦除整行 - fmt.Printf("\r| %-2s | %-15s | %-4s |%s \n", + fmt.Printf("\033[2K\r") // 擦除整行 + fmt.Printf("\r| %-2s | %-15s | %-4s |%-50s \n", fmt.Sprintf("%s", color.GreenString("%s", "✓")), host, port,