fix: NFS plugin RPC probe + UDP dispatch in auto mode
测试构建 / 代码检查 (push) Has been cancelled
测试构建 / 单元测试和构建 (push) Has been cancelled
测试构建 / 构建验证 (push) Has been cancelled

NFS: use RPC NULL call to detect NFS service before MOUNT EXPORT
UDP dispatch: query plugin registry directly in auto mode instead of
GetPlugins which excludes UDP from FilterService
This commit is contained in:
ZacharyZcR
2026-05-19 00:37:35 +08:00
parent 0a28db7371
commit a92df59dfe
2 changed files with 65 additions and 14 deletions
+12 -3
View File
@@ -221,12 +221,21 @@ func (s *ServiceScanStrategy) performHostScan(ctx context.Context, session *comm
// dispatchUDPPlugins 分发UDP协议插件,跳过TCP端口扫描链路 // dispatchUDPPlugins 分发UDP协议插件,跳过TCP端口扫描链路
func (s *ServiceScanStrategy) dispatchUDPPlugins(ctx context.Context, session *common.ScanSession, hosts []string, baseInfo common.HostInfo, config *common.Config, ch chan struct{}, wg *sync.WaitGroup) { func (s *ServiceScanStrategy) dispatchUDPPlugins(ctx context.Context, session *common.ScanSession, hosts []string, baseInfo common.HostInfo, config *common.Config, ch chan struct{}, wg *sync.WaitGroup) {
allPlugins, isCustomMode := s.GetPlugins(config) _, isCustomMode := s.GetPlugins(config)
var udpPlugins []string var udpPlugins []string
for _, name := range allPlugins { if isCustomMode {
// custom mode: 只跑用户指定的 UDP 插件
requested, _ := s.GetPlugins(config)
for _, name := range requested {
if plugins.IsUDP(name) { if plugins.IsUDP(name) {
if isCustomMode || plugins.IsSafe(name) { udpPlugins = append(udpPlugins, name)
}
}
} else {
// auto mode: 跑所有已注册的安全 UDP 插件
for _, name := range plugins.All() {
if plugins.IsUDP(name) && plugins.IsSafe(name) {
udpPlugins = append(udpPlugins, name) udpPlugins = append(udpPlugins, name)
} }
} }
+54 -12
View File
@@ -34,28 +34,70 @@ func (p *NFSPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
defer conn.Close() defer conn.Close()
_ = conn.SetDeadline(time.Now().Add(timeout)) _ = conn.SetDeadline(time.Now().Add(timeout))
exports, err := p.getExports(conn) // NFS NULL call (program=100003, version=3, procedure=0) to confirm NFS service
if err != nil { if err := p.rpcNullCall(conn, 100003, 3); err != nil {
// Try v4
_ = conn.SetDeadline(time.Now().Add(timeout))
if err := p.rpcNullCall(conn, 100003, 4); err != nil {
return &ScanResult{Success: false, Service: "nfs"} return &ScanResult{Success: false, Service: "nfs"}
} }
if len(exports) == 0 {
return &ScanResult{
Success: true,
Type: plugins.ResultTypeService,
Service: "nfs",
Banner: "NFS service detected (no exports)",
}
} }
banner := fmt.Sprintf("NFS exports: %v", exports) // NFS confirmed. Try MOUNT EXPORT on a separate connection (port 2049 may also host mountd).
var exports []string
mountConn, err := session.DialTCP(ctx, "tcp", addr, timeout)
if err == nil {
_ = mountConn.SetDeadline(time.Now().Add(timeout))
exports, _ = p.getExports(mountConn)
mountConn.Close()
}
if len(exports) > 0 {
return &ScanResult{ return &ScanResult{
Success: true, Success: true,
Type: plugins.ResultTypeVuln, Type: plugins.ResultTypeVuln,
Service: "nfs", Service: "nfs",
VulInfo: fmt.Sprintf("NFS Exported Shares: %v", exports), VulInfo: fmt.Sprintf("NFS Exported Shares: %v", exports),
Banner: banner, Banner: fmt.Sprintf("NFS exports: %v", exports),
} }
}
return &ScanResult{
Success: true,
Type: plugins.ResultTypeService,
Service: "nfs",
Banner: "NFS service detected",
}
}
func (p *NFSPlugin) rpcNullCall(conn interface {
Read([]byte) (int, error)
Write([]byte) (int, error)
}, program, version uint32) error {
xid := uint32(0x12340000 + program)
rpcCall := p.buildRPCCall(xid, program, version, 0, nil)
rpcFragment := p.wrapRPCFragment(rpcCall)
if _, err := conn.Write(rpcFragment); err != nil {
return err
}
buf := make([]byte, 512)
n, err := conn.Read(buf)
if err != nil || n < 28 {
return fmt.Errorf("short response")
}
reply := buf[4:n]
replyXID := binary.BigEndian.Uint32(reply[0:4])
if replyXID != xid {
return fmt.Errorf("xid mismatch")
}
msgType := binary.BigEndian.Uint32(reply[4:8])
if msgType != 1 {
return fmt.Errorf("not a reply")
}
return nil
} }
func (p *NFSPlugin) getExports(conn interface { func (p *NFSPlugin) getExports(conn interface {