量大管饱的Fscan源码详细分析
字数 1251 2025-08-22 12:22:54

Fscan源码分析与使用指南

1. Fscan概述

Fscan是一款功能强大的内网扫描工具,主要特点包括:

  • 信息搜集:存活探测、端口扫描
  • 爆破功能:各类服务爆破、数据库密码爆破
  • 系统信息与漏洞扫描:域控识别、高危漏洞检测
  • Web探测:webtitle探测、指纹识别、漏洞扫描
  • 漏洞利用:Redis写公钥、SSH命令执行、MS17017利用等

2. 主要参数解析

基础参数

  • -h:目标IP,支持多种格式(192.168.11.11 | 192.168.11.11-255 | 192.168.11.11,192.168.11.12)
  • -hf:从文件中读取目标
  • -hn:扫描时要跳过的IP
  • -m:设置扫描模式(默认"all")
  • -p:设置扫描端口(默认"21,22,80,81,135,139,443,445,1433,3306,5432,6379,7001,8000,8080,8089,9000,9200,11211,27017")

功能控制参数

  • -nobr:跳过密码爆破
  • -nopoc:跳过web poc扫描
  • -np:跳过存活探测
  • -ping:使用ping代替icmp进行存活探测
  • -silent:静默扫描(适合CS扫描时不回显)

爆破相关参数

  • -user/-userf:指定爆破用户名/用户名字典文件
  • -pwd/-pwdf:指定爆破密码/密码字典文件
  • -domain:smb爆破时设置域名

漏洞利用参数

  • -rf:指定redis写公钥用模块的文件
  • -rs:redis计划任务反弹shell的IP端口
  • -sc:指定ms17010利用模块shellcode

3. 源码架构分析

3.1 主流程

func main() {
    start := time.Now()
    var Info common.HostInfo
    common.Flag(&Info)      // 参数解析
    common.Parse(&Info)     // 参数处理
    Plugins.Scan(Info)      // 核心扫描逻辑
    fmt.Printf("[*] 扫描结束,耗时: %s\n", time.Since(start))
}

3.2 参数处理模块

参数处理主要在common.config.go中实现:

func Flag(Info *HostInfo) {
    flag.StringVar(&Info.Host, "h", "", "IP address of the host...")
    flag.StringVar(&NoHosts, "hn", "", "the hosts no scan...")
    flag.StringVar(&Ports, "p", DefaultPorts, "Select a port...")
    // 其他参数...
}

3.3 扫描流程

  1. IP提取:支持多种格式(CIDR、IP段、逗号分隔等)
  2. 主机探活:ICMP或Ping探测
  3. 端口扫描:TCP连接扫描
  4. 漏洞扫描:根据端口服务调用相应模块

4. 核心功能实现

4.1 IP提取逻辑

func parseIP(ip string) []string {
    switch {
    case ip == "192": return parseIP("192.168.0.0/8")
    case ip == "172": return parseIP("172.16.0.0/12")
    case ip == "10": return parseIP("10.0.0.0/8")
    case strings.HasSuffix(ip, "/8"): return parseIP8(ip)
    case strings.Contains(ip, "/"): return parseIP2(ip)
    case reg.MatchString(ip): return []string{ip}
    case strings.Contains(ip, "-"): return parseIP1(ip)
    default: return []string{ip}
    }
}

4.2 主机探活实现

支持ICMP和Ping两种方式:

func CheckLive(hostslist []string, Ping bool) []string {
    if Ping {
        RunPing(hostslist, chanHosts)  // 使用Ping探测
    } else {
        conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
        if err == nil {
            RunIcmp1(hostslist, conn, chanHosts)  // 使用ICMP探测
        }
    }
}

4.3 端口扫描实现

func PortScan(hostslist []string, ports string, timeout int64) []string {
    workers := common.Threads
    Addrs := make(chan Addr, len(hostslist)*len(probePorts))
    results := make(chan string, len(hostslist)*len(probePorts))
    
    // 多线程扫描
    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()
    return AliveAddress
}

4.4 Web扫描实现

func WebTitle(info *common.HostInfo) error {
    // URL处理
    if info.Url == "" {
        switch info.Ports {
        case "80": info.Url = fmt.Sprintf("http://%s", info.Host)
        case "443": info.Url = fmt.Sprintf("https://%s", info.Host)
        default: 
            host := fmt.Sprintf("%s:%s", info.Host, info.Ports)
            protocol := GetProtocol(host, common.Timeout)
            info.Url = fmt.Sprintf("%s://%s:%s", protocol, info.Host, info.Ports)
        }
    }
    
    // 获取网页标题和内容
    err, CheckData := GOWebTitle(info)
    info.Infostr = WebScan.InfoCheck(info.Url, &CheckData)
    
    // 执行POC扫描
    if !common.NoPoc && err == nil {
        WebScan.WebScan(info)
    }
    return err
}

5. POC引擎实现

5.1 POC执行流程

func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
    // 1. 初始化CEL环境
    c := NewEnvOption()
    c.UpdateCompileOptions(p.Set)
    
    // 2. 解析请求
    req, err := ParseRequest(oReq)
    
    // 3. 设置变量
    variableMap := make(map[string]interface{})
    variableMap["request"] = req
    
    // 4. 执行规则
    for _, rule := range p.Rules {
        success, err = clustersend(oReq, variableMap, req, env, rule)
        if !success {
            return false, err
        }
    }
    
    return true, nil, ""
}

5.2 CEL表达式环境

func NewEnvOption() CustomLib {
    c := CustomLib{}
    c.envOptions = []cel.EnvOption{
        cel.Container("lib"),
        cel.Types(&UrlType{}, &Request{}, &Response{}, &Reverse{}),
        cel.Declarations(
            decls.NewIdent("request", decls.NewObjectType("lib.Request"), nil),
            decls.NewIdent("response", decls.NewObjectType("lib.Response"), nil),
            decls.NewIdent("reverse", decls.NewObjectType("lib.Reverse"), nil),
        ),
        cel.Declarations(
            decls.NewFunction("bcontains", 
                decls.NewInstanceOverload("bytes_bcontains_bytes", 
                    []*exprpb.Type{decls.Bytes, decls.Bytes}, decls.Bool)),
            // 其他函数...
        ),
    }
    return c
}

5.3 规则执行

func clustersend(oReq *http.Request, variableMap map[string]interface{}, 
    req *Request, env *cel.Env, rule Rules) (bool, error) {
    
    // 1. 替换变量
    for k1, v1 := range variableMap {
        value := fmt.Sprintf("%v", v1)
        rule.Path = strings.ReplaceAll(rule.Path, "{{"+k1+"}}", value)
        rule.Body = strings.ReplaceAll(rule.Body, "{{"+k1+"}}", value)
    }
    
    // 2. 创建新请求
    newRequest, err := http.NewRequest(rule.Method, 
        fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path), 
        strings.NewReader(rule.Body))
    
    // 3. 发送请求
    resp, err := DoRequest(newRequest, rule.FollowRedirects)
    variableMap["response"] = resp
    
    // 4. 检查响应
    if rule.Search != "" {
        result := doSearch(rule.Search, GetHeader(resp.Headers)+string(resp.Body))
        if result == nil {
            return false, nil
        }
    }
    
    // 5. 评估表达式
    out, err := Evaluate(env, rule.Expression, variableMap)
    if fmt.Sprintf("%v", out) == "false" {
        return false, err
    }
    
    return true, err
}

6. 使用示例

6.1 基本扫描

fscan -h 192.168.1.1/24 -p 1-65535

6.2 指定模块扫描

fscan -h 192.168.1.1 -m ms17010

6.3 Web扫描

fscan -h 192.168.1.1 -m web -nobr

6.4 爆破功能

fscan -h 192.168.1.1 -userf user.txt -pwdf pass.txt

7. 开发建议

  1. 性能优化

    • 增加SYN扫描模式
    • 优化ICMP探测逻辑
    • 改进线程调度机制
  2. 功能扩展

    • 增加更多服务识别模块
    • 支持自定义POC优先级
    • 增强报告生成功能
  3. 代码改进

    • 重构参数解析逻辑
    • 优化模块化设计
    • 增强错误处理机制

8. 总结

Fscan作为一款内网渗透测试工具,其设计思想和实现方式值得学习:

  • 模块化设计,便于功能扩展
  • 灵活的扫描策略配置
  • 强大的POC引擎支持
  • 高效的并发处理机制

通过深入分析其源码,可以更好地理解扫描器的工作原理,并为开发类似工具提供参考。

Fscan源码分析与使用指南 1. Fscan概述 Fscan是一款功能强大的内网扫描工具,主要特点包括: 信息搜集:存活探测、端口扫描 爆破功能:各类服务爆破、数据库密码爆破 系统信息与漏洞扫描:域控识别、高危漏洞检测 Web探测:webtitle探测、指纹识别、漏洞扫描 漏洞利用:Redis写公钥、SSH命令执行、MS17017利用等 2. 主要参数解析 基础参数 -h :目标IP,支持多种格式(192.168.11.11 | 192.168.11.11-255 | 192.168.11.11,192.168.11.12) -hf :从文件中读取目标 -hn :扫描时要跳过的IP -m :设置扫描模式(默认"all") -p :设置扫描端口(默认"21,22,80,81,135,139,443,445,1433,3306,5432,6379,7001,8000,8080,8089,9000,9200,11211,27017") 功能控制参数 -nobr :跳过密码爆破 -nopoc :跳过web poc扫描 -np :跳过存活探测 -ping :使用ping代替icmp进行存活探测 -silent :静默扫描(适合CS扫描时不回显) 爆破相关参数 -user / -userf :指定爆破用户名/用户名字典文件 -pwd / -pwdf :指定爆破密码/密码字典文件 -domain :smb爆破时设置域名 漏洞利用参数 -rf :指定redis写公钥用模块的文件 -rs :redis计划任务反弹shell的IP端口 -sc :指定ms17010利用模块shellcode 3. 源码架构分析 3.1 主流程 3.2 参数处理模块 参数处理主要在 common.config.go 中实现: 3.3 扫描流程 IP提取 :支持多种格式(CIDR、IP段、逗号分隔等) 主机探活 :ICMP或Ping探测 端口扫描 :TCP连接扫描 漏洞扫描 :根据端口服务调用相应模块 4. 核心功能实现 4.1 IP提取逻辑 4.2 主机探活实现 支持ICMP和Ping两种方式: 4.3 端口扫描实现 4.4 Web扫描实现 5. POC引擎实现 5.1 POC执行流程 5.2 CEL表达式环境 5.3 规则执行 6. 使用示例 6.1 基本扫描 6.2 指定模块扫描 6.3 Web扫描 6.4 爆破功能 7. 开发建议 性能优化 : 增加SYN扫描模式 优化ICMP探测逻辑 改进线程调度机制 功能扩展 : 增加更多服务识别模块 支持自定义POC优先级 增强报告生成功能 代码改进 : 重构参数解析逻辑 优化模块化设计 增强错误处理机制 8. 总结 Fscan作为一款内网渗透测试工具,其设计思想和实现方式值得学习: 模块化设计,便于功能扩展 灵活的扫描策略配置 强大的POC引擎支持 高效的并发处理机制 通过深入分析其源码,可以更好地理解扫描器的工作原理,并为开发类似工具提供参考。