packagerdpimport("encoding/asn1""fmt")// TSRequest is the top-level structure for CredSSP messages//
// TSRequest ::= SEQUENCE {// version [0] INTEGER,// negoTokens [1] SEQUENCE OF NegoData OPTIONAL,// authInfo [2] OCTET STRING OPTIONAL,// pubKeyAuth [3] OCTET STRING OPTIONAL// }typetsRequeststruct{Versionint`asn1:"tag:0,explicit"`NegoTokens[]negoData`asn1:"tag:1,explicit,optional"`AuthInfo[]byte`asn1:"tag:2,explicit,optional"`PubKeyAuth[]byte`asn1:"tag:3,explicit,optional"`}// NegoData ::= SEQUENCE {// negoToken [0] OCTET STRING// }typenegoDatastruct{NegoToken[]byte`asn1:"tag:0,explicit"`}// ParseTSRequest parses a CredSSP TSRequest from bytesfuncparseTSRequest(data[]byte)(*tsRequest,error){vartstsRequest_,err:=asn1.Unmarshal(data,&ts)iferr!=nil{returnnil,err}return&ts,nil}// BuildTSResponse builds a CredSSP TSRequest message (used for responses)funcbuildTSResponse(token[]byte)([]byte,error){ts:=tsRequest{Version:6,// Updated to version 6 for modern clientsNegoTokens:[]negoData{{NegoToken:token},},}returnasn1.Marshal(ts)}// NTLM signatures and message typesconst(NTLMSSP_SIGNATURE="NTLMSSP\x00"NTLM_TYPE1=1// NegotiateNTLM_TYPE2=2// ChallengeNTLM_TYPE3=3// Authenticate)// Minimal NTLM helper to extract username/hash from Type 3 messagefuncparseNTLMType3(data[]byte)(username,domain,workstation,ntlmHashstring){iflen(data)<64||string(data[:8])!=NTLMSSP_SIGNATURE{return}// Helper to read NTLM fields (offset and length)readField:=func(offsetint)[]byte{iflen(data)<offset+8{returnnil}length:=int(data[offset])|int(data[offset+1])<<8start:=int(data[offset+4])|int(data[offset+5])<<8|int(data[offset+6])<<16|int(data[offset+7])<<24ifstart+length>len(data){returnnil}returndata[start:start+length]}// NTLM Type 3 offsets:// Workstation: 44// Domain: 28// User: 36// NTLM Response: 20domainBytes:=readField(28)userBytes:=readField(36)workstationBytes:=readField(44)ntlmResponse:=readField(20)// UTF-16 to ASCII (crude but usually enough for honeypot purposes)utf16ToAscii:=func(b[]byte)string{iflen(b)==0{return""}res:=make([]byte,0,len(b)/2)fori:=0;i<len(b);i+=2{res=append(res,b[i])}returnstring(res)}username=utf16ToAscii(userBytes)domain=utf16ToAscii(domainBytes)workstation=utf16ToAscii(workstationBytes)// NTLM response is usually hex encoded for logging// In NTLMv2, we only want the 16-byte proof stringiflen(ntlmResponse)>16{ntlmResponse=ntlmResponse[:16]}ntlmHash=fmt.Sprintf("%x",ntlmResponse)return}