量大管饱的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 扫描流程
- IP提取:支持多种格式(CIDR、IP段、逗号分隔等)
- 主机探活:ICMP或Ping探测
- 端口扫描:TCP连接扫描
- 漏洞扫描:根据端口服务调用相应模块
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. 开发建议
-
性能优化:
- 增加SYN扫描模式
- 优化ICMP探测逻辑
- 改进线程调度机制
-
功能扩展:
- 增加更多服务识别模块
- 支持自定义POC优先级
- 增强报告生成功能
-
代码改进:
- 重构参数解析逻辑
- 优化模块化设计
- 增强错误处理机制
8. 总结
Fscan作为一款内网渗透测试工具,其设计思想和实现方式值得学习:
- 模块化设计,便于功能扩展
- 灵活的扫描策略配置
- 强大的POC引擎支持
- 高效的并发处理机制
通过深入分析其源码,可以更好地理解扫描器的工作原理,并为开发类似工具提供参考。