Add native protocol service plugins
测试构建 / 代码检查 (push) Has been cancelled
测试构建 / 单元测试和构建 (push) Has been cancelled
测试构建 / 构建验证 (push) Has been cancelled

This commit is contained in:
ZacharyZcR
2026-05-23 15:51:50 +08:00
parent 73cbe803c4
commit 8d30ee334c
16 changed files with 812 additions and 2 deletions
+114
View File
@@ -0,0 +1,114 @@
//go:build plugin_mqtt || !plugin_selective
package services
import (
"context"
"crypto/tls"
"fmt"
"io"
"net"
"time"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/plugins"
)
var mqttConnectPacket = []byte{
0x10, 0x0c,
0x00, 0x04, 'M', 'Q', 'T', 'T',
0x04,
0x02,
0x00, 0x00,
0x00, 0x00,
}
type MQTTPlugin struct {
plugins.BasePlugin
}
func NewMQTTPlugin() *MQTTPlugin {
return &MQTTPlugin{BasePlugin: plugins.NewBasePlugin("mqtt")}
}
func (p *MQTTPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *ScanResult {
timeout := session.Config.Timeout
if timeout <= 0 {
timeout = 3 * time.Second
}
addr := fmt.Sprintf("%s:%d", info.Host, info.Port)
conn, err := session.DialTCP(ctx, "tcp", addr, timeout)
if err != nil {
return &ScanResult{Success: false, Service: "mqtt"}
}
defer conn.Close()
if info.Port == 8883 {
_ = conn.SetDeadline(time.Now().Add(timeout))
conn, err = p.wrapTLS(ctx, conn)
if err != nil {
return &ScanResult{Success: false, Service: "mqtt"}
}
defer conn.Close()
}
_ = conn.SetDeadline(time.Now().Add(timeout))
if _, err := conn.Write(mqttConnectPacket); err != nil {
return &ScanResult{Success: false, Service: "mqtt"}
}
header := make([]byte, 4)
if _, err := io.ReadFull(conn, header); err != nil {
return &ScanResult{Success: false, Service: "mqtt"}
}
banner, ok := parseMQTTConnack(header)
if !ok {
return &ScanResult{Success: false, Service: "mqtt"}
}
return &ScanResult{
Success: true,
Type: plugins.ResultTypeService,
Service: "mqtt",
Banner: banner,
}
}
func (p *MQTTPlugin) wrapTLS(ctx context.Context, conn net.Conn) (net.Conn, error) {
tlsConn := tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
if err := tlsConn.HandshakeContext(ctx); err != nil {
return nil, err
}
return tlsConn, nil
}
func parseMQTTConnack(data []byte) (string, bool) {
if len(data) < 4 || data[0] != 0x20 || data[1] != 0x02 {
return "", false
}
switch data[3] {
case 0x00:
return "MQTT CONNACK accepted", true
case 0x01:
return "MQTT CONNACK unacceptable protocol version", true
case 0x02:
return "MQTT CONNACK identifier rejected", true
case 0x03:
return "MQTT CONNACK server unavailable", true
case 0x04:
return "MQTT CONNACK bad username or password", true
case 0x05:
return "MQTT CONNACK not authorized", true
default:
return fmt.Sprintf("MQTT CONNACK return_code=%d", data[3]), true
}
}
func init() {
RegisterPluginWithPorts("mqtt", func() Plugin {
return NewMQTTPlugin()
}, []int{1883, 8883})
}