Files
fscan/mylib/grdp/plugin/drdynvc/dvc.go
T
ZacharyZcR 71b92d4408 feat: v2.1.0 核心重构与功能增强
## 架构重构
- 全局变量消除,迁移至 Config/State 对象
- SMB 插件融合(smb/smb2/smbghost/smbinfo)
- 服务探测重构,实现 Nmap 风格 fallback 机制
- 输出系统重构,TXT 实时刷盘 + 双写机制
- i18n 框架升级至 go-i18n

## 性能优化
- 正则表达式预编译
- 内存优化 map[string]struct{}
- 并发指纹匹配
- SOCKS5 连接复用
- 滑动窗口调度 + 自适应线程池

## 新功能
- Web 管理界面
- 多格式 POC 适配(xray/afrog)
- 增强指纹库(3139条)
- Favicon hash 指纹识别
- 插件选择性编译(Build Tags)
- fscan-lab 靶场环境
- 默认端口扩展(62→133)

## 构建系统
- 添加 no_local tag 支持排除本地插件
- 多版本构建:fscan/fscan-nolocal/fscan-web
- CI 添加 snapshot 模式支持仅测试构建

## Bug 修复
- 修复 120+ 个问题,包括 RDP panic、批量扫描漏报、
  JSON 输出格式、Redis 检测、Context 超时等

## 测试增强
- 单元测试覆盖率 74-100%
- 并发安全测试
- 集成测试(Web/端口/服务/SSH/ICMP)
2026-01-11 20:16:23 +08:00

160 lines
3.5 KiB
Go

package drdynvc
import (
"bytes"
"encoding/hex"
"io"
"github.com/shadow1ng/fscan/mylib/grdp/core"
"github.com/shadow1ng/fscan/mylib/grdp/glog"
"github.com/shadow1ng/fscan/mylib/grdp/plugin"
)
const (
ChannelName = plugin.DRDYNVC_SVC_CHANNEL_NAME
ChannelOption = plugin.CHANNEL_OPTION_INITIALIZED |
plugin.CHANNEL_OPTION_ENCRYPT_RDP
)
const (
MAX_DVC_CHANNELS = 20
)
const (
DYNVC_CREATE_REQ = 0x01
DYNVC_DATA_FIRST = 0x02
DYNVC_DATA = 0x03
DYNVC_CLOSE = 0x04
DYNVC_CAPABILITIES = 0x05
DYNVC_DATA_FIRST_COMPRESSED = 0x06
DYNVC_DATA_COMPRESSED = 0x07
DYNVC_SOFT_SYNC_REQUEST = 0x08
DYNVC_SOFT_SYNC_RESPONSE = 0x09
)
type ChannelClient struct {
}
type DvcClient struct {
w core.ChannelSender
channels map[string]ChannelClient
}
func NewDvcClient() *DvcClient {
return &DvcClient{
channels: make(map[string]ChannelClient, 100),
}
}
func (c *DvcClient) LoadAddin(f core.ChannelSender) {
}
type DvcHeader struct {
cmd uint8
sp uint8
cbChId uint8
}
func readHeader(r io.Reader) *DvcHeader {
value, _ := core.ReadUInt8(r)
cmd := (value & 0xf0) >> 4
sp := (value & 0x0c) >> 2
cbChId := (value & 0x03) >> 0
return &DvcHeader{cmd, sp, cbChId}
}
func (h *DvcHeader) serialize(channelId uint32) []byte {
b := &bytes.Buffer{}
core.WriteUInt8((h.cmd<<4)|(h.sp<<2)|h.cbChId, b)
if h.cbChId == 0 {
core.WriteUInt8(uint8(channelId), b)
} else if h.cbChId == 1 {
core.WriteUInt16LE(uint16(channelId), b)
} else {
core.WriteUInt32LE(channelId, b)
}
return b.Bytes()
}
func (c *DvcClient) Send(s []byte) (int, error) {
glog.Debug("len:", len(s), "data:", hex.EncodeToString(s))
name, _ := c.GetType()
return c.w.SendToChannel(name, s)
}
func (c *DvcClient) Sender(f core.ChannelSender) {
c.w = f
}
func (c *DvcClient) GetType() (string, uint32) {
return ChannelName, ChannelOption
}
func (c *DvcClient) Process(s []byte) {
glog.Debug("recv:", hex.EncodeToString(s))
r := bytes.NewReader(s)
hdr := readHeader(r)
glog.Infof("dvc: Cmd=0x%x, Sp=%d CbChId=%d all=%d", hdr.cmd, hdr.sp, hdr.cbChId, r.Len())
b, _ := core.ReadBytes(r.Len(), r)
switch hdr.cmd {
case DYNVC_CAPABILITIES:
glog.Info("DYNVC_CAPABILITIES")
c.processCapsPdu(hdr, b)
case DYNVC_CREATE_REQ:
glog.Info("DYNVC_CREATE_REQ")
c.processCreateReq(hdr, b)
case DYNVC_DATA_FIRST:
glog.Info("DYNVC_DATA_FIRST")
case DYNVC_DATA:
glog.Info("DYNVC_DATA")
case DYNVC_CLOSE:
glog.Info("DYNVC_CLOSE")
default:
glog.Errorf("type 0x%x not supported", hdr.cmd)
}
}
func (c *DvcClient) processCreateReq(hdr *DvcHeader, s []byte) {
r := bytes.NewReader(s)
channelId := readDvcId(r, hdr.cbChId)
name, _ := core.ReadBytes(r.Len(), r)
channelName := string(name)
glog.Infof("Server requests channelId=%d, name=%s", channelId, channelName)
//response
b := &bytes.Buffer{}
b.Write(hdr.serialize(channelId))
core.WriteUInt32LE(0, b)
c.Send(b.Bytes())
}
func readDvcId(r io.Reader, cbLen uint8) (id uint32) {
switch cbLen {
case 0:
i, _ := core.ReadUInt8(r)
id = uint32(i)
case 1:
i, _ := core.ReadUint16LE(r)
id = uint32(i)
default:
id, _ = core.ReadUInt32LE(r)
}
return
}
func (c *DvcClient) processCapsPdu(hdr *DvcHeader, s []byte) {
r := bytes.NewReader(s)
core.ReadUInt8(r)
ver, _ := core.ReadUint16LE(r)
glog.Infof("Server supports dvc=%d", ver)
hdr.cmd = DYNVC_CAPABILITIES
hdr.cbChId = 0
hdr.sp = 0
b := &bytes.Buffer{}
core.WriteUInt16LE(0x0050, b)
core.WriteUInt16LE(ver, b)
c.Send(b.Bytes())
}