diff --git a/Plugins/ICMP.go b/Plugins/ICMP.go index 240228b..4648e5b 100644 --- a/Plugins/ICMP.go +++ b/Plugins/ICMP.go @@ -14,88 +14,118 @@ import ( ) var ( - AliveHosts []string - ExistHosts = make(map[string]struct{}) - livewg sync.WaitGroup + AliveHosts []string // 存活主机列表 + ExistHosts = make(map[string]struct{}) // 已发现主机记录 + livewg sync.WaitGroup // 存活检测等待组 ) +// CheckLive 检测主机存活状态 func CheckLive(hostslist []string, Ping bool) []string { + // 创建主机通道 chanHosts := make(chan string, len(hostslist)) - go func() { - for ip := range chanHosts { - if _, ok := ExistHosts[ip]; !ok && IsContain(hostslist, ip) { - ExistHosts[ip] = struct{}{} - if Common.Silent == false { - if Ping == false { - fmt.Printf("(icmp) Target %-15s is alive\n", ip) - } else { - fmt.Printf("(ping) Target %-15s is alive\n", ip) - } - } - AliveHosts = append(AliveHosts, ip) - } - livewg.Done() - } - }() - if Ping == true { - //使用ping探测 + // 处理存活主机 + go handleAliveHosts(chanHosts, hostslist, Ping) + + // 根据Ping参数选择检测方式 + if Ping { + // 使用ping方式探测 RunPing(hostslist, chanHosts) } else { - //优先尝试监听本地icmp,批量探测 - conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") - if err == nil { - RunIcmp1(hostslist, conn, chanHosts) - } else { - Common.LogError(err) - //尝试无监听icmp探测 - fmt.Println("trying RunIcmp2") - conn, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second) - defer func() { - if conn != nil { - conn.Close() - } - }() - if err == nil { - RunIcmp2(hostslist, chanHosts) - } else { - Common.LogError(err) - //使用ping探测 - fmt.Println("The current user permissions unable to send icmp packets") - fmt.Println("start ping") - RunPing(hostslist, chanHosts) - } - } + probeWithICMP(hostslist, chanHosts) } + // 等待所有检测完成 livewg.Wait() close(chanHosts) - if len(hostslist) > 1000 { - arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, true) - for i := 0; i < len(arrTop); i++ { - output := fmt.Sprintf("[*] LiveTop %-16s 段存活数量为: %d", arrTop[i]+".0.0/16", arrLen[i]) - Common.LogSuccess(output) - } - } - if len(hostslist) > 256 { - arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, false) - for i := 0; i < len(arrTop); i++ { - output := fmt.Sprintf("[*] LiveTop %-16s 段存活数量为: %d", arrTop[i]+".0/24", arrLen[i]) - Common.LogSuccess(output) - } - } + // 输出存活统计信息 + printAliveStats(hostslist) return AliveHosts } +// handleAliveHosts 处理存活主机信息 +func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) { + for ip := range chanHosts { + if _, ok := ExistHosts[ip]; !ok && IsContain(hostslist, ip) { + ExistHosts[ip] = struct{}{} + + // 输出存活信息 + if !Common.Silent { + protocol := "ICMP" + if isPing { + protocol = "PING" + } + fmt.Printf("[+] 目标 %-15s 存活 (%s)\n", ip, protocol) + } + + AliveHosts = append(AliveHosts, ip) + } + livewg.Done() + } +} + +// probeWithICMP 使用ICMP方式探测 +func probeWithICMP(hostslist []string, chanHosts chan string) { + // 尝试监听本地ICMP + conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") + if err == nil { + RunIcmp1(hostslist, conn, chanHosts) + return + } + + Common.LogError(err) + fmt.Println("[-] 正在尝试无监听ICMP探测...") + + // 尝试无监听ICMP探测 + conn2, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second) + if err == nil { + defer conn2.Close() + RunIcmp2(hostslist, chanHosts) + return + } + + Common.LogError(err) + fmt.Println("[-] 当前用户权限不足,无法发送ICMP包") + fmt.Println("[*] 切换为PING方式探测...") + + // 降级使用ping探测 + RunPing(hostslist, chanHosts) +} + +// printAliveStats 打印存活统计信息 +func printAliveStats(hostslist []string) { + // 大规模扫描时输出 /16 网段统计 + if len(hostslist) > 1000 { + arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, true) + for i := 0; i < len(arrTop); i++ { + output := fmt.Sprintf("[*] B段 %-16s 存活主机数: %d", arrTop[i]+".0.0/16", arrLen[i]) + Common.LogSuccess(output) + } + } + + // 输出 /24 网段统计 + if len(hostslist) > 256 { + arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, false) + for i := 0; i < len(arrTop); i++ { + output := fmt.Sprintf("[*] C段 %-16s 存活主机数: %d", arrTop[i]+".0/24", arrLen[i]) + Common.LogSuccess(output) + } + } +} + +// RunIcmp1 使用ICMP批量探测主机存活(监听模式) func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) { endflag := false + + // 启动监听协程 go func() { for { - if endflag == true { + if endflag { return } + // 接收ICMP响应 msg := make([]byte, 100) _, sourceIP, _ := conn.ReadFrom(msg) if sourceIP != nil { @@ -105,71 +135,93 @@ func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) } }() + // 发送ICMP请求 for _, host := range hostslist { dst, _ := net.ResolveIPAddr("ip", host) IcmpByte := makemsg(host) conn.WriteTo(IcmpByte, dst) } - //根据hosts数量修改icmp监听时间 + + // 等待响应 start := time.Now() for { + // 所有主机都已响应则退出 if len(AliveHosts) == len(hostslist) { break } + + // 根据主机数量设置超时时间 since := time.Since(start) - var wait time.Duration - switch { - case len(hostslist) <= 256: + wait := time.Second * 6 + if len(hostslist) <= 256 { wait = time.Second * 3 - default: - wait = time.Second * 6 } + if since > wait { break } } + endflag = true conn.Close() } +// RunIcmp2 使用ICMP并发探测主机存活(无监听模式) func RunIcmp2(hostslist []string, chanHosts chan string) { + // 控制并发数 num := 1000 if len(hostslist) < num { num = len(hostslist) } + var wg sync.WaitGroup limiter := make(chan struct{}, num) + + // 并发探测 for _, host := range hostslist { wg.Add(1) limiter <- struct{}{} + go func(host string) { + defer func() { + <-limiter + wg.Done() + }() + if icmpalive(host) { livewg.Add(1) chanHosts <- host } - <-limiter - wg.Done() }(host) } + wg.Wait() close(limiter) } +// icmpalive 检测主机ICMP是否存活 func icmpalive(host string) bool { startTime := time.Now() + + // 建立ICMP连接 conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second) if err != nil { return false } defer conn.Close() + + // 设置超时时间 if err := conn.SetDeadline(startTime.Add(6 * time.Second)); err != nil { return false } + + // 构造并发送ICMP请求 msg := makemsg(host) if _, err := conn.Write(msg); err != nil { return false } + // 接收ICMP响应 receive := make([]byte, 60) if _, err := conn.Read(receive); err != nil { return false @@ -178,133 +230,174 @@ func icmpalive(host string) bool { return true } +// RunPing 使用系统Ping命令并发探测主机存活 func RunPing(hostslist []string, chanHosts chan string) { var wg sync.WaitGroup + // 限制并发数为50 limiter := make(chan struct{}, 50) + + // 并发探测 for _, host := range hostslist { wg.Add(1) limiter <- struct{}{} + go func(host string) { + defer func() { + <-limiter + wg.Done() + }() + if ExecCommandPing(host) { livewg.Add(1) chanHosts <- host } - <-limiter - wg.Done() }(host) } + wg.Wait() } +// ExecCommandPing 执行系统Ping命令检测主机存活 func ExecCommandPing(ip string) bool { var command *exec.Cmd + + // 根据操作系统选择不同的ping命令 switch runtime.GOOS { case "windows": - command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" + command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false") case "darwin": - command = exec.Command("/bin/bash", "-c", "ping -c 1 -W 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" - default: //linux - command = exec.Command("/bin/bash", "-c", "ping -c 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" + command = exec.Command("/bin/bash", "-c", "ping -c 1 -W 1 "+ip+" && echo true || echo false") + default: // linux + command = exec.Command("/bin/bash", "-c", "ping -c 1 -w 1 "+ip+" && echo true || echo false") } - outinfo := bytes.Buffer{} + + // 捕获命令输出 + var outinfo bytes.Buffer command.Stdout = &outinfo - err := command.Start() - if err != nil { + + // 执行命令 + if err := command.Start(); err != nil { return false } - if err = command.Wait(); err != nil { + + if err := command.Wait(); err != nil { return false - } else { - if strings.Contains(outinfo.String(), "true") && strings.Count(outinfo.String(), ip) > 2 { - return true - } else { - return false - } } + + // 分析输出结果 + output := outinfo.String() + return strings.Contains(output, "true") && strings.Count(output, ip) > 2 } +// makemsg 构造ICMP echo请求消息 func makemsg(host string) []byte { msg := make([]byte, 40) + + // 获取标识符 id0, id1 := genIdentifier(host) - msg[0] = 8 - msg[1] = 0 - msg[2] = 0 - msg[3] = 0 - msg[4], msg[5] = id0, id1 - msg[6], msg[7] = genSequence(1) + + // 设置ICMP头部 + msg[0] = 8 // Type: Echo Request + msg[1] = 0 // Code: 0 + msg[2] = 0 // Checksum高位(待计算) + msg[3] = 0 // Checksum低位(待计算) + msg[4], msg[5] = id0, id1 // Identifier + msg[6], msg[7] = genSequence(1) // Sequence Number + + // 计算校验和 check := checkSum(msg[0:40]) - msg[2] = byte(check >> 8) - msg[3] = byte(check & 255) + msg[2] = byte(check >> 8) // 设置校验和高位 + msg[3] = byte(check & 255) // 设置校验和低位 + return msg } +// checkSum 计算ICMP校验和 func checkSum(msg []byte) uint16 { sum := 0 length := len(msg) + + // 按16位累加 for i := 0; i < length-1; i += 2 { sum += int(msg[i])*256 + int(msg[i+1]) } + + // 处理奇数长度情况 if length%2 == 1 { sum += int(msg[length-1]) * 256 } + + // 将高16位加到低16位 sum = (sum >> 16) + (sum & 0xffff) sum = sum + (sum >> 16) - answer := uint16(^sum) - return answer + + // 取反得到校验和 + return uint16(^sum) } +// genSequence 生成ICMP序列号 func genSequence(v int16) (byte, byte) { - ret1 := byte(v >> 8) - ret2 := byte(v & 255) + ret1 := byte(v >> 8) // 高8位 + ret2 := byte(v & 255) // 低8位 return ret1, ret2 } +// genIdentifier 根据主机地址生成标识符 func genIdentifier(host string) (byte, byte) { - return host[0], host[1] + return host[0], host[1] // 使用主机地址前两个字节 } +// ArrayCountValueTop 统计IP地址段存活数量并返回TOP N结果 func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []string, arrLen []int) { if len(arrInit) == 0 { return } - arrMap1 := make(map[string]int) - arrMap2 := make(map[string]int) - for _, value := range arrInit { - line := strings.Split(value, ".") - if len(line) == 4 { - if flag { - value = fmt.Sprintf("%s.%s", line[0], line[1]) - } else { - value = fmt.Sprintf("%s.%s.%s", line[0], line[1], line[2]) - } + + // 统计各网段出现次数 + segmentCounts := make(map[string]int) + for _, ip := range arrInit { + segments := strings.Split(ip, ".") + if len(segments) != 4 { + continue } - if arrMap1[value] != 0 { - arrMap1[value]++ + + // 根据flag确定统计B段还是C段 + var segment string + if flag { + segment = fmt.Sprintf("%s.%s", segments[0], segments[1]) // B段 } else { - arrMap1[value] = 1 + segment = fmt.Sprintf("%s.%s.%s", segments[0], segments[1], segments[2]) // C段 } - } - for k, v := range arrMap1 { - arrMap2[k] = v + + segmentCounts[segment]++ } - i := 0 - for range arrMap1 { - var maxCountKey string - var maxCountVal = 0 - for key, val := range arrMap2 { - if val > maxCountVal { - maxCountVal = val - maxCountKey = key + // 创建副本用于排序 + sortMap := make(map[string]int) + for k, v := range segmentCounts { + sortMap[k] = v + } + + // 获取TOP N结果 + for i := 0; i < length && len(sortMap) > 0; i++ { + maxSegment := "" + maxCount := 0 + + // 查找当前最大值 + for segment, count := range sortMap { + if count > maxCount { + maxCount = count + maxSegment = segment } } - arrTop = append(arrTop, maxCountKey) - arrLen = append(arrLen, maxCountVal) - i++ - if i >= length { - return - } - delete(arrMap2, maxCountKey) + + // 添加到结果集 + arrTop = append(arrTop, maxSegment) + arrLen = append(arrLen, maxCount) + + // 从待处理map中删除已处理项 + delete(sortMap, maxSegment) } + return }