1
0
mirror of https://github.com/sairson/Yasso.git synced 2026-11-04 14:44:59 +08:00

Yasso更新大改动,更新扫描方式,去除不常用功能,增加指纹和协议识别,修补bug等

This commit is contained in:
sairson
2022-05-29 09:11:07 +08:00
parent a6cd80f8e8
commit cb72f18edd
129 changed files with 16619 additions and 6278 deletions

View File

@@ -0,0 +1,181 @@
package lic
import (
"io"
"Yasso/pkg/grdp/core"
)
const (
LICENSE_REQUEST = 0x01
PLATFORM_CHALLENGE = 0x02
NEW_LICENSE = 0x03
UPGRADE_LICENSE = 0x04
LICENSE_INFO = 0x12
NEW_LICENSE_REQUEST = 0x13
PLATFORM_CHALLENGE_RESPONSE = 0x15
ERROR_ALERT = 0xFF
)
// error code
const (
ERR_INVALID_SERVER_CERTIFICATE = 0x00000001
ERR_NO_LICENSE = 0x00000002
ERR_INVALID_SCOPE = 0x00000004
ERR_NO_LICENSE_SERVER = 0x00000006
STATUS_VALID_CLIENT = 0x00000007
ERR_INVALID_CLIENT = 0x00000008
ERR_INVALID_PRODUCTID = 0x0000000B
ERR_INVALID_MESSAGE_LEN = 0x0000000C
ERR_INVALID_MAC = 0x00000003
)
// state transition
const (
ST_TOTAL_ABORT = 0x00000001
ST_NO_TRANSITION = 0x00000002
ST_RESET_PHASE_TO_START = 0x00000003
ST_RESEND_LAST_MESSAGE = 0x00000004
)
/*
"""
@summary: Binary blob data type
@see: http://msdn.microsoft.com/en-us/library/cc240481.aspx
"""
*/
type BinaryBlobType uint16
const (
BB_ANY_BLOB = 0x0000
BB_DATA_BLOB = 0x0001
BB_RANDOM_BLOB = 0x0002
BB_CERTIFICATE_BLOB = 0x0003
BB_ERROR_BLOB = 0x0004
BB_ENCRYPTED_DATA_BLOB = 0x0009
BB_KEY_EXCHG_ALG_BLOB = 0x000D
BB_SCOPE_BLOB = 0x000E
BB_CLIENT_USER_NAME_BLOB = 0x000F
BB_CLIENT_MACHINE_NAME_BLOB = 0x0010
)
type ErrorMessage struct {
DwErrorCode uint32
DwStateTransaction uint32
Blob []byte
}
func readErrorMessage(r io.Reader) *ErrorMessage {
m := &ErrorMessage{}
m.DwErrorCode, _ = core.ReadUInt32LE(r)
m.DwStateTransaction, _ = core.ReadUInt32LE(r)
return m
}
type LicensePacket struct {
BMsgtype uint8
Flag uint8
WMsgSize uint16
LicensingMessage interface{}
}
func ReadLicensePacket(r io.Reader) *LicensePacket {
l := &LicensePacket{}
l.BMsgtype, _ = core.ReadUInt8(r)
l.Flag, _ = core.ReadUInt8(r)
l.WMsgSize, _ = core.ReadUint16LE(r)
switch l.BMsgtype {
case ERROR_ALERT:
l.LicensingMessage = readErrorMessage(r)
default:
l.LicensingMessage, _ = core.ReadBytes(int(l.WMsgSize-4), r)
}
return l
}
/*
"""
@summary: Blob use by license manager to exchange security data
@see: http://msdn.microsoft.com/en-us/library/cc240481.aspx
"""
*/
type LicenseBinaryBlob struct {
WBlobType uint16 `struc:"little"`
WBlobLen uint16 `struc:"little"`
BlobData []byte `struc:"sizefrom=WBlobLen"`
}
func NewLicenseBinaryBlob(WBlobType uint16) *LicenseBinaryBlob {
return &LicenseBinaryBlob{}
}
/*
"""
@summary: License server product information
@see: http://msdn.microsoft.com/en-us/library/cc241915.aspx
"""
*/
type ProductInformation struct {
DwVersion uint32 `struc:"little"`
CbCompanyName uint32 `struc:"little"`
//may contain "Microsoft Corporation" from server microsoft
PbCompanyName []byte `struc:"sizefrom=CbCompanyName"`
CbProductId uint32 `struc:"little"`
//may contain "A02" from microsoft license server
PbProductId []byte `struc:"sizefrom=CbProductId"`
}
/*
@summary: Send by server to signal license request
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc241914.aspx
*/
type ServerLicenseRequest struct {
ServerRandom []byte `struc:"[32]byte"`
ProductInfo ProductInformation `struc:"little"`
KeyExchangeList LicenseBinaryBlob `struc:"little"`
ServerCertificate LicenseBinaryBlob `struc:"little"`
//ScopeList ScopeList
}
/*
@summary: Send by client to ask new license for client.
RDPY doesn'support license reuse, need it in futur version
@see: http://msdn.microsoft.com/en-us/library/cc241918.aspx
#RSA and must be only RSA
#pure microsoft client ;-)
#http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10
*/
type ClientNewLicenseRequest struct {
PreferredKeyExchangeAlg uint32 `struc:"little"`
PlatformId uint32 `struc:"little"`
ClientRandom []byte `struc:"little"`
EncryptedPreMasterSecret LicenseBinaryBlob `struc:"little"`
ClientUserName LicenseBinaryBlob `struc:"little"`
ClientMachineName LicenseBinaryBlob `struc:"little"`
}
/*
@summary: challenge send from server to client
@see: http://msdn.microsoft.com/en-us/library/cc241921.aspx
*/
type ServerPlatformChallenge struct {
ConnectFlags uint32
EncryptedPlatformChallenge LicenseBinaryBlob
MACData [16]byte
}
/*
"""
@summary: client challenge response
@see: http://msdn.microsoft.com/en-us/library/cc241922.aspx
"""
*/
type ClientPLatformChallengeResponse struct {
EncryptedPlatformChallengeResponse LicenseBinaryBlob
EncryptedHWID LicenseBinaryBlob
MACData []byte //[16]byte
}

View File

@@ -0,0 +1,99 @@
package nla
import (
"encoding/asn1"
"Yasso/pkg/grdp/glog"
)
type NegoToken struct {
Data []byte `asn1:"explicit,tag:0"`
}
type TSRequest struct {
Version int `asn1:"explicit,tag:0"`
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"`
}
type TSCredentials struct {
CredType int `asn1:"explicit,tag:0"`
Credentials []byte `asn1:"explicit,tag:1"`
}
type TSPasswordCreds struct {
DomainName []byte `asn1:"explicit,tag:0"`
UserName []byte `asn1:"explicit,tag:1"`
Password []byte `asn1:"explicit,tag:2"`
}
type TSCspDataDetail struct {
KeySpec int `asn1:"explicit,tag:0"`
CardName string `asn1:"explicit,tag:1"`
ReaderName string `asn1:"explicit,tag:2"`
ContainerName string `asn1:"explicit,tag:3"`
CspName string `asn1:"explicit,tag:4"`
}
type TSSmartCardCreds struct {
Pin string `asn1:"explicit,tag:0"`
CspData []TSCspDataDetail `asn1:"explicit,tag:1"`
UserHint string `asn1:"explicit,tag:2"`
DomainHint string `asn1:"explicit,tag:3"`
}
func EncodeDERTRequest(msgs []Message, authInfo []byte, pubKeyAuth []byte) []byte {
req := TSRequest{
Version: 2,
}
if len(msgs) > 0 {
req.NegoTokens = make([]NegoToken, 0, len(msgs))
}
for _, msg := range msgs {
token := NegoToken{msg.Serialize()}
req.NegoTokens = append(req.NegoTokens, token)
}
if len(authInfo) > 0 {
req.AuthInfo = authInfo
}
if len(pubKeyAuth) > 0 {
req.PubKeyAuth = pubKeyAuth
}
result, err := asn1.Marshal(req)
if err != nil {
glog.Error(err)
}
return result
}
func DecodeDERTRequest(s []byte) (*TSRequest, error) {
treq := &TSRequest{}
_, err := asn1.Unmarshal(s, treq)
return treq, err
}
func EncodeDERTCredentials(domain, username, password []byte) []byte {
tpas := TSPasswordCreds{domain, username, password}
result, err := asn1.Marshal(tpas)
if err != nil {
glog.Error(err)
}
tcre := TSCredentials{1, result}
result, err = asn1.Marshal(tcre)
if err != nil {
glog.Error(err)
}
return result
}
func DecodeDERTCredentials(s []byte) (*TSCredentials, error) {
tcre := &TSCredentials{}
_, err := asn1.Unmarshal(s, tcre)
return tcre, err
}

View File

@@ -0,0 +1,46 @@
package nla
import (
"crypto/hmac"
"crypto/md5"
"crypto/rc4"
"strings"
"Yasso/pkg/grdp/core"
"golang.org/x/crypto/md4"
)
func MD4(data []byte) []byte {
h := md4.New()
h.Write(data)
return h.Sum(nil)
}
func MD5(data []byte) []byte {
h := md5.New()
h.Write(data)
return h.Sum(nil)
}
func HMAC_MD5(key, data []byte) []byte {
h := hmac.New(md5.New, key)
h.Write(data)
return h.Sum(nil)
}
// Version 2 of NTLM hash function
func NTOWFv2(password, user, domain string) []byte {
return HMAC_MD5(MD4(core.UnicodeEncode(password)), core.UnicodeEncode(strings.ToUpper(user)+domain))
}
// Same as NTOWFv2
func LMOWFv2(password, user, domain string) []byte {
return NTOWFv2(password, user, domain)
}
func RC4K(key, src []byte) []byte {
result := make([]byte, len(src))
rc4obj, _ := rc4.NewCipher(key)
rc4obj.XORKeyStream(result, src)
return result
}

View File

@@ -0,0 +1,32 @@
package nla_test
import (
"encoding/hex"
"testing"
"Yasso/pkg/grdp/protocol/nla"
)
func TestNTOWFv2(t *testing.T) {
res := hex.EncodeToString(nla.NTOWFv2("", "", ""))
expected := "f4c1a15dd59d4da9bd595599220d971a"
if res != expected {
t.Error(res, "not equal to", expected)
}
res = hex.EncodeToString(nla.NTOWFv2("user", "pwd", "dom"))
expected = "652feb8208b3a8a6264c9c5d5b820979"
if res != expected {
t.Error(res, "not equal to", expected)
}
}
func TestRC4K(t *testing.T) {
key, _ := hex.DecodeString("55638e834ce774c100637f197bc0683f")
src, _ := hex.DecodeString("177d16086dd3f06fa8d594e3bad005b7")
res := hex.EncodeToString(nla.RC4K(key, src))
expected := "f5ab375222707a492bd5a90705d96d1d"
if res != expected {
t.Error(res, "not equal to", expected)
}
}

View File

@@ -0,0 +1,515 @@
package nla
import (
"bytes"
"crypto/md5"
"crypto/rc4"
"encoding/binary"
"encoding/hex"
"time"
"Yasso/pkg/grdp/core"
"Yasso/pkg/grdp/glog"
"github.com/lunixbochs/struc"
)
const (
WINDOWS_MINOR_VERSION_0 = 0x00
WINDOWS_MINOR_VERSION_1 = 0x01
WINDOWS_MINOR_VERSION_2 = 0x02
WINDOWS_MINOR_VERSION_3 = 0x03
WINDOWS_MAJOR_VERSION_5 = 0x05
WINDOWS_MAJOR_VERSION_6 = 0x06
NTLMSSP_REVISION_W2K3 = 0x0F
)
const (
MsvAvEOL = 0x0000
MsvAvNbComputerName = 0x0001
MsvAvNbDomainName = 0x0002
MsvAvDnsComputerName = 0x0003
MsvAvDnsDomainName = 0x0004
MsvAvDnsTreeName = 0x0005
MsvAvFlags = 0x0006
MsvAvTimestamp = 0x0007
MsvAvSingleHost = 0x0008
MsvAvTargetName = 0x0009
MsvChannelBindings = 0x000A
)
type AVPair struct {
Id uint16 `struc:"little"`
Len uint16 `struc:"little,sizeof=Value"`
Value []byte `struc:"little"`
}
const (
NTLMSSP_NEGOTIATE_56 = 0x80000000
NTLMSSP_NEGOTIATE_KEY_EXCH = 0x40000000
NTLMSSP_NEGOTIATE_128 = 0x20000000
NTLMSSP_NEGOTIATE_VERSION = 0x02000000
NTLMSSP_NEGOTIATE_TARGET_INFO = 0x00800000
NTLMSSP_REQUEST_NON_NT_SESSION_KEY = 0x00400000
NTLMSSP_NEGOTIATE_IDENTIFY = 0x00100000
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000
NTLMSSP_TARGET_TYPE_SERVER = 0x00020000
NTLMSSP_TARGET_TYPE_DOMAIN = 0x00010000
NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x00008000
NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000
NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000
NTLMSSP_NEGOTIATE_NTLM = 0x00000200
NTLMSSP_NEGOTIATE_LM_KEY = 0x00000080
NTLMSSP_NEGOTIATE_DATAGRAM = 0x00000040
NTLMSSP_NEGOTIATE_SEAL = 0x00000020
NTLMSSP_NEGOTIATE_SIGN = 0x00000010
NTLMSSP_REQUEST_TARGET = 0x00000004
NTLM_NEGOTIATE_OEM = 0x00000002
NTLMSSP_NEGOTIATE_UNICODE = 0x00000001
)
type NVersion struct {
ProductMajorVersion uint8 `struc:"little"`
ProductMinorVersion uint8 `struc:"little"`
ProductBuild uint16 `struc:"little"`
Reserved [3]byte `struc:"little"`
NTLMRevisionCurrent uint8 `struc:"little"`
}
func NewNVersion() NVersion {
return NVersion{
ProductMajorVersion: WINDOWS_MAJOR_VERSION_6,
ProductMinorVersion: WINDOWS_MINOR_VERSION_0,
ProductBuild: 6002,
NTLMRevisionCurrent: NTLMSSP_REVISION_W2K3,
}
}
type Message interface {
Serialize() []byte
}
type NegotiateMessage struct {
Signature [8]byte `struc:"little"`
MessageType uint32 `struc:"little"`
NegotiateFlags uint32 `struc:"little"`
DomainNameLen uint16 `struc:"little"`
DomainNameMaxLen uint16 `struc:"little"`
DomainNameBufferOffset uint32 `struc:"little"`
WorkstationLen uint16 `struc:"little"`
WorkstationMaxLen uint16 `struc:"little"`
WorkstationBufferOffset uint32 `struc:"little"`
Version NVersion `struc:"little"`
Payload [32]byte `struc:"skip"`
}
func NewNegotiateMessage() *NegotiateMessage {
return &NegotiateMessage{
Signature: [8]byte{'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00},
MessageType: 0x00000001,
}
}
func (m *NegotiateMessage) Serialize() []byte {
if (m.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) != 0 {
m.Version = NewNVersion()
}
buff := &bytes.Buffer{}
struc.Pack(buff, m)
return buff.Bytes()
}
type ChallengeMessage struct {
Signature []byte `struc:"[8]byte"`
MessageType uint32 `struc:"little"`
TargetNameLen uint16 `struc:"little"`
TargetNameMaxLen uint16 `struc:"little"`
TargetNameBufferOffset uint32 `struc:"little"`
NegotiateFlags uint32 `struc:"little"`
ServerChallenge [8]byte `struc:"little"`
Reserved [8]byte `struc:"little"`
TargetInfoLen uint16 `struc:"little"`
TargetInfoMaxLen uint16 `struc:"little"`
TargetInfoBufferOffset uint32 `struc:"little"`
Version NVersion `struc:"skip"`
Payload []byte `struc:"skip"`
}
func (m *ChallengeMessage) Serialize() []byte {
buff := &bytes.Buffer{}
struc.Pack(buff, m)
if (m.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) != 0 {
struc.Pack(buff, m.Version)
}
buff.Write(m.Payload)
return buff.Bytes()
}
func NewChallengeMessage() *ChallengeMessage {
return &ChallengeMessage{
Signature: []byte{'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00},
MessageType: 0x00000002,
}
}
// total len - payload len
func (m *ChallengeMessage) BaseLen() uint32 {
return 56
}
func (m *ChallengeMessage) getTargetInfo() []byte {
if m.TargetInfoLen == 0 {
return make([]byte, 0)
}
offset := m.BaseLen()
start := m.TargetInfoBufferOffset - offset
return m.Payload[start : start+uint32(m.TargetInfoLen)]
}
func (m *ChallengeMessage) getTargetName() []byte {
if m.TargetNameLen == 0 {
return make([]byte, 0)
}
offset := m.BaseLen()
start := m.TargetNameBufferOffset - offset
return m.Payload[start : start+uint32(m.TargetNameLen)]
}
func (m *ChallengeMessage) getTargetInfoTimestamp(data []byte) []byte {
r := bytes.NewReader(data)
for r.Len() > 0 {
avPair := &AVPair{}
struc.Unpack(r, avPair)
if avPair.Id == MsvAvTimestamp {
return avPair.Value
}
if avPair.Id == MsvAvEOL {
break
}
}
return nil
}
type AuthenticateMessage struct {
Signature [8]byte
MessageType uint32 `struc:"little"`
LmChallengeResponseLen uint16 `struc:"little"`
LmChallengeResponseMaxLen uint16 `struc:"little"`
LmChallengeResponseBufferOffset uint32 `struc:"little"`
NtChallengeResponseLen uint16 `struc:"little"`
NtChallengeResponseMaxLen uint16 `struc:"little"`
NtChallengeResponseBufferOffset uint32 `struc:"little"`
DomainNameLen uint16 `struc:"little"`
DomainNameMaxLen uint16 `struc:"little"`
DomainNameBufferOffset uint32 `struc:"little"`
UserNameLen uint16 `struc:"little"`
UserNameMaxLen uint16 `struc:"little"`
UserNameBufferOffset uint32 `struc:"little"`
WorkstationLen uint16 `struc:"little"`
WorkstationMaxLen uint16 `struc:"little"`
WorkstationBufferOffset uint32 `struc:"little"`
EncryptedRandomSessionLen uint16 `struc:"little"`
EncryptedRandomSessionMaxLen uint16 `struc:"little"`
EncryptedRandomSessionBufferOffset uint32 `struc:"little"`
NegotiateFlags uint32 `struc:"little"`
Version NVersion `struc:"little"`
MIC [16]byte `struc:"little"`
Payload []byte `struc:"skip"`
}
func (m *AuthenticateMessage) BaseLen() uint32 {
return 88
}
func NewAuthenticateMessage(negFlag uint32, domain, user, workstation []byte,
lmchallResp, ntchallResp, enRandomSessKey []byte) *AuthenticateMessage {
msg := &AuthenticateMessage{
Signature: [8]byte{'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00},
MessageType: 0x00000003,
NegotiateFlags: negFlag,
}
payloadBuff := &bytes.Buffer{}
msg.LmChallengeResponseLen = uint16(len(lmchallResp))
msg.LmChallengeResponseMaxLen = msg.LmChallengeResponseLen
msg.LmChallengeResponseBufferOffset = msg.BaseLen()
payloadBuff.Write(lmchallResp)
msg.NtChallengeResponseLen = uint16(len(ntchallResp))
msg.NtChallengeResponseMaxLen = msg.NtChallengeResponseLen
msg.NtChallengeResponseBufferOffset = msg.LmChallengeResponseBufferOffset + uint32(msg.LmChallengeResponseLen)
payloadBuff.Write(ntchallResp)
msg.DomainNameLen = uint16(len(domain))
msg.DomainNameMaxLen = msg.DomainNameLen
msg.DomainNameBufferOffset = msg.NtChallengeResponseBufferOffset + uint32(msg.NtChallengeResponseLen)
payloadBuff.Write(domain)
msg.UserNameLen = uint16(len(user))
msg.UserNameMaxLen = msg.UserNameLen
msg.UserNameBufferOffset = msg.DomainNameBufferOffset + uint32(msg.DomainNameLen)
payloadBuff.Write(user)
msg.WorkstationLen = uint16(len(workstation))
msg.WorkstationMaxLen = msg.WorkstationLen
msg.WorkstationBufferOffset = msg.UserNameBufferOffset + uint32(msg.UserNameLen)
payloadBuff.Write(workstation)
msg.EncryptedRandomSessionLen = uint16(len(enRandomSessKey))
msg.EncryptedRandomSessionMaxLen = msg.EncryptedRandomSessionLen
msg.EncryptedRandomSessionBufferOffset = msg.WorkstationBufferOffset + uint32(msg.WorkstationLen)
payloadBuff.Write(enRandomSessKey)
if (msg.NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) != 0 {
msg.Version = NewNVersion()
}
msg.Payload = payloadBuff.Bytes()
return msg
}
func (m *AuthenticateMessage) Serialize() []byte {
buff := &bytes.Buffer{}
struc.Pack(buff, m)
buff.Write(m.Payload)
return buff.Bytes()
}
type NTLMv2 struct {
domain string
user string
password string
respKeyNT []byte
respKeyLM []byte
negotiateMessage *NegotiateMessage
challengeMessage *ChallengeMessage
authenticateMessage *AuthenticateMessage
enableUnicode bool
}
func NewNTLMv2(domain, user, password string) *NTLMv2 {
return &NTLMv2{
domain: domain,
user: user,
password: password,
respKeyNT: NTOWFv2(password, user, domain),
respKeyLM: LMOWFv2(password, user, domain),
}
}
// generate first handshake messgae
func (n *NTLMv2) GetNegotiateMessage() *NegotiateMessage {
negoMsg := NewNegotiateMessage()
negoMsg.NegotiateFlags = NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY |
NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_NEGOTIATE_SEAL |
NTLMSSP_NEGOTIATE_SIGN |
NTLMSSP_REQUEST_TARGET |
NTLMSSP_NEGOTIATE_UNICODE
n.negotiateMessage = negoMsg
return n.negotiateMessage
}
// process NTLMv2 Authenticate hash
func (n *NTLMv2) ComputeResponseV2(respKeyNT, respKeyLM, serverChallenge, clientChallenge,
timestamp, serverInfo []byte) (ntChallResp, lmChallResp, SessBaseKey []byte) {
tempBuff := &bytes.Buffer{}
tempBuff.Write([]byte{0x01, 0x01}) // Responser version, HiResponser version
tempBuff.Write([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
tempBuff.Write(timestamp)
tempBuff.Write(clientChallenge)
tempBuff.Write([]byte{0x00, 0x00, 0x00, 0x00})
tempBuff.Write(serverInfo)
tempBuff.Write([]byte{0x00, 0x00, 0x00, 0x00})
ntBuf := bytes.NewBuffer(serverChallenge)
ntBuf.Write(tempBuff.Bytes())
ntProof := HMAC_MD5(respKeyNT, ntBuf.Bytes())
ntChallResp = make([]byte, 0, len(ntProof)+tempBuff.Len())
ntChallResp = append(ntChallResp, ntProof...)
ntChallResp = append(ntChallResp, tempBuff.Bytes()...)
lmBuf := bytes.NewBuffer(serverChallenge)
lmBuf.Write(clientChallenge)
lmChallResp = HMAC_MD5(respKeyLM, lmBuf.Bytes())
lmChallResp = append(lmChallResp, clientChallenge...)
SessBaseKey = HMAC_MD5(respKeyNT, ntProof)
return
}
func MIC(exportedSessionKey []byte, negotiateMessage, challengeMessage, authenticateMessage Message) []byte {
buff := bytes.Buffer{}
buff.Write(negotiateMessage.Serialize())
buff.Write(challengeMessage.Serialize())
buff.Write(authenticateMessage.Serialize())
return HMAC_MD5(exportedSessionKey, buff.Bytes())
}
func concat(bs ...[]byte) []byte {
return bytes.Join(bs, nil)
}
var (
clientSigning = concat([]byte("session key to client-to-server signing key magic constant"), []byte{0x00})
serverSigning = concat([]byte("session key to server-to-client signing key magic constant"), []byte{0x00})
clientSealing = concat([]byte("session key to client-to-server sealing key magic constant"), []byte{0x00})
serverSealing = concat([]byte("session key to server-to-client sealing key magic constant"), []byte{0x00})
)
func (n *NTLMv2) GetAuthenticateMessage(s []byte) (*AuthenticateMessage, *NTLMv2Security) {
challengeMsg := &ChallengeMessage{}
r := bytes.NewReader(s)
err := struc.Unpack(r, challengeMsg)
if err != nil {
glog.Error("read challengeMsg", err)
return nil, nil
}
if challengeMsg.NegotiateFlags&NTLMSSP_NEGOTIATE_VERSION != 0 {
version := NVersion{}
err := struc.Unpack(r, &version)
if err != nil {
glog.Error("read version", err)
return nil, nil
}
challengeMsg.Version = version
}
challengeMsg.Payload, _ = core.ReadBytes(r.Len(), r)
n.challengeMessage = challengeMsg
glog.Debugf("challengeMsg:%+v", challengeMsg)
serverName := challengeMsg.getTargetName()
serverInfo := challengeMsg.getTargetInfo()
timestamp := challengeMsg.getTargetInfoTimestamp(serverInfo)
computeMIC := false
if timestamp == nil {
ft := uint64(time.Now().UnixNano()) / 100
ft += 116444736000000000 // add time between unix & windows offset
timestamp = make([]byte, 8)
binary.LittleEndian.PutUint64(timestamp, ft)
} else {
computeMIC = true
}
glog.Infof("serverName=%+v", string(serverName))
serverChallenge := challengeMsg.ServerChallenge[:]
clientChallenge := core.Random(8)
ntChallengeResponse, lmChallengeResponse, SessionBaseKey := n.ComputeResponseV2(
n.respKeyNT, n.respKeyLM, serverChallenge, clientChallenge, timestamp, serverInfo)
exchangeKey := SessionBaseKey
exportedSessionKey := core.Random(16)
EncryptedRandomSessionKey := make([]byte, len(exportedSessionKey))
rc, _ := rc4.NewCipher(exchangeKey)
rc.XORKeyStream(EncryptedRandomSessionKey, exportedSessionKey)
if challengeMsg.NegotiateFlags&NTLMSSP_NEGOTIATE_UNICODE != 0 {
n.enableUnicode = true
}
glog.Infof("user: %s, passwd:%s", n.user, n.password)
domain, user, _ := n.GetEncodedCredentials()
n.authenticateMessage = NewAuthenticateMessage(challengeMsg.NegotiateFlags,
domain, user, []byte(""), lmChallengeResponse, ntChallengeResponse, EncryptedRandomSessionKey)
if computeMIC {
copy(n.authenticateMessage.MIC[:], MIC(exportedSessionKey, n.negotiateMessage, n.challengeMessage, n.authenticateMessage)[:16])
}
md := md5.New()
//ClientSigningKey
a := concat(exportedSessionKey, clientSigning)
md.Write(a)
ClientSigningKey := md.Sum(nil)
//ServerSigningKey
md.Reset()
a = concat(exportedSessionKey, serverSigning)
md.Write(a)
ServerSigningKey := md.Sum(nil)
//ClientSealingKey
md.Reset()
a = concat(exportedSessionKey, clientSealing)
md.Write(a)
ClientSealingKey := md.Sum(nil)
//ServerSealingKey
md.Reset()
a = concat(exportedSessionKey, serverSealing)
md.Write(a)
ServerSealingKey := md.Sum(nil)
glog.Debugf("ClientSigningKey:%s", hex.EncodeToString(ClientSigningKey))
glog.Debugf("ServerSigningKey:%s", hex.EncodeToString(ServerSigningKey))
glog.Debugf("ClientSealingKey:%s", hex.EncodeToString(ClientSealingKey))
glog.Debugf("ServerSealingKey:%s", hex.EncodeToString(ServerSealingKey))
encryptRC4, _ := rc4.NewCipher(ClientSealingKey)
decryptRC4, _ := rc4.NewCipher(ServerSealingKey)
ntlmSec := &NTLMv2Security{encryptRC4, decryptRC4, ClientSigningKey, ServerSigningKey, 0}
return n.authenticateMessage, ntlmSec
}
func (n *NTLMv2) GetEncodedCredentials() ([]byte, []byte, []byte) {
if n.enableUnicode {
return core.UnicodeEncode(n.domain), core.UnicodeEncode(n.user), core.UnicodeEncode(n.password)
}
return []byte(n.domain), []byte(n.user), []byte(n.password)
}
type NTLMv2Security struct {
EncryptRC4 *rc4.Cipher
DecryptRC4 *rc4.Cipher
SigningKey []byte
VerifyKey []byte
SeqNum uint32
}
func (n *NTLMv2Security) GssEncrypt(s []byte) []byte {
p := make([]byte, len(s))
n.EncryptRC4.XORKeyStream(p, s)
b := &bytes.Buffer{}
//signature
core.WriteUInt32LE(n.SeqNum, b)
core.WriteBytes(s, b)
s1 := HMAC_MD5(n.SigningKey, b.Bytes())[:8]
checksum := make([]byte, 8)
n.EncryptRC4.XORKeyStream(checksum, s1)
b.Reset()
core.WriteUInt32LE(0x00000001, b)
core.WriteBytes(checksum, b)
core.WriteUInt32LE(n.SeqNum, b)
core.WriteBytes(p, b)
n.SeqNum++
return b.Bytes()
}
func (n *NTLMv2Security) GssDecrypt(s []byte) []byte {
r := bytes.NewReader(s)
core.ReadUInt32LE(r) //version
checksum, _ := core.ReadBytes(8, r)
seqNum, _ := core.ReadUInt32LE(r)
data, _ := core.ReadBytes(r.Len(), r)
p := make([]byte, len(data))
n.DecryptRC4.XORKeyStream(p, data)
check := make([]byte, len(checksum))
n.DecryptRC4.XORKeyStream(check, checksum)
b := &bytes.Buffer{}
core.WriteUInt32LE(seqNum, b)
core.WriteBytes(p, b)
verify := HMAC_MD5(n.VerifyKey, b.Bytes())
if string(verify) != string(check) {
return nil
}
return p
}

View File

@@ -0,0 +1,53 @@
package nla_test
//func TestNewNegotiateMessage(t *testing.T) {
// ntlm := nla.NewNTLMv2("", "", "")
// negoMsg := ntlm.GetNegotiateMessage()
// buff := &bytes.Buffer{}
// struc.Pack(buff, negoMsg)
//
// result := hex.EncodeToString(buff.Bytes())
// expected := "4e544c4d535350000100000035820860000000000000000000000000000000000000000000000000"
//
// if result != expected {
// t.Error(result, " not equals to", expected)
// }
//}
//
//func TestNTLMv2_ComputeResponse(t *testing.T) {
// ntlm := nla.NewNTLMv2("", "", "")
//
// ResponseKeyNT, _ := hex.DecodeString("39e32c766260586a9036f1ceb04c3007")
// ResponseKeyLM, _ := hex.DecodeString("39e32c766260586a9036f1ceb04c3007")
// ServerChallenge, _ := hex.DecodeString("adcb9d1c8d4a5ed8")
// ClienChallenge, _ := hex.DecodeString("1a78bed8e5d5efa7")
// Timestamp, _ := hex.DecodeString("a02f44f01267d501")
// ServerName, _ := hex.DecodeString("02001e00570049004e002d00460037005200410041004d004100500034004a00430001001e00570049004e002d00460037005200410041004d004100500034004a00430004001e00570049004e002d00460037005200410041004d004100500034004a00430003001e00570049004e002d00460037005200410041004d004100500034004a00430007000800a02f44f01267d50100000000")
//
// NtChallengeResponse, LmChallengeResponse, SessionBaseKey := ntlm.ComputeResponse(ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClienChallenge, Timestamp, ServerName)
//
// ntChallRespExpected := "4e7316531937d2fc91e7230853844b890101000000000000a02f44f01267d5011a78bed8e5d5efa70000000002001e00570049004e002d00460037005200410041004d004100500034004a00430001001e00570049004e002d00460037005200410041004d004100500034004a00430004001e00570049004e002d00460037005200410041004d004100500034004a00430003001e00570049004e002d00460037005200410041004d004100500034004a00430007000800a02f44f01267d50100000000"
// lmChallRespExpected := "d4dc6edc0c37dd70f69b5c4f05a615661a78bed8e5d5efa7"
// sessBaseKeyExpected := "034009be89a0507b2bd6d28e966e1dab"
//
// if hex.EncodeToString(NtChallengeResponse) != ntChallRespExpected {
// t.Error("NtChallengeResponse incorrect")
// }
//
// if hex.EncodeToString(LmChallengeResponse) != lmChallRespExpected {
// t.Error("LmChallengeResponse incorrect")
// }
//
// if hex.EncodeToString(SessionBaseKey) != sessBaseKeyExpected {
// t.Error("SessionBaseKey incorrect")
// }
//}
//
//func TestSIGNKEY(t *testing.T) {
// exportedSessionKey, _ := hex.DecodeString("be32c3c56ea6683200a35329d67880c3")
// result := hex.EncodeToString(nla.SIGNKEY(exportedSessionKey, true))
// expected := "79b4f9a4113230f378a0af99f784adae"
// if result != expected {
// t.Error(result, "not equal to", expected)
// }
//}

View File

@@ -0,0 +1,656 @@
package pdu
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"io"
"Yasso/pkg/grdp/glog"
"Yasso/pkg/grdp/core"
"Yasso/pkg/grdp/protocol/t125/gcc"
"github.com/lunixbochs/struc"
)
type CapsType uint16
const (
CAPSTYPE_GENERAL CapsType = 0x0001
CAPSTYPE_BITMAP = 0x0002
CAPSTYPE_ORDER = 0x0003
CAPSTYPE_BITMAPCACHE = 0x0004
CAPSTYPE_CONTROL = 0x0005
CAPSTYPE_ACTIVATION = 0x0007
CAPSTYPE_POINTER = 0x0008
CAPSTYPE_SHARE = 0x0009
CAPSTYPE_COLORCACHE = 0x000A
CAPSTYPE_SOUND = 0x000C
CAPSTYPE_INPUT = 0x000D
CAPSTYPE_FONT = 0x000E
CAPSTYPE_BRUSH = 0x000F
CAPSTYPE_GLYPHCACHE = 0x0010
CAPSTYPE_OFFSCREENCACHE = 0x0011
CAPSTYPE_BITMAPCACHE_HOSTSUPPORT = 0x0012
CAPSTYPE_BITMAPCACHE_REV2 = 0x0013
CAPSTYPE_VIRTUALCHANNEL = 0x0014
CAPSTYPE_DRAWNINEGRIDCACHE = 0x0015
CAPSTYPE_DRAWGDIPLUS = 0x0016
CAPSTYPE_RAIL = 0x0017
CAPSTYPE_WINDOW = 0x0018
CAPSETTYPE_COMPDESK = 0x0019
CAPSETTYPE_MULTIFRAGMENTUPDATE = 0x001A
CAPSETTYPE_LARGE_POINTER = 0x001B
CAPSETTYPE_SURFACE_COMMANDS = 0x001C
CAPSETTYPE_BITMAP_CODECS = 0x001D
CAPSSETTYPE_FRAME_ACKNOWLEDGE = 0x001E
)
type MajorType uint16
const (
OSMAJORTYPE_UNSPECIFIED MajorType = 0x0000
OSMAJORTYPE_WINDOWS = 0x0001
OSMAJORTYPE_OS2 = 0x0002
OSMAJORTYPE_MACINTOSH = 0x0003
OSMAJORTYPE_UNIX = 0x0004
OSMAJORTYPE_IOS = 0x0005
OSMAJORTYPE_OSX = 0x0006
OSMAJORTYPE_ANDROID = 0x0007
)
type MinorType uint16
const (
OSMINORTYPE_UNSPECIFIED MinorType = 0x0000
OSMINORTYPE_WINDOWS_31X = 0x0001
OSMINORTYPE_WINDOWS_95 = 0x0002
OSMINORTYPE_WINDOWS_NT = 0x0003
OSMINORTYPE_OS2_V21 = 0x0004
OSMINORTYPE_POWER_PC = 0x0005
OSMINORTYPE_MACINTOSH = 0x0006
OSMINORTYPE_NATIVE_XSERVER = 0x0007
OSMINORTYPE_PSEUDO_XSERVER = 0x0008
OSMINORTYPE_WINDOWS_RT = 0x0009
)
const (
FASTPATH_OUTPUT_SUPPORTED uint16 = 0x0001
NO_BITMAP_COMPRESSION_HDR = 0x0400
LONG_CREDENTIALS_SUPPORTED = 0x0004
AUTORECONNECT_SUPPORTED = 0x0008
ENC_SALTED_CHECKSUM = 0x0010
)
type OrderFlag uint16
const (
NEGOTIATEORDERSUPPORT OrderFlag = 0x0002
ZEROBOUNDSDELTASSUPPORT = 0x0008
COLORINDEXSUPPORT = 0x0020
SOLIDPATTERNBRUSHONLY = 0x0040
ORDERFLAGS_EXTRA_FLAGS = 0x0080
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
*/
type Order uint8
const (
TS_NEG_DSTBLT_INDEX Order = 0x00
TS_NEG_PATBLT_INDEX = 0x01
TS_NEG_SCRBLT_INDEX = 0x02
TS_NEG_MEMBLT_INDEX = 0x03
TS_NEG_MEM3BLT_INDEX = 0x04
TS_NEG_DRAWNINEGRID_INDEX = 0x07
TS_NEG_LINETO_INDEX = 0x08
TS_NEG_MULTI_DRAWNINEGRID_INDEX = 0x09
TS_NEG_SAVEBITMAP_INDEX = 0x0B
TS_NEG_MULTIDSTBLT_INDEX = 0x0F
TS_NEG_MULTIPATBLT_INDEX = 0x10
TS_NEG_MULTISCRBLT_INDEX = 0x11
TS_NEG_MULTIOPAQUERECT_INDEX = 0x12
TS_NEG_FAST_INDEX_INDEX = 0x13
TS_NEG_POLYGON_SC_INDEX = 0x14
TS_NEG_POLYGON_CB_INDEX = 0x15
TS_NEG_POLYLINE_INDEX = 0x16
TS_NEG_FAST_GLYPH_INDEX = 0x18
TS_NEG_ELLIPSE_SC_INDEX = 0x19
TS_NEG_ELLIPSE_CB_INDEX = 0x1A
TS_NEG_INDEX_INDEX = 0x1B
)
type OrderEx uint16
const (
ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT OrderEx = 0x0002
ORDERFLAGS_EX_ALTSEC_FRAME_MARKER_SUPPORT = 0x0004
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240563.aspx
*/
const (
INPUT_FLAG_SCANCODES uint16 = 0x0001
INPUT_FLAG_MOUSEX = 0x0004
INPUT_FLAG_FASTPATH_INPUT = 0x0008
INPUT_FLAG_UNICODE = 0x0010
INPUT_FLAG_FASTPATH_INPUT2 = 0x0020
INPUT_FLAG_UNUSED1 = 0x0040
INPUT_FLAG_UNUSED2 = 0x0080
INPUT_FLAG_MOUSE_HWHEEL = 0x0100
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240564.aspx
*/
type BrushSupport uint32
const (
BRUSH_DEFAULT BrushSupport = 0x00000000
BRUSH_COLOR_8x8 = 0x00000001
BRUSH_COLOR_FULL = 0x00000002
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240565.aspx
*/
type GlyphSupport uint16
const (
GLYPH_SUPPORT_NONE GlyphSupport = 0x0000
GLYPH_SUPPORT_PARTIAL = 0x0001
GLYPH_SUPPORT_FULL = 0x0002
GLYPH_SUPPORT_ENCODE = 0x0003
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240550.aspx
*/
type OffscreenSupportLevel uint32
const (
OSL_FALSE OffscreenSupportLevel = 0x00000000
OSL_TRUE = 0x00000001
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240551.aspx
*/
type VirtualChannelCompressionFlag uint32
const (
VCCAPS_NO_COMPR VirtualChannelCompressionFlag = 0x00000000
VCCAPS_COMPR_SC = 0x00000001
VCCAPS_COMPR_CS_8K = 0x00000002
)
type SoundFlag uint16
const (
SOUND_NONE SoundFlag = 0x0000
SOUND_BEEPS_FLAG = 0x0001
)
type RailsupportLevel uint32
const (
RAIL_LEVEL_SUPPORTED = 0x00000001
RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED = 0x00000002
RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED = 0x00000004
RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED = 0x00000008
RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED = 0x00000010
RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED = 0x00000020
RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED = 0x00000040
RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED = 0x00000080
)
const (
INPUT_EVENT_SYNC = 0x0000
INPUT_EVENT_UNUSED = 0x0002
INPUT_EVENT_SCANCODE = 0x0004
INPUT_EVENT_UNICODE = 0x0005
INPUT_EVENT_MOUSE = 0x8001
INPUT_EVENT_MOUSEX = 0x8002
)
const (
PTRFLAGS_HWHEEL = 0x0400
PTRFLAGS_WHEEL = 0x0200
PTRFLAGS_WHEEL_NEGATIVE = 0x0100
WheelRotationMask = 0x01FF
PTRFLAGS_MOVE = 0x0800
PTRFLAGS_DOWN = 0x8000
PTRFLAGS_BUTTON1 = 0x1000
PTRFLAGS_BUTTON2 = 0x2000
PTRFLAGS_BUTTON3 = 0x4000
)
const (
KBDFLAGS_EXTENDED = 0x0100
KBDFLAGS_DOWN = 0x4000
KBDFLAGS_RELEASE = 0x8000
)
type Capability interface {
Type() CapsType
}
type GeneralCapability struct {
// 010018000100030000020000000015040000000000000000
OSMajorType MajorType `struc:"little"`
OSMinorType MinorType `struc:"little"`
ProtocolVersion uint16 `struc:"little"`
Pad2octetsA uint16 `struc:"little"`
GeneralCompressionTypes uint16 `struc:"little"`
ExtraFlags uint16 `struc:"little"`
UpdateCapabilityFlag uint16 `struc:"little"`
RemoteUnshareFlag uint16 `struc:"little"`
GeneralCompressionLevel uint16 `struc:"little"`
RefreshRectSupport uint8 `struc:"little"`
SuppressOutputSupport uint8 `struc:"little"`
}
func (*GeneralCapability) Type() CapsType {
return CAPSTYPE_GENERAL
}
type BitmapCapability struct {
// 02001c00180001000100010000052003000000000100000001000000
PreferredBitsPerPixel gcc.HighColor `struc:"little"`
Receive1BitPerPixel uint16 `struc:"little"`
Receive4BitsPerPixel uint16 `struc:"little"`
Receive8BitsPerPixel uint16 `struc:"little"`
DesktopWidth uint16 `struc:"little"`
DesktopHeight uint16 `struc:"little"`
Pad2octets uint16 `struc:"little"`
DesktopResizeFlag uint16 `struc:"little"`
BitmapCompressionFlag uint16 `struc:"little"`
HighColorFlags uint8 `struc:"little"`
DrawingFlags uint8 `struc:"little"`
MultipleRectangleSupport uint16 `struc:"little"`
Pad2octetsB uint16 `struc:"little"`
}
func (*BitmapCapability) Type() CapsType {
return CAPSTYPE_BITMAP
}
type BitmapCacheCapability struct {
// 04002800000000000000000000000000000000000000000000000000000000000000000000000000
Pad1 uint32 `struc:"little"`
Pad2 uint32 `struc:"little"`
Pad3 uint32 `struc:"little"`
Pad4 uint32 `struc:"little"`
Pad5 uint32 `struc:"little"`
Pad6 uint32 `struc:"little"`
Cache0Entries uint16 `struc:"little"`
Cache0MaximumCellSize uint16 `struc:"little"`
Cache1Entries uint16 `struc:"little"`
Cache1MaximumCellSize uint16 `struc:"little"`
Cache2Entries uint16 `struc:"little"`
Cache2MaximumCellSize uint16 `struc:"little"`
}
func (*BitmapCacheCapability) Type() CapsType {
return CAPSTYPE_BITMAPCACHE
}
type OrderCapability struct {
// 030058000000000000000000000000000000000000000000010014000000010000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000008403000000000000000000
TerminalDescriptor [16]byte
Pad4octetsA uint32 `struc:"little"`
DesktopSaveXGranularity uint16 `struc:"little"`
DesktopSaveYGranularity uint16 `struc:"little"`
Pad2octetsA uint16 `struc:"little"`
MaximumOrderLevel uint16 `struc:"little"`
NumberFonts uint16 `struc:"little"`
OrderFlags OrderFlag `struc:"little"`
OrderSupport [32]byte
TextFlags uint16 `struc:"little"`
OrderSupportExFlags uint16 `struc:"little"`
Pad4octetsB uint32 `struc:"little"`
DesktopSaveSize uint32 `struc:"little"`
Pad2octetsC uint16 `struc:"little"`
Pad2octetsD uint16 `struc:"little"`
TextANSICodePage uint16 `struc:"little"`
Pad2octetsE uint16 `struc:"little"`
}
func (*OrderCapability) Type() CapsType {
return CAPSTYPE_ORDER
}
type PointerCapability struct {
ColorPointerFlag uint16 `struc:"little"`
ColorPointerCacheSize uint16 `struc:"little"`
// old version of rdp doesn't support ...
// PointerCacheSize uint16 `struc:"little"` // only server need
}
func (*PointerCapability) Type() CapsType {
return CAPSTYPE_POINTER
}
type InputCapability struct {
// 0d005c001500000009040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000
Flags uint16 `struc:"little"`
Pad2octetsA uint16 `struc:"little"`
// same value as gcc.ClientCoreSettings.kbdLayout
KeyboardLayout gcc.KeyboardLayout `struc:"little"`
// same value as gcc.ClientCoreSettings.keyboardType
KeyboardType uint32 `struc:"little"`
// same value as gcc.ClientCoreSettings.keyboardSubType
KeyboardSubType uint32 `struc:"little"`
// same value as gcc.ClientCoreSettings.keyboardFnKeys
KeyboardFunctionKey uint32 `struc:"little"`
// same value as gcc.ClientCoreSettingrrs.imeFileName
ImeFileName [64]byte
//need add 0c000000 in the end
}
func (*InputCapability) Type() CapsType {
return CAPSTYPE_INPUT
}
type BrushCapability struct {
// 0f00080000000000
SupportLevel BrushSupport `struc:"little"`
}
func (*BrushCapability) Type() CapsType {
return CAPSTYPE_BRUSH
}
type cacheEntry struct {
Entries uint16 `struc:"little"`
MaximumCellSize uint16 `struc:"little"`
}
type GlyphCapability struct {
// 10003400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
GlyphCache [10]cacheEntry `struc:"little"`
FragCache uint32 `struc:"little"`
SupportLevel GlyphSupport `struc:"little"`
Pad2octets uint16 `struc:"little"`
}
func (*GlyphCapability) Type() CapsType {
return CAPSTYPE_GLYPHCACHE
}
type OffscreenBitmapCacheCapability struct {
// 11000c000000000000000000
SupportLevel OffscreenSupportLevel `struc:"little"`
CacheSize uint16 `struc:"little"`
CacheEntries uint16 `struc:"little"`
}
func (*OffscreenBitmapCacheCapability) Type() CapsType {
return CAPSTYPE_OFFSCREENCACHE
}
type VirtualChannelCapability struct {
// 14000c000000000000000000
Flags VirtualChannelCompressionFlag `struc:"little"`
VCChunkSize uint32 `struc:"little"` // optional
}
func (*VirtualChannelCapability) Type() CapsType {
return CAPSTYPE_VIRTUALCHANNEL
}
type SoundCapability struct {
// 0c00080000000000
Flags SoundFlag `struc:"little"`
Pad2octets uint16 `struc:"little"`
}
func (*SoundCapability) Type() CapsType {
return CAPSTYPE_SOUND
}
type ControlCapability struct {
ControlFlags uint16 `struc:"little"`
RemoteDetachFlag uint16 `struc:"little"`
ControlInterest uint16 `struc:"little"`
DetachInterest uint16 `struc:"little"`
}
func (*ControlCapability) Type() CapsType {
return CAPSTYPE_CONTROL
}
type WindowActivationCapability struct {
HelpKeyFlag uint16 `struc:"little"`
HelpKeyIndexFlag uint16 `struc:"little"`
HelpExtendedKeyFlag uint16 `struc:"little"`
WindowManagerKeyFlag uint16 `struc:"little"`
}
func (*WindowActivationCapability) Type() CapsType {
return CAPSTYPE_ACTIVATION
}
type FontCapability struct {
SupportFlags uint16 `struc:"little"`
Pad2octets uint16 `struc:"little"`
}
func (*FontCapability) Type() CapsType {
return CAPSTYPE_FONT
}
type ColorCacheCapability struct {
CacheSize uint16 `struc:"little"`
Pad2octets uint16 `struc:"little"`
}
func (*ColorCacheCapability) Type() CapsType {
return CAPSTYPE_COLORCACHE
}
type ShareCapability struct {
NodeId uint16 `struc:"little"`
Pad2octets uint16 `struc:"little"`
}
func (*ShareCapability) Type() CapsType {
return CAPSTYPE_SHARE
}
type MultiFragmentUpdate struct {
// 1a00080000000000
MaxRequestSize uint32 `struc:"little"`
}
func (*MultiFragmentUpdate) Type() CapsType {
return CAPSETTYPE_MULTIFRAGMENTUPDATE
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegdi/52635737-d144-4f47-9c88-b48ceaf3efb4
type DrawGDIPlusCapability struct {
SupportLevel uint32
GdipVersion uint32
CacheLevel uint32
GdipCacheEntries [10]byte
GdipCacheChunkSize [8]byte
GdipImageCacheProperties [6]byte
}
func (*DrawGDIPlusCapability) Type() CapsType {
return CAPSTYPE_DRAWGDIPLUS
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/86507fed-a0ee-4242-b802-237534a8f65e
type BitmapCodec struct {
GUID [16]byte
ID uint8
PropertiesLength uint16 `struc:"little,sizeof=Properties"`
Properties []byte
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/408b1878-9f6e-4106-8329-1af42219ba6a
type BitmapCodecS struct {
Count uint8 `struc:"sizeof=Array"`
Array []BitmapCodec
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/17e80f50-d163-49de-a23b-fd6456aa472f
type BitmapCodecsCapability struct {
SupportedBitmapCodecs BitmapCodecS // A variable-length field containing a TS_BITMAPCODECS structure (section 2.2.7.2.10.1).
}
func (*BitmapCodecsCapability) Type() CapsType {
return CAPSETTYPE_BITMAP_CODECS
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/fc05c385-46c3-42cb-9ed2-c475a3990e0b
type BitmapCacheHostSupportCapability struct {
CacheVersion uint8
Pad1 uint8
Pad2 uint16
}
func (*BitmapCacheHostSupportCapability) Type() CapsType {
return CAPSTYPE_BITMAPCACHE_HOSTSUPPORT
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/41323437-c753-460e-8108-495a6fdd68a8
type LargePointerCapability struct {
SupportFlags uint16 `struc:"little"`
}
func (*LargePointerCapability) Type() CapsType {
return CAPSETTYPE_LARGE_POINTER
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdperp/36a25e21-25e1-4954-aae8-09aaf6715c79
type RemoteProgramsCapability struct {
RailSupportLevel uint32 `struc:"little"`
}
func (*RemoteProgramsCapability) Type() CapsType {
return CAPSTYPE_RAIL
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdperp/82ec7a69-f7e3-4294-830d-666178b35d15
type WindowListCapability struct {
WndSupportLevel uint32 `struc:"little"`
NumIconCaches uint8
NumIconCacheEntries uint16 `struc:"little"`
}
func (*WindowListCapability) Type() CapsType {
return CAPSTYPE_WINDOW
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/9132002f-f133-4a0f-ba2f-2dc48f1e7f93
type DesktopCompositionCapability struct {
CompDeskSupportLevel uint16 `struc:"little"`
}
func (*DesktopCompositionCapability) Type() CapsType {
return CAPSETTYPE_COMPDESK
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/aa953018-c0a8-4761-bb12-86586c2cd56a
type SurfaceCommandsCapability struct {
CmdFlags uint32 `struc:"little"`
Reserved uint32 `struc:"little"`
}
func (*SurfaceCommandsCapability) Type() CapsType {
return CAPSETTYPE_SURFACE_COMMANDS
}
func readCapability(r io.Reader) (Capability, error) {
capType, err := core.ReadUint16LE(r)
if err != nil {
return nil, err
}
capLen, err := core.ReadUint16LE(r)
if err != nil {
return nil, err
}
if int(capLen)-4 <= 0 {
return nil, err
}
capBytes, err := core.ReadBytes(int(capLen)-4, r)
if err != nil {
return nil, err
}
capReader := bytes.NewReader(capBytes)
var c Capability
glog.Debugf("Capability type 0x%04x", capType)
switch CapsType(capType) {
case CAPSTYPE_GENERAL:
c = &GeneralCapability{}
case CAPSTYPE_BITMAP:
c = &BitmapCapability{}
case CAPSTYPE_ORDER:
c = &OrderCapability{}
case CAPSTYPE_BITMAPCACHE:
c = &BitmapCacheCapability{}
case CAPSTYPE_POINTER:
c = &PointerCapability{}
case CAPSTYPE_INPUT:
c = &InputCapability{}
case CAPSTYPE_BRUSH:
c = &BrushCapability{}
case CAPSTYPE_GLYPHCACHE:
c = &GlyphCapability{}
case CAPSTYPE_OFFSCREENCACHE:
c = &OffscreenBitmapCacheCapability{}
case CAPSTYPE_VIRTUALCHANNEL:
c = &VirtualChannelCapability{}
case CAPSTYPE_SOUND:
c = &SoundCapability{}
case CAPSTYPE_CONTROL:
c = &ControlCapability{}
case CAPSTYPE_ACTIVATION:
c = &WindowActivationCapability{}
case CAPSTYPE_FONT:
c = &FontCapability{}
case CAPSTYPE_COLORCACHE:
c = &ColorCacheCapability{}
case CAPSTYPE_SHARE:
c = &ShareCapability{}
case CAPSETTYPE_MULTIFRAGMENTUPDATE:
c = &MultiFragmentUpdate{}
case CAPSTYPE_DRAWGDIPLUS:
c = &DrawGDIPlusCapability{}
case CAPSETTYPE_BITMAP_CODECS:
c = &BitmapCodecsCapability{}
case CAPSTYPE_BITMAPCACHE_HOSTSUPPORT:
c = &BitmapCacheHostSupportCapability{}
case CAPSETTYPE_LARGE_POINTER:
c = &LargePointerCapability{}
case CAPSTYPE_RAIL:
c = &RemoteProgramsCapability{}
case CAPSTYPE_WINDOW:
c = &WindowListCapability{}
case CAPSETTYPE_COMPDESK:
c = &DesktopCompositionCapability{}
case CAPSETTYPE_SURFACE_COMMANDS:
c = &SurfaceCommandsCapability{}
//case CAPSSETTYPE_FRAME_ACKNOWLEDGE:
//c =
//glog.Error("CAPSSETTYPE_FRAME_ACKNOWLEDGE")
default:
err := errors.New(fmt.Sprintf("unsupported Capability type 0x%04x", capType))
glog.Error(err)
return nil, err
}
if err := struc.Unpack(capReader, c); err != nil {
glog.Error("Capability unpack error", err, fmt.Sprintf("0x%04x", capType), hex.EncodeToString(capBytes))
return nil, err
}
glog.Debugf("Capability: %+v", c)
return c, nil
}

View File

@@ -0,0 +1,339 @@
package pdu
import (
"bytes"
"Yasso/pkg/grdp/core"
"Yasso/pkg/grdp/glog"
)
/**
* Initialization Sequence\n
* Client Server\n
* | |\n
* |<----------------------Server Clipboard Capabilities PDU-----------------|\n
* |<-----------------------------Monitor Ready PDU--------------------------|\n
* |-----------------------Client Clipboard Capabilities PDU---------------->|\n
* |---------------------------Temporary Directory PDU---------------------->|\n
* |-------------------------------Format List PDU-------------------------->|\n
* |<--------------------------Format List Response PDU----------------------|\n
*
*/
/**
* Data Transfer Sequences\n
* Shared Local\n
* Clipboard Owner Clipboard Owner\n
* | |\n
* |-------------------------------------------------------------------------|\n _
* |-------------------------------Format List PDU-------------------------->|\n |
* |<--------------------------Format List Response PDU----------------------|\n _| Copy
* Sequence
* |<---------------------Lock Clipboard Data PDU (Optional)-----------------|\n
* |-------------------------------------------------------------------------|\n
* |-------------------------------------------------------------------------|\n _
* |<--------------------------Format Data Request PDU-----------------------|\n | Paste
* Sequence Palette,
* |---------------------------Format Data Response PDU--------------------->|\n _| Metafile,
* File List Data
* |-------------------------------------------------------------------------|\n
* |-------------------------------------------------------------------------|\n _
* |<------------------------Format Contents Request PDU---------------------|\n | Paste
* Sequence
* |-------------------------Format Contents Response PDU------------------->|\n _| File
* Stream Data
* |<---------------------Lock Clipboard Data PDU (Optional)-----------------|\n
* |-------------------------------------------------------------------------|\n
*
*/
type MsgType uint16
const (
CB_MONITOR_READY = 0x0001
CB_FORMAT_LIST = 0x0002
CB_FORMAT_LIST_RESPONSE = 0x0003
CB_FORMAT_DATA_REQUEST = 0x0004
CB_FORMAT_DATA_RESPONSE = 0x0005
CB_TEMP_DIRECTORY = 0x0006
CB_CLIP_CAPS = 0x0007
CB_FILECONTENTS_REQUEST = 0x0008
CB_FILECONTENTS_RESPONSE = 0x0009
CB_LOCK_CLIPDATA = 0x000A
CB_UNLOCK_CLIPDATA = 0x000B
)
type MsgFlags uint16
const (
CB_RESPONSE_OK = 0x0001
CB_RESPONSE_FAIL = 0x0002
CB_ASCII_NAMES = 0x0004
)
type DwFlags uint32
const (
FILECONTENTS_SIZE = 0x00000001
FILECONTENTS_RANGE = 0x00000002
)
type CliprdrPDUHeader struct {
MsgType uint16 `struc:"little"`
MsgFlags uint16 `struc:"little"`
DataLen uint32 `struc:"little"`
}
func NewCliprdrPDUHeader(mType, flags uint16, ln uint32) *CliprdrPDUHeader {
return &CliprdrPDUHeader{
MsgType: mType,
MsgFlags: flags,
DataLen: ln,
}
}
/*func (c *CliprdrPDU) serialize() []byte {
b := &bytes.Buffer{}
return b.Bytes()
}
func (c *CliprdrPDU) SendCliprdrGeneralCapability() {
}
func (c *CliprdrPDU) RecvCliprdrCaps() {
}
func (c *CliprdrPDU) RecvMonitorReady() {
}
func (c *CliprdrPDU) SendCliprdrFileContentsRequest() {
}
func (c *CliprdrPDU) SendCliprdrFileContentsResponse() {
}
func (c *CliprdrPDU) SendCliprdrClientFormatList() {
}
func (c *CliprdrPDU) RecvCliprdrClientFormatListResponse() {
}
*/
type CliprdrClient struct {
useLongFormatNames bool
streamFileClipEnabled bool
fileClipNoFilePaths bool
canLockClipData bool
hasHugeFileSupport bool
}
func process_message(s []byte) {
r := bytes.NewReader(s)
msgType, _ := core.ReadUint16LE(r)
flag, _ := core.ReadUint16LE(r)
length, _ := core.ReadUInt32LE(r)
glog.Debug("cliprdr: type=%d flag=%d length=%d", msgType, flag, length)
switch msgType {
case CB_MONITOR_READY:
//clipboard_sync(plugin->device_data);
break
case CB_FORMAT_LIST:
//clipboard_format_list(plugin->device_data, flag,
// data + 8, length);
//cliprdr_send_packet(plugin, CB_FORMAT_LIST_RESPONSE,
// CB_RESPONSE_OK, NULL, 0);
break
case CB_FORMAT_LIST_RESPONSE:
//clipboard_format_list_response(plugin->device_data, flag);
break
case CB_FORMAT_DATA_REQUEST:
//format = GET_UINT32(data, 8);
//clipboard_request_data(plugin->device_data, format);
break
case CB_FORMAT_DATA_RESPONSE:
//clipboard_handle_data(plugin->device_data, flag,
//data + 8, length);
//break;
case CB_CLIP_CAPS:
//clipboard_handle_caps(plugin->device_data, flag,
//data + 8, length);
break
default:
glog.Error("type %d not supported", msgType)
break
}
}
type CliprdrGeneralCapabilitySet struct {
CapabilitySetType uint16 `struc:"little"`
CapabilitySetLength uint16 `struc:"little"`
Version uint32 `struc:"little"`
GeneralFlags uint32 `struc:"little"`
}
type CliprdrCapabilitySets struct {
CapabilitySetType uint16 `struc:"little"`
LengthCapability uint16 `struc:"little,sizeof=CapabilityData"`
CapabilityData []byte `struc:"little"`
}
type CliprdrCapabilitiesPDU struct {
*CliprdrPDUHeader `struc:"little"`
CCapabilitiesSets uint16 `struc:"little"`
Pad1 uint16 `struc:"little"`
CapabilitySets CliprdrGeneralCapabilitySet `struc:"little"`
}
type CliprdrMonitorReady struct {
*CliprdrPDUHeader `struc:"little"`
}
type GeneralFlags uint32
const (
/* CLIPRDR_GENERAL_CAPABILITY.generalFlags */
CB_USE_LONG_FORMAT_NAMES = 0x00000002
CB_STREAM_FILECLIP_ENABLED = 0x00000004
CB_FILECLIP_NO_FILE_PATHS = 0x00000008
CB_CAN_LOCK_CLIPDATA = 0x00000010
CB_HUGE_FILE_SUPPORT_ENABLED = 0x00000020
)
const (
/* CLIPRDR_GENERAL_CAPABILITY.version */
CB_CAPS_VERSION_1 = 0x00000001
CB_CAPS_VERSION_2 = 0x00000002
)
const (
CB_CAPSTYPE_GENERAL_LEN = 12
)
func CliprdrInit(context CliprdrClient) {
var (
generalFlags uint32
generalCapabilitySet CliprdrGeneralCapabilitySet
monitorReady CliprdrMonitorReady
capabilities CliprdrCapabilitiesPDU
)
generalFlags = 0
monitorReady.MsgType = CB_MONITOR_READY
capabilities.MsgType = CB_CLIP_CAPS
if context.useLongFormatNames {
generalFlags |= CB_USE_LONG_FORMAT_NAMES
}
if context.streamFileClipEnabled {
generalFlags |= CB_STREAM_FILECLIP_ENABLED
}
if context.fileClipNoFilePaths {
generalFlags |= CB_FILECLIP_NO_FILE_PATHS
}
if context.canLockClipData {
generalFlags |= CB_CAN_LOCK_CLIPDATA
}
if context.hasHugeFileSupport {
generalFlags |= CB_HUGE_FILE_SUPPORT_ENABLED
}
capabilities.MsgType = CB_CLIP_CAPS
capabilities.MsgFlags = 0
capabilities.DataLen = 4 + CB_CAPSTYPE_GENERAL_LEN
capabilities.CCapabilitiesSets = 1
generalCapabilitySet.CapabilitySetType = 0x0001
generalCapabilitySet.CapabilitySetLength = CB_CAPSTYPE_GENERAL_LEN
generalCapabilitySet.Version = CB_CAPS_VERSION_2
generalCapabilitySet.GeneralFlags = generalFlags
capabilities.CapabilitySets = generalCapabilitySet
/* if ((err= context->ServerCapabilities(context, &capabilities))){
//glog.Error(TAG, "ServerCapabilities failed with error %" PRIu32 "!", err);
return err
}
if ((err = context->MonitorReady(context, &monitorReady))){
//glog.Error("MonitorReady failed with error %" PRIu32 "!", err);
return err
}*/
//return err
}
// temp dir
type CliprdrTempDirectory struct {
Header *CliprdrPDUHeader
SzTempDir string
}
// format list
type CliprdrFormat struct {
FormatId uint32
FormatName string
}
type CliprdrFormatList struct {
Header *CliprdrPDUHeader
NumFormats uint32
Formats []CliprdrFormat
}
type ClipboardFormats uint16
const (
CB_FORMAT_HTML = 0xD010
CB_FORMAT_PNG = 0xD011
CB_FORMAT_JPEG = 0xD012
CB_FORMAT_GIF = 0xD013
CB_FORMAT_TEXTURILIST = 0xD014
CB_FORMAT_GNOMECOPIEDFILES = 0xD015
CB_FORMAT_MATECOPIEDFILES = 0xD016
)
// lock or unlock
type CliprdrCtrlClipboardData struct {
Header *CliprdrPDUHeader
ClipDataId uint32
}
// format data
type CliprdrFormatDataRequest struct {
Header *CliprdrPDUHeader
RequestedFormatId uint32
}
type CliprdrFormatDataResponse struct {
Header *CliprdrPDUHeader
RequestedFormatData []byte
}
// file contents
type CliprdrFileContentsRequest struct {
Header *CliprdrPDUHeader
StreamId uint32
Lindex int32
DwFlags uint32
NPositionLow uint32
NPositionHigh uint32
CbRequested uint32
ClipDataId uint32
}
func NewCliprdrFileContentsRequest() *CliprdrFileContentsRequest {
return &CliprdrFileContentsRequest{
Header: NewCliprdrPDUHeader(CB_FILECONTENTS_REQUEST, 0, 0),
}
}
type CliprdrFileContentsResponse struct {
Header *CliprdrPDUHeader
StreamId uint32
CbRequested uint32
RequestedData []byte
}

View File

@@ -0,0 +1,824 @@
package pdu
import (
"bytes"
"errors"
"fmt"
"io"
"Yasso/pkg/grdp/core"
"Yasso/pkg/grdp/glog"
"github.com/lunixbochs/struc"
)
const (
PDUTYPE_DEMANDACTIVEPDU = 0x11
PDUTYPE_CONFIRMACTIVEPDU = 0x13
PDUTYPE_DEACTIVATEALLPDU = 0x16
PDUTYPE_DATAPDU = 0x17
PDUTYPE_SERVER_REDIR_PKT = 0x1A
)
const (
PDUTYPE2_UPDATE = 0x02
PDUTYPE2_CONTROL = 0x14
PDUTYPE2_POINTER = 0x1B
PDUTYPE2_INPUT = 0x1C
PDUTYPE2_SYNCHRONIZE = 0x1F
PDUTYPE2_REFRESH_RECT = 0x21
PDUTYPE2_PLAY_SOUND = 0x22
PDUTYPE2_SUPPRESS_OUTPUT = 0x23
PDUTYPE2_SHUTDOWN_REQUEST = 0x24
PDUTYPE2_SHUTDOWN_DENIED = 0x25
PDUTYPE2_SAVE_SESSION_INFO = 0x26
PDUTYPE2_FONTLIST = 0x27
PDUTYPE2_FONTMAP = 0x28
PDUTYPE2_SET_KEYBOARD_INDICATORS = 0x29
PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST = 0x2B
PDUTYPE2_BITMAPCACHE_ERROR_PDU = 0x2C
PDUTYPE2_SET_KEYBOARD_IME_STATUS = 0x2D
PDUTYPE2_OFFSCRCACHE_ERROR_PDU = 0x2E
PDUTYPE2_SET_ERROR_INFO_PDU = 0x2F
PDUTYPE2_DRAWNINEGRID_ERROR_PDU = 0x30
PDUTYPE2_DRAWGDIPLUS_ERROR_PDU = 0x31
PDUTYPE2_ARC_STATUS_PDU = 0x32
PDUTYPE2_STATUS_INFO_PDU = 0x36
PDUTYPE2_MONITOR_LAYOUT_PDU = 0x37
)
const (
CTRLACTION_REQUEST_CONTROL = 0x0001
CTRLACTION_GRANTED_CONTROL = 0x0002
CTRLACTION_DETACH = 0x0003
CTRLACTION_COOPERATE = 0x0004
)
const (
STREAM_UNDEFINED = 0x00
STREAM_LOW = 0x01
STREAM_MED = 0x02
STREAM_HI = 0x04
)
const (
FASTPATH_UPDATETYPE_ORDERS = 0x0
FASTPATH_UPDATETYPE_BITMAP = 0x1
FASTPATH_UPDATETYPE_PALETTE = 0x2
FASTPATH_UPDATETYPE_SYNCHRONIZE = 0x3
FASTPATH_UPDATETYPE_SURFCMDS = 0x4
FASTPATH_UPDATETYPE_PTR_NULL = 0x5
FASTPATH_UPDATETYPE_PTR_DEFAULT = 0x6
FASTPATH_UPDATETYPE_PTR_POSITION = 0x8
FASTPATH_UPDATETYPE_COLOR = 0x9
FASTPATH_UPDATETYPE_CACHED = 0xA
FASTPATH_UPDATETYPE_POINTER = 0xB
)
const (
BITMAP_COMPRESSION = 0x0001
//NO_BITMAP_COMPRESSION_HDR = 0x0400
)
type ShareDataHeader struct {
SharedId uint32 `struc:"little"`
Padding1 uint8 `struc:"little"`
StreamId uint8 `struc:"little"`
UncompressedLength uint16 `struc:"little"`
PDUType2 uint8 `struc:"little"`
CompressedType uint8 `struc:"little"`
CompressedLength uint16 `struc:"little"`
}
func NewShareDataHeader(size int, type2 uint8, shareId uint32) *ShareDataHeader {
return &ShareDataHeader{
SharedId: shareId,
PDUType2: type2,
StreamId: STREAM_LOW,
UncompressedLength: uint16(size + 4),
}
}
type PDUMessage interface {
Type() uint16
Serialize() []byte
}
type DemandActivePDU struct {
SharedId uint32 `struc:"little"`
LengthSourceDescriptor uint16 `struc:"little,sizeof=SourceDescriptor"`
LengthCombinedCapabilities uint16 `struc:"little"`
SourceDescriptor []byte `struc:"sizefrom=LengthSourceDescriptor"`
NumberCapabilities uint16 `struc:"little,sizeof=CapabilitySets"`
Pad2Octets uint16 `struc:"little"`
CapabilitySets []Capability `struc:"sizefrom=NumberCapabilities"`
SessionId uint32 `struc:"little"`
}
func (d *DemandActivePDU) Type() uint16 {
return PDUTYPE_DEMANDACTIVEPDU
}
func (d *DemandActivePDU) Serialize() []byte {
buff := &bytes.Buffer{}
core.WriteUInt32LE(d.SharedId, buff)
core.WriteUInt16LE(d.LengthSourceDescriptor, buff)
core.WriteUInt16LE(d.LengthCombinedCapabilities, buff)
core.WriteBytes([]byte(d.SourceDescriptor), buff)
core.WriteUInt16LE(uint16(len(d.CapabilitySets)), buff)
core.WriteUInt16LE(d.Pad2Octets, buff)
for _, cap := range d.CapabilitySets {
core.WriteUInt16LE(uint16(cap.Type()), buff)
capBuff := &bytes.Buffer{}
struc.Pack(capBuff, cap)
capBytes := capBuff.Bytes()
core.WriteUInt16LE(uint16(len(capBytes)+4), buff)
core.WriteBytes(capBytes, buff)
}
core.WriteUInt32LE(d.SessionId, buff)
return buff.Bytes()
}
func readDemandActivePDU(r io.Reader) (*DemandActivePDU, error) {
d := &DemandActivePDU{}
var err error
d.SharedId, err = core.ReadUInt32LE(r)
if err != nil {
return nil, err
}
d.LengthSourceDescriptor, err = core.ReadUint16LE(r)
d.LengthCombinedCapabilities, err = core.ReadUint16LE(r)
sourceDescriptorBytes, err := core.ReadBytes(int(d.LengthSourceDescriptor), r)
if err != nil {
return nil, err
}
d.SourceDescriptor = sourceDescriptorBytes
d.NumberCapabilities, err = core.ReadUint16LE(r)
d.Pad2Octets, err = core.ReadUint16LE(r)
d.CapabilitySets = make([]Capability, 0)
glog.Debug("NumberCapabilities is", d.NumberCapabilities)
for i := 0; i < int(d.NumberCapabilities); i++ {
c, err := readCapability(r)
if err != nil {
//return nil, err
continue
}
d.CapabilitySets = append(d.CapabilitySets, c)
}
d.NumberCapabilities = uint16(len(d.CapabilitySets))
d.SessionId, err = core.ReadUInt32LE(r)
//glog.Info("SessionId:", d.SessionId)
if err != nil {
return nil, err
}
return d, nil
}
type ConfirmActivePDU struct {
SharedId uint32 `struc:"little"`
OriginatorId uint16 `struc:"little"`
LengthSourceDescriptor uint16 `struc:"little,sizeof=SourceDescriptor"`
LengthCombinedCapabilities uint16 `struc:"little"`
SourceDescriptor []byte `struc:"sizefrom=LengthSourceDescriptor"`
NumberCapabilities uint16 `struc:"little,sizeof=CapabilitySets"`
Pad2Octets uint16 `struc:"little"`
CapabilitySets []Capability `struc:"sizefrom=NumberCapabilities"`
}
func (*ConfirmActivePDU) Type() uint16 {
return PDUTYPE_CONFIRMACTIVEPDU
}
func (c *ConfirmActivePDU) Serialize() []byte {
buff := &bytes.Buffer{}
core.WriteUInt32LE(c.SharedId, buff)
core.WriteUInt16LE(c.OriginatorId, buff)
core.WriteUInt16LE(uint16(len(c.SourceDescriptor)), buff)
capsBuff := &bytes.Buffer{}
for _, capa := range c.CapabilitySets {
core.WriteUInt16LE(uint16(capa.Type()), capsBuff)
capBuff := &bytes.Buffer{}
struc.Pack(capBuff, capa)
if capa.Type() == CAPSTYPE_INPUT {
core.WriteBytes([]byte{0x0c, 0x00, 0x00, 0x00}, capBuff)
}
capBytes := capBuff.Bytes()
core.WriteUInt16LE(uint16(len(capBytes)+4), capsBuff)
core.WriteBytes(capBytes, capsBuff)
}
capsBytes := capsBuff.Bytes()
core.WriteUInt16LE(uint16(2+2+len(capsBytes)), buff)
core.WriteBytes([]byte(c.SourceDescriptor), buff)
core.WriteUInt16LE(uint16(len(c.CapabilitySets)), buff)
core.WriteUInt16LE(c.Pad2Octets, buff)
core.WriteBytes(capsBytes, buff)
return buff.Bytes()
}
// 9401 => share control header
// 1300 => share control header
// ec03 => share control header
// ea030100 => shareId 66538
// ea03 => OriginatorId
// 0400
// 8001 => LengthCombinedCapabilities
// 72647079
// 0c00 => NumberCapabilities 12
// 0000
// caps below
// 010018000100030000020000000015040000000000000000
// 02001c00180001000100010000052003000000000100000001000000
// 030058000000000000000000000000000000000000000000010014000000010000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000008403000000000000000000
// 04002800000000000000000000000000000000000000000000000000000000000000000000000000
// 0800080000001400
// 0c00080000000000
// 0d005c001500000009040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000
// 0f00080000000000
// 10003400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
// 11000c000000000000000000
// 14000c000000000000000000
// 1a00080000000000
func NewConfirmActivePDU() *ConfirmActivePDU {
return &ConfirmActivePDU{
OriginatorId: 0x03EA,
CapabilitySets: make([]Capability, 0),
SourceDescriptor: []byte("rdpy"),
}
}
func readConfirmActivePDU(r io.Reader) (*ConfirmActivePDU, error) {
p := &ConfirmActivePDU{}
var err error
p.SharedId, err = core.ReadUInt32LE(r)
if err != nil {
return nil, err
}
p.OriginatorId, err = core.ReadUint16LE(r)
p.LengthSourceDescriptor, err = core.ReadUint16LE(r)
p.LengthCombinedCapabilities, err = core.ReadUint16LE(r)
sourceDescriptorBytes, err := core.ReadBytes(int(p.LengthSourceDescriptor), r)
if err != nil {
return nil, err
}
p.SourceDescriptor = sourceDescriptorBytes
p.NumberCapabilities, err = core.ReadUint16LE(r)
p.Pad2Octets, err = core.ReadUint16LE(r)
p.CapabilitySets = make([]Capability, 0)
for i := 0; i < int(p.NumberCapabilities); i++ {
c, err := readCapability(r)
if err != nil {
return nil, err
}
p.CapabilitySets = append(p.CapabilitySets, c)
}
s, _ := core.ReadUInt32LE(r)
glog.Info("sessionid:", s)
return p, nil
}
type DeactiveAllPDU struct {
ShareId uint32 `struc:"little"`
LengthSourceDescriptor uint16 `struc:"little,sizeof=SourceDescriptor"`
SourceDescriptor []byte
}
func (*DeactiveAllPDU) Type() uint16 {
return PDUTYPE_DEACTIVATEALLPDU
}
func (d *DeactiveAllPDU) Serialize() []byte {
buff := &bytes.Buffer{}
struc.Pack(buff, d)
return buff.Bytes()
}
func readDeactiveAllPDU(r io.Reader) (*DeactiveAllPDU, error) {
p := &DeactiveAllPDU{}
err := struc.Unpack(r, p)
return p, err
}
type DataPDU struct {
Header *ShareDataHeader
Data DataPDUData
}
func (*DataPDU) Type() uint16 {
return PDUTYPE_DATAPDU
}
func (d *DataPDU) Serialize() []byte {
buff := &bytes.Buffer{}
struc.Pack(buff, d.Header)
struc.Pack(buff, d.Data)
return buff.Bytes()
}
func NewDataPDU(data DataPDUData, shareId uint32) *DataPDU {
dataBuff := &bytes.Buffer{}
struc.Pack(dataBuff, data)
return &DataPDU{
Header: NewShareDataHeader(len(dataBuff.Bytes()), data.Type2(), shareId),
Data: data,
}
}
func readDataPDU(r io.Reader) (*DataPDU, error) {
header := &ShareDataHeader{}
err := struc.Unpack(r, header)
if err != nil {
glog.Error("read data pdu header error", err)
return nil, err
}
var d DataPDUData
glog.Debugf("header=%02x", header.PDUType2)
switch header.PDUType2 {
case PDUTYPE2_SYNCHRONIZE:
d = &SynchronizeDataPDU{}
case PDUTYPE2_CONTROL:
d = &ControlDataPDU{}
case PDUTYPE2_FONTLIST:
d = &FontListDataPDU{}
case PDUTYPE2_SET_ERROR_INFO_PDU:
d = &ErrorInfoDataPDU{}
case PDUTYPE2_FONTMAP:
d = &FontMapDataPDU{}
case PDUTYPE2_SAVE_SESSION_INFO:
s := &SaveSessionInfo{}
s.Unpack(r)
d = s
default:
err = errors.New(fmt.Sprintf("Unknown data pdu type2 0x%02x", header.PDUType2))
glog.Error(err)
return nil, err
}
if header.PDUType2 != PDUTYPE2_SAVE_SESSION_INFO {
err = struc.Unpack(r, d)
if err != nil {
glog.Error("read data pdu error", err)
return nil, err
}
}
glog.Debugf("d=%+v", d)
p := &DataPDU{
Header: header,
Data: d,
}
return p, nil
}
type DataPDUData interface {
Type2() uint8
}
type SynchronizeDataPDU struct {
MessageType uint16 `struc:"little"`
TargetUser uint16 `struc:"little"`
}
func (*SynchronizeDataPDU) Type2() uint8 {
return PDUTYPE2_SYNCHRONIZE
}
func NewSynchronizeDataPDU(targetUser uint16) *SynchronizeDataPDU {
return &SynchronizeDataPDU{
MessageType: 1,
TargetUser: targetUser,
}
}
type ControlDataPDU struct {
Action uint16 `struc:"little"`
GrantId uint16 `struc:"little"`
ControlId uint32 `struc:"little"`
}
func (*ControlDataPDU) Type2() uint8 {
return PDUTYPE2_CONTROL
}
type FontListDataPDU struct {
NumberFonts uint16 `struc:"little"`
TotalNumFonts uint16 `struc:"little"`
ListFlags uint16 `struc:"little"`
EntrySize uint16 `struc:"little"`
}
func (*FontListDataPDU) Type2() uint8 {
return PDUTYPE2_FONTLIST
}
type ErrorInfoDataPDU struct {
ErrorInfo uint32 `struc:"little"`
}
func (*ErrorInfoDataPDU) Type2() uint8 {
return PDUTYPE2_SET_ERROR_INFO_PDU
}
type FontMapDataPDU struct {
NumberEntries uint16 `struc:"little"`
TotalNumEntries uint16 `struc:"little"`
MapFlags uint16 `struc:"little"`
EntrySize uint16 `struc:"little"`
}
func (*FontMapDataPDU) Type2() uint8 {
return PDUTYPE2_FONTMAP
}
type InfoType uint32
const (
INFOTYPE_LOGON = 0x00000000
INFOTYPE_LOGON_LONG = 0x00000001
INFOTYPE_LOGON_PLAINNOTIFY = 0x00000002
INFOTYPE_LOGON_EXTENDED_INFO = 0x00000003
)
const (
LOGON_EX_AUTORECONNECTCOOKIE = 0x00000001
LOGON_EX_LOGONERRORS = 0x00000002
)
type LogonFields struct {
CbFileData uint32 `struc:"little"`
Len uint32 //28 `struc:"little"`
Version uint32 // 1 `struc:"little"`
LogonId uint32 `struc:"little"`
random [16]byte //16 `struc:"little"`
}
type SaveSessionInfo struct {
InfoType uint32
Length uint16
FieldsPresent uint32
LogonId uint32
Random []byte
}
func (s *SaveSessionInfo) logonInfoV1(r io.Reader) (err error) {
core.ReadUInt32LE(r) // cbDomain
b, _ := core.ReadBytes(52, r)
domain := core.UnicodeDecode(b)
core.ReadUInt32LE(r) // cbUserName
b, _ = core.ReadBytes(512, r)
userName := core.UnicodeDecode(b)
sessionId, _ := core.ReadUInt32LE(r)
s.LogonId = sessionId
glog.Infof("SessionId:[%d] UserName:[%s] Domain:[%s]", s.LogonId, userName, domain)
return err
}
func (s *SaveSessionInfo) logonInfoV2(r io.Reader) (err error) {
core.ReadUint16LE(r)
core.ReadUInt32LE(r)
sessionId, _ := core.ReadUInt32LE(r)
s.LogonId = sessionId
cbDomain, _ := core.ReadUInt32LE(r)
cbUserName, _ := core.ReadUInt32LE(r)
core.ReadBytes(558, r)
b, _ := core.ReadBytes(int(cbDomain), r)
domain := core.UnicodeDecode(b)
b, _ = core.ReadBytes(int(cbUserName), r)
userName := core.UnicodeDecode(b)
glog.Infof("SessionId:[%d] UserName:[%s] Domain:[%s]", s.LogonId, userName, domain)
return err
}
func (s *SaveSessionInfo) logonPlainNotify(r io.Reader) (err error) {
core.ReadBytes(576, r) /* pad (576 bytes) */
return err
}
func (s *SaveSessionInfo) logonInfoExtended(r io.Reader) (err error) {
s.Length, err = core.ReadUint16LE(r)
s.FieldsPresent, err = core.ReadUInt32LE(r)
glog.Info("FieldsPresent:", s.FieldsPresent)
// auto reconnect cookie
if s.FieldsPresent&LOGON_EX_AUTORECONNECTCOOKIE != 0 {
core.ReadUInt32LE(r)
b, _ := core.ReadUInt32LE(r)
if b != 28 {
return errors.New(fmt.Sprintf("invalid length in Auto-Reconnect packet"))
}
b, _ = core.ReadUInt32LE(r)
if b != 1 {
return errors.New(fmt.Sprintf("unsupported version of Auto-Reconnect packet"))
}
b, _ = core.ReadUInt32LE(r)
s.LogonId = b
s.Random, _ = core.ReadBytes(16, r)
} else { // logon error info
core.ReadUInt32LE(r)
b, _ := core.ReadUInt32LE(r)
b, _ = core.ReadUInt32LE(r)
s.LogonId = b
}
core.ReadBytes(570, r)
return err
}
func (s *SaveSessionInfo) Unpack(r io.Reader) (err error) {
s.InfoType, err = core.ReadUInt32LE(r)
switch s.InfoType {
case INFOTYPE_LOGON:
err = s.logonInfoV1(r)
case INFOTYPE_LOGON_LONG:
err = s.logonInfoV2(r)
case INFOTYPE_LOGON_PLAINNOTIFY:
err = s.logonPlainNotify(r)
case INFOTYPE_LOGON_EXTENDED_INFO:
err = s.logonInfoExtended(r)
default:
glog.Error("Unhandled saveSessionInfo type 0x%", s.InfoType)
return fmt.Errorf("Unhandled saveSessionInfo type 0x%", s.InfoType)
}
return err
}
func (*SaveSessionInfo) Type2() uint8 {
return PDUTYPE2_SAVE_SESSION_INFO
}
type PersistKeyPDU struct {
NumEntriesCache0 uint16 `struc:"little"`
NumEntriesCache1 uint16 `struc:"little"`
NumEntriesCache2 uint16 `struc:"little"`
NumEntriesCache3 uint16 `struc:"little"`
NumEntriesCache4 uint16 `struc:"little"`
TotalEntriesCache0 uint16 `struc:"little"`
TotalEntriesCache1 uint16 `struc:"little"`
TotalEntriesCache2 uint16 `struc:"little"`
TotalEntriesCache3 uint16 `struc:"little"`
TotalEntriesCache4 uint16 `struc:"little"`
BBitMask uint8 `struc:"little"`
Pad1 uint8 `struc:"little"`
Ppad3 uint16 `struc:"little"`
}
func (*PersistKeyPDU) Type2() uint8 {
return PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST
}
type UpdateData interface {
FastPathUpdateType() uint8
Unpack(io.Reader) error
}
type BitmapCompressedDataHeader struct {
CbCompFirstRowSize uint16 `struc:"little"`
CbCompMainBodySize uint16 `struc:"little"`
CbScanWidth uint16 `struc:"little"`
CbUncompressedSize uint16 `struc:"little"`
}
type BitmapData struct {
DestLeft uint16 `struc:"little"`
DestTop uint16 `struc:"little"`
DestRight uint16 `struc:"little"`
DestBottom uint16 `struc:"little"`
Width uint16 `struc:"little"`
Height uint16 `struc:"little"`
BitsPerPixel uint16 `struc:"little"`
Flags uint16 `struc:"little"`
BitmapLength uint16 `struc:"little,sizeof=BitmapDataStream"`
BitmapComprHdr *BitmapCompressedDataHeader
BitmapDataStream []byte
}
func (b *BitmapData) IsCompress() bool {
return b.Flags&BITMAP_COMPRESSION != 0
}
type FastPathBitmapUpdateDataPDU struct {
Header uint16 `struc:"little"`
NumberRectangles uint16 `struc:"little,sizeof=Rectangles"`
Rectangles []BitmapData
}
func (f *FastPathBitmapUpdateDataPDU) Unpack(r io.Reader) error {
var err error
f.Header, err = core.ReadUint16LE(r)
f.NumberRectangles, err = core.ReadUint16LE(r)
f.Rectangles = make([]BitmapData, 0, f.NumberRectangles)
for i := 0; i < int(f.NumberRectangles); i++ {
rect := BitmapData{}
rect.DestLeft, err = core.ReadUint16LE(r)
rect.DestTop, err = core.ReadUint16LE(r)
rect.DestRight, err = core.ReadUint16LE(r)
rect.DestBottom, err = core.ReadUint16LE(r)
rect.Width, err = core.ReadUint16LE(r)
rect.Height, err = core.ReadUint16LE(r)
rect.BitsPerPixel, err = core.ReadUint16LE(r)
rect.Flags, err = core.ReadUint16LE(r)
rect.BitmapLength, err = core.ReadUint16LE(r)
ln := rect.BitmapLength
if rect.Flags&BITMAP_COMPRESSION != 0 && (rect.Flags&NO_BITMAP_COMPRESSION_HDR == 0) {
rect.BitmapComprHdr = new(BitmapCompressedDataHeader)
rect.BitmapComprHdr.CbCompFirstRowSize, err = core.ReadUint16LE(r)
rect.BitmapComprHdr.CbCompMainBodySize, err = core.ReadUint16LE(r)
rect.BitmapComprHdr.CbScanWidth, err = core.ReadUint16LE(r)
rect.BitmapComprHdr.CbUncompressedSize, err = core.ReadUint16LE(r)
ln = rect.BitmapComprHdr.CbCompMainBodySize
}
rect.BitmapDataStream, err = core.ReadBytes(int(ln), r)
f.Rectangles = append(f.Rectangles, rect)
}
return err
}
func (*FastPathBitmapUpdateDataPDU) FastPathUpdateType() uint8 {
return FASTPATH_UPDATETYPE_BITMAP
}
type FastPathUpdatePDU struct {
UpdateHeader uint8
CompressionFlags uint8
Size uint16
Data UpdateData
}
const (
FASTPATH_OUTPUT_COMPRESSION_USED = 0x2
)
func readFastPathUpdatePDU(r io.Reader) (*FastPathUpdatePDU, error) {
f := &FastPathUpdatePDU{}
var err error
f.UpdateHeader, err = core.ReadUInt8(r)
if err != nil {
return nil, err
}
if (f.UpdateHeader>>4)&FASTPATH_OUTPUT_COMPRESSION_USED != 0 {
f.CompressionFlags, err = core.ReadUInt8(r)
}
f.Size, err = core.ReadUint16LE(r)
if err != nil {
return nil, err
}
if f.Size == 0 {
return f, nil
}
dataBytes, err := core.ReadBytes(int(f.Size), r)
if err != nil {
glog.Info(err)
return nil, err
}
var d UpdateData
switch f.UpdateHeader & 0xf {
case FASTPATH_UPDATETYPE_BITMAP:
d = &FastPathBitmapUpdateDataPDU{}
default:
glog.Debugf("Unknown Fast Path PDU type 0x%x", f.UpdateHeader)
return f, errors.New(fmt.Sprintf("Unknown Fast Path PDU type 0x%x", f.UpdateHeader))
//d = nil
}
if d != nil {
err = d.Unpack(bytes.NewReader(dataBytes))
if err != nil {
glog.Error("Unpack:", err)
return nil, err
}
}
f.Data = d
return f, nil
}
type ShareControlHeader struct {
TotalLength uint16 `struc:"little"`
PDUType uint16 `struc:"little"`
PDUSource uint16 `struc:"little"`
}
type PDU struct {
ShareCtrlHeader *ShareControlHeader
Message PDUMessage
}
func NewPDU(userId uint16, message PDUMessage) *PDU {
pdu := &PDU{}
pdu.ShareCtrlHeader = &ShareControlHeader{
TotalLength: uint16(len(message.Serialize()) + 6),
PDUType: message.Type(),
PDUSource: userId,
}
pdu.Message = message
return pdu
}
func readPDU(r io.Reader) (*PDU, error) {
pdu := &PDU{}
var err error
header := &ShareControlHeader{}
err = struc.Unpack(r, header)
if err != nil {
return nil, err
}
pdu.ShareCtrlHeader = header
var d PDUMessage
switch pdu.ShareCtrlHeader.PDUType {
case PDUTYPE_DEMANDACTIVEPDU:
glog.Debug("PDUTYPE_DEMANDACTIVEPDU")
d, err = readDemandActivePDU(r)
case PDUTYPE_DATAPDU:
glog.Debug("PDUTYPE_DATAPDU")
d, err = readDataPDU(r)
case PDUTYPE_CONFIRMACTIVEPDU:
glog.Debug("PDUTYPE_CONFIRMACTIVEPDU")
d, err = readConfirmActivePDU(r)
case PDUTYPE_DEACTIVATEALLPDU:
glog.Debug("PDUTYPE_DEACTIVATEALLPDU")
d, err = readDeactiveAllPDU(r)
default:
glog.Errorf("PDU invalid pdu type: 0x%02x", pdu.ShareCtrlHeader.PDUType)
}
if err != nil {
return nil, err
}
pdu.Message = d
return pdu, err
}
func (p *PDU) serialize() []byte {
buff := &bytes.Buffer{}
struc.Pack(buff, p.ShareCtrlHeader)
core.WriteBytes(p.Message.Serialize(), buff)
return buff.Bytes()
}
type SlowPathInputEvent struct {
EventTime uint32 `struc:"little"`
MessageType uint16 `struc:"little"`
Size int `struc:"skip"`
SlowPathInputData []byte `struc:"sizefrom=Size"`
}
type PointerEvent struct {
PointerFlags uint16 `struc:"little"`
XPos uint16 `struc:"little"`
YPos uint16 `struc:"little"`
}
func (p *PointerEvent) Serialize() []byte {
buff := &bytes.Buffer{}
struc.Pack(buff, p)
return buff.Bytes()
}
type SynchronizeEvent struct {
Pad2Octets uint16 `struc:"little"`
ToggleFlags uint32 `struc:"little"`
}
func (p *SynchronizeEvent) Serialize() []byte {
buff := &bytes.Buffer{}
struc.Pack(buff, p)
return buff.Bytes()
}
type ScancodeKeyEvent struct {
KeyboardFlags uint16 `struc:"little"`
KeyCode uint16 `struc:"little"`
Pad2Octets uint16 `struc:"little"`
}
func (p *ScancodeKeyEvent) Serialize() []byte {
buff := &bytes.Buffer{}
struc.Pack(buff, p)
return buff.Bytes()
}
type UnicodeKeyEvent struct {
KeyboardFlags uint16 `struc:"little"`
Unicode uint16 `struc:"little"`
Pad2Octets uint16 `struc:"little"`
}
func (p *UnicodeKeyEvent) Serialize() []byte {
buff := &bytes.Buffer{}
struc.Pack(buff, p)
return buff.Bytes()
}
type ClientInputEventPDU struct {
NumEvents uint16 `struc:"little,sizeof=SlowPathInputEvents"`
Pad2Octets uint16 `struc:"little"`
SlowPathInputEvents []SlowPathInputEvent `struc:"little"`
}
func (*ClientInputEventPDU) Type2() uint8 {
return PDUTYPE2_INPUT
}

View File

@@ -0,0 +1,370 @@
package pdu
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"Yasso/pkg/grdp/core"
"Yasso/pkg/grdp/emission"
"Yasso/pkg/grdp/glog"
"Yasso/pkg/grdp/protocol/t125/gcc"
)
type PDULayer struct {
emission.Emitter
transport core.Transport
sharedId uint32
userId uint16
channelId uint16
serverCapabilities map[CapsType]Capability
clientCapabilities map[CapsType]Capability
fastPathSender core.FastPathSender
demandActivePDU *DemandActivePDU
}
func NewPDULayer(t core.Transport) *PDULayer {
p := &PDULayer{
Emitter: *emission.NewEmitter(),
transport: t,
sharedId: 0x103EA,
serverCapabilities: map[CapsType]Capability{
CAPSTYPE_GENERAL: &GeneralCapability{
ProtocolVersion: 0x0200,
},
CAPSTYPE_BITMAP: &BitmapCapability{
Receive1BitPerPixel: 0x0001,
Receive4BitsPerPixel: 0x0001,
Receive8BitsPerPixel: 0x0001,
BitmapCompressionFlag: 0x0001,
MultipleRectangleSupport: 0x0001,
},
CAPSTYPE_ORDER: &OrderCapability{
DesktopSaveXGranularity: 1,
DesktopSaveYGranularity: 20,
MaximumOrderLevel: 1,
OrderFlags: NEGOTIATEORDERSUPPORT,
DesktopSaveSize: 480 * 480,
},
CAPSTYPE_POINTER: &PointerCapability{ColorPointerCacheSize: 20},
CAPSTYPE_INPUT: &InputCapability{},
CAPSTYPE_VIRTUALCHANNEL: &VirtualChannelCapability{},
CAPSTYPE_FONT: &FontCapability{SupportFlags: 0x0001},
CAPSTYPE_COLORCACHE: &ColorCacheCapability{CacheSize: 0x0006},
CAPSTYPE_SHARE: &ShareCapability{},
},
clientCapabilities: map[CapsType]Capability{
CAPSTYPE_GENERAL: &GeneralCapability{
ProtocolVersion: 0x0200,
},
CAPSTYPE_BITMAP: &BitmapCapability{
Receive1BitPerPixel: 0x0001,
Receive4BitsPerPixel: 0x0001,
Receive8BitsPerPixel: 0x0001,
BitmapCompressionFlag: 0x0001,
MultipleRectangleSupport: 0x0001,
},
CAPSTYPE_ORDER: &OrderCapability{
DesktopSaveXGranularity: 1,
DesktopSaveYGranularity: 20,
MaximumOrderLevel: 1,
OrderFlags: NEGOTIATEORDERSUPPORT,
DesktopSaveSize: 480 * 480,
},
CAPSTYPE_BITMAPCACHE: &BitmapCacheCapability{},
CAPSTYPE_POINTER: &PointerCapability{ColorPointerCacheSize: 20},
CAPSTYPE_INPUT: &InputCapability{},
CAPSTYPE_BRUSH: &BrushCapability{},
CAPSTYPE_GLYPHCACHE: &GlyphCapability{},
CAPSTYPE_OFFSCREENCACHE: &OffscreenBitmapCacheCapability{},
CAPSTYPE_VIRTUALCHANNEL: &VirtualChannelCapability{},
CAPSTYPE_SOUND: &SoundCapability{},
CAPSETTYPE_MULTIFRAGMENTUPDATE: &MultiFragmentUpdate{},
CAPSTYPE_RAIL: &RemoteProgramsCapability{
RailSupportLevel: RAIL_LEVEL_SUPPORTED |
RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED |
RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED |
RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED |
RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED |
RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED |
RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED |
RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED,
},
},
}
t.On("close", func() {
p.Emit("close")
}).On("error", func(err error) {
p.Emit("error", err)
})
return p
}
func (p *PDULayer) sendPDU(message PDUMessage) {
pdu := NewPDU(p.userId, message)
p.transport.Write(pdu.serialize())
}
func (p *PDULayer) sendDataPDU(message DataPDUData) {
dataPdu := NewDataPDU(message, p.sharedId)
p.sendPDU(dataPdu)
}
func (p *PDULayer) SetFastPathSender(f core.FastPathSender) {
p.fastPathSender = f
}
type Client struct {
*PDULayer
clientCoreData *gcc.ClientCoreData
remoteAppMode bool
enableCliprdr bool
}
func NewClient(t core.Transport) *Client {
c := &Client{
PDULayer: NewPDULayer(t),
}
c.transport.Once("connect", c.connect)
return c
}
func (c *Client) connect(data *gcc.ClientCoreData, userId uint16, channelId uint16) {
glog.Debug("pdu connect:", userId, ",", channelId)
c.clientCoreData = data
c.userId = userId
c.channelId = channelId
c.transport.Once("data", c.recvDemandActivePDU)
}
func (c *Client) recvDemandActivePDU(s []byte) {
defer func() {
if e := recover(); e != nil {
err := errors.New(fmt.Sprint("recv demand active pdu error: ", e))
glog.Debug(err, e)
return
}
}()
glog.Debug("PDU recvDemandActivePDU", hex.EncodeToString(s))
r := bytes.NewReader(s)
pdu, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
if pdu.ShareCtrlHeader.PDUType != PDUTYPE_DEMANDACTIVEPDU {
glog.Info("PDU ignore message during connection sequence, type is", pdu.ShareCtrlHeader.PDUType)
c.transport.Once("data", c.recvDemandActivePDU)
return
}
c.sharedId = pdu.Message.(*DemandActivePDU).SharedId
c.demandActivePDU = pdu.Message.(*DemandActivePDU)
for _, caps := range pdu.Message.(*DemandActivePDU).CapabilitySets {
c.serverCapabilities[caps.Type()] = caps
}
c.sendConfirmActivePDU()
c.sendClientFinalizeSynchronizePDU()
c.transport.Once("data", c.recvServerSynchronizePDU)
}
func (c *Client) sendConfirmActivePDU() {
glog.Debug("PDU start sendConfirmActivePDU")
pdu := NewConfirmActivePDU()
generalCapa := c.clientCapabilities[CAPSTYPE_GENERAL].(*GeneralCapability)
generalCapa.OSMajorType = OSMAJORTYPE_WINDOWS
generalCapa.OSMinorType = OSMINORTYPE_WINDOWS_NT
generalCapa.ExtraFlags = LONG_CREDENTIALS_SUPPORTED | NO_BITMAP_COMPRESSION_HDR | ENC_SALTED_CHECKSUM
//if not self._fastPathSender is None:
generalCapa.ExtraFlags |= FASTPATH_OUTPUT_SUPPORTED
bitmapCapa := c.clientCapabilities[CAPSTYPE_BITMAP].(*BitmapCapability)
bitmapCapa.PreferredBitsPerPixel = c.clientCoreData.HighColorDepth
bitmapCapa.DesktopWidth = c.clientCoreData.DesktopWidth
bitmapCapa.DesktopHeight = c.clientCoreData.DesktopHeight
orderCapa := c.clientCapabilities[CAPSTYPE_ORDER].(*OrderCapability)
orderCapa.OrderFlags |= ZEROBOUNDSDELTASSUPPORT
inputCapa := c.clientCapabilities[CAPSTYPE_INPUT].(*InputCapability)
inputCapa.Flags = INPUT_FLAG_SCANCODES | INPUT_FLAG_MOUSEX | INPUT_FLAG_UNICODE
inputCapa.KeyboardLayout = c.clientCoreData.KbdLayout
inputCapa.KeyboardType = c.clientCoreData.KeyboardType
inputCapa.KeyboardSubType = c.clientCoreData.KeyboardSubType
inputCapa.KeyboardFunctionKey = c.clientCoreData.KeyboardFnKeys
inputCapa.ImeFileName = c.clientCoreData.ImeFileName
pdu.SharedId = c.sharedId
pdu.NumberCapabilities = c.demandActivePDU.NumberCapabilities
for _, v := range c.clientCapabilities {
glog.Debugf("clientCapabilities: 0x%04x", v.Type())
pdu.CapabilitySets = append(pdu.CapabilitySets, v)
}
if c.remoteAppMode {
pdu.CapabilitySets = append(pdu.CapabilitySets, c.serverCapabilities[CAPSTYPE_RAIL])
pdu.CapabilitySets = append(pdu.CapabilitySets, c.serverCapabilities[CAPSTYPE_WINDOW])
}
pdu.LengthSourceDescriptor = c.demandActivePDU.LengthSourceDescriptor
pdu.SourceDescriptor = c.demandActivePDU.SourceDescriptor
pdu.LengthCombinedCapabilities = c.demandActivePDU.LengthCombinedCapabilities
c.sendPDU(pdu)
}
func (c *Client) sendClientFinalizeSynchronizePDU() {
glog.Debug("PDU start sendClientFinalizeSynchronizePDU")
c.sendDataPDU(NewSynchronizeDataPDU(c.channelId))
c.sendDataPDU(&ControlDataPDU{Action: CTRLACTION_COOPERATE})
c.sendDataPDU(&ControlDataPDU{Action: CTRLACTION_REQUEST_CONTROL})
//c.sendDataPDU(&PersistKeyPDU{BBitMask: 0x03})
c.sendDataPDU(&FontListDataPDU{ListFlags: 0x0003, EntrySize: 0x0032})
}
func (c *Client) recvServerSynchronizePDU(s []byte) {
glog.Debug("PDU recvServerSynchronizePDU")
r := bytes.NewReader(s)
pdu, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
dataPdu, ok := pdu.Message.(*DataPDU)
if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_SYNCHRONIZE {
if ok {
glog.Error("recvServerSynchronizePDU ignore datapdu type2", dataPdu.Header.PDUType2)
} else {
glog.Error("recvServerSynchronizePDU ignore message type", pdu.ShareCtrlHeader.PDUType)
}
glog.Infof("%+v", dataPdu)
c.transport.Once("data", c.recvServerSynchronizePDU)
return
}
c.transport.Once("data", c.recvServerControlCooperatePDU)
}
func (c *Client) recvServerControlCooperatePDU(s []byte) {
glog.Debug("PDU recvServerControlCooperatePDU")
r := bytes.NewReader(s)
pdu, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
dataPdu, ok := pdu.Message.(*DataPDU)
if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_CONTROL {
if ok {
glog.Error("recvServerControlCooperatePDU ignore datapdu type2", dataPdu.Header.PDUType2)
} else {
glog.Error("recvServerControlCooperatePDU ignore message type", pdu.ShareCtrlHeader.PDUType)
}
c.transport.Once("data", c.recvServerControlCooperatePDU)
return
}
if dataPdu.Data.(*ControlDataPDU).Action != CTRLACTION_COOPERATE {
glog.Error("recvServerControlCooperatePDU ignore action", dataPdu.Data.(*ControlDataPDU).Action)
c.transport.Once("data", c.recvServerControlCooperatePDU)
return
}
c.transport.Once("data", c.recvServerControlGrantedPDU)
}
func (c *Client) recvServerControlGrantedPDU(s []byte) {
glog.Debug("PDU recvServerControlGrantedPDU")
r := bytes.NewReader(s)
pdu, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
dataPdu, ok := pdu.Message.(*DataPDU)
if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_CONTROL {
if ok {
glog.Error("recvServerControlGrantedPDU ignore datapdu type2", dataPdu.Header.PDUType2)
} else {
glog.Error("recvServerControlGrantedPDU ignore message type", pdu.ShareCtrlHeader.PDUType)
}
c.transport.Once("data", c.recvServerControlGrantedPDU)
return
}
if dataPdu.Data.(*ControlDataPDU).Action != CTRLACTION_GRANTED_CONTROL {
glog.Error("recvServerControlGrantedPDU ignore action", dataPdu.Data.(*ControlDataPDU).Action)
c.transport.Once("data", c.recvServerControlGrantedPDU)
return
}
c.transport.Once("data", c.recvServerFontMapPDU)
}
func (c *Client) recvServerFontMapPDU(s []byte) {
glog.Debug("PDU recvServerFontMapPDU")
r := bytes.NewReader(s)
pdu, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
dataPdu, ok := pdu.Message.(*DataPDU)
if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_FONTMAP {
if ok {
glog.Error("recvServerFontMapPDU ignore datapdu type2", dataPdu.Header.PDUType2)
} else {
glog.Error("recvServerFontMapPDU ignore message type", pdu.ShareCtrlHeader.PDUType)
}
return
}
c.transport.On("data", c.recvPDU)
c.Emit("ready")
}
func (c *Client) recvPDU(s []byte) {
glog.Debug("PDU recvPDU", hex.EncodeToString(s))
r := bytes.NewReader(s)
if r.Len() > 0 {
p, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
if p.ShareCtrlHeader.PDUType == PDUTYPE_DEACTIVATEALLPDU {
c.transport.On("data", c.recvDemandActivePDU)
}
}
}
func (c *Client) RecvFastPath(secFlag byte, s []byte) {
//glog.Debug("PDU RecvFastPath", hex.EncodeToString(s))
glog.Debug("PDU RecvFastPath", secFlag&0x2 != 0)
r := bytes.NewReader(s)
for r.Len() > 0 {
p, err := readFastPathUpdatePDU(r)
if err != nil {
glog.Debug("readFastPathUpdatePDU:", err)
//continue
return
}
if p.UpdateHeader == FASTPATH_UPDATETYPE_BITMAP {
c.Emit("update", p.Data.(*FastPathBitmapUpdateDataPDU).Rectangles)
}
}
}
type InputEventsInterface interface {
Serialize() []byte
}
func (c *Client) SendInputEvents(msgType uint16, events []InputEventsInterface) {
pdu := &ClientInputEventPDU{}
pdu.NumEvents = uint16(len(events))
pdu.SlowPathInputEvents = make([]SlowPathInputEvent, 0, pdu.NumEvents)
for _, in := range events {
seria := in.Serialize()
s := SlowPathInputEvent{0, msgType, len(seria), seria}
pdu.SlowPathInputEvents = append(pdu.SlowPathInputEvents, s)
}
c.sendDataPDU(pdu)
}

View File

@@ -0,0 +1,462 @@
// rfb.go
package rfb
import (
"bytes"
"crypto/des"
"encoding/hex"
"fmt"
"io"
"log"
"net"
"github.com/lunixbochs/struc"
"Yasso/pkg/grdp/core"
"Yasso/pkg/grdp/emission"
"Yasso/pkg/grdp/glog"
)
// ProtocolVersion
const (
RFB003003 = "RFB 003.003\n"
RFB003007 = "RFB 003.007\n"
RFB003008 = "RFB 003.008\n"
)
// SecurityType
const (
SEC_INVALID uint8 = 0
SEC_NONE uint8 = 1
SEC_VNC uint8 = 2
)
type RFBConn struct {
emission.Emitter
// The Socket connection to the client
Conn net.Conn
s *ServerInit
NbRect uint16
BitRect *BitRect
}
func NewRFBConn(s net.Conn) *RFBConn {
fc := &RFBConn{
Emitter: *emission.NewEmitter(),
Conn: s,
BitRect: new(BitRect),
}
core.StartReadBytes(12, fc, fc.recvProtocolVersion)
return fc
}
func (fc *RFBConn) Read(b []byte) (n int, err error) {
return fc.Conn.Read(b)
}
func (fc *RFBConn) Write(data []byte) (n int, err error) {
buff := &bytes.Buffer{}
buff.Write(data)
return fc.Conn.Write(buff.Bytes())
}
func (fc *RFBConn) Close() error {
return fc.Conn.Close()
}
func (fc *RFBConn) recvProtocolVersion(s []byte, err error) {
version := string(s)
glog.Debug("RFBConn recvProtocolVersion", version, err)
if err != nil {
fc.Emit("error", err)
return
}
fc.Emit("data", version)
if version == RFB003003 {
fc.Emit("error", fmt.Errorf("%s", "Not Support RFB003003"))
return
//core.StartReadBytes(4, fc, fc.recvSecurityServer)
} else {
core.StartReadBytes(1, fc, fc.checkSecurityList)
}
}
func (fc *RFBConn) checkSecurityList(s []byte, err error) {
r := bytes.NewReader(s)
result, _ := core.ReadUInt8(r)
glog.Debug("RFBConn recvSecurityList", result, err)
core.StartReadBytes(int(result), fc, fc.recvSecurityList)
}
func (fc *RFBConn) recvSecurityList(s []byte, err error) {
r := bytes.NewReader(s)
secLevel := SEC_VNC
for r.Len() > 0 {
result, _ := core.ReadUInt8(r)
if result == SEC_NONE || result == SEC_VNC {
secLevel = result
break
}
}
glog.Debug("RFBConn recvSecurityList", secLevel, err)
buff := &bytes.Buffer{}
core.WriteUInt8(secLevel, buff)
fc.Write(buff.Bytes())
if secLevel == SEC_VNC {
core.StartReadBytes(16, fc, fc.recvVNCChallenge)
} else {
core.StartReadBytes(4, fc, fc.recvSecurityResult)
}
}
func fixDesKeyByte(val byte) byte {
var newval byte = 0
for i := 0; i < 8; i++ {
newval <<= 1
newval += (val & 1)
val >>= 1
}
return newval
}
// fixDesKey will make sure that exactly 8 bytes is used either by truncating or padding with nulls
// The bytes are then bit mirrored and returned
func fixDesKey(key []byte) []byte {
tmp := key
buf := make([]byte, 8)
if len(tmp) <= 8 {
copy(buf, tmp)
} else {
copy(buf, tmp[:8])
}
for i := 0; i < 8; i++ {
buf[i] = fixDesKeyByte(buf[i])
}
return buf
}
func (fc *RFBConn) recvVNCChallenge(s []byte, err error) {
glog.Debug("RFBConn recvVNCChallenge", hex.EncodeToString(s), len(s), err)
key := core.Random(8)
bk, err := des.NewCipher(fixDesKey(key))
if err != nil {
log.Printf("Error generating authentication cipher: %s\n", err.Error())
return
}
result := make([]byte, 16)
bk.Encrypt(result, s) //Encrypt first 8 bytes
bk.Encrypt(result[8:], s[8:])
if err != nil {
fmt.Println(err)
}
fmt.Println(string(result))
fc.Write(result)
core.StartReadBytes(4, fc, fc.recvSecurityResult)
}
func (fc *RFBConn) recvSecurityResult(s []byte, err error) {
r := bytes.NewReader(s)
result, _ := core.ReadUInt32BE(r)
glog.Debug("RFBConn recvSecurityResult", result, err)
if result == 1 {
fc.Emit("error", fmt.Errorf("%s", "Authentification failed"))
return
}
buff := &bytes.Buffer{}
core.WriteUInt8(0, buff) //share
fc.Write(buff.Bytes())
core.StartReadBytes(20, fc, fc.recvServerInit)
}
type ServerInit struct {
Width uint16 `struc:"little"`
Height uint16 `struc:"little"`
PixelFormat *PixelFormat `struc:"little"`
}
func (fc *RFBConn) recvServerInit(s []byte, err error) {
glog.Debug("RFBConn recvServerInit", len(s), err)
r := bytes.NewReader(s)
si := &ServerInit{}
si.Width, err = core.ReadUint16BE(r)
si.Height, err = core.ReadUint16BE(r)
si.PixelFormat = ReadPixelFormat(r)
glog.Infof("serverInit:%+v, %+v", si, si.PixelFormat)
fc.s = si
fc.BitRect.Pf = si.PixelFormat
core.StartReadBytes(4, fc, fc.checkServerName)
}
func (fc *RFBConn) checkServerName(s []byte, err error) {
r := bytes.NewReader(s)
result, _ := core.ReadUInt32BE(r)
glog.Debug("RFBConn recvSecurityList", result, err)
core.StartReadBytes(int(result), fc, fc.recvServerName)
}
func (fc *RFBConn) recvServerName(s []byte, err error) {
glog.Debug("RFBConn recvServerName", string(s), err)
//fc.sendPixelFormat()
fc.sendSetEncoding()
fc.sendFramebufferUpdateRequest(0, 0, 0, fc.s.Width, fc.s.Height)
fc.Emit("ready")
core.StartReadBytes(1, fc, fc.recvServerOrder)
}
func (fc *RFBConn) sendPixelFormat() {
glog.Debug("sendPixelFormat")
buff := &bytes.Buffer{}
core.WriteUInt8(0, buff)
core.WriteUInt16BE(0, buff)
core.WriteUInt8(0, buff)
err := struc.Pack(buff, NewPixelFormat())
if err != nil {
fc.Emit("error", err)
return
}
fc.Write(buff.Bytes())
}
func (fc *RFBConn) sendSetEncoding() {
glog.Debug("sendSetEncoding")
buff := &bytes.Buffer{}
core.WriteUInt8(2, buff)
core.WriteUInt8(0, buff)
core.WriteUInt16BE(1, buff)
core.WriteUInt32BE(0, buff)
fc.Write(buff.Bytes())
}
type FrameBufferUpdateRequest struct {
Incremental uint8
X uint16
Y uint16
Width uint16
Height uint16
}
func (fc *RFBConn) sendFramebufferUpdateRequest(Incremental uint8,
X uint16,
Y uint16,
Width uint16,
Height uint16) {
glog.Debug("sendFramebufferUpdateRequest")
buff := &bytes.Buffer{}
core.WriteUInt8(3, buff)
core.WriteUInt8(Incremental, buff)
core.WriteUInt16BE(X, buff)
core.WriteUInt16BE(Y, buff)
core.WriteUInt16BE(Width, buff)
core.WriteUInt16BE(Height, buff)
fc.Write(buff.Bytes())
}
func (fc *RFBConn) recvServerOrder(s []byte, err error) {
glog.Debug("RFBConn recvServerOrder", hex.EncodeToString(s), err)
r := bytes.NewReader(s)
packetType, _ := core.ReadUInt8(r)
switch packetType {
case 0:
core.StartReadBytes(3, fc, fc.recvFrameBufferUpdateHeader)
case 2:
//TODO
case 3:
core.StartReadBytes(7, fc, fc.recvServerCutTextHeader)
default:
glog.Errorf("Unknown message type %s", packetType)
}
}
type BitRect struct {
Rects []Rectangles
Pf *PixelFormat
}
type Rectangles struct {
Rect *Rectangle
Data []byte
}
func (fc *RFBConn) recvFrameBufferUpdateHeader(s []byte, err error) {
glog.Debug("RFBConn recvFrameBufferUpdateHeader", hex.EncodeToString(s), err)
r := bytes.NewReader(s)
core.ReadUInt8(r)
NbRect, _ := core.ReadUint16BE(r)
fc.NbRect = NbRect
fc.BitRect.Rects = make([]Rectangles, fc.NbRect)
if NbRect == 0 {
return
}
glog.Info("NbRect:", NbRect)
core.StartReadBytes(12, fc, fc.recvRectHeader)
}
type Rectangle struct {
X uint16 `struc:"little"`
Y uint16 `struc:"little"`
Width uint16 `struc:"little"`
Height uint16 `struc:"little"`
Encoding uint32 `struc:"little"`
}
func (fc *RFBConn) recvRectHeader(s []byte, err error) {
glog.Debug("RFBConn recvRectHeader", hex.EncodeToString(s), err)
r := bytes.NewReader(s)
x, err := core.ReadUint16BE(r)
y, err := core.ReadUint16BE(r)
w, err := core.ReadUint16BE(r)
h, err := core.ReadUint16BE(r)
e, err := core.ReadUInt32BE(r)
rect := &Rectangle{x, y, w, h, e}
fc.BitRect.Rects[fc.NbRect-1].Rect = rect
glog.Infof("rect:%+v, len=%d", rect, int(rect.Width)*int(rect.Height)*4)
core.StartReadBytes(int(rect.Width)*int(rect.Height)*4, fc, fc.recvRectBody)
}
func (fc *RFBConn) recvRectBody(s []byte, err error) {
glog.Debug("RFBConn recvRectBody", hex.EncodeToString(s), err)
fc.BitRect.Rects[fc.NbRect-1].Data = s
fc.NbRect--
glog.Info("fc.NbRect:", fc.NbRect)
if fc.NbRect == 0 {
fc.Emit("update", fc.BitRect)
fc.sendFramebufferUpdateRequest(1, 0, 0, fc.s.Width, fc.s.Height)
core.StartReadBytes(1, fc, fc.recvServerOrder)
} else {
core.StartReadBytes(12, fc, fc.recvRectHeader)
}
}
type ServerCutTextHeader struct {
Padding [3]byte `struc:"little"`
Size uint32 `struc:"little"`
}
func (fc *RFBConn) recvServerCutTextHeader(s []byte, err error) {
glog.Debug("RFBConn recvServerCutTextHeader", string(s), err)
r := bytes.NewReader(s)
header := &ServerCutTextHeader{}
err = struc.Unpack(r, header)
if err != nil {
fc.Emit("error", err)
return
}
core.StartReadBytes(int(header.Size), fc, fc.recvServerCutTextBody)
}
func (fc *RFBConn) recvServerCutTextBody(s []byte, err error) {
glog.Debug("RFBConn recvServerCutTextBody", string(s), err)
fc.Emit("CutText", s)
core.StartReadBytes(1, fc, fc.recvServerOrder)
}
type PixelFormat struct {
BitsPerPixel uint8 `struc:"little"`
Depth uint8 `struc:"little"`
BigEndianFlag uint8 `struc:"little"`
TrueColorFlag uint8 `struc:"little"`
RedMax uint16 `struc:"little"`
GreenMax uint16 `struc:"little"`
BlueMax uint16 `struc:"little"`
RedShift uint8 `struc:"little"`
GreenShift uint8 `struc:"little"`
BlueShift uint8 `struc:"little"`
Padding uint16 `struc:"little"`
Padding1 uint8 `struc:"little"`
}
func ReadPixelFormat(r io.Reader) *PixelFormat {
p := NewPixelFormat()
p.BitsPerPixel, _ = core.ReadUInt8(r)
p.Depth, _ = core.ReadUInt8(r)
p.BigEndianFlag, _ = core.ReadUInt8(r)
p.TrueColorFlag, _ = core.ReadUInt8(r)
p.RedMax, _ = core.ReadUint16BE(r)
p.GreenMax, _ = core.ReadUint16BE(r)
p.BlueMax, _ = core.ReadUint16BE(r)
p.RedShift, _ = core.ReadUInt8(r)
p.GreenShift, _ = core.ReadUInt8(r)
p.BlueShift, _ = core.ReadUInt8(r)
p.Padding, _ = core.ReadUint16BE(r)
p.Padding1, _ = core.ReadUInt8(r)
return p
}
func NewPixelFormat() *PixelFormat {
return &PixelFormat{
32, 24, 0, 1, 65280, 65280, 65280, 16, 8, 0, 0, 0,
}
}
type RFB struct {
core.Transport
Version string
SecurityLevel uint8
ServerName string
PixelFormat *PixelFormat
NbRect int
CurrentRect *Rectangle
Password string
}
func NewRFB(t core.Transport) *RFB {
fb := &RFB{t, RFB003008, SEC_INVALID, "", NewPixelFormat(), 0, &Rectangle{}, ""}
fb.Once("data", fb.recvProtocolVersion)
return fb
}
func (fb *RFB) recvProtocolVersion(version string) {
if version != RFB003003 || version != RFB003007 || version != RFB003008 {
version = RFB003008
}
glog.Infof("version:%s", version)
b := &bytes.Buffer{}
b.WriteString(version)
fb.Write(b.Bytes())
}
type KeyEvent struct {
DownFlag uint8 `struc:"little"`
Padding uint16 `struc:"little"`
Key uint32 `struc:"little"`
}
func (fb *RFB) SendKeyEvent(k *KeyEvent) {
b := &bytes.Buffer{}
core.WriteUInt8(4, b)
core.WriteUInt8(k.DownFlag, b)
core.WriteUInt16BE(k.Padding, b)
core.WriteUInt32BE(k.Key, b)
fmt.Println(b.Bytes())
fb.Write(b.Bytes())
}
type PointerEvent struct {
Mask uint8 `struc:"little"`
XPos uint16 `struc:"little"`
YPos uint16 `struc:"little"`
}
func (fb *RFB) SendPointEvent(p *PointerEvent) {
b := &bytes.Buffer{}
core.WriteUInt8(5, b)
core.WriteUInt8(p.Mask, b)
core.WriteUInt16BE(p.XPos, b)
core.WriteUInt16BE(p.YPos, b)
fmt.Println(b.Bytes())
fb.Write(b.Bytes())
}
type ClientCutText struct {
Padding uint16 `struc:"little"`
Padding1 uint8 `struc:"little"`
Size uint32 `struc:"little"`
Message string `struc:"little"`
}
func (fb *RFB) SendClientCutText(t *ClientCutText) {
b := &bytes.Buffer{}
core.WriteUInt8(6, b)
struc.Pack(b, t)
fb.Write(b.Bytes())
}

View File

@@ -0,0 +1,882 @@
package sec
import (
"bytes"
"crypto/md5"
"crypto/rc4"
"crypto/sha1"
"encoding/hex"
"errors"
"fmt"
"io"
"math/big"
"unicode/utf16"
"github.com/lunixbochs/struc"
"Yasso/pkg/grdp/protocol/nla"
"Yasso/pkg/grdp/core"
"Yasso/pkg/grdp/emission"
"Yasso/pkg/grdp/glog"
"Yasso/pkg/grdp/protocol/lic"
"Yasso/pkg/grdp/protocol/t125"
"Yasso/pkg/grdp/protocol/t125/gcc"
)
/**
* SecurityFlag
* @see http://msdn.microsoft.com/en-us/library/cc240579.aspx
*/
const (
EXCHANGE_PKT uint16 = 0x0001
TRANSPORT_REQ = 0x0002
TRANSPORT_RSP = 0x0004
ENCRYPT = 0x0008
RESET_SEQNO = 0x0010
IGNORE_SEQNO = 0x0020
INFO_PKT = 0x0040
LICENSE_PKT = 0x0080
LICENSE_ENCRYPT_CS = 0x0200
LICENSE_ENCRYPT_SC = 0x0200
REDIRECTION_PKT = 0x0400
SECURE_CHECKSUM = 0x0800
AUTODETECT_REQ = 0x1000
AUTODETECT_RSP = 0x2000
HEARTBEAT = 0x4000
FLAGSHI_VALID = 0x8000
)
const (
INFO_MOUSE uint32 = 0x00000001
INFO_DISABLECTRLALTDEL = 0x00000002
INFO_AUTOLOGON = 0x00000008
INFO_UNICODE = 0x00000010
INFO_MAXIMIZESHELL = 0x00000020
INFO_LOGONNOTIFY = 0x00000040
INFO_COMPRESSION = 0x00000080
INFO_ENABLEWINDOWSKEY = 0x00000100
INFO_REMOTECONSOLEAUDIO = 0x00002000
INFO_FORCE_ENCRYPTED_CS_PDU = 0x00004000
INFO_RAIL = 0x00008000
INFO_LOGONERRORS = 0x00010000
INFO_MOUSE_HAS_WHEEL = 0x00020000
INFO_PASSWORD_IS_SC_PIN = 0x00040000
INFO_NOAUDIOPLAYBACK = 0x00080000
INFO_USING_SAVED_CREDS = 0x00100000
INFO_AUDIOCAPTURE = 0x00200000
INFO_VIDEO_DISABLE = 0x00400000
INFO_CompressionTypeMask = 0x00001E00
)
const (
AF_INET uint16 = 0x00002
AF_INET6 = 0x0017
)
const (
PERF_DISABLE_WALLPAPER uint32 = 0x00000001
PERF_DISABLE_FULLWINDOWDRAG = 0x00000002
PERF_DISABLE_MENUANIMATIONS = 0x00000004
PERF_DISABLE_THEMING = 0x00000008
PERF_DISABLE_CURSOR_SHADOW = 0x00000020
PERF_DISABLE_CURSORSETTINGS = 0x00000040
PERF_ENABLE_FONT_SMOOTHING = 0x00000080
PERF_ENABLE_DESKTOP_COMPOSITION = 0x00000100
)
const (
FASTPATH_OUTPUT_SECURE_CHECKSUM = 0x1
FASTPATH_OUTPUT_ENCRYPTED = 0x2
)
type ClientAutoReconnect struct {
CbAutoReconnectLen uint16
CbLen uint32
Version uint32
LogonId uint32
SecVerifier []byte
}
func NewClientAutoReconnect(id uint32, random []byte) *ClientAutoReconnect {
return &ClientAutoReconnect{
CbAutoReconnectLen: 28,
CbLen: 28,
Version: 1,
LogonId: id,
SecVerifier: nla.HMAC_MD5(random, random),
}
}
type RDPExtendedInfo struct {
ClientAddressFamily uint16 `struc:"little"`
CbClientAddress uint16 `struc:"little,sizeof=ClientAddress"`
ClientAddress []byte `struc:"[]byte"`
CbClientDir uint16 `struc:"little,sizeof=ClientDir"`
ClientDir []byte `struc:"[]byte"`
ClientTimeZone []byte `struc:"[172]byte"`
ClientSessionId uint32 `struc:"litttle"`
PerformanceFlags uint32 `struc:"little"`
AutoReconnect *ClientAutoReconnect
}
func NewExtendedInfo(auto *ClientAutoReconnect) *RDPExtendedInfo {
return &RDPExtendedInfo{
ClientAddressFamily: AF_INET,
ClientAddress: []byte{0, 0},
ClientDir: []byte{0, 0},
ClientTimeZone: make([]byte, 172),
ClientSessionId: 0,
AutoReconnect: auto,
}
}
func (o *RDPExtendedInfo) Serialize() []byte {
buff := &bytes.Buffer{}
core.WriteUInt16LE(o.ClientAddressFamily, buff)
core.WriteUInt16LE(uint16(len(o.ClientAddress)), buff)
core.WriteBytes(o.ClientAddress, buff)
core.WriteUInt16LE(uint16(len(o.ClientDir)), buff)
core.WriteBytes(o.ClientDir, buff)
core.WriteBytes(o.ClientTimeZone, buff)
core.WriteUInt32LE(o.ClientSessionId, buff)
core.WriteUInt32LE(o.PerformanceFlags, buff)
if o.AutoReconnect != nil {
core.WriteUInt16LE(o.AutoReconnect.CbAutoReconnectLen, buff)
core.WriteUInt32LE(o.AutoReconnect.CbLen, buff)
core.WriteUInt32LE(o.AutoReconnect.Version, buff)
core.WriteUInt32LE(o.AutoReconnect.LogonId, buff)
core.WriteBytes(o.AutoReconnect.SecVerifier, buff)
}
return buff.Bytes()
}
type RDPInfo struct {
CodePage uint32
Flag uint32
CbDomain uint16
CbUserName uint16
CbPassword uint16
CbAlternateShell uint16
CbWorkingDir uint16
Domain []byte
UserName []byte
Password []byte
AlternateShell []byte
WorkingDir []byte
ExtendedInfo *RDPExtendedInfo
}
func NewRDPInfo() *RDPInfo {
info := &RDPInfo{
//Flag: INFO_MOUSE | INFO_UNICODE | INFO_LOGONNOTIFY | INFO_LOGONERRORS | INFO_DISABLECTRLALTDEL | INFO_ENABLEWINDOWSKEY | INFO_FORCE_ENCRYPTED_CS_PDU,
Flag: INFO_MOUSE | INFO_UNICODE | INFO_LOGONNOTIFY | INFO_LOGONERRORS | INFO_DISABLECTRLALTDEL | INFO_ENABLEWINDOWSKEY | INFO_AUTOLOGON,
Domain: []byte{0, 0},
UserName: []byte{0, 0},
Password: []byte{0, 0},
AlternateShell: []byte{0, 0},
WorkingDir: []byte{0, 0},
ExtendedInfo: NewExtendedInfo(nil),
}
return info
}
func (o *RDPInfo) SetClientAutoReconnect(auto *ClientAutoReconnect) {
o.ExtendedInfo.AutoReconnect = auto
}
func (o *RDPInfo) Serialize(hasExtended bool) []byte {
buff := &bytes.Buffer{}
core.WriteUInt32LE(o.CodePage, buff) // 0000000
core.WriteUInt32LE(o.Flag, buff) // 0530101
core.WriteUInt16LE(uint16(len(o.Domain)-2), buff) // 001c
core.WriteUInt16LE(uint16(len(o.UserName)-2), buff) // 0008
core.WriteUInt16LE(uint16(len(o.Password)-2), buff) //000c
core.WriteUInt16LE(uint16(len(o.AlternateShell)-2), buff) //0000
core.WriteUInt16LE(uint16(len(o.WorkingDir)-2), buff) //0000
core.WriteBytes(o.Domain, buff)
core.WriteBytes(o.UserName, buff)
core.WriteBytes(o.Password, buff)
core.WriteBytes(o.AlternateShell, buff)
core.WriteBytes(o.WorkingDir, buff)
if hasExtended {
core.WriteBytes(o.ExtendedInfo.Serialize(), buff)
}
return buff.Bytes()
}
type SecurityHeader struct {
securityFlag uint16
securityFlagHi uint16
}
func readSecurityHeader(r io.Reader) *SecurityHeader {
s := &SecurityHeader{}
s.securityFlag, _ = core.ReadUint16LE(r)
s.securityFlagHi, _ = core.ReadUint16LE(r)
return s
}
type SEC struct {
emission.Emitter
transport core.Transport
info *RDPInfo
machineName string
clientData []interface{}
serverData []interface{}
enableEncryption bool
//Enable Secure Mac generation
enableSecureCheckSum bool
//counter before update
nbEncryptedPacket int
nbDecryptedPacket int
currentDecrytKey []byte
currentEncryptKey []byte
//current rc4 tab
decryptRc4 *rc4.Cipher
encryptRc4 *rc4.Cipher
macKey []byte
}
func NewSEC(t core.Transport) *SEC {
sec := &SEC{
*emission.NewEmitter(),
t,
NewRDPInfo(),
"",
nil,
nil,
false,
false,
0,
0,
nil,
nil,
nil,
nil,
nil,
}
t.On("close", func() {
sec.Emit("close")
}).On("error", func(err error) {
sec.Emit("error", err)
})
return sec
}
func (s *SEC) Read(data []byte) (n int, err error) {
return s.transport.Read(data)
}
func (s *SEC) Write(b []byte) (n int, err error) {
if !s.enableEncryption {
return s.transport.Write(b)
}
var flag uint16 = ENCRYPT
if s.enableSecureCheckSum {
flag |= SECURE_CHECKSUM
}
return s.sendFlagged(flag, b)
}
func (s *SEC) Close() error {
return s.transport.Close()
}
func (s *SEC) sendFlagged(flag uint16, data []byte) (n int, err error) {
glog.Debug("sendFlagged:", hex.EncodeToString(data))
if flag&ENCRYPT != 0 {
data = s.writeEncryptedPayload(data, flag&SECURE_CHECKSUM != 0)
}
buff := &bytes.Buffer{}
core.WriteUInt16LE(flag, buff)
core.WriteUInt16LE(0, buff)
core.WriteBytes(data, buff)
glog.Debug("sendFlagged end:", hex.EncodeToString(buff.Bytes()))
return s.transport.Write(buff.Bytes())
}
/*
@see: http://msdn.microsoft.com/en-us/library/cc241995.aspx
@param macSaltKey: {str} mac key
@param data: {str} data to sign
@return: {str} signature
*/
func macData(macSaltKey, data []byte) []byte {
sha1Digest := sha1.New()
md5Digest := md5.New()
b := &bytes.Buffer{}
core.WriteUInt32LE(uint32(len(data)), b)
sha1Digest.Write(macSaltKey)
for i := 0; i < 40; i++ {
sha1Digest.Write([]byte("\x36"))
}
sha1Digest.Write(b.Bytes())
sha1Digest.Write(data)
sha1Sig := sha1Digest.Sum(nil)
md5Digest.Write(macSaltKey)
for i := 0; i < 48; i++ {
md5Digest.Write([]byte("\x5c"))
}
md5Digest.Write(sha1Sig)
return md5Digest.Sum(nil)
}
func (s *SEC) readEncryptedPayload(data []byte, checkSum bool) []byte {
r := bytes.NewReader(data)
sign, _ := core.ReadBytes(8, r)
glog.Info("read sign:", sign)
encryptedPayload, _ := core.ReadBytes(r.Len(), r)
if s.decryptRc4 == nil {
s.decryptRc4, _ = rc4.NewCipher(s.currentDecrytKey)
}
s.nbDecryptedPacket++
glog.Info("nbDecryptedPacket:", s.nbDecryptedPacket)
plaintext := make([]byte, len(encryptedPayload))
s.decryptRc4.XORKeyStream(plaintext, encryptedPayload)
return plaintext
}
func (s *SEC) writeEncryptedPayload(data []byte, checkSum bool) []byte {
defer func() {
if e := recover(); e != nil {
err := errors.New(fmt.Sprint("write encrypted payload error: ", e))
glog.Debug(err, e)
return
}
}()
if s.nbEncryptedPacket == 4096 {
}
if checkSum {
return []byte{}
}
s.nbEncryptedPacket++
glog.Info("nbEncryptedPacket:", s.nbEncryptedPacket)
b := &bytes.Buffer{}
sign := macData(s.macKey, data)[:8]
if s.encryptRc4 == nil {
s.encryptRc4, _ = rc4.NewCipher(s.currentEncryptKey)
}
plaintext := make([]byte, len(data))
s.encryptRc4.XORKeyStream(plaintext, data)
b.Write(sign)
b.Write(plaintext)
glog.Debug("sign:", hex.EncodeToString(sign), "plaintext:", hex.EncodeToString(plaintext))
return b.Bytes()
}
type Client struct {
*SEC
userId uint16
channelId uint16
//initialise decrypt and encrypt keys
initialDecrytKey []byte
initialEncryptKey []byte
fastPathListener core.FastPathListener
}
func NewClient(t core.Transport) *Client {
c := &Client{
SEC: NewSEC(t),
}
t.On("connect", c.connect)
return c
}
func (c *Client) SetClientAutoReconnect(id uint32, random []byte) {
auto := NewClientAutoReconnect(id, random)
c.info.SetClientAutoReconnect(auto)
}
func (c *Client) SetAlternateShell(shell string) {
buff := &bytes.Buffer{}
for _, ch := range utf16.Encode([]rune(shell)) {
core.WriteUInt16LE(ch, buff)
}
core.WriteUInt16LE(0, buff)
c.info.AlternateShell = buff.Bytes()
}
func (c *Client) SetUser(user string) {
buff := &bytes.Buffer{}
for _, ch := range utf16.Encode([]rune(user)) {
core.WriteUInt16LE(ch, buff)
}
core.WriteUInt16LE(0, buff)
c.info.UserName = buff.Bytes()
}
func (c *Client) SetPwd(pwd string) {
buff := &bytes.Buffer{}
for _, ch := range utf16.Encode([]rune(pwd)) {
core.WriteUInt16LE(ch, buff)
}
core.WriteUInt16LE(0, buff)
c.info.Password = buff.Bytes()
}
func (c *Client) SetDomain(domain string) {
buff := &bytes.Buffer{}
for _, ch := range utf16.Encode([]rune(domain)) {
core.WriteUInt16LE(ch, buff)
}
core.WriteUInt16LE(0, buff)
c.info.Domain = buff.Bytes()
}
func (c *Client) connect(clientData []interface{}, serverData []interface{}, userId uint16, channels []t125.MCSChannelInfo) {
glog.Debug("sec on connect:", clientData)
glog.Debug("sec on connect:", serverData)
glog.Debug("sec on connect:", userId)
glog.Debug("sec on connect:", channels)
glog.Debug("clientData:", clientData)
glog.Debug("serverData:", serverData)
c.clientData = clientData
c.serverData = serverData
c.userId = userId
for _, channel := range channels {
glog.Debug("channel:", channel.Name, channel.ID)
if channel.Name == "global" {
c.channelId = channel.ID
break
}
}
c.enableEncryption = c.ClientCoreData().ServerSelectedProtocol == 0
if c.enableEncryption {
c.sendClientRandom()
}
c.sendInfoPkt()
c.transport.Once("global", c.recvLicenceInfo)
}
func (c *Client) ClientCoreData() *gcc.ClientCoreData {
return c.clientData[0].(*gcc.ClientCoreData)
}
func (c *Client) ClientSecurityData() *gcc.ClientSecurityData {
return c.clientData[1].(*gcc.ClientSecurityData)
}
func (c *Client) ClientNetworkData() *gcc.ClientNetworkData {
return c.clientData[2].(*gcc.ClientNetworkData)
}
func (c *Client) serverCoreData() *gcc.ServerCoreData {
return c.serverData[0].(*gcc.ServerCoreData)
}
func (c *Client) ServerSecurityData() *gcc.ServerSecurityData {
return c.serverData[1].(*gcc.ServerSecurityData)
}
/*
@summary: generate 40 bits data from 128 bits data
@param data: {str} 128 bits data
@return: {str} 40 bits data
@see: http://msdn.microsoft.com/en-us/library/cc240785.aspx
*/
//func gen40bits(data string)string{
// return "\xd1\x26\x9e" + data[:8][-5:]
//}
/*
@summary: generate 56 bits data from 128 bits data
@param data: {str} 128 bits data
@return: {str} 56 bits data
@see: http://msdn.microsoft.com/en-us/library/cc240785.aspx
*/
//func gen56bits(data string) string{
// return "\xd1" + data[:8][-7:]
//}
/*
@summary: Generate particular signature from combination of sha1 and md5
@see: http://msdn.microsoft.com/en-us/library/cc241992.aspx
@param inputData: strange input (see doc)
@param salt: salt for context call
@param salt1: another salt (ex : client random)
@param salt2: another another salt (ex: server random)
@return : MD5(Salt + SHA1(Input + Salt + Salt1 + Salt2))
*/
func saltedHash(inputData, salt, salt1, salt2 []byte) []byte {
sha1Digest := sha1.New()
md5Digest := md5.New()
sha1Digest.Write(inputData)
sha1Digest.Write(salt[:48])
sha1Digest.Write(salt1)
sha1Digest.Write(salt2)
sha1Sig := sha1Digest.Sum(nil)
md5Digest.Write(salt[:48])
md5Digest.Write(sha1Sig)
return md5Digest.Sum(nil)[:16]
}
/*
@summary: MD5(in0[:16] + in1[:32] + in2[:32])
@param key: in 16
@param random1: in 32
@param random2: in 32
@return MD5(in0[:16] + in1[:32] + in2[:32])
*/
func finalHash(key, random1, random2 []byte) []byte {
md5Digest := md5.New()
md5Digest.Write(key)
md5Digest.Write(random1)
md5Digest.Write(random2)
return md5Digest.Sum(nil)
}
/*
@summary: Generate master secret
@param secret: {str} secret
@param clientRandom : {str} client random
@param serverRandom : {str} server random
@see: http://msdn.microsoft.com/en-us/library/cc241992.aspx
*/
func masterSecret(secret, random1, random2 []byte) []byte {
sh1 := saltedHash([]byte("A"), secret, random1, random2)
sh2 := saltedHash([]byte("BB"), secret, random1, random2)
sh3 := saltedHash([]byte("CCC"), secret, random1, random2)
ms := bytes.NewBuffer(nil)
ms.Write(sh1)
ms.Write(sh2)
ms.Write(sh3)
return ms.Bytes()
}
/*
@summary: Generate master secret
@param secret: secret
@param clientRandom : client random
@param serverRandom : server random
*/
func sessionKeyBlob(secret, random1, random2 []byte) []byte {
sh1 := saltedHash([]byte("X"), secret, random1, random2)
sh2 := saltedHash([]byte("YY"), secret, random1, random2)
sh3 := saltedHash([]byte("ZZZ"), secret, random1, random2)
ms := bytes.NewBuffer(nil)
ms.Write(sh1)
ms.Write(sh2)
ms.Write(sh3)
return ms.Bytes()
}
func generateKeys(clientRandom, serverRandom []byte, method uint32) ([]byte, []byte, []byte) {
b := &bytes.Buffer{}
b.Write(clientRandom[:24])
b.Write(serverRandom[:24])
preMasterHash := b.Bytes()
glog.Info("preMasterHash:", string(preMasterHash))
masterHash := masterSecret(preMasterHash, clientRandom, serverRandom)
glog.Info("masterHash:", hex.EncodeToString(masterHash))
sessionKey := sessionKeyBlob(masterHash, clientRandom, serverRandom)
glog.Info("sessionKey:", hex.EncodeToString(sessionKey))
macKey128 := sessionKey[:16]
initialFirstKey128 := finalHash(sessionKey[16:32], clientRandom, serverRandom)
initialSecondKey128 := finalHash(sessionKey[32:48], clientRandom, serverRandom)
glog.Debug("macKey128:", hex.EncodeToString(macKey128))
glog.Debug("FirstKey128:", hex.EncodeToString(initialFirstKey128))
glog.Debug("SecondKey128:", hex.EncodeToString(initialSecondKey128))
//generate valid key
if method == gcc.ENCRYPTION_FLAG_40BIT {
//return gen40bits(macKey128), gen40bits(initialFirstKey128), gen40bits(initialSecondKey128)
} else if method == gcc.ENCRYPTION_FLAG_56BIT {
//return gen56bits(macKey128), gen56bits(initialFirstKey128), gen56bits(initialSecondKey128)
} //else if method == gcc.ENCRYPTION_FLAG_128BIT{
return macKey128, initialFirstKey128, initialSecondKey128
//}
}
type ClientSecurityExchangePDU struct {
Length uint32 `struc:"little"`
EncryptedClientRandom []byte `struc:"little"`
Padding []byte `struc:"[8]byte"`
}
func (e *ClientSecurityExchangePDU) serialize() []byte {
buff := &bytes.Buffer{}
core.WriteUInt32LE(e.Length, buff)
core.WriteBytes(e.EncryptedClientRandom, buff)
core.WriteBytes(e.Padding, buff)
return buff.Bytes()
}
func (c *Client) sendClientRandom() {
defer func() {
if e := recover(); e != nil {
err := errors.New(fmt.Sprint("send client random error: ", e))
glog.Debug(err, e)
_ = c.Close()
return
}
}()
glog.Info("send Client Random")
clientRandom := core.Random(32)
glog.Info("clientRandom:", string(clientRandom))
serverRandom := c.ServerSecurityData().ServerRandom
glog.Info("ServerRandom:", string(serverRandom))
c.macKey, c.initialDecrytKey, c.initialEncryptKey = generateKeys(clientRandom,
serverRandom, c.ServerSecurityData().EncryptionMethod)
//initialize keys
c.currentDecrytKey = c.initialDecrytKey
c.currentEncryptKey = c.initialEncryptKey
//verify certificate
if !c.ServerSecurityData().ServerCertificate.CertData.Verify() {
glog.Warn("Cannot verify server identity")
}
ePublicKey, mPublicKey := c.ServerSecurityData().ServerCertificate.CertData.GetPublicKey()
b := new(big.Int).SetBytes(core.Reverse(mPublicKey))
e := new(big.Int).SetInt64(int64(ePublicKey))
d := new(big.Int).SetBytes(core.Reverse(clientRandom))
r := new(big.Int).Exp(d, e, b)
var ret []byte
if len(b.Bytes()) > 0 {
if len(r.Bytes()) < len(b.Bytes()) {
ret = r.Bytes()[:len(r.Bytes())]
} else {
ret = r.Bytes()[:len(b.Bytes())]
}
} else {
ln := len(r.Bytes())
if ln < 1 {
ln = 1
}
ret = r.Bytes()[:ln]
}
message := ClientSecurityExchangePDU{}
message.EncryptedClientRandom = core.Reverse(ret)
message.Length = uint32(len(message.EncryptedClientRandom) + 8)
message.Padding = make([]byte, 8)
glog.Debug("message:", message)
c.sendFlagged(EXCHANGE_PKT, message.serialize())
}
func (c *Client) sendInfoPkt() {
var secFlag uint16 = INFO_PKT
if c.enableEncryption {
secFlag |= ENCRYPT
}
glog.Debug("RdpVersion:", c.ClientCoreData().RdpVersion, ":", gcc.RDP_VERSION_5_PLUS)
c.sendFlagged(secFlag, c.info.Serialize(c.ClientCoreData().RdpVersion == gcc.RDP_VERSION_5_PLUS))
}
func (c *Client) recvLicenceInfo(s []byte) {
glog.Debug("sec recvLicenceInfo", hex.EncodeToString(s))
r := bytes.NewReader(s)
h := readSecurityHeader(r)
if (h.securityFlag & LICENSE_PKT) == 0 {
c.Emit("error", errors.New("NODE_RDP_PROTOCOL_PDU_SEC_BAD_LICENSE_HEADER"))
return
}
p := lic.ReadLicensePacket(r)
switch p.BMsgtype {
case lic.NEW_LICENSE:
glog.Info("sec NEW_LICENSE")
c.Emit("success")
goto connect
case lic.ERROR_ALERT:
message := p.LicensingMessage.(*lic.ErrorMessage)
glog.Info("sec ERROR_ALERT and ErrorCode:", message.DwErrorCode)
if message.DwErrorCode == lic.STATUS_VALID_CLIENT && message.DwStateTransaction == lic.ST_NO_TRANSITION {
goto connect
}
goto retry
case lic.LICENSE_REQUEST:
glog.Info("sec LICENSE_REQUEST")
c.sendClientNewLicenseRequest(p.LicensingMessage.([]byte))
goto retry
case lic.PLATFORM_CHALLENGE:
glog.Info("sec PLATFORM_CHALLENGE")
c.sendClientChallengeResponse(p.LicensingMessage.([]byte))
goto retry
default:
glog.Error("Not a valid license packet")
c.Emit("error", errors.New("Not a valid license packet"))
return
}
connect:
c.transport.On("global", c.recvData)
//c.Emit("connect", c.clientData[0].(*gcc.ClientCoreData), c.serverData[0].(*gcc.ServerCoreData), c.userId, c.channelId)
c.Emit("connect", c.clientData[0].(*gcc.ClientCoreData), c.userId, c.channelId)
return
retry:
c.transport.Once("global", c.recvLicenceInfo)
return
}
func (c *Client) sendClientNewLicenseRequest(data []byte) {
var req lic.ServerLicenseRequest
struc.Unpack(bytes.NewReader(data), &req)
var sc gcc.ServerCertificate
if c.ServerSecurityData().ServerCertificate.DwVersion != 0 {
sc = c.ServerSecurityData().ServerCertificate
} else {
rd := bytes.NewReader(req.ServerCertificate.BlobData)
//err := sc.Unpack(rd)
err := struc.Unpack(rd, &req)
if err != nil {
glog.Error(err)
return
}
}
serverRandom := req.ServerRandom
clientRandom := core.Random(32)
preMasterSecret := core.Random(48)
masSecret := masterSecret(preMasterSecret, clientRandom, serverRandom)
sessionKeyBlob := masterSecret(masSecret, serverRandom, clientRandom)
c.macKey = sessionKeyBlob[:16]
c.initialDecrytKey = finalHash(sessionKeyBlob[16:32], clientRandom, serverRandom)
//format message
message := &lic.ClientNewLicenseRequest{}
message.ClientRandom = clientRandom
buff := &bytes.Buffer{}
ePublicKey, mPublicKey := sc.CertData.GetPublicKey()
b := new(big.Int).SetBytes(core.Reverse(mPublicKey))
e := new(big.Int).SetInt64(int64(ePublicKey))
d := new(big.Int).SetBytes(core.Reverse(clientRandom))
r := new(big.Int).Exp(d, e, b)
var ret []byte
if len(b.Bytes()) > 0 {
ret = r.Bytes()[:len(b.Bytes())]
} else {
ln := len(r.Bytes())
if ln < 1 {
ln = 1
}
ret = r.Bytes()[:ln]
}
buff.Write(core.Reverse(ret))
buff.Write([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
message.EncryptedPreMasterSecret.BlobData = buff.Bytes()
buff.Reset()
buff.Write(c.ClientCoreData().ClientName[:])
buff.Write([]byte{0x00})
message.ClientMachineName.BlobData = buff.Bytes()
buff.Reset()
buff.Write(c.info.UserName)
buff.Write([]byte{0x00})
message.ClientUserName.BlobData = buff.Bytes()
buff.Reset()
struc.Pack(buff, message)
c.sendFlagged(LICENSE_PKT, b.Bytes())
}
func (c *Client) sendClientChallengeResponse(data []byte) {
var pc lic.ServerPlatformChallenge
struc.Unpack(bytes.NewReader(data), &pc)
serverEncryptedChallenge := pc.EncryptedPlatformChallenge.BlobData
//decrypt server challenge
//it should be TEST word in unicode format
rc, _ := rc4.NewCipher(c.initialDecrytKey)
serverChallenge := make([]byte, 20)
rc.XORKeyStream(serverChallenge, serverEncryptedChallenge)
//if serverChallenge != "T\x00E\x00S\x00T\x00\x00\x00":
//raise InvalidExpectedDataException("bad license server challenge")
//generate hwid
b := &bytes.Buffer{}
b.Write(c.ClientCoreData().ClientName[:])
b.Write(c.info.UserName)
for i := 0; i < 2; i++ {
b.Write([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
}
hwid := b.Bytes()[:20]
encryptedHWID := make([]byte, 20)
rc.XORKeyStream(encryptedHWID, hwid)
b.Reset()
b.Write(serverChallenge)
b.Write(hwid)
message := &lic.ClientPLatformChallengeResponse{}
message.EncryptedPlatformChallengeResponse.BlobData = serverEncryptedChallenge
message.EncryptedHWID.BlobData = encryptedHWID
message.MACData = macData(c.macKey, b.Bytes())[:16]
b.Reset()
struc.Pack(b, message)
c.sendFlagged(LICENSE_PKT, b.Bytes())
}
func (c *Client) recvData(s []byte) {
glog.Debug("sec recvData", hex.EncodeToString(s))
if !c.enableEncryption {
c.Emit("data", s)
return
}
r := bytes.NewReader(s)
securityFlag, _ := core.ReadUint16LE(r)
_, _ = core.ReadUint16LE(r) //securityFlagHi
s1, _ := core.ReadBytes(r.Len(), r)
if securityFlag&ENCRYPT != 0 {
data := c.readEncryptedPayload(s1, securityFlag&SECURE_CHECKSUM != 0)
c.Emit("data", data)
}
}
func (c *Client) SetFastPathListener(f core.FastPathListener) {
c.fastPathListener = f
}
func (c *Client) RecvFastPath(secFlag byte, s []byte) {
data := s
if c.enableEncryption && secFlag&FASTPATH_OUTPUT_ENCRYPTED != 0 {
data = c.readEncryptedPayload(s, secFlag&FASTPATH_OUTPUT_SECURE_CHECKSUM != 0)
}
c.fastPathListener.RecvFastPath(secFlag, data)
}

View File

@@ -0,0 +1,189 @@
package ber
import (
"errors"
"fmt"
"io"
"Yasso/pkg/grdp/core"
)
const (
CLASS_MASK uint8 = 0xC0
CLASS_UNIV = 0x00
CLASS_APPL = 0x40
CLASS_CTXT = 0x80
CLASS_PRIV = 0xC0
)
const (
PC_MASK uint8 = 0x20
PC_PRIMITIVE = 0x00
PC_CONSTRUCT = 0x20
)
const (
TAG_MASK uint8 = 0x1F
TAG_BOOLEAN = 0x01
TAG_INTEGER = 0x02
TAG_BIT_STRING = 0x03
TAG_OCTET_STRING = 0x04
TAG_OBJECT_IDENFIER = 0x06
TAG_ENUMERATED = 0x0A
TAG_SEQUENCE = 0x10
TAG_SEQUENCE_OF = 0x10
)
func berPC(pc bool) uint8 {
if pc {
return PC_CONSTRUCT
}
return PC_PRIMITIVE
}
func ReadEnumerated(r io.Reader) (uint8, error) {
if !ReadUniversalTag(TAG_ENUMERATED, false, r) {
return 0, errors.New("invalid ber tag")
}
length, err := ReadLength(r)
if err != nil {
return 0, err
}
if length != 1 {
return 0, errors.New(fmt.Sprintf("enumerate size is wrong, get %v, expect 1", length))
}
return core.ReadUInt8(r)
}
func ReadUniversalTag(tag uint8, pc bool, r io.Reader) bool {
bb, _ := core.ReadUInt8(r)
return bb == (CLASS_UNIV|berPC(pc))|(TAG_MASK&tag)
}
func WriteUniversalTag(tag uint8, pc bool, w io.Writer) {
core.WriteUInt8((CLASS_UNIV|berPC(pc))|(TAG_MASK&tag), w)
}
func ReadLength(r io.Reader) (int, error) {
ret := 0
size, _ := core.ReadUInt8(r)
if size&0x80 > 0 {
size = size &^ 0x80
if size == 1 {
r, err := core.ReadUInt8(r)
if err != nil {
return 0, err
}
ret = int(r)
} else if size == 2 {
r, err := core.ReadUint16BE(r)
if err != nil {
return 0, err
}
ret = int(r)
} else {
return 0, errors.New("BER length may be 1 or 2")
}
} else {
ret = int(size)
}
return ret, nil
}
func WriteLength(size int, w io.Writer) {
if size > 0x7f {
core.WriteUInt8(0x82, w)
core.WriteUInt16BE(uint16(size), w)
} else {
core.WriteUInt8(uint8(size), w)
}
}
func ReadInteger(r io.Reader) (int, error) {
if !ReadUniversalTag(TAG_INTEGER, false, r) {
return 0, errors.New("Bad integer tag")
}
size, _ := ReadLength(r)
switch size {
case 1:
num, _ := core.ReadUInt8(r)
return int(num), nil
case 2:
num, _ := core.ReadUint16BE(r)
return int(num), nil
case 3:
integer1, _ := core.ReadUInt8(r)
integer2, _ := core.ReadUint16BE(r)
return int(integer2) + int(integer1<<16), nil
case 4:
num, _ := core.ReadUInt32BE(r)
return int(num), nil
default:
return 0, errors.New("wrong size")
}
}
func WriteInteger(n int, w io.Writer) {
WriteUniversalTag(TAG_INTEGER, false, w)
if n <= 0xff {
WriteLength(1, w)
core.WriteUInt8(uint8(n), w)
} else if n <= 0xffff {
WriteLength(2, w)
core.WriteUInt16BE(uint16(n), w)
} else {
WriteLength(4, w)
core.WriteUInt32BE(uint32(n), w)
}
}
func WriteOctetstring(str string, w io.Writer) {
WriteUniversalTag(TAG_OCTET_STRING, false, w)
WriteLength(len(str), w)
core.WriteBytes([]byte(str), w)
}
func WriteBoolean(b bool, w io.Writer) {
bb := uint8(0)
if b {
bb = uint8(0xff)
}
WriteUniversalTag(TAG_BOOLEAN, false, w)
WriteLength(1, w)
core.WriteUInt8(bb, w)
}
func ReadApplicationTag(tag uint8, r io.Reader) (int, error) {
bb, _ := core.ReadUInt8(r)
if tag > 30 {
if bb != (CLASS_APPL|PC_CONSTRUCT)|TAG_MASK {
return 0, errors.New("ReadApplicationTag invalid data")
}
bb, _ := core.ReadUInt8(r)
if bb != tag {
return 0, errors.New("ReadApplicationTag bad tag")
}
} else {
if bb != (CLASS_APPL|PC_CONSTRUCT)|(TAG_MASK&tag) {
return 0, errors.New("ReadApplicationTag invalid data2")
}
}
return ReadLength(r)
}
func WriteApplicationTag(tag uint8, size int, w io.Writer) {
if tag > 30 {
core.WriteUInt8((CLASS_APPL|PC_CONSTRUCT)|TAG_MASK, w)
core.WriteUInt8(tag, w)
WriteLength(size, w)
} else {
core.WriteUInt8((CLASS_APPL|PC_CONSTRUCT)|(TAG_MASK&tag), w)
WriteLength(size, w)
}
}
func WriteEncodedDomainParams(data []byte, w io.Writer) {
WriteUniversalTag(TAG_SEQUENCE, true, w)
WriteLength(len(data), w)
core.WriteBytes(data, w)
}

View File

@@ -0,0 +1,568 @@
package gcc
import (
"bytes"
"errors"
"io"
"os"
"Yasso/pkg/grdp/glog"
"Yasso/pkg/grdp/core"
"Yasso/pkg/grdp/protocol/t125/per"
"github.com/lunixbochs/struc"
)
var t124_02_98_oid = []byte{0, 0, 20, 124, 0, 1}
var h221_cs_key = "Duca"
var h221_sc_key = "McDn"
/**
* @see http://msdn.microsoft.com/en-us/library/cc240509.aspx
*/
type Message uint16
const (
//server -> client
SC_CORE Message = 0x0C01
SC_SECURITY = 0x0C02
SC_NET = 0x0C03
//client -> server
CS_CORE = 0xC001
CS_SECURITY = 0xC002
CS_NET = 0xC003
CS_CLUSTER = 0xC004
CS_MONITOR = 0xC005
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
*/
type ColorDepth uint16
const (
RNS_UD_COLOR_8BPP ColorDepth = 0xCA01
RNS_UD_COLOR_16BPP_555 = 0xCA02
RNS_UD_COLOR_16BPP_565 = 0xCA03
RNS_UD_COLOR_24BPP = 0xCA04
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
*/
type HighColor uint16
const (
HIGH_COLOR_4BPP HighColor = 0x0004
HIGH_COLOR_8BPP = 0x0008
HIGH_COLOR_15BPP = 0x000f
HIGH_COLOR_16BPP = 0x0010
HIGH_COLOR_24BPP = 0x0018
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
*/
type Support uint16
const (
RNS_UD_24BPP_SUPPORT uint16 = 0x0001
RNS_UD_16BPP_SUPPORT = 0x0002
RNS_UD_15BPP_SUPPORT = 0x0004
RNS_UD_32BPP_SUPPORT = 0x0008
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
*/
type CapabilityFlag uint16
const (
RNS_UD_CS_SUPPORT_ERRINFO_PDU uint16 = 0x0001
RNS_UD_CS_WANT_32BPP_SESSION = 0x0002
RNS_UD_CS_SUPPORT_STATUSINFO_PDU = 0x0004
RNS_UD_CS_STRONG_ASYMMETRIC_KEYS = 0x0008
RNS_UD_CS_UNUSED = 0x0010
RNS_UD_CS_VALID_CONNECTION_TYPE = 0x0020
RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU = 0x0040
RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT = 0x0080
RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL = 0x0100
RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE = 0x0200
RNS_UD_CS_SUPPORT_HEARTBEAT_PDU = 0x0400
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
*/
type ConnectionType uint8
const (
CONNECTION_TYPE_MODEM ConnectionType = 0x01
CONNECTION_TYPE_BROADBAND_LOW = 0x02
CONNECTION_TYPE_SATELLITEV = 0x03
CONNECTION_TYPE_BROADBAND_HIGH = 0x04
CONNECTION_TYPE_WAN = 0x05
CONNECTION_TYPE_LAN = 0x06
CONNECTION_TYPE_AUTODETECT = 0x07
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
*/
type VERSION uint32
const (
RDP_VERSION_4 VERSION = 0x00080001
RDP_VERSION_5_PLUS = 0x00080004
)
type Sequence uint16
const (
RNS_UD_SAS_DEL Sequence = 0xAA03
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240511.aspx
*/
type EncryptionMethod uint32
const (
ENCRYPTION_FLAG_40BIT uint32 = 0x00000001
ENCRYPTION_FLAG_128BIT = 0x00000002
ENCRYPTION_FLAG_56BIT = 0x00000008
FIPS_ENCRYPTION_FLAG = 0x00000010
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240518.aspx
*/
type EncryptionLevel uint32
const (
ENCRYPTION_LEVEL_NONE EncryptionLevel = 0x00000000
ENCRYPTION_LEVEL_LOW = 0x00000001
ENCRYPTION_LEVEL_CLIENT_COMPATIBLE = 0x00000002
ENCRYPTION_LEVEL_HIGH = 0x00000003
ENCRYPTION_LEVEL_FIPS = 0x00000004
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240513.aspx
*/
type ChannelOptions uint32
const (
CHANNEL_OPTION_INITIALIZED ChannelOptions = 0x80000000
CHANNEL_OPTION_ENCRYPT_RDP = 0x40000000
CHANNEL_OPTION_ENCRYPT_SC = 0x20000000
CHANNEL_OPTION_ENCRYPT_CS = 0x10000000
CHANNEL_OPTION_PRI_HIGH = 0x08000000
CHANNEL_OPTION_PRI_MED = 0x04000000
CHANNEL_OPTION_PRI_LOW = 0x02000000
CHANNEL_OPTION_COMPRESS_RDP = 0x00800000
CHANNEL_OPTION_COMPRESS = 0x00400000
CHANNEL_OPTION_SHOW_PROTOCOL = 0x00200000
REMOTE_CONTROL_PERSISTENT = 0x00100000
)
/**
* IBM_101_102_KEYS is the most common keyboard type
*/
type KeyboardType uint32
const (
KT_IBM_PC_XT_83_KEY KeyboardType = 0x00000001
KT_OLIVETTI = 0x00000002
KT_IBM_PC_AT_84_KEY = 0x00000003
KT_IBM_101_102_KEYS = 0x00000004
KT_NOKIA_1050 = 0x00000005
KT_NOKIA_9140 = 0x00000006
KT_JAPANESE = 0x00000007
)
/**
* @see http://technet.microsoft.com/en-us/library/cc766503%28WS.10%29.aspx
*/
type KeyboardLayout uint32
const (
ARABIC KeyboardLayout = 0x00000401
BULGARIAN = 0x00000402
CHINESE_US_KEYBOARD = 0x00000404
CZECH = 0x00000405
DANISH = 0x00000406
GERMAN = 0x00000407
GREEK = 0x00000408
US = 0x00000409
SPANISH = 0x0000040a
FINNISH = 0x0000040b
FRENCH = 0x0000040c
HEBREW = 0x0000040d
HUNGARIAN = 0x0000040e
ICELANDIC = 0x0000040f
ITALIAN = 0x00000410
JAPANESE = 0x00000411
KOREAN = 0x00000412
DUTCH = 0x00000413
NORWEGIAN = 0x00000414
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240521.aspx
*/
type CertificateType uint32
const (
CERT_CHAIN_VERSION_1 CertificateType = 0x00000001
CERT_CHAIN_VERSION_2 = 0x00000002
)
type ChannelDef struct {
Name [8]byte
Options uint32
}
type ClientCoreData struct {
RdpVersion VERSION `struc:"uint32,little"`
DesktopWidth uint16 `struc:"little"`
DesktopHeight uint16 `struc:"little"`
ColorDepth ColorDepth `struc:"little"`
SasSequence Sequence `struc:"little"`
KbdLayout KeyboardLayout `struc:"little"`
ClientBuild uint32 `struc:"little"`
ClientName [32]byte `struc:"[32]byte"`
KeyboardType uint32 `struc:"little"`
KeyboardSubType uint32 `struc:"little"`
KeyboardFnKeys uint32 `struc:"little"`
ImeFileName [64]byte `struc:"[64]byte"`
PostBeta2ColorDepth ColorDepth `struc:"little"`
ClientProductId uint16 `struc:"little"`
SerialNumber uint32 `struc:"little"`
HighColorDepth HighColor `struc:"little"`
SupportedColorDepths uint16 `struc:"little"`
EarlyCapabilityFlags uint16 `struc:"little"`
ClientDigProductId [64]byte `struc:"[64]byte"`
ConnectionType uint8 `struc:"uint8"`
Pad1octet uint8 `struc:"uint8"`
ServerSelectedProtocol uint32 `struc:"little"`
}
func NewClientCoreData() *ClientCoreData {
name, _ := os.Hostname()
var ClientName [32]byte
copy(ClientName[:], core.UnicodeEncode(name)[:])
return &ClientCoreData{
RDP_VERSION_5_PLUS, 1280, 800, RNS_UD_COLOR_8BPP,
RNS_UD_SAS_DEL, US, 3790, ClientName, KT_IBM_101_102_KEYS,
0, 12, [64]byte{}, RNS_UD_COLOR_8BPP, 1, 0, HIGH_COLOR_24BPP,
RNS_UD_15BPP_SUPPORT | RNS_UD_16BPP_SUPPORT | RNS_UD_24BPP_SUPPORT | RNS_UD_32BPP_SUPPORT,
RNS_UD_CS_SUPPORT_ERRINFO_PDU, [64]byte{}, 0, 0, 0}
}
func (data *ClientCoreData) Block() []byte {
buff := &bytes.Buffer{}
core.WriteUInt16LE(CS_CORE, buff) // 01C0
core.WriteUInt16LE(0xd8, buff) // d800
struc.Pack(buff, data)
return buff.Bytes()
}
type ClientNetworkData struct {
ChannelCount uint32
ChannelDefArray []ChannelDef
}
func NewClientNetworkData() *ClientNetworkData {
return &ClientNetworkData{}
}
func (d *ClientNetworkData) Block() []byte {
buff := &bytes.Buffer{}
core.WriteUInt16LE(CS_NET, buff) // type
core.WriteUInt16LE(0x08, buff) // len 8
buff.Write([]byte{0, 0, 0, 0}) // data
return buff.Bytes()
}
type ClientSecurityData struct {
EncryptionMethods uint32
ExtEncryptionMethods uint32
}
func NewClientSecurityData() *ClientSecurityData {
return &ClientSecurityData{
ENCRYPTION_FLAG_40BIT | ENCRYPTION_FLAG_56BIT | ENCRYPTION_FLAG_128BIT,
00}
}
func (d *ClientSecurityData) Block() []byte {
buff := &bytes.Buffer{}
core.WriteUInt16LE(CS_SECURITY, buff) // type
core.WriteUInt16LE(0x0c, buff) // len 12
core.WriteUInt32LE(d.EncryptionMethods, buff)
core.WriteUInt32LE(d.ExtEncryptionMethods, buff)
return buff.Bytes()
}
type RSAPublicKey struct {
Magic uint32 `struc:"little"` //0x31415352
Keylen uint32 `struc:"little,sizeof=Modulus"`
Bitlen uint32 `struc:"little"`
Datalen uint32 `struc:"little"`
PubExp uint32 `struc:"little"`
Modulus []byte `struc:"little"`
Padding []byte `struc:"[8]byte"`
}
type ProprietaryServerCertificate struct {
DwSigAlgId uint32 `struc:"little"` //0x00000001
DwKeyAlgId uint32 `struc:"little"` //0x00000001
PublicKeyBlobType uint16 `struc:"little"` //0x0006
PublicKeyBlobLen uint16 `struc:"little,sizeof=PublicKeyBlob"`
PublicKeyBlob RSAPublicKey `struc:"little"`
SignatureBlobType uint16 `struc:"little"` //0x0008
SignatureBlobLen uint16 `struc:"little,sizeof=SignatureBlob"`
SignatureBlob []byte `struc:"little"`
//PaddingLen uint16 `struc:"little,sizeof=Padding,skip"`
Padding []byte `struc:"[8]byte"`
}
func (p *ProprietaryServerCertificate) GetPublicKey() (uint32, []byte) {
return p.PublicKeyBlob.PubExp, p.PublicKeyBlob.Modulus
}
func (p *ProprietaryServerCertificate) Verify() bool {
//todo
return true
}
func (p *ProprietaryServerCertificate) Encrypt() []byte {
//todo
return nil
}
func (p *ProprietaryServerCertificate) Unpack(r io.Reader) error {
p.DwSigAlgId, _ = core.ReadUInt32LE(r)
p.DwKeyAlgId, _ = core.ReadUInt32LE(r)
p.PublicKeyBlobType, _ = core.ReadUint16LE(r)
p.PublicKeyBlobLen, _ = core.ReadUint16LE(r)
var b RSAPublicKey
b.Magic, _ = core.ReadUInt32LE(r)
b.Keylen, _ = core.ReadUInt32LE(r)
b.Bitlen, _ = core.ReadUInt32LE(r)
b.Datalen, _ = core.ReadUInt32LE(r)
b.PubExp, _ = core.ReadUInt32LE(r)
b.Modulus, _ = core.ReadBytes(int(b.Keylen)-8, r)
b.Padding, _ = core.ReadBytes(8, r)
p.PublicKeyBlob = b
p.SignatureBlobType, _ = core.ReadUint16LE(r)
p.SignatureBlobLen, _ = core.ReadUint16LE(r)
p.SignatureBlob, _ = core.ReadBytes(int(p.SignatureBlobLen)-8, r)
p.Padding, _ = core.ReadBytes(8, r)
return nil
}
type CertBlob struct {
CbCert uint32 `struc:"little,sizeof=AbCert"`
AbCert []byte `struc:"little"`
}
type X509CertificateChain struct {
NumCertBlobs uint32 `struc:"little,sizeof=CertBlobArray"`
CertBlobArray []CertBlob `struc:"little"`
Padding []byte `struc:"little"`
}
func (p *X509CertificateChain) GetPublicKey() (uint32, []byte) {
//todo
return 0, nil
}
func (p *X509CertificateChain) Verify() bool {
return true
}
func (p *X509CertificateChain) Encrypt() []byte {
//todo
return nil
}
func (p *X509CertificateChain) Unpack(r io.Reader) error {
return struc.Unpack(r, p)
}
type ServerCoreData struct {
RdpVersion VERSION `struc:"uint32,little"`
ClientRequestedProtocol uint32 `struc:"little"`
EarlyCapabilityFlags uint32 `struc:"little"`
}
func NewServerCoreData() *ServerCoreData {
return &ServerCoreData{
RDP_VERSION_5_PLUS, 0, 0}
}
func (d *ServerCoreData) Serialize() []byte {
return []byte{}
}
func (d *ServerCoreData) ScType() Message {
return SC_CORE
}
func (d *ServerCoreData) Unpack(r io.Reader) error {
return struc.Unpack(r, d)
}
type ServerNetworkData struct {
MCSChannelId uint16 `struc:"little"`
ChannelCount uint16 `struc:"little,sizeof=ChannelIdArray"`
ChannelIdArray []uint16 `struc:"little"`
}
func NewServerNetworkData() *ServerNetworkData {
return &ServerNetworkData{}
}
func (d *ServerNetworkData) ScType() Message {
return SC_NET
}
func (d *ServerNetworkData) Unpack(r io.Reader) error {
return struc.Unpack(r, d)
}
type CertData interface {
GetPublicKey() (uint32, []byte)
Verify() bool
Unpack(io.Reader) error
}
type ServerCertificate struct {
DwVersion uint32
CertData CertData
}
type ServerSecurityData struct {
EncryptionMethod uint32 `struc:"little"`
EncryptionLevel uint32 `struc:"little"`
ServerRandomLen uint32 //0x00000020
ServerCertLen uint32
ServerRandom []byte
ServerCertificate ServerCertificate
}
func NewServerSecurityData() *ServerSecurityData {
return &ServerSecurityData{
0, 0, 0x00000020, 0, []byte{}, ServerCertificate{}}
}
func (d *ServerSecurityData) ScType() Message {
return SC_SECURITY
}
func (s *ServerSecurityData) Unpack(r io.Reader) error {
s.EncryptionMethod, _ = core.ReadUInt32LE(r)
s.EncryptionLevel, _ = core.ReadUInt32LE(r)
if !(s.EncryptionMethod == 0 && s.EncryptionLevel == 0) {
s.ServerRandomLen, _ = core.ReadUInt32LE(r)
s.ServerCertLen, _ = core.ReadUInt32LE(r)
s.ServerRandom, _ = core.ReadBytes(int(s.ServerRandomLen), r)
var sc ServerCertificate
data, _ := core.ReadBytes(int(s.ServerCertLen), r)
rd := bytes.NewReader(data)
sc.DwVersion, _ = core.ReadUInt32LE(rd)
var cd CertData
switch CertificateType(sc.DwVersion & 0x7fffffff) {
case CERT_CHAIN_VERSION_1:
glog.Debug("ProprietaryServerCertificate")
cd = &ProprietaryServerCertificate{}
case CERT_CHAIN_VERSION_2:
glog.Debug("X509CertificateChain")
cd = &X509CertificateChain{}
default:
glog.Error("Unsupported version:", sc.DwVersion&0x7fffffff)
return errors.New("Unsupported version")
}
if cd != nil {
//err := struc.Unpack(rd, cd)
err := cd.Unpack(rd)
if err != nil {
glog.Error("Unpack:", err)
return err
}
glog.Infof("d:%+v", cd)
}
sc.CertData = cd
s.ServerCertificate = sc
}
return nil
}
func MakeConferenceCreateRequest(userData []byte) []byte {
buff := &bytes.Buffer{}
per.WriteChoice(0, buff) // 00
per.WriteObjectIdentifier(t124_02_98_oid, buff) // 05:00:14:7c:00:01
per.WriteLength(len(userData)+14, buff)
per.WriteChoice(0, buff) // 00
per.WriteSelection(0x08, buff) // 08
per.WriteNumericString("1", 1, buff) // 00 10
per.WritePadding(1, buff) // 00
per.WriteNumberOfSet(1, buff) // 01
per.WriteChoice(0xc0, buff) // c0
per.WriteOctetStream(h221_cs_key, 4, buff) // 00 44:75:63:61
per.WriteOctetStream(string(userData), 0, buff)
return buff.Bytes()
}
type ScData interface {
ScType() Message
Unpack(io.Reader) error
}
func ReadConferenceCreateResponse(data []byte) []interface{} {
ret := make([]interface{}, 0, 3)
r := bytes.NewReader(data)
per.ReadChoice(r)
if !per.ReadObjectIdentifier(r, t124_02_98_oid) {
glog.Error("NODE_RDP_PROTOCOL_T125_GCC_BAD_OBJECT_IDENTIFIER_T124")
return ret
}
per.ReadLength(r)
per.ReadChoice(r)
per.ReadInteger16(r)
per.ReadInteger(r)
per.ReadEnumerates(r)
per.ReadNumberOfSet(r)
per.ReadChoice(r)
if !per.ReadOctetStream(r, h221_sc_key, 4) {
glog.Error("NODE_RDP_PROTOCOL_T125_GCC_BAD_H221_SC_KEY")
return ret
}
glog.Debug("all:", SC_CORE, SC_SECURITY, SC_NET,
CS_CORE, CS_SECURITY, CS_NET, CS_CLUSTER, CS_MONITOR)
ln, _ := per.ReadLength(r)
for ln > 0 {
t, _ := core.ReadUint16LE(r)
l, _ := core.ReadUint16LE(r)
dataBytes, _ := core.ReadBytes(int(l)-4, r)
ln = ln - l
var d ScData
switch Message(t) {
case SC_CORE:
d = &ServerCoreData{}
case SC_SECURITY:
d = &ServerSecurityData{}
case SC_NET:
d = &ServerNetworkData{}
default:
glog.Error("Unknown type", t)
continue
}
r := bytes.NewReader(dataBytes)
err := d.Unpack(r)
if err != nil {
glog.Error("Unpack:", err)
if err.Error() != "EOF" {
return ret
}
}
ret = append(ret, d)
glog.Debugf("d:%+v", d)
}
return ret
}

View File

@@ -0,0 +1,537 @@
package t125
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"io"
"reflect"
"Yasso/pkg/grdp/core"
"Yasso/pkg/grdp/emission"
"Yasso/pkg/grdp/glog"
"Yasso/pkg/grdp/protocol/t125/ber"
"Yasso/pkg/grdp/protocol/t125/gcc"
"Yasso/pkg/grdp/protocol/t125/per"
)
// take idea from https://github.com/Madnikulin50/gordp
// Multiple Channel Service layer
type MCSMessage uint8
const (
MCS_TYPE_CONNECT_INITIAL MCSMessage = 0x65
MCS_TYPE_CONNECT_RESPONSE = 0x66
)
type MCSDomainPDU uint16
const (
ERECT_DOMAIN_REQUEST MCSDomainPDU = 1
DISCONNECT_PROVIDER_ULTIMATUM = 8
ATTACH_USER_REQUEST = 10
ATTACH_USER_CONFIRM = 11
CHANNEL_JOIN_REQUEST = 14
CHANNEL_JOIN_CONFIRM = 15
SEND_DATA_REQUEST = 25
SEND_DATA_INDICATION = 26
)
const (
MCS_GLOBAL_CHANNEL uint16 = 1003
MCS_USERCHANNEL_BASE = 1001
)
/**
* Format MCS PDULayer header packet
* @param mcsPdu {integer}
* @param options {integer}
* @returns {type.UInt8} headers
*/
func writeMCSPDUHeader(mcsPdu MCSDomainPDU, options uint8, w io.Writer) {
core.WriteUInt8((uint8(mcsPdu)<<2)|options, w)
}
func readMCSPDUHeader(options uint8, mcsPdu MCSDomainPDU) bool {
return (options >> 2) == uint8(mcsPdu)
}
type DomainParameters struct {
MaxChannelIds int
MaxUserIds int
MaxTokenIds int
NumPriorities int
MinThoughput int
MaxHeight int
MaxMCSPDUsize int
ProtocolVersion int
}
/**
* @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
* @returns {asn1.univ.Sequence}
*/
func NewDomainParameters(
maxChannelIds int,
maxUserIds int,
maxTokenIds int,
numPriorities int,
minThoughput int,
maxHeight int,
maxMCSPDUsize int,
protocolVersion int) *DomainParameters {
return &DomainParameters{maxChannelIds, maxUserIds, maxTokenIds,
numPriorities, minThoughput, maxHeight, maxMCSPDUsize, protocolVersion}
}
func (d *DomainParameters) BER() []byte {
buff := &bytes.Buffer{}
ber.WriteInteger(d.MaxChannelIds, buff)
ber.WriteInteger(d.MaxUserIds, buff)
ber.WriteInteger(d.MaxTokenIds, buff)
ber.WriteInteger(1, buff)
ber.WriteInteger(0, buff)
ber.WriteInteger(1, buff)
ber.WriteInteger(d.MaxMCSPDUsize, buff)
ber.WriteInteger(2, buff)
return buff.Bytes()
}
func ReadDomainParameters(r io.Reader) (*DomainParameters, error) {
if !ber.ReadUniversalTag(ber.TAG_SEQUENCE, true, r) {
return nil, errors.New("bad BER tags")
}
d := &DomainParameters{}
ber.ReadLength(r)
d.MaxChannelIds, _ = ber.ReadInteger(r)
d.MaxUserIds, _ = ber.ReadInteger(r)
d.MaxTokenIds, _ = ber.ReadInteger(r)
ber.ReadInteger(r)
ber.ReadInteger(r)
ber.ReadInteger(r)
d.MaxMCSPDUsize, _ = ber.ReadInteger(r)
ber.ReadInteger(r)
return d, nil
}
/**
* @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
* @param userData {Buffer}
* @returns {asn1.univ.Sequence}
*/
type ConnectInitial struct {
CallingDomainSelector []byte
CalledDomainSelector []byte
UpwardFlag bool
TargetParameters DomainParameters
MinimumParameters DomainParameters
MaximumParameters DomainParameters
UserData []byte
}
func NewConnectInitial(userData []byte) ConnectInitial {
return ConnectInitial{[]byte{0x1},
[]byte{0x1},
true,
*NewDomainParameters(34, 2, 0, 1, 0, 1, 0xffff, 2),
*NewDomainParameters(1, 1, 1, 1, 0, 1, 0x420, 2),
*NewDomainParameters(0xffff, 0xfc17, 0xffff, 1, 0, 1, 0xffff, 2),
userData}
}
func (c *ConnectInitial) BER() []byte {
buff := &bytes.Buffer{}
ber.WriteOctetstring(string(c.CallingDomainSelector), buff)
ber.WriteOctetstring(string(c.CalledDomainSelector), buff)
ber.WriteBoolean(c.UpwardFlag, buff)
ber.WriteEncodedDomainParams(c.TargetParameters.BER(), buff)
ber.WriteEncodedDomainParams(c.MinimumParameters.BER(), buff)
ber.WriteEncodedDomainParams(c.MaximumParameters.BER(), buff)
ber.WriteOctetstring(string(c.UserData), buff)
return buff.Bytes()
}
/**
* @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
* @returns {asn1.univ.Sequence}
*/
type ConnectResponse struct {
result uint8
calledConnectId int
domainParameters *DomainParameters
userData []byte
}
func NewConnectResponse(userData []byte) *ConnectResponse {
return &ConnectResponse{0,
0,
NewDomainParameters(22, 3, 0, 1, 0, 1, 0xfff8, 2),
userData}
}
func ReadConnectResponse(r io.Reader) (*ConnectResponse, error) {
c := &ConnectResponse{}
var err error
_, err = ber.ReadApplicationTag(MCS_TYPE_CONNECT_RESPONSE, r)
if err != nil {
return nil, err
}
c.result, err = ber.ReadEnumerated(r)
if err != nil {
return nil, err
}
c.calledConnectId, err = ber.ReadInteger(r)
c.domainParameters, err = ReadDomainParameters(r)
if err != nil {
return nil, err
}
if !ber.ReadUniversalTag(ber.TAG_OCTET_STRING, false, r) {
return nil, errors.New("invalid expected BER tag")
}
dataLen, _ := ber.ReadLength(r)
c.userData, err = core.ReadBytes(dataLen, r)
return c, err
}
type MCSChannelInfo struct {
ID uint16
Name string
}
type MCS struct {
emission.Emitter
transport core.Transport
recvOpCode MCSDomainPDU
sendOpCode MCSDomainPDU
channels []MCSChannelInfo
}
func NewMCS(t core.Transport, recvOpCode MCSDomainPDU, sendOpCode MCSDomainPDU) *MCS {
m := &MCS{
*emission.NewEmitter(),
t,
recvOpCode,
sendOpCode,
[]MCSChannelInfo{{MCS_GLOBAL_CHANNEL, "global"}},
}
m.transport.On("close", func() {
m.Emit("close")
}).On("error", func(err error) {
m.Emit("error", err)
})
return m
}
func (x *MCS) Read(b []byte) (n int, err error) {
return x.transport.Read(b)
}
func (x *MCS) Write(b []byte) (n int, err error) {
return x.transport.Write(b)
}
func (m *MCS) Close() error {
return m.transport.Close()
}
type MCSClient struct {
*MCS
clientCoreData *gcc.ClientCoreData
clientNetworkData *gcc.ClientNetworkData
clientSecurityData *gcc.ClientSecurityData
serverCoreData *gcc.ServerCoreData
serverNetworkData *gcc.ServerNetworkData
serverSecurityData *gcc.ServerSecurityData
channelsConnected int
userId uint16
nbChannelRequested int
}
func NewMCSClient(t core.Transport) *MCSClient {
c := &MCSClient{
MCS: NewMCS(t, SEND_DATA_INDICATION, SEND_DATA_REQUEST),
clientCoreData: gcc.NewClientCoreData(),
clientNetworkData: gcc.NewClientNetworkData(),
clientSecurityData: gcc.NewClientSecurityData(),
userId: 1 + MCS_USERCHANNEL_BASE,
}
c.transport.On("connect", c.connect)
return c
}
func (c *MCSClient) SetClientCoreData(width, height uint16) {
c.clientCoreData.DesktopWidth = width
c.clientCoreData.DesktopHeight = height
}
func (c *MCSClient) connect(selectedProtocol uint32) {
glog.Debug("mcs client on connect", selectedProtocol)
c.clientCoreData.ServerSelectedProtocol = selectedProtocol
// sendConnectInitial
userDataBuff := bytes.Buffer{}
userDataBuff.Write(c.clientCoreData.Block())
userDataBuff.Write(c.clientNetworkData.Block())
userDataBuff.Write(c.clientSecurityData.Block())
ccReq := gcc.MakeConferenceCreateRequest(userDataBuff.Bytes())
connectInitial := NewConnectInitial(ccReq)
connectInitialBerEncoded := connectInitial.BER()
dataBuff := &bytes.Buffer{}
ber.WriteApplicationTag(uint8(MCS_TYPE_CONNECT_INITIAL), len(connectInitialBerEncoded), dataBuff)
dataBuff.Write(connectInitialBerEncoded)
_, err := c.transport.Write(dataBuff.Bytes())
if err != nil {
c.Emit("error", errors.New(fmt.Sprintf("mcs sendConnectInitial write error %v", err)))
return
}
glog.Debug("mcs wait for data event")
c.transport.Once("data", c.recvConnectResponse)
}
func (c *MCSClient) recvConnectResponse(s []byte) {
glog.Debug("mcs recvConnectResponse", hex.EncodeToString(s))
cResp, err := ReadConnectResponse(bytes.NewReader(s))
if err != nil {
c.Emit("error", errors.New(fmt.Sprintf("ReadConnectResponse %v", err)))
return
}
// record server gcc block
serverSettings := gcc.ReadConferenceCreateResponse(cResp.userData)
for _, v := range serverSettings {
switch v.(type) {
case *gcc.ServerSecurityData:
c.serverSecurityData = v.(*gcc.ServerSecurityData)
case *gcc.ServerCoreData:
c.serverCoreData = v.(*gcc.ServerCoreData)
case *gcc.ServerNetworkData:
c.serverNetworkData = v.(*gcc.ServerNetworkData)
default:
err := errors.New(fmt.Sprintf("unhandle server gcc block %v", reflect.TypeOf(v)))
glog.Error(err)
c.Emit("error", err)
return
}
}
glog.Debugf("serverSecurityData: %+v", c.serverSecurityData)
glog.Debugf("serverCoreData: %+v", c.serverCoreData)
glog.Debugf("serverNetworkData: %+v", c.serverNetworkData)
glog.Debug("mcs sendErectDomainRequest")
c.sendErectDomainRequest()
glog.Debug("mcs sendAttachUserRequest")
c.sendAttachUserRequest()
c.transport.Once("data", c.recvAttachUserConfirm)
}
func (c *MCSClient) sendErectDomainRequest() {
buff := &bytes.Buffer{}
writeMCSPDUHeader(ERECT_DOMAIN_REQUEST, 0, buff)
per.WriteInteger(0, buff)
per.WriteInteger(0, buff)
c.transport.Write(buff.Bytes())
}
func (c *MCSClient) sendAttachUserRequest() {
buff := &bytes.Buffer{}
writeMCSPDUHeader(ATTACH_USER_REQUEST, 0, buff)
c.transport.Write(buff.Bytes())
}
func (c *MCSClient) recvAttachUserConfirm(s []byte) {
glog.Debug("mcs recvAttachUserConfirm", hex.EncodeToString(s))
r := bytes.NewReader(s)
option, err := core.ReadUInt8(r)
if err != nil {
c.Emit("error", err)
return
}
if !readMCSPDUHeader(option, ATTACH_USER_CONFIRM) {
c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_BAD_HEADER"))
return
}
e, err := per.ReadEnumerates(r)
if err != nil {
c.Emit("error", err)
return
}
if e != 0 {
c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_SERVER_REJECT_USER'"))
return
}
userId, _ := per.ReadInteger16(r)
userId += MCS_USERCHANNEL_BASE
c.userId = userId
c.channels = append(c.channels, MCSChannelInfo{userId, "user"})
c.connectChannels()
}
func (c *MCSClient) connectChannels() {
glog.Debug("mcs connectChannels:", c.channelsConnected, ":", len(c.channels))
if c.channelsConnected == len(c.channels) {
//if c.nbChannelRequested < int(c.serverNetworkData.ChannelCount) {
//static virtual channel
//chanId := c.serverNetworkData.ChannelIdArray[c.nbChannelRequested]
//c.nbChannelRequested++
//c.sendChannelJoinRequest(chanId)
//return
//}
c.transport.On("data", c.recvData)
// send client and sever gcc informations callback to sec
clientData := make([]interface{}, 0)
clientData = append(clientData, c.clientCoreData)
clientData = append(clientData, c.clientSecurityData)
clientData = append(clientData, c.clientNetworkData)
serverData := make([]interface{}, 0)
serverData = append(serverData, c.serverCoreData)
serverData = append(serverData, c.serverSecurityData)
glog.Debug("msc connectChannels callback to sec")
c.Emit("connect", clientData, serverData, c.userId, c.channels)
return
}
// sendChannelJoinRequest
glog.Debug("sendChannelJoinRequest:", c.channels[c.channelsConnected].Name)
c.sendChannelJoinRequest(c.channels[c.channelsConnected].ID)
c.channelsConnected += 1
c.transport.Once("data", c.recvChannelJoinConfirm)
}
func (c *MCSClient) sendChannelJoinRequest(channelId uint16) {
glog.Debug("mcs sendChannelJoinRequest", channelId)
buff := &bytes.Buffer{}
writeMCSPDUHeader(CHANNEL_JOIN_REQUEST, 0, buff)
per.WriteInteger16(c.userId-MCS_USERCHANNEL_BASE, buff)
per.WriteInteger16(channelId, buff)
c.transport.Write(buff.Bytes())
}
func (c *MCSClient) recvData(s []byte) {
glog.Debug("msc on data recvData:", hex.EncodeToString(s))
r := bytes.NewReader(s)
option, err := core.ReadUInt8(r)
if err != nil {
c.Emit("error", err)
return
}
if readMCSPDUHeader(option, DISCONNECT_PROVIDER_ULTIMATUM) {
c.Emit("error", errors.New("MCS DISCONNECT_PROVIDER_ULTIMATUM"))
c.transport.Close()
return
} else if !readMCSPDUHeader(option, c.recvOpCode) {
c.Emit("error", errors.New("Invalid expected MCS opcode receive data"))
return
}
userId, _ := per.ReadInteger16(r)
userId += MCS_USERCHANNEL_BASE
channelId, _ := per.ReadInteger16(r)
per.ReadEnumerates(r)
size, _ := per.ReadLength(r)
// channel ID doesn't match a requested layer
found := false
channelName := ""
for _, channel := range c.channels {
if channel.ID == channelId {
found = true
channelName = channel.Name
break
}
}
if !found {
glog.Error("mcs receive data for an unconnected layer")
return
}
left, err := core.ReadBytes(int(size), r)
if err != nil {
c.Emit("error", errors.New(fmt.Sprintf("mcs recvData get data error %v", err)))
return
}
glog.Debug("mcs emit channel", channelName, left)
c.Emit(channelName, left)
//c.Emit(channelName, s)
}
func (c *MCSClient) recvChannelJoinConfirm(s []byte) {
glog.Debug("mcs recvChannelJoinConfirm", hex.EncodeToString(s))
r := bytes.NewReader(s)
option, err := core.ReadUInt8(r)
if err != nil {
c.Emit("error", err)
return
}
if !readMCSPDUHeader(option, CHANNEL_JOIN_CONFIRM) {
c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM"))
return
}
confirm, _ := per.ReadEnumerates(r)
userId, _ := per.ReadInteger16(r)
userId += MCS_USERCHANNEL_BASE
if c.userId != userId {
c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_INVALID_USER_ID"))
return
}
channelId, _ := per.ReadInteger16(r)
if (confirm != 0) && (channelId == uint16(MCS_GLOBAL_CHANNEL) || channelId == c.userId) {
c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL"))
return
}
/*if confirm == 0 {
for i := 0; i < int(c.serverNetworkData.ChannelCount); i++ {
if channelId == c.serverNetworkData.ChannelIdArray[i] {
c.channels[channelId] = c.serverNetworkData.ChannelIdArray[i][1]
}
}
}*/
c.connectChannels()
}
func (c *MCSClient) SendToChannel(data []byte, channelId uint16) (n int, err error) {
buff := &bytes.Buffer{}
writeMCSPDUHeader(c.sendOpCode, 0, buff)
per.WriteInteger16(c.userId-MCS_USERCHANNEL_BASE, buff)
per.WriteInteger16(channelId, buff)
core.WriteUInt8(0x70, buff)
per.WriteLength(len(data), buff)
core.WriteBytes(data, buff)
glog.Debug("MCSClient write", hex.EncodeToString(buff.Bytes()))
return c.transport.Write(buff.Bytes())
}
func (c *MCSClient) Write(data []byte) (n int, err error) {
return c.SendToChannel(data, c.channels[0].ID)
}

View File

@@ -0,0 +1,203 @@
package per
import (
"bytes"
"io"
"Yasso/pkg/grdp/glog"
"Yasso/pkg/grdp/core"
)
func ReadEnumerates(r io.Reader) (uint8, error) {
return core.ReadUInt8(r)
}
func WriteInteger(n int, w io.Writer) {
if n <= 0xff {
WriteLength(1, w)
core.WriteUInt8(uint8(n), w)
} else if n <= 0xffff {
WriteLength(2, w)
core.WriteUInt16BE(uint16(n), w)
} else {
WriteLength(4, w)
core.WriteUInt32BE(uint32(n), w)
}
}
func ReadInteger16(r io.Reader) (uint16, error) {
return core.ReadUint16BE(r)
}
func WriteInteger16(value uint16, w io.Writer) {
core.WriteUInt16BE(value, w)
}
/**
* @param choice {integer}
* @returns {type.UInt8} choice per encoded
*/
func WriteChoice(choice uint8, w io.Writer) {
core.WriteUInt8(choice, w)
}
/**
* @param value {raw} value to convert to per format
* @returns type objects per encoding value
*/
func WriteLength(value int, w io.Writer) {
if value > 0x7f {
core.WriteUInt16BE(uint16(value|0x8000), w)
} else {
core.WriteUInt8(uint8(value), w)
}
}
func ReadLength(r io.Reader) (uint16, error) {
b, err := core.ReadUInt8(r)
if err != nil {
return 0, nil
}
var size uint16
if b&0x80 > 0 {
b = b &^ 0x80
size = uint16(b) << 8
left, _ := core.ReadUInt8(r)
size += uint16(left)
} else {
size = uint16(b)
}
return size, nil
}
/**
* @param oid {array} oid to write
* @returns {type.Component} per encoded object identifier
*/
func WriteObjectIdentifier(oid []byte, w io.Writer) {
core.WriteUInt8(5, w)
core.WriteByte((oid[0]<<4)&(oid[1]&0x0f), w)
core.WriteByte(oid[2], w)
core.WriteByte(oid[3], w)
core.WriteByte(oid[4], w)
core.WriteByte(oid[5], w)
}
/**
* @param selection {integer}
* @returns {type.UInt8} per encoded selection
*/
func WriteSelection(selection uint8, w io.Writer) {
core.WriteUInt8(selection, w)
}
func WriteNumericString(s string, minValue int, w io.Writer) {
length := len(s)
mLength := minValue
if length >= minValue {
mLength = length - minValue
}
buff := &bytes.Buffer{}
for i := 0; i < length; i += 2 {
c1 := int(s[i])
c2 := 0x30
if i+1 < length {
c2 = int(s[i+1])
}
c1 = (c1 - 0x30) % 10
c2 = (c2 - 0x30) % 10
core.WriteUInt8(uint8((c1<<4)|c2), buff)
}
WriteLength(mLength, w)
w.Write(buff.Bytes())
}
func WritePadding(length int, w io.Writer) {
b := make([]byte, length)
w.Write(b)
}
func WriteNumberOfSet(n int, w io.Writer) {
core.WriteUInt8(uint8(n), w)
}
/**
* @param oStr {String}
* @param minValue {integer} default 0
* @returns {type.Component} per encoded octet stream
*/
func WriteOctetStream(oStr string, minValue int, w io.Writer) {
length := len(oStr)
mlength := minValue
if length-minValue >= 0 {
mlength = length - minValue
}
WriteLength(mlength, w)
w.Write([]byte(oStr)[:length])
}
func ReadChoice(r io.Reader) uint8 {
choice, _ := core.ReadUInt8(r)
return choice
}
func ReadNumberOfSet(r io.Reader) uint8 {
choice, _ := core.ReadUInt8(r)
return choice
}
func ReadInteger(r io.Reader) uint32 {
size, _ := ReadLength(r)
switch size {
case 1:
ret, _ := core.ReadUInt8(r)
return uint32(ret)
case 2:
ret, _ := core.ReadUint16BE(r)
return uint32(ret)
case 4:
ret, _ := core.ReadUInt32BE(r)
return ret
default:
glog.Info("ReadInteger")
}
return 0
}
func ReadObjectIdentifier(r io.Reader, oid []byte) bool {
size, _ := ReadLength(r)
if size != 5 {
return false
}
a_oid := []byte{0, 0, 0, 0, 0, 0}
t12, _ := core.ReadByte(r)
a_oid[0] = t12 >> 4
a_oid[1] = t12 & 0x0f
a_oid[2], _ = core.ReadByte(r)
a_oid[3], _ = core.ReadByte(r)
a_oid[4], _ = core.ReadByte(r)
a_oid[5], _ = core.ReadByte(r)
for i, _ := range oid {
if oid[i] != a_oid[i] {
return false
}
}
return true
}
func ReadOctetStream(r io.Reader, s string, min int) bool {
ln, _ := ReadLength(r)
size := int(ln) + min
if size != len(s) {
return false
}
for i := 0; i < size; i++ {
b, _ := core.ReadByte(r)
if b != s[i] {
return false
}
}
return true
}

View File

@@ -0,0 +1,229 @@
package tpkt
import (
"bytes"
"encoding/hex"
"fmt"
"Yasso/pkg/grdp/core"
"Yasso/pkg/grdp/emission"
"Yasso/pkg/grdp/glog"
"Yasso/pkg/grdp/protocol/nla"
)
// take idea from https://github.com/Madnikulin50/gordp
/**
* Type of tpkt packet
* Fastpath is use to shortcut RDP stack
* @see http://msdn.microsoft.com/en-us/library/cc240621.aspx
* @see http://msdn.microsoft.com/en-us/library/cc240589.aspx
*/
const (
FASTPATH_ACTION_FASTPATH = 0x0
FASTPATH_ACTION_X224 = 0x3
)
/**
* TPKT layer of rdp stack
*/
type TPKT struct {
emission.Emitter
Conn *core.SocketLayer
ntlm *nla.NTLMv2
secFlag byte
lastShortLength int
fastPathListener core.FastPathListener
ntlmSec *nla.NTLMv2Security
}
func New(s *core.SocketLayer, ntlm *nla.NTLMv2) *TPKT {
t := &TPKT{
Emitter: *emission.NewEmitter(),
Conn: s,
secFlag: 0,
ntlm: ntlm}
core.StartReadBytes(2, s, t.recvHeader)
return t
}
func (t *TPKT) StartTLS() error {
return t.Conn.StartTLS()
}
func (t *TPKT) StartNLA() error {
err := t.StartTLS()
if err != nil {
glog.Info("start tls failed", err)
return err
}
req := nla.EncodeDERTRequest([]nla.Message{t.ntlm.GetNegotiateMessage()}, nil, nil)
_, err = t.Conn.Write(req)
if err != nil {
glog.Info("send NegotiateMessage", err)
return err
}
resp := make([]byte, 1024)
n, err := t.Conn.Read(resp)
if err != nil {
return fmt.Errorf("read %s", err)
} else {
glog.Debug("StartNLA Read success")
}
return t.recvChallenge(resp[:n])
}
func (t *TPKT) recvChallenge(data []byte) error {
glog.Debug("recvChallenge", hex.EncodeToString(data))
tsreq, err := nla.DecodeDERTRequest(data)
if err != nil {
glog.Info("DecodeDERTRequest", err)
return err
}
glog.Debugf("tsreq:%+v", tsreq)
// get pubkey
pubkey, err := t.Conn.TlsPubKey()
glog.Debugf("pubkey=%+v", pubkey)
authMsg, ntlmSec := t.ntlm.GetAuthenticateMessage(tsreq.NegoTokens[0].Data)
t.ntlmSec = ntlmSec
encryptPubkey := ntlmSec.GssEncrypt(pubkey)
req := nla.EncodeDERTRequest([]nla.Message{authMsg}, nil, encryptPubkey)
_, err = t.Conn.Write(req)
if err != nil {
glog.Info("send AuthenticateMessage", err)
return err
}
resp := make([]byte, 1024)
n, err := t.Conn.Read(resp)
if err != nil {
glog.Error("Read:", err)
return fmt.Errorf("read %s", err)
} else {
glog.Debug("recvChallenge Read success")
}
return t.recvPubKeyInc(resp[:n])
}
func (t *TPKT) recvPubKeyInc(data []byte) error {
glog.Debug("recvPubKeyInc", hex.EncodeToString(data))
tsreq, err := nla.DecodeDERTRequest(data)
if err != nil {
glog.Info("DecodeDERTRequest", err)
return err
}
glog.Debug("PubKeyAuth:", tsreq.PubKeyAuth)
//ignore
//pubkey := t.ntlmSec.GssDecrypt([]byte(tsreq.PubKeyAuth))
domain, username, password := t.ntlm.GetEncodedCredentials()
credentials := nla.EncodeDERTCredentials(domain, username, password)
authInfo := t.ntlmSec.GssEncrypt(credentials)
req := nla.EncodeDERTRequest(nil, authInfo, nil)
_, err = t.Conn.Write(req)
if err != nil {
glog.Info("send AuthenticateMessage", err)
return err
}
return nil
}
func (t *TPKT) Read(b []byte) (n int, err error) {
return t.Conn.Read(b)
}
func (t *TPKT) Write(data []byte) (n int, err error) {
buff := &bytes.Buffer{}
core.WriteUInt8(FASTPATH_ACTION_X224, buff)
core.WriteUInt8(0, buff)
core.WriteUInt16BE(uint16(len(data)+4), buff)
buff.Write(data)
glog.Debug("tpkt Write", hex.EncodeToString(buff.Bytes()))
return t.Conn.Write(buff.Bytes())
}
func (t *TPKT) Close() error {
return t.Conn.Close()
}
func (t *TPKT) SetFastPathListener(f core.FastPathListener) {
t.fastPathListener = f
}
func (t *TPKT) SendFastPath(secFlag byte, data []byte) (n int, err error) {
buff := &bytes.Buffer{}
core.WriteUInt8(FASTPATH_ACTION_FASTPATH|((secFlag&0x3)<<6), buff)
core.WriteUInt16BE(uint16(len(data)+3)|0x8000, buff)
buff.Write(data)
glog.Debug("TPTK SendFastPath", hex.EncodeToString(buff.Bytes()))
return t.Conn.Write(buff.Bytes())
}
func (t *TPKT) recvHeader(s []byte, err error) {
glog.Debug("tpkt recvHeader", hex.EncodeToString(s), err)
if err != nil {
t.Emit("error", err)
return
}
r := bytes.NewReader(s)
version, _ := core.ReadUInt8(r)
if version == FASTPATH_ACTION_X224 {
glog.Debug("tptk recvHeader FASTPATH_ACTION_X224, wait for recvExtendedHeader")
core.StartReadBytes(2, t.Conn, t.recvExtendedHeader)
} else {
t.secFlag = (version >> 6) & 0x3
length, _ := core.ReadUInt8(r)
t.lastShortLength = int(length)
if t.lastShortLength&0x80 != 0 {
core.StartReadBytes(1, t.Conn, t.recvExtendedFastPathHeader)
} else {
core.StartReadBytes(t.lastShortLength-2, t.Conn, t.recvFastPath)
}
}
}
func (t *TPKT) recvExtendedHeader(s []byte, err error) {
glog.Debug("tpkt recvExtendedHeader", hex.EncodeToString(s), err)
if err != nil {
return
}
r := bytes.NewReader(s)
size, _ := core.ReadUint16BE(r)
glog.Debug("tpkt wait recvData:", size)
core.StartReadBytes(int(size-4), t.Conn, t.recvData)
}
func (t *TPKT) recvData(s []byte, err error) {
glog.Debug("tpkt recvData", hex.EncodeToString(s), err)
if err != nil {
return
}
t.Emit("data", s)
core.StartReadBytes(2, t.Conn, t.recvHeader)
}
func (t *TPKT) recvExtendedFastPathHeader(s []byte, err error) {
glog.Debug("tpkt recvExtendedFastPathHeader", hex.EncodeToString(s))
r := bytes.NewReader(s)
rightPart, err := core.ReadUInt8(r)
if err != nil {
glog.Error("TPTK recvExtendedFastPathHeader", err)
return
}
leftPart := t.lastShortLength & ^0x80
packetSize := (leftPart << 8) + int(rightPart)
core.StartReadBytes(packetSize-3, t.Conn, t.recvFastPath)
}
func (t *TPKT) recvFastPath(s []byte, err error) {
glog.Debug("tpkt recvFastPath")
if err != nil {
return
}
t.fastPathListener.RecvFastPath(t.secFlag, s)
core.StartReadBytes(2, t.Conn, t.recvHeader)
}

View File

@@ -0,0 +1,272 @@
package x224
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"Yasso/pkg/grdp/glog"
"Yasso/pkg/grdp/core"
"Yasso/pkg/grdp/emission"
"Yasso/pkg/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}
}
/**
* 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
ProtocolNeg *Negotiation
}
func NewClientConnectionRequestPDU(coockie []byte) *ClientConnectionRequestPDU {
x := ClientConnectionRequestPDU{0, TPDU_CONNECTION_REQUEST, 0, 0, 0,
coockie, NewNegotiation()}
x.Len = uint8(len(x.Serialize()) - 1)
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)
buff.Write(x.Cookie)
if x.Len > 14 {
core.WriteUInt16LE(0x0A0D, buff)
}
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 {
x := &X224{
*emission.NewEmitter(),
t,
PROTOCOL_RDP | PROTOCOL_SSL | PROTOCOL_HYBRID,
PROTOCOL_SSL,
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.Debug("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")
}
message := NewClientConnectionRequestPDU(make([]byte, 0))
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))
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.Emit("error", errors.New("PROTOCOL_RDP"))
}
x.Close()
return
}
if message.ProtocolNeg.Type == TYPE_RDP_NEG_RSP {
glog.Info("TYPE_RDP_NEG_RSP")
x.selectedProtocol = message.ProtocolNeg.Result
}
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.Debug("x224 recvData", hex.EncodeToString(s), "emit data")
// x224 header takes 3 bytes
x.Emit("data", s[3:])
}