mirror of
https://github.com/yv1ing/ShotRDP.git
synced 2025-09-16 15:10:57 +08:00
324 lines
8.4 KiB
Go
324 lines
8.4 KiB
Go
package x224
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"ShotRDP/grdp/core"
|
|
"ShotRDP/grdp/emission"
|
|
"ShotRDP/grdp/glog"
|
|
"ShotRDP/grdp/protocol/tpkt"
|
|
|
|
"github.com/lunixbochs/struc"
|
|
)
|
|
|
|
// take idea from https://github.com/Madnikulin50/gordp
|
|
|
|
/**
|
|
* Message type present in X224 packet header
|
|
*/
|
|
type MessageType byte
|
|
|
|
const (
|
|
TPDU_CONNECTION_REQUEST MessageType = 0xE0
|
|
TPDU_CONNECTION_CONFIRM = 0xD0
|
|
TPDU_DISCONNECT_REQUEST = 0x80
|
|
TPDU_DATA = 0xF0
|
|
TPDU_ERROR = 0x70
|
|
)
|
|
|
|
/**
|
|
* Type of negotiation present in negotiation packet
|
|
*/
|
|
type NegotiationType byte
|
|
|
|
const (
|
|
TYPE_RDP_NEG_REQ NegotiationType = 0x01
|
|
TYPE_RDP_NEG_RSP = 0x02
|
|
TYPE_RDP_NEG_FAILURE = 0x03
|
|
)
|
|
|
|
/**
|
|
* Protocols available for x224 layer
|
|
*/
|
|
|
|
const (
|
|
PROTOCOL_RDP uint32 = 0x00000000
|
|
PROTOCOL_SSL = 0x00000001
|
|
PROTOCOL_HYBRID = 0x00000002
|
|
PROTOCOL_HYBRID_EX = 0x00000008
|
|
)
|
|
|
|
/**
|
|
* Use to negotiate security layer of RDP stack
|
|
* In node-rdpjs only ssl is available
|
|
* @param opt {object} component type options
|
|
* @see request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx
|
|
* @see response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
|
|
* @see failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
|
|
*/
|
|
type Negotiation struct {
|
|
Type NegotiationType `struc:"byte"`
|
|
Flag uint8 `struc:"uint8"`
|
|
Length uint16 `struc:"little"`
|
|
Result uint32 `struc:"little"`
|
|
}
|
|
|
|
func NewNegotiation() *Negotiation {
|
|
return &Negotiation{0, 0, 0x0008 /*constant*/, PROTOCOL_RDP}
|
|
}
|
|
|
|
type failureCode int
|
|
|
|
const (
|
|
//The server requires that the client support Enhanced RDP Security (section 5.4) with either TLS 1.0, 1.1 or 1.2 (section 5.4.5.1) or CredSSP (section 5.4.5.2). If only CredSSP was requested then the server only supports TLS.
|
|
SSL_REQUIRED_BY_SERVER = 0x00000001
|
|
|
|
//The server is configured to only use Standard RDP Security mechanisms (section 5.3) and does not support any External Security Protocols (section 5.4.5).
|
|
SSL_NOT_ALLOWED_BY_SERVER = 0x00000002
|
|
|
|
//The server does not possess a valid authentication certificate and cannot initialize the External Security Protocol Provider (section 5.4.5).
|
|
SSL_CERT_NOT_ON_SERVER = 0x00000003
|
|
|
|
//The list of requested security protocols is not consistent with the current security protocol in effect. This error is only possible when the Direct Approach (sections 5.4.2.2 and 1.3.1.2) is used and an External Security Protocol (section 5.4.5) is already being used.
|
|
INCONSISTENT_FLAGS = 0x00000004
|
|
|
|
//The server requires that the client support Enhanced RDP Security (section 5.4) with CredSSP (section 5.4.5.2).
|
|
HYBRID_REQUIRED_BY_SERVER = 0x00000005
|
|
|
|
//The server requires that the client support Enhanced RDP Security (section 5.4) with TLS 1.0, 1.1 or 1.2 (section 5.4.5.1) and certificate-based client authentication.<4>
|
|
SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006
|
|
)
|
|
|
|
/**
|
|
* X224 client connection request
|
|
* @param opt {object} component type options
|
|
* @see http://msdn.microsoft.com/en-us/library/cc240470.aspx
|
|
*/
|
|
type ClientConnectionRequestPDU struct {
|
|
Len uint8
|
|
Code MessageType
|
|
Padding1 uint16
|
|
Padding2 uint16
|
|
Padding3 uint8
|
|
Cookie []byte
|
|
requestedProtocol uint32
|
|
ProtocolNeg *Negotiation
|
|
}
|
|
|
|
func NewClientConnectionRequestPDU(cookie []byte, requestedProtocol uint32) *ClientConnectionRequestPDU {
|
|
x := ClientConnectionRequestPDU{0, TPDU_CONNECTION_REQUEST, 0, 0, 0,
|
|
cookie, requestedProtocol, NewNegotiation()}
|
|
|
|
x.Len = 6
|
|
if len(cookie) > 0 {
|
|
x.Len += uint8(len(cookie) + 2)
|
|
}
|
|
if x.requestedProtocol > PROTOCOL_RDP {
|
|
x.Len += 8
|
|
}
|
|
|
|
return &x
|
|
}
|
|
|
|
func (x *ClientConnectionRequestPDU) Serialize() []byte {
|
|
buff := &bytes.Buffer{}
|
|
core.WriteUInt8(x.Len, buff)
|
|
core.WriteUInt8(uint8(x.Code), buff)
|
|
core.WriteUInt16BE(x.Padding1, buff)
|
|
core.WriteUInt16BE(x.Padding2, buff)
|
|
core.WriteUInt8(x.Padding3, buff)
|
|
|
|
if len(x.Cookie) > 0 {
|
|
buff.Write(x.Cookie)
|
|
core.WriteUInt8(0x0D, buff)
|
|
core.WriteUInt8(0x0A, buff)
|
|
}
|
|
|
|
if x.requestedProtocol > PROTOCOL_RDP {
|
|
struc.Pack(buff, x.ProtocolNeg)
|
|
}
|
|
|
|
return buff.Bytes()
|
|
}
|
|
|
|
/**
|
|
* X224 Server connection confirm
|
|
* @param opt {object} component type options
|
|
* @see http://msdn.microsoft.com/en-us/library/cc240506.aspx
|
|
*/
|
|
type ServerConnectionConfirm struct {
|
|
Len uint8
|
|
Code MessageType
|
|
Padding1 uint16
|
|
Padding2 uint16
|
|
Padding3 uint8
|
|
ProtocolNeg *Negotiation
|
|
}
|
|
|
|
/**
|
|
* Header of each data message from x224 layer
|
|
* @returns {type.Component}
|
|
*/
|
|
type DataHeader struct {
|
|
Header uint8 `struc:"little"`
|
|
MessageType MessageType `struc:"uint8"`
|
|
Separator uint8 `struc:"little"`
|
|
}
|
|
|
|
func NewDataHeader() *DataHeader {
|
|
return &DataHeader{2, TPDU_DATA /* constant */, 0x80 /*constant*/}
|
|
}
|
|
|
|
/**
|
|
* Common X224 Automata
|
|
* @param presentation {Layer} presentation layer
|
|
*/
|
|
type X224 struct {
|
|
emission.Emitter
|
|
transport core.Transport
|
|
requestedProtocol uint32
|
|
selectedProtocol uint32
|
|
dataHeader *DataHeader
|
|
}
|
|
|
|
func New(t core.Transport) *X224 {
|
|
//TODO: 修改RDP验证方式
|
|
//x := &X224{
|
|
// *emission.NewEmitter(),
|
|
// t,
|
|
// PROTOCOL_RDP | PROTOCOL_SSL | PROTOCOL_HYBRID,
|
|
// PROTOCOL_SSL,
|
|
// NewDataHeader(),
|
|
//}
|
|
|
|
x := &X224{
|
|
*emission.NewEmitter(),
|
|
t,
|
|
PROTOCOL_RDP | PROTOCOL_SSL,
|
|
PROTOCOL_RDP,
|
|
NewDataHeader(),
|
|
}
|
|
|
|
t.On("close", func() {
|
|
x.Emit("close")
|
|
}).On("error", func(err error) {
|
|
x.Emit("error", err)
|
|
})
|
|
|
|
return x
|
|
}
|
|
|
|
func (x *X224) Read(b []byte) (n int, err error) {
|
|
return x.transport.Read(b)
|
|
}
|
|
|
|
func (x *X224) Write(b []byte) (n int, err error) {
|
|
buff := &bytes.Buffer{}
|
|
err = struc.Pack(buff, x.dataHeader)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
buff.Write(b)
|
|
|
|
glog.Trace("x224 write:", hex.EncodeToString(buff.Bytes()))
|
|
return x.transport.Write(buff.Bytes())
|
|
}
|
|
|
|
func (x *X224) Close() error {
|
|
return x.transport.Close()
|
|
}
|
|
|
|
func (x *X224) SetRequestedProtocol(p uint32) {
|
|
x.requestedProtocol = p
|
|
}
|
|
|
|
func (x *X224) Connect() error {
|
|
if x.transport == nil {
|
|
return errors.New("no transport")
|
|
}
|
|
cookie := "Cookie: mstshash=test"
|
|
message := NewClientConnectionRequestPDU([]byte(cookie), x.requestedProtocol)
|
|
message.ProtocolNeg.Type = TYPE_RDP_NEG_REQ
|
|
message.ProtocolNeg.Result = uint32(x.requestedProtocol)
|
|
|
|
glog.Debug("x224 sendConnectionRequest", hex.EncodeToString(message.Serialize()))
|
|
_, err := x.transport.Write(message.Serialize())
|
|
x.transport.Once("data", x.recvConnectionConfirm)
|
|
return err
|
|
}
|
|
|
|
func (x *X224) recvConnectionConfirm(s []byte) {
|
|
glog.Debug("x224 recvConnectionConfirm ", hex.EncodeToString(s))
|
|
r := bytes.NewReader(s)
|
|
ln, _ := core.ReadUInt8(r)
|
|
if ln > 6 {
|
|
message := &ServerConnectionConfirm{}
|
|
if err := struc.Unpack(bytes.NewReader(s), message); err != nil {
|
|
glog.Error("ReadServerConnectionConfirm err", err)
|
|
return
|
|
}
|
|
glog.Debugf("message: %+v", *message.ProtocolNeg)
|
|
if message.ProtocolNeg.Type == TYPE_RDP_NEG_FAILURE {
|
|
glog.Error(fmt.Sprintf("NODE_RDP_PROTOCOL_X224_NEG_FAILURE with code: %d,see https://msdn.microsoft.com/en-us/library/cc240507.aspx",
|
|
message.ProtocolNeg.Result))
|
|
//only use Standard RDP Security mechanisms
|
|
if message.ProtocolNeg.Result == 2 {
|
|
glog.Info("Only use Standard RDP Security mechanisms, Reconnect with Standard RDP")
|
|
}
|
|
x.Close()
|
|
return
|
|
}
|
|
|
|
if message.ProtocolNeg.Type == TYPE_RDP_NEG_RSP {
|
|
glog.Info("TYPE_RDP_NEG_RSP")
|
|
x.selectedProtocol = message.ProtocolNeg.Result
|
|
}
|
|
} else {
|
|
x.selectedProtocol = PROTOCOL_RDP
|
|
}
|
|
|
|
if x.selectedProtocol == PROTOCOL_HYBRID_EX {
|
|
glog.Error("NODE_RDP_PROTOCOL_HYBRID_EX_NOT_SUPPORTED")
|
|
return
|
|
}
|
|
|
|
x.transport.On("data", x.recvData)
|
|
|
|
if x.selectedProtocol == PROTOCOL_RDP {
|
|
glog.Info("*** RDP security selected ***")
|
|
x.Emit("connect", x.selectedProtocol)
|
|
return
|
|
}
|
|
|
|
if x.selectedProtocol == PROTOCOL_SSL {
|
|
glog.Info("*** SSL security selected ***")
|
|
err := x.transport.(*tpkt.TPKT).StartTLS()
|
|
if err != nil {
|
|
glog.Error("start tls failed:", err)
|
|
return
|
|
}
|
|
x.Emit("connect", x.selectedProtocol)
|
|
return
|
|
}
|
|
|
|
if x.selectedProtocol == PROTOCOL_HYBRID {
|
|
glog.Info("*** NLA Security selected ***")
|
|
err := x.transport.(*tpkt.TPKT).StartNLA()
|
|
if err != nil {
|
|
glog.Error("start NLA failed:", err)
|
|
return
|
|
}
|
|
x.Emit("connect", x.selectedProtocol)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (x *X224) recvData(s []byte) {
|
|
glog.Trace("x224 recvData", hex.EncodeToString(s), "emit data")
|
|
// x224 header takes 3 bytes
|
|
x.Emit("data", s[3:])
|
|
}
|