fscan/plugins/services/telnet/plugin.go
ZacharyZcR 4a3f281b6b refactor: 统一Plugins目录大小写为小写
- 将所有Plugins路径重命名为plugins
- 修复Git索引与实际文件系统大小写不一致问题
- 确保跨平台兼容性和路径一致性
2025-08-12 13:08:06 +08:00

184 lines
4.8 KiB
Go
Raw 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 telnet
import (
"context"
"fmt"
"strings"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/common/i18n"
"github.com/shadow1ng/fscan/plugins/base"
)
// TelnetPlugin Telnet服务插件
type TelnetPlugin struct {
*base.ServicePlugin
exploiter *TelnetExploiter
}
// NewTelnetPlugin 创建Telnet插件
func NewTelnetPlugin() *TelnetPlugin {
// 插件元数据
metadata := &base.PluginMetadata{
Name: "telnet",
Version: "2.0.0",
Author: "fscan-team",
Description: "Telnet远程终端协议服务检测和弱口令扫描",
Category: "service",
Ports: []int{23}, // Telnet默认端口
Protocols: []string{"tcp"},
Tags: []string{"telnet", "remote-access", "weak-password", "unauthorized-access"},
}
// 创建连接器和服务插件
connector := NewTelnetConnector()
servicePlugin := base.NewServicePlugin(metadata, connector)
// 创建Telnet插件
plugin := &TelnetPlugin{
ServicePlugin: servicePlugin,
exploiter: NewTelnetExploiter(),
}
// 设置能力
plugin.SetCapabilities([]base.Capability{
base.CapWeakPassword,
base.CapUnauthorized,
})
return plugin
}
// init 自动注册Telnet插件
func init() {
// 创建插件工厂
metadata := &base.PluginMetadata{
Name: "telnet",
Version: "2.0.0",
Author: "fscan-team",
Description: "Telnet远程终端协议服务检测和弱口令扫描",
Category: "service",
Ports: []int{23},
Protocols: []string{"tcp"},
Tags: []string{"telnet", "remote-access", "weak-password", "unauthorized-access"},
}
factory := base.NewSimplePluginFactory(metadata, func() base.Plugin {
return NewTelnetPlugin()
})
base.GlobalPluginRegistry.Register("telnet", factory)
}
// Scan 重写扫描方法进行Telnet服务扫描
func (p *TelnetPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
// 如果禁用了暴力破解,只进行服务识别
if common.DisableBrute {
return p.performServiceIdentification(ctx, info)
}
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 生成凭据进行暴力破解
credentials := p.generateCredentials()
if len(credentials) == 0 {
return &base.ScanResult{
Success: false,
Error: fmt.Errorf("no credentials available"),
}, nil
}
// 遍历凭据进行测试
for _, cred := range credentials {
result, err := p.ScanCredential(ctx, info, cred)
if err == nil && result.Success {
// 检查是否无需认证
if result.Extra != nil && result.Extra["type"] == "unauthorized-access" {
common.LogSuccess(i18n.GetText("telnet_unauthorized_access", target))
} else {
// 认证成功
common.LogSuccess(i18n.GetText("telnet_weak_password_success", target, cred.Username, cred.Password))
}
return &base.ScanResult{
Success: true,
Service: "Telnet",
Credentials: []*base.Credential{cred},
Banner: result.Banner,
Extra: map[string]interface{}{
"service": "Telnet",
"port": info.Ports,
"username": cred.Username,
"password": cred.Password,
"type": "weak-password",
},
}, nil
}
}
// 没有找到有效凭据
return &base.ScanResult{
Success: false,
Service: "Telnet",
Error: fmt.Errorf("authentication failed for all credentials"),
}, nil
}
// performServiceIdentification 执行服务识别
func (p *TelnetPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
// 尝试连接到服务进行基本识别
conn, err := p.GetServiceConnector().Connect(ctx, info)
if err != nil {
return &base.ScanResult{
Success: false,
Error: err,
}, nil
}
defer p.GetServiceConnector().Close(conn)
// 服务识别成功
return &base.ScanResult{
Success: true,
Service: "Telnet",
Banner: "Telnet service detected",
Extra: map[string]interface{}{
"service": "Telnet",
"port": info.Ports,
"type": "service-identification",
},
}, nil
}
// generateCredentials 生成Telnet认证凭据
func (p *TelnetPlugin) generateCredentials() []*base.Credential {
var credentials []*base.Credential
// 获取用户名字典
usernames := common.Userdict["telnet"]
if len(usernames) == 0 {
// 使用默认用户名
usernames = []string{"admin", "root", "user", "test", "guest"}
}
// 获取密码字典
passwords := common.Passwords
if len(passwords) == 0 {
// 使用默认密码
passwords = []string{"", "admin", "root", "123456", "password", "test", "guest"}
}
// 生成凭据组合
for _, username := range usernames {
for _, password := range passwords {
// 处理密码中的用户名占位符
actualPassword := strings.Replace(password, "{user}", username, -1)
credentials = append(credentials, &base.Credential{
Username: username,
Password: actualPassword,
})
}
}
return credentials
}