mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-23 19:51:52 +08:00
refacor: 结构化更改
This commit is contained in:
+403
@@ -0,0 +1,403 @@
|
||||
package Core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/Common"
|
||||
"golang.org/x/net/icmp"
|
||||
"net"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
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 handleAliveHosts(chanHosts, hostslist, Ping)
|
||||
|
||||
// 根据Ping参数选择检测方式
|
||||
if Ping {
|
||||
// 使用ping方式探测
|
||||
RunPing(hostslist, chanHosts)
|
||||
} else {
|
||||
probeWithICMP(hostslist, chanHosts)
|
||||
}
|
||||
|
||||
// 等待所有检测完成
|
||||
livewg.Wait()
|
||||
close(chanHosts)
|
||||
|
||||
// 输出存活统计信息
|
||||
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 {
|
||||
return
|
||||
}
|
||||
// 接收ICMP响应
|
||||
msg := make([]byte, 100)
|
||||
_, sourceIP, _ := conn.ReadFrom(msg)
|
||||
if sourceIP != nil {
|
||||
livewg.Add(1)
|
||||
chanHosts <- sourceIP.String()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 发送ICMP请求
|
||||
for _, host := range hostslist {
|
||||
dst, _ := net.ResolveIPAddr("ip", host)
|
||||
IcmpByte := makemsg(host)
|
||||
conn.WriteTo(IcmpByte, dst)
|
||||
}
|
||||
|
||||
// 等待响应
|
||||
start := time.Now()
|
||||
for {
|
||||
// 所有主机都已响应则退出
|
||||
if len(AliveHosts) == len(hostslist) {
|
||||
break
|
||||
}
|
||||
|
||||
// 根据主机数量设置超时时间
|
||||
since := time.Since(start)
|
||||
wait := time.Second * 6
|
||||
if len(hostslist) <= 256 {
|
||||
wait = time.Second * 3
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}(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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}(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")
|
||||
case "darwin":
|
||||
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")
|
||||
}
|
||||
|
||||
// 捕获命令输出
|
||||
var outinfo bytes.Buffer
|
||||
command.Stdout = &outinfo
|
||||
|
||||
// 执行命令
|
||||
if err := command.Start(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if err := command.Wait(); err != nil {
|
||||
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)
|
||||
|
||||
// 设置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) // 设置校验和低位
|
||||
|
||||
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)
|
||||
|
||||
// 取反得到校验和
|
||||
return uint16(^sum)
|
||||
}
|
||||
|
||||
// genSequence 生成ICMP序列号
|
||||
func genSequence(v int16) (byte, byte) {
|
||||
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] // 使用主机地址前两个字节
|
||||
}
|
||||
|
||||
// ArrayCountValueTop 统计IP地址段存活数量并返回TOP N结果
|
||||
func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []string, arrLen []int) {
|
||||
if len(arrInit) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// 统计各网段出现次数
|
||||
segmentCounts := make(map[string]int)
|
||||
for _, ip := range arrInit {
|
||||
segments := strings.Split(ip, ".")
|
||||
if len(segments) != 4 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 根据flag确定统计B段还是C段
|
||||
var segment string
|
||||
if flag {
|
||||
segment = fmt.Sprintf("%s.%s", segments[0], segments[1]) // B段
|
||||
} else {
|
||||
segment = fmt.Sprintf("%s.%s.%s", segments[0], segments[1], segments[2]) // C段
|
||||
}
|
||||
|
||||
segmentCounts[segment]++
|
||||
}
|
||||
|
||||
// 创建副本用于排序
|
||||
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, maxSegment)
|
||||
arrLen = append(arrLen, maxCount)
|
||||
|
||||
// 从待处理map中删除已处理项
|
||||
delete(sortMap, maxSegment)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package Core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/Common"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Addr 表示待扫描的地址
|
||||
type Addr struct {
|
||||
ip string // IP地址
|
||||
port int // 端口号
|
||||
}
|
||||
|
||||
// PortScan 执行端口扫描
|
||||
func PortScan(hostslist []string, ports string, timeout int64) []string {
|
||||
var AliveAddress []string
|
||||
|
||||
// 解析端口列表
|
||||
probePorts := Common.ParsePort(ports)
|
||||
if len(probePorts) == 0 {
|
||||
fmt.Printf("[-] 端口格式错误: %s, 请检查端口格式\n", ports)
|
||||
return AliveAddress
|
||||
}
|
||||
|
||||
// 排除指定端口
|
||||
probePorts = excludeNoPorts(probePorts)
|
||||
|
||||
// 创建通道
|
||||
workers := Common.Threads
|
||||
addrs := make(chan Addr, 100)
|
||||
results := make(chan string, 100)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// 接收扫描结果
|
||||
go collectResults(&AliveAddress, results, &wg)
|
||||
|
||||
// 启动扫描协程
|
||||
for i := 0; i < workers; i++ {
|
||||
go func() {
|
||||
for addr := range addrs {
|
||||
PortConnect(addr, results, timeout, &wg)
|
||||
wg.Done()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 添加扫描目标
|
||||
for _, port := range probePorts {
|
||||
for _, host := range hostslist {
|
||||
wg.Add(1)
|
||||
addrs <- Addr{host, port}
|
||||
}
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(addrs)
|
||||
close(results)
|
||||
return AliveAddress
|
||||
}
|
||||
|
||||
// collectResults 收集扫描结果
|
||||
func collectResults(aliveAddrs *[]string, results <-chan string, wg *sync.WaitGroup) {
|
||||
for found := range results {
|
||||
*aliveAddrs = append(*aliveAddrs, found)
|
||||
wg.Done()
|
||||
}
|
||||
}
|
||||
|
||||
// PortConnect 尝试连接指定端口
|
||||
func PortConnect(addr Addr, respondingHosts chan<- string, timeout int64, wg *sync.WaitGroup) {
|
||||
// 建立TCP连接
|
||||
conn, err := Common.WrapperTcpWithTimeout("tcp4",
|
||||
fmt.Sprintf("%s:%v", addr.ip, addr.port),
|
||||
time.Duration(timeout)*time.Second)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// 记录开放端口
|
||||
address := fmt.Sprintf("%s:%d", addr.ip, addr.port)
|
||||
result := fmt.Sprintf("[+] 端口开放 %s", address)
|
||||
Common.LogSuccess(result)
|
||||
|
||||
wg.Add(1)
|
||||
respondingHosts <- address
|
||||
}
|
||||
|
||||
// NoPortScan 生成端口列表(不进行扫描)
|
||||
func NoPortScan(hostslist []string, ports string) []string {
|
||||
var AliveAddress []string
|
||||
|
||||
// 解析并排除端口
|
||||
probePorts := excludeNoPorts(Common.ParsePort(ports))
|
||||
|
||||
// 生成地址列表
|
||||
for _, port := range probePorts {
|
||||
for _, host := range hostslist {
|
||||
address := fmt.Sprintf("%s:%d", host, port)
|
||||
AliveAddress = append(AliveAddress, address)
|
||||
}
|
||||
}
|
||||
|
||||
return AliveAddress
|
||||
}
|
||||
|
||||
// excludeNoPorts 排除指定的端口
|
||||
func excludeNoPorts(ports []int) []int {
|
||||
noPorts := Common.ParsePort(Common.NoPorts)
|
||||
if len(noPorts) == 0 {
|
||||
return ports
|
||||
}
|
||||
|
||||
// 使用map过滤端口
|
||||
temp := make(map[int]struct{})
|
||||
for _, port := range ports {
|
||||
temp[port] = struct{}{}
|
||||
}
|
||||
|
||||
for _, port := range noPorts {
|
||||
delete(temp, port)
|
||||
}
|
||||
|
||||
// 转换为切片并排序
|
||||
var newPorts []int
|
||||
for port := range temp {
|
||||
newPorts = append(newPorts, port)
|
||||
}
|
||||
sort.Ints(newPorts)
|
||||
|
||||
return newPorts
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package Core
|
||||
|
||||
import (
|
||||
"github.com/shadow1ng/fscan/Config"
|
||||
"github.com/shadow1ng/fscan/Plugins"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 注册标准端口服务扫描
|
||||
Config.RegisterPlugin("ftp", Config.ScanPlugin{
|
||||
Name: "FTP",
|
||||
Port: 21,
|
||||
ScanFunc: Plugins.FtpScan,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("ssh", Config.ScanPlugin{
|
||||
Name: "SSH",
|
||||
Port: 22,
|
||||
ScanFunc: Plugins.SshScan,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("findnet", Config.ScanPlugin{
|
||||
Name: "FindNet",
|
||||
Port: 135,
|
||||
ScanFunc: Plugins.Findnet,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("netbios", Config.ScanPlugin{
|
||||
Name: "NetBIOS",
|
||||
Port: 139,
|
||||
ScanFunc: Plugins.NetBIOS,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("smb", Config.ScanPlugin{
|
||||
Name: "SMB",
|
||||
Port: 445,
|
||||
ScanFunc: Plugins.SmbScan,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("mssql", Config.ScanPlugin{
|
||||
Name: "MSSQL",
|
||||
Port: 1433,
|
||||
ScanFunc: Plugins.MssqlScan,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("oracle", Config.ScanPlugin{
|
||||
Name: "Oracle",
|
||||
Port: 1521,
|
||||
ScanFunc: Plugins.OracleScan,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("mysql", Config.ScanPlugin{
|
||||
Name: "MySQL",
|
||||
Port: 3306,
|
||||
ScanFunc: Plugins.MysqlScan,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("rdp", Config.ScanPlugin{
|
||||
Name: "RDP",
|
||||
Port: 3389,
|
||||
ScanFunc: Plugins.RdpScan,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("postgres", Config.ScanPlugin{
|
||||
Name: "PostgreSQL",
|
||||
Port: 5432,
|
||||
ScanFunc: Plugins.PostgresScan,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("redis", Config.ScanPlugin{
|
||||
Name: "Redis",
|
||||
Port: 6379,
|
||||
ScanFunc: Plugins.RedisScan,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("fcgi", Config.ScanPlugin{
|
||||
Name: "FastCGI",
|
||||
Port: 9000,
|
||||
ScanFunc: Plugins.FcgiScan,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("memcached", Config.ScanPlugin{
|
||||
Name: "Memcached",
|
||||
Port: 11211,
|
||||
ScanFunc: Plugins.MemcachedScan,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("mongodb", Config.ScanPlugin{
|
||||
Name: "MongoDB",
|
||||
Port: 27017,
|
||||
ScanFunc: Plugins.MongodbScan,
|
||||
})
|
||||
|
||||
// 注册特殊扫描类型
|
||||
Config.RegisterPlugin("ms17010", Config.ScanPlugin{
|
||||
Name: "MS17010",
|
||||
Port: 445,
|
||||
ScanFunc: Plugins.MS17010,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("smbghost", Config.ScanPlugin{
|
||||
Name: "SMBGhost",
|
||||
Port: 445,
|
||||
ScanFunc: Plugins.SmbGhost,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("web", Config.ScanPlugin{
|
||||
Name: "WebTitle",
|
||||
Port: 0,
|
||||
ScanFunc: Plugins.WebTitle,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("smb2", Config.ScanPlugin{
|
||||
Name: "SMBScan2",
|
||||
Port: 445,
|
||||
ScanFunc: Plugins.SmbScan2,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("wmiexec", Config.ScanPlugin{
|
||||
Name: "WMIExec",
|
||||
Port: 135,
|
||||
ScanFunc: Plugins.WmiExec,
|
||||
})
|
||||
|
||||
Config.RegisterPlugin("localinfo", Config.ScanPlugin{
|
||||
Name: "LocalInfo",
|
||||
Port: 0,
|
||||
ScanFunc: Plugins.LocalInfoScan,
|
||||
})
|
||||
}
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
package Core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/shadow1ng/fscan/Common"
|
||||
"github.com/shadow1ng/fscan/Config"
|
||||
"github.com/shadow1ng/fscan/WebScan/lib"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func Scan(info Config.HostInfo) {
|
||||
fmt.Println("[*] 开始信息扫描...")
|
||||
|
||||
// 本地信息收集模块
|
||||
if Common.Scantype == "localinfo" {
|
||||
ch := make(chan struct{}, Common.Threads)
|
||||
wg := sync.WaitGroup{}
|
||||
AddScan("localinfo", info, &ch, &wg)
|
||||
wg.Wait()
|
||||
Common.LogWG.Wait()
|
||||
close(Common.Results)
|
||||
fmt.Printf("[✓] 扫描完成 %v/%v\n", Common.End, Common.Num)
|
||||
return
|
||||
}
|
||||
|
||||
// 解析目标主机IP
|
||||
Hosts, err := Common.ParseIP(info.Host, Common.HostFile, Common.NoHosts)
|
||||
if err != nil {
|
||||
fmt.Printf("[!] 解析主机错误: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 初始化配置
|
||||
lib.Inithttp()
|
||||
ch := make(chan struct{}, Common.Threads)
|
||||
wg := sync.WaitGroup{}
|
||||
var AlivePorts []string
|
||||
|
||||
if len(Hosts) > 0 || len(Common.HostPort) > 0 {
|
||||
// ICMP存活性检测
|
||||
if (Common.NoPing == false && len(Hosts) > 1) || Common.Scantype == "icmp" {
|
||||
Hosts = CheckLive(Hosts, Common.Ping)
|
||||
fmt.Printf("[+] ICMP存活主机数量: %d\n", len(Hosts))
|
||||
if Common.Scantype == "icmp" {
|
||||
Common.LogWG.Wait()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 端口扫描策略
|
||||
AlivePorts = executeScanStrategy(Hosts, Common.Scantype)
|
||||
|
||||
// 处理自定义端口
|
||||
if len(Common.HostPort) > 0 {
|
||||
AlivePorts = append(AlivePorts, Common.HostPort...)
|
||||
AlivePorts = Common.RemoveDuplicate(AlivePorts)
|
||||
Common.HostPort = nil
|
||||
fmt.Printf("[+] 总计存活端口: %d\n", len(AlivePorts))
|
||||
}
|
||||
|
||||
// 执行扫描任务
|
||||
fmt.Println("[*] 开始漏洞扫描...")
|
||||
for _, targetIP := range AlivePorts {
|
||||
hostParts := strings.Split(targetIP, ":")
|
||||
if len(hostParts) != 2 {
|
||||
fmt.Printf("[!] 无效的目标地址格式: %s\n", targetIP)
|
||||
continue
|
||||
}
|
||||
info.Host, info.Ports = hostParts[0], hostParts[1]
|
||||
|
||||
executeScanTasks(info, Common.Scantype, &ch, &wg)
|
||||
}
|
||||
}
|
||||
|
||||
// URL扫描
|
||||
for _, url := range Common.Urls {
|
||||
info.Url = url
|
||||
AddScan("web", info, &ch, &wg)
|
||||
}
|
||||
|
||||
// 等待所有任务完成
|
||||
wg.Wait()
|
||||
Common.LogWG.Wait()
|
||||
close(Common.Results)
|
||||
fmt.Printf("[✓] 扫描已完成: %v/%v\n", Common.End, Common.Num)
|
||||
}
|
||||
|
||||
// executeScanStrategy 执行端口扫描策略
|
||||
func executeScanStrategy(Hosts []string, scanType string) []string {
|
||||
switch scanType {
|
||||
case "webonly", "webpoc":
|
||||
return NoPortScan(Hosts, Common.Ports)
|
||||
case "hostname":
|
||||
Common.Ports = "139"
|
||||
return NoPortScan(Hosts, Common.Ports)
|
||||
default:
|
||||
if len(Hosts) > 0 {
|
||||
ports := PortScan(Hosts, Common.Ports, Common.Timeout)
|
||||
fmt.Printf("[+] 存活端口数量: %d\n", len(ports))
|
||||
if scanType == "portscan" {
|
||||
Common.LogWG.Wait()
|
||||
return nil
|
||||
}
|
||||
return ports
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// executeScanTasks 执行扫描任务
|
||||
func executeScanTasks(info Config.HostInfo, scanType string, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
if scanType == "all" || scanType == "main" {
|
||||
// 根据端口选择扫描插件
|
||||
switch info.Ports {
|
||||
case "135":
|
||||
AddScan("findnet", info, ch, wg)
|
||||
if Common.IsWmi {
|
||||
AddScan("wmiexec", info, ch, wg)
|
||||
}
|
||||
case "445":
|
||||
AddScan("ms17010", info, ch, wg)
|
||||
case "9000":
|
||||
AddScan("web", info, ch, wg)
|
||||
AddScan("fcgi", info, ch, wg)
|
||||
default:
|
||||
// 查找对应端口的插件
|
||||
for name, plugin := range Config.PluginManager {
|
||||
if strconv.Itoa(plugin.Port) == info.Ports {
|
||||
AddScan(name, info, ch, wg)
|
||||
return
|
||||
}
|
||||
}
|
||||
// 默认执行Web扫描
|
||||
AddScan("web", info, ch, wg)
|
||||
}
|
||||
} else {
|
||||
// 直接使用指定的扫描类型
|
||||
AddScan(scanType, info, ch, wg)
|
||||
}
|
||||
}
|
||||
|
||||
// Mutex用于保护共享资源的并发访问
|
||||
var Mutex = &sync.Mutex{}
|
||||
|
||||
// AddScan 添加扫描任务到并发队列
|
||||
func AddScan(scantype string, info Config.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
// 获取信号量,控制并发数
|
||||
*ch <- struct{}{}
|
||||
// 添加等待组计数
|
||||
wg.Add(1)
|
||||
|
||||
// 启动goroutine执行扫描任务
|
||||
go func() {
|
||||
defer func() {
|
||||
wg.Done() // 完成任务后减少等待组计数
|
||||
<-*ch // 释放信号量
|
||||
}()
|
||||
|
||||
// 增加总任务数
|
||||
Mutex.Lock()
|
||||
Common.Num += 1
|
||||
Mutex.Unlock()
|
||||
|
||||
// 执行扫描
|
||||
ScanFunc(&scantype, &info)
|
||||
|
||||
// 增加已完成任务数
|
||||
Mutex.Lock()
|
||||
Common.End += 1
|
||||
Mutex.Unlock()
|
||||
}()
|
||||
}
|
||||
|
||||
// ScanFunc 执行扫描插件
|
||||
func ScanFunc(name *string, info *Config.HostInfo) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Printf("[!] 扫描错误 %v:%v - %v\n", info.Host, info.Ports, err)
|
||||
}
|
||||
}()
|
||||
|
||||
// 检查插件是否存在
|
||||
plugin, exists := Config.PluginManager[*name]
|
||||
if !exists {
|
||||
fmt.Printf("[*] 扫描类型 %v 无对应插件,已跳过\n", *name)
|
||||
return
|
||||
}
|
||||
|
||||
// 直接调用扫描函数
|
||||
if err := plugin.ScanFunc(info); err != nil {
|
||||
fmt.Printf("[!] 扫描错误 %v:%v - %v\n", info.Host, info.Ports, err)
|
||||
}
|
||||
}
|
||||
|
||||
// IsContain 检查切片中是否包含指定元素
|
||||
func IsContain(items []string, item string) bool {
|
||||
for _, eachItem := range items {
|
||||
if eachItem == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user