mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
- ipmi: 删除未使用的 encoding/binary 导入 - rmi: TCP读取改用 io.ReadFull 避免分片导致的解析错误 - jdwp: handshake响应读取改用 io.ReadFull 避免分片误判 - nfs: v4协议回退时使用新连接避免残留数据污染 - snmp: 修正timeout计算与其他插件保持一致
94 lines
2.3 KiB
Go
94 lines
2.3 KiB
Go
//go:build plugin_rmi || !plugin_selective
|
|
|
|
package services
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
|
|
"github.com/shadow1ng/fscan/common"
|
|
"github.com/shadow1ng/fscan/plugins"
|
|
)
|
|
|
|
// Java RMI protocol magic: "JRMI" + version 2 + StreamProtocol
|
|
var rmiHandshake = []byte{0x4a, 0x52, 0x4d, 0x49, 0x00, 0x02, 0x4b}
|
|
|
|
type RMIPlugin struct {
|
|
plugins.BasePlugin
|
|
}
|
|
|
|
func NewRMIPlugin() *RMIPlugin {
|
|
return &RMIPlugin{BasePlugin: plugins.NewBasePlugin("rmi")}
|
|
}
|
|
|
|
func (p *RMIPlugin) 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: "rmi"}
|
|
}
|
|
defer conn.Close()
|
|
_ = conn.SetDeadline(time.Now().Add(timeout))
|
|
|
|
if _, err := conn.Write(rmiHandshake); err != nil {
|
|
return &ScanResult{Success: false, Service: "rmi"}
|
|
}
|
|
|
|
// RMI server responds with ProtocolAck (0x4e) followed by endpoint info.
|
|
// Read at least 1 byte for the ack; io.ReadFull guarantees it.
|
|
ack := make([]byte, 1)
|
|
if _, err := io.ReadFull(conn, ack); err != nil {
|
|
return &ScanResult{Success: false, Service: "rmi"}
|
|
}
|
|
if ack[0] != 0x4e {
|
|
return &ScanResult{Success: false, Service: "rmi"}
|
|
}
|
|
|
|
buf := make([]byte, 255)
|
|
n, err := conn.Read(buf)
|
|
if err != nil && n == 0 {
|
|
return &ScanResult{Success: false, Service: "rmi"}
|
|
}
|
|
|
|
endpoint := parseRMIEndpoint(buf[:n])
|
|
|
|
return &ScanResult{
|
|
Success: true,
|
|
Type: plugins.ResultTypeVuln,
|
|
Service: "rmi",
|
|
VulInfo: "Java RMI/JMX Service Exposed",
|
|
Banner: endpoint,
|
|
}
|
|
}
|
|
|
|
func parseRMIEndpoint(data []byte) string {
|
|
if len(data) < 4 {
|
|
return "Java RMI"
|
|
}
|
|
// Skip 2 bytes (host length big-endian)
|
|
hostLen := int(data[0])<<8 | int(data[1])
|
|
if hostLen <= 0 || hostLen+2 > len(data) {
|
|
return "Java RMI"
|
|
}
|
|
host := string(data[2 : 2+hostLen])
|
|
offset := 2 + hostLen
|
|
if offset+4 > len(data) {
|
|
return fmt.Sprintf("Java RMI endpoint=%s", host)
|
|
}
|
|
port := int(data[offset])<<24 | int(data[offset+1])<<16 | int(data[offset+2])<<8 | int(data[offset+3])
|
|
return fmt.Sprintf("Java RMI endpoint=%s:%d", host, port)
|
|
}
|
|
|
|
func init() {
|
|
RegisterPluginWithPorts("rmi", func() Plugin {
|
|
return NewRMIPlugin()
|
|
}, []int{1099, 1098, 9999, 4444})
|
|
}
|