fscan/plugins/services/mssql.go
ZacharyZcR f8c8f3d1eb refactor: 重构MSSQL和Oracle插件使用统一发包控制
- 修改MSSQL插件,在testCredential和identifyService中添加发包控制
- 修改Oracle插件,虽然是占位代码,但为一致性添加发包检查
- 统一包计数逻辑,确保TCP连接成功和失败都正确计数
- 完成数据库插件系列的发包控制统一改造
2025-09-02 11:46:42 +00:00

174 lines
3.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package services
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
_ "github.com/denisenkom/go-mssqldb"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/plugins"
)
type MSSQLPlugin struct {
plugins.BasePlugin
}
func NewMSSQLPlugin() *MSSQLPlugin {
return &MSSQLPlugin{
BasePlugin: plugins.NewBasePlugin("mssql"),
}
}
func (p *MSSQLPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
if common.DisableBrute {
return p.identifyService(ctx, info)
}
credentials := GenerateCredentials("mssql")
if len(credentials) == 0 {
return &ScanResult{
Success: false,
Service: "mssql",
Error: fmt.Errorf("没有可用的测试凭据"),
}
}
for _, cred := range credentials {
if db := p.testCredential(ctx, info, cred); db != nil {
db.Close()
common.LogSuccess(fmt.Sprintf("MSSQL %s %s:%s", target, cred.Username, cred.Password))
return &ScanResult{
Success: true,
Service: "mssql",
Username: cred.Username,
Password: cred.Password,
}
}
}
return &ScanResult{
Success: false,
Service: "mssql",
Error: fmt.Errorf("未发现弱密码"),
}
}
func (p *MSSQLPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) *sql.DB {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("MSSQL连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return nil
}
connStr := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%s;database=master;connection timeout=%d",
info.Host, cred.Username, cred.Password, info.Ports, common.Timeout)
db, err := sql.Open("mssql", connStr)
if err != nil {
return nil
}
db.SetConnMaxLifetime(time.Duration(common.Timeout) * time.Second)
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(0)
pingCtx, cancel := context.WithTimeout(ctx, time.Duration(common.Timeout)*time.Second)
defer cancel()
err = db.PingContext(pingCtx)
if err != nil {
common.IncrementTCPFailedPacketCount()
db.Close()
return nil
}
// 连接成功计数TCP成功包
common.IncrementTCPSuccessPacketCount()
return db
}
func (p *MSSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("MSSQL识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "mssql",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
connStr := fmt.Sprintf("server=%s;user id=invalid;password=invalid;port=%s;database=master;connection timeout=%d",
info.Host, info.Ports, common.Timeout)
db, err := sql.Open("mssql", connStr)
if err != nil {
return &ScanResult{
Success: false,
Service: "mssql",
Error: err,
}
}
defer db.Close()
pingCtx, cancel := context.WithTimeout(ctx, time.Duration(common.Timeout)*time.Second)
defer cancel()
err = db.PingContext(pingCtx)
// 统计包数量
if err != nil {
common.IncrementTCPFailedPacketCount()
} else {
common.IncrementTCPSuccessPacketCount()
}
var banner string
if err != nil && (strings.Contains(strings.ToLower(err.Error()), "login failed") ||
strings.Contains(strings.ToLower(err.Error()), "mssql") ||
strings.Contains(strings.ToLower(err.Error()), "sql server")) {
banner = "MSSQL"
} else if err == nil {
banner = "MSSQL"
} else {
return &ScanResult{
Success: false,
Service: "mssql",
Error: fmt.Errorf("无法识别为MSSQL服务"),
}
}
common.LogSuccess(fmt.Sprintf("MSSQL %s %s", target, banner))
return &ScanResult{
Success: true,
Service: "mssql",
Banner: banner,
}
}
func init() {
// 使用高效注册方式:直接传递端口信息,避免实例创建
RegisterPluginWithPorts("mssql", func() Plugin {
return NewMSSQLPlugin()
}, []int{1433, 1434})
}