mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 11:20:41 +08:00
fix: 修复RDP爆破高误报率问题 (#555)
- 移除 screen.go 中错误的认证结果覆盖逻辑 - 启用 NLA 协议的 ErrorCode 字段检测 - 添加 PubKeyAuth 验证确保认证真正成功 - 修复 io.go 中错误被静默忽略的问题 - 修复 socket.go/io.go 中可能导致 panic 的代码 - 修复 screen.go 中文件句柄泄漏和 log.Panic
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user