安全开发01:fscan源码解析-上
字数 844 2025-08-22 12:22:54

FScan源码解析与安全开发教学文档

一、FScan概述

FScan是一款用Go语言编写的内网综合扫描工具,具有以下特点:

  • 面向过程编写,结构清晰
  • 支持多种扫描类型(端口扫描、漏洞检测、Web扫描等)
  • 高性能并发处理
  • 模块化设计,易于扩展

目录结构

common/      # 公用模块(参数解析、代理、配置等)
plugins/     # 核心扫描功能(框架调度流程)
webscan/     # Web扫描功能(基于YAML格式的指纹插件)

二、程序入口与参数解析

主函数流程

func main() {
    start := time.Now()
    var Info common.HostInfo
    common.Flag(&Info)      // 从命令行获取参数
    common.Parse(&Info)     // 解析输入内容
    Plugins.Scan(Info)      // 开始扫描
    t := time.Now().Sub(start)
    fmt.Printf("[*] 扫描结束,耗时: %s\n", t)
}

参数解析实现

func Parse(Info *HostInfo) {
    ParseUser()         // 解析用户名
    ParsePass(Info)     // 解析密码
    ParseInput(Info)    // 解析输入参数
    ParseScantype(Info) // 检查采用的模块
}

三、扫描核心流程

1. 初始化阶段

// 解析主机IP
Hosts, err := common.ParseIP(info.Host, common.HostFile, common.NoHosts)

// 初始化HTTP客户端
lib.Inithttp()

// 创建并发控制通道和等待组
var ch = make(chan struct{}, common.Threads) // 并发控制
var wg = sync.WaitGroup{}                    // 同步等待

// 获取常用端口
web := strconv.Itoa(common.PORTList["web"])
ms17010 := strconv.Itoa(common.PORTList["ms17010"])

2. 主机探活机制

ICMP探活实现

func icmpalive(host string) bool {
    conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second)
    if err != nil {
        return false
    }
    defer conn.Close()
    
    msg := makemsg(host)
    if _, err := conn.Write(msg); err != nil {
        return false
    }
    
    receive := make([]byte, 60)
    if _, err := conn.Read(receive); err != nil {
        return false
    }
    return true
}

Ping探活实现

func ExecCommandPing(ip string) bool {
    var command *exec.Cmd
    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")
    }
    
    outinfo := bytes.Buffer{}
    command.Stdout = &outinfo
    err := command.Start()
    if err != nil {
        return false
    }
    
    if err = command.Wait(); err != nil {
        return false
    } else {
        return strings.Contains(outinfo.String(), "true") && 
               strings.Count(outinfo.String(), ip) > 2
    }
}

3. 端口扫描实现

端口扫描核心函数

func PortConnect(addr Addr, respondingHosts chan<- string, adjustedTimeout int64, wg *sync.WaitGroup) {
    host, port := addr.ip, addr.port
    conn, err := common.WrapperTcpWithTimeout("tcp4", 
        fmt.Sprintf("%s:%v", host, port), 
        time.Duration(adjustedTimeout)*time.Second)
    
    if err == nil {
        defer conn.Close()
        address := host + ":" + strconv.Itoa(port)
        result := fmt.Sprintf("%s open", address)
        common.LogSuccess(result)
        wg.Add(1)
        respondingHosts <- address
    }
}

并发控制实现

// 创建通道和工作池
workers := common.Threads
Addrs := make(chan Addr, 100)       // 扫描任务队列
results := make(chan string, 100)   // 结果收集队列
var wg sync.WaitGroup

// 启动结果收集goroutine
go func() {
    for found := range results {
        AliveAddress = append(AliveAddress, found)
        wg.Done()
    }
}()

// 创建工作池
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)

四、漏洞扫描机制

插件调度系统

插件映射表

var PluginList = map[string]interface{}{
    "21":     FtpScan,
    "22":     SshScan,
    "135":    Findnet,
    "139":    NetBIOS,
    "445":    SmbScan,
    "1433":   MssqlScan,
    "1521":   OracleScan,
    "3306":   MysqlScan,
    "3389":   RdpScan,
    "5432":   PostgresScan,
    "6379":   RedisScan,
    "9000":   FcgiScan,
    "11211":  MemcachedScan,
    "27017":  MongodbScan,
    "1000001": MS17010,
    "1000002": SmbGhost,
    "1000003": WebTitle,
    "1000004": SmbScan2,
    "1000005": WmiExec,
}

动态调用机制

func ScanFunc(name *string, info *common.HostInfo) {
    defer func() {
        if err := recover(); err != nil {
            fmt.Printf("[-] %v:%v scan error: %v\n", info.Host, info.Ports, err)
        }
    }()
    
    f := reflect.ValueOf(PluginList[*name])
    in := []reflect.Value{reflect.ValueOf(info)}
    f.Call(in)
}

并发控制实现

func AddScan(scantype string, info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
    *ch <- struct{}{}  // 获取信号量
    wg.Add(1)          // 增加等待计数
    
    go func() {
        Mutex.Lock()
        common.Num += 1  // 全局计数加1
        Mutex.Unlock()
        
        ScanFunc(&scantype, &info)  // 执行扫描
        
        Mutex.Lock()
        common.End += 1  // 全局完成计数加1
        Mutex.Unlock()
        
        wg.Done()       // 完成等待
        <-*ch           // 释放信号量
    }()
}

五、Web扫描实现

Web扫描位于webscan目录,主要特点:

  • 基于YAML格式的指纹插件
  • 支持自定义POC
  • 独立的扫描流程

Web扫描流程

  1. 识别Web服务(通过端口或主动探测)
  2. 获取Web标题和基本信息
  3. 匹配指纹特征
  4. 执行对应的POC检测

六、关键技术与实现细节

1. 并发控制技术

WaitGroup使用模式

var wg sync.WaitGroup

// 启动goroutine前
wg.Add(1)
go func() {
    defer wg.Done()
    // 工作代码
}()

// 等待所有goroutine完成
wg.Wait()

信号量限制并发

limiter := make(chan struct{}, 50) // 限制50并发

for _, task := range tasks {
    wg.Add(1)
    limiter <- struct{}{}  // 获取信号量
    
    go func(t Task) {
        defer func() {
            <-limiter  // 释放信号量
            wg.Done()
        }()
        // 执行任务
    }(task)
}

2. 错误处理机制

Recover机制

defer func() {
    if err := recover(); err != nil {
        // 错误处理逻辑
    }
}()

3. 插件扩展机制

添加新插件的步骤:

  1. 在plugins目录创建新的go文件
  2. 实现扫描函数,如:func MyScan(info *common.HostInfo)
  3. 在base.go的PluginList中添加映射
  4. 指定触发端口或特殊编号

七、开发自己的扫描器建议

  1. 基础功能

    • 实现高效的端口扫描(并发TCP连接)
    • 添加常见服务识别
    • 基础漏洞检测
  2. 进阶功能

    • 模块化设计,便于扩展
    • 支持多种输入输出格式
    • 完善的日志和错误处理
  3. 优化方向

    • 智能超时设置
    • 自适应并发控制
    • 指纹识别准确性提升
  4. 安全开发要点

    • 异常处理要完善
    • 资源释放要彻底
    • 避免过高的系统负载

八、总结

FScan的架构设计和技术实现提供了很好的安全开发学习案例,主要亮点包括:

  • 清晰的模块划分
  • 高效的并发模型
  • 灵活的插件机制
  • 完善的错误处理

通过分析其源码,可以掌握安全工具开发的核心技术,为开发自己的安全工具打下坚实基础。

FScan源码解析与安全开发教学文档 一、FScan概述 FScan是一款用Go语言编写的内网综合扫描工具,具有以下特点: 面向过程编写,结构清晰 支持多种扫描类型(端口扫描、漏洞检测、Web扫描等) 高性能并发处理 模块化设计,易于扩展 目录结构 二、程序入口与参数解析 主函数流程 参数解析实现 三、扫描核心流程 1. 初始化阶段 2. 主机探活机制 ICMP探活实现 Ping探活实现 3. 端口扫描实现 端口扫描核心函数 并发控制实现 四、漏洞扫描机制 插件调度系统 插件映射表 动态调用机制 并发控制实现 五、Web扫描实现 Web扫描位于webscan目录,主要特点: 基于YAML格式的指纹插件 支持自定义POC 独立的扫描流程 Web扫描流程 识别Web服务(通过端口或主动探测) 获取Web标题和基本信息 匹配指纹特征 执行对应的POC检测 六、关键技术与实现细节 1. 并发控制技术 WaitGroup使用模式 信号量限制并发 2. 错误处理机制 Recover机制 3. 插件扩展机制 添加新插件的步骤: 在plugins目录创建新的go文件 实现扫描函数,如: func MyScan(info *common.HostInfo) 在base.go的PluginList中添加映射 指定触发端口或特殊编号 七、开发自己的扫描器建议 基础功能 : 实现高效的端口扫描(并发TCP连接) 添加常见服务识别 基础漏洞检测 进阶功能 : 模块化设计,便于扩展 支持多种输入输出格式 完善的日志和错误处理 优化方向 : 智能超时设置 自适应并发控制 指纹识别准确性提升 安全开发要点 : 异常处理要完善 资源释放要彻底 避免过高的系统负载 八、总结 FScan的架构设计和技术实现提供了很好的安全开发学习案例,主要亮点包括: 清晰的模块划分 高效的并发模型 灵活的插件机制 完善的错误处理 通过分析其源码,可以掌握安全工具开发的核心技术,为开发自己的安全工具打下坚实基础。