From 90c7f9c27ed5d85eac867bfa443d54e65d517f48 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Wed, 14 Jan 2026 22:54:31 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DRDP=E7=88=86=E7=A0=B4?= =?UTF-8?q?=E9=AB=98=E8=AF=AF=E6=8A=A5=E7=8E=87=E9=97=AE=E9=A2=98=20(#555)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 screen.go 中错误的认证结果覆盖逻辑 - 启用 NLA 协议的 ErrorCode 字段检测 - 添加 PubKeyAuth 验证确保认证真正成功 - 修复 io.go 中错误被静默忽略的问题 - 修复 socket.go/io.go 中可能导致 panic 的代码 - 修复 screen.go 中文件句柄泄漏和 log.Panic --- mylib/grdp/core/io.go | 13 ++++++++----- mylib/grdp/core/socket.go | 9 ++++++++- mylib/grdp/login/screen.go | 32 +++++++++----------------------- mylib/grdp/protocol/nla/cssp.go | 2 +- mylib/grdp/protocol/tpkt/tpkt.go | 23 +++++++++++++++++++++-- 5 files changed, 47 insertions(+), 32 deletions(-) diff --git a/mylib/grdp/core/io.go b/mylib/grdp/core/io.go index 45c6eb7..dc47f4f 100644 --- a/mylib/grdp/core/io.go +++ b/mylib/grdp/core/io.go @@ -26,7 +26,10 @@ func ReadBytes(len int, r io.Reader) ([]byte, error) { func ReadByte(r io.Reader) (byte, error) { b, err := ReadBytes(1, r) - return b[0], err + if err != nil || len(b) == 0 { + return 0, err + } + return b[0], nil } func ReadUInt8(r io.Reader) (uint8, error) { @@ -42,7 +45,7 @@ func ReadUint16LE(r io.Reader) (uint16, error) { b := make([]byte, 2) _, err := io.ReadFull(r, b) if err != nil { - return 0, nil + return 0, err } return binary.LittleEndian.Uint16(b), nil } @@ -51,7 +54,7 @@ func ReadUint16BE(r io.Reader) (uint16, error) { b := make([]byte, 2) _, err := io.ReadFull(r, b) if err != nil { - return 0, nil + return 0, err } return binary.BigEndian.Uint16(b), nil } @@ -60,7 +63,7 @@ func ReadUInt32LE(r io.Reader) (uint32, error) { b := make([]byte, 4) _, err := io.ReadFull(r, b) if err != nil { - return 0, nil + return 0, err } return binary.LittleEndian.Uint32(b), nil } @@ -69,7 +72,7 @@ func ReadUInt32BE(r io.Reader) (uint32, error) { b := make([]byte, 4) _, err := io.ReadFull(r, b) if err != nil { - return 0, nil + return 0, err } return binary.BigEndian.Uint32(b), nil } diff --git a/mylib/grdp/core/socket.go b/mylib/grdp/core/socket.go index 1a70947..7c43d48 100644 --- a/mylib/grdp/core/socket.go +++ b/mylib/grdp/core/socket.go @@ -69,6 +69,13 @@ func (s *SocketLayer) TlsPubKey() ([]byte, error) { if s.tlsConn == nil { return nil, errors.New("TLS conn does not exist") } - pub := s.tlsConn.ConnectionState().PeerCertificates[0].PublicKey.(*rsa.PublicKey) + certs := s.tlsConn.ConnectionState().PeerCertificates + if len(certs) == 0 { + return nil, errors.New("no peer certificates") + } + pub, ok := certs[0].PublicKey.(*rsa.PublicKey) + if !ok { + return nil, errors.New("invalid public key type") + } return asn1ber.Marshal(*pub) } diff --git a/mylib/grdp/login/screen.go b/mylib/grdp/login/screen.go index cadedc5..e911116 100644 --- a/mylib/grdp/login/screen.go +++ b/mylib/grdp/login/screen.go @@ -323,7 +323,6 @@ func (g *Client) ScreenShot(domain, user, pwd string, timeout int64, rdpProtocol now := start screenImage := image.NewRGBA(image.Rect(0, 0, pic_length, pic_width)) - index := 1 targetSlice := strings.Split(g.Host, ":") ip := targetSlice[0] port := targetSlice[1] @@ -489,11 +488,7 @@ loop: } glog.Debug("循环结束,总时间过去了:", time.Since(start)) - if g.x224.ServerChooseProtocol() == x224.PROTOCOL_HYBRID && g.x224.ServerChooseProtocol() == x224.PROTOCOL_HYBRID { - if err == nil { - status = true - } - } + // 认证结果由 success 事件回调设置,不在此处覆盖 if needReconnect { return status, err, reconnProtocol @@ -501,26 +496,27 @@ loop: glog.Info("get screen ok") // Encode to jpeg. var imageBuf bytes.Buffer - err = jpeg.Encode(&imageBuf, screenImage, nil) - - if err != nil { - log.Panic(err) + encodeErr := jpeg.Encode(&imageBuf, screenImage, nil) + if encodeErr != nil { + glog.Error("Failed to encode screenshot:", encodeErr) + return status, err, reconnProtocol } // Write to file. saveDate := time.Now().Format("2006_01_02_15_04_05") fo, writeErr := os.Create(fmt.Sprintf("%s/%s_%s_%s.jpg", OutputDir, ip, port, saveDate)) - index += 1 if writeErr != nil { glog.Error("Can not create rdp screenshot file:", writeErr) } else { + defer fo.Close() fw := bufio.NewWriter(fo) _, writeErr := fw.Write(imageBuf.Bytes()) if writeErr != nil { glog.Error("Can not write rdp screenshot file:", writeErr) + } else { + fw.Flush() } } - } return status, err, reconnProtocol @@ -529,7 +525,6 @@ loop: func (g *Client) Crack(domain, user, pwd string, timeout int64, rdpProtocol uint32) (status bool, err error, reconnProtocol uint32) { //glog.SetLevel(glog.ERROR) reconnProtocol = rdpProtocol - needReconnect := false refresh := make(chan bool) exitFlag := make(chan bool) start := time.Now() @@ -570,7 +565,6 @@ func (g *Client) Crack(domain, user, pwd string, timeout int64, rdpProtocol uint g.x224.SetRequestedProtocol(rdpProtocol) //x224.PROTOCOL_SSL , x224.PROTOCOL_RDP , x224.PROTOCOL_HYBRID , x224.PROTOCOL_HYBRID_EX g.x224.On("reconnect", func(protocol uint32) { - needReconnect = true reconnProtocol = protocol glog.Info("need reconnect with protocol:", protocol) g.pdu.Emit("close") @@ -649,14 +643,6 @@ loop: } glog.Debug("循环结束,总时间过去了:", time.Since(start)) - if g.x224.ServerChooseProtocol() == x224.PROTOCOL_HYBRID && g.x224.ServerChooseProtocol() == x224.PROTOCOL_HYBRID { - if err == nil { - status = true - } - } - - if needReconnect { - return status, err, reconnProtocol - } + // 认证结果由 success 事件回调设置,不在此处覆盖 return status, err, reconnProtocol } diff --git a/mylib/grdp/protocol/nla/cssp.go b/mylib/grdp/protocol/nla/cssp.go index c67af83..16fd373 100644 --- a/mylib/grdp/protocol/nla/cssp.go +++ b/mylib/grdp/protocol/nla/cssp.go @@ -15,7 +15,7 @@ type TSRequest struct { NegoTokens []NegoToken `asn1:"optional,explicit,tag:1"` AuthInfo []byte `asn1:"optional,explicit,tag:2"` PubKeyAuth []byte `asn1:"optional,explicit,tag:3"` - //ErrorCode int `asn1:"optional,explicit,tag:4"` + ErrorCode int `asn1:"optional,explicit,tag:4"` } type TSCredentials struct { diff --git a/mylib/grdp/protocol/tpkt/tpkt.go b/mylib/grdp/protocol/tpkt/tpkt.go index d1a6205..3bd2a9d 100644 --- a/mylib/grdp/protocol/tpkt/tpkt.go +++ b/mylib/grdp/protocol/tpkt/tpkt.go @@ -317,9 +317,28 @@ func (t *TPKT) recvPubKeyInc(data []byte) error { glog.Info("DecodeDERTRequest", err) return err } + + // 检查服务器是否返回错误码(认证失败) + if tsreq.ErrorCode != 0 { + glog.Error("NLA authentication failed with error code:", tsreq.ErrorCode) + return fmt.Errorf("NLA auth failed: error code %d", tsreq.ErrorCode) + } + + // 验证 PubKeyAuth 不为空(认证成功的标志) + if len(tsreq.PubKeyAuth) == 0 { + glog.Error("NLA authentication failed: empty PubKeyAuth") + return fmt.Errorf("NLA auth failed: empty PubKeyAuth") + } + glog.Trace("PubKeyAuth:", tsreq.PubKeyAuth) - //ignore - //pubkey := t.ntlmSec.GssDecrypt([]byte(tsreq.PubKeyAuth)) + + // 验证服务器返回的公钥(可选但推荐) + pubkey := t.ntlmSec.GssDecrypt(tsreq.PubKeyAuth) + if pubkey == nil { + glog.Error("NLA authentication failed: invalid PubKeyAuth signature") + return fmt.Errorf("NLA auth failed: invalid PubKeyAuth") + } + domain, username, password := t.ntlm.GetEncodedCredentials() credentials := nla.EncodeDERTCredentials(domain, username, password) authInfo := t.ntlmSec.GssEncrypt(credentials)