安全开发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扫描流程
- 识别Web服务(通过端口或主动探测)
- 获取Web标题和基本信息
- 匹配指纹特征
- 执行对应的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. 插件扩展机制
添加新插件的步骤:
- 在plugins目录创建新的go文件
- 实现扫描函数,如:
func MyScan(info *common.HostInfo) - 在base.go的PluginList中添加映射
- 指定触发端口或特殊编号
七、开发自己的扫描器建议
-
基础功能:
- 实现高效的端口扫描(并发TCP连接)
- 添加常见服务识别
- 基础漏洞检测
-
进阶功能:
- 模块化设计,便于扩展
- 支持多种输入输出格式
- 完善的日志和错误处理
-
优化方向:
- 智能超时设置
- 自适应并发控制
- 指纹识别准确性提升
-
安全开发要点:
- 异常处理要完善
- 资源释放要彻底
- 避免过高的系统负载
八、总结
FScan的架构设计和技术实现提供了很好的安全开发学习案例,主要亮点包括:
- 清晰的模块划分
- 高效的并发模型
- 灵活的插件机制
- 完善的错误处理
通过分析其源码,可以掌握安全工具开发的核心技术,为开发自己的安全工具打下坚实基础。