def sendClientNewLicenseRequest(self, licenseRequest): """ @summary: Create new license request in response to server license request @param licenseRequest: {ServerLicenseRequest} @see: http://msdn.microsoft.com/en-us/library/cc241989.aspx @see: http://msdn.microsoft.com/en-us/library/cc241918.aspx """ #get server information serverRandom = licenseRequest.serverRandom.value if self._transport.getGCCServerSettings().SC_SECURITY.serverCertificate._is_readed: serverCertificate = self._transport.getGCCServerSettings().SC_SECURITY.serverCertificate else: s = Stream(licenseRequest.serverCertificate.blobData.value) serverCertificate = gcc.ServerCertificate() s.readType(serverCertificate) #generate crypto values clientRandom = rsa.random(256) preMasterSecret = rsa.random(384) masterSecret = sec.masterSecret(preMasterSecret, clientRandom, serverRandom) sessionKeyBlob = sec.masterSecret(masterSecret, serverRandom, clientRandom) self._macSalt = sessionKeyBlob[:16] self._licenseKey = sec.finalHash(sessionKeyBlob[16:32], clientRandom, serverRandom) #format message message = ClientNewLicenseRequest() message.clientRandom.value = clientRandom message.encryptedPreMasterSecret.blobData.value = rsa.encrypt(preMasterSecret[::-1], serverCertificate.certData.getPublicKey())[::-1] + "\x00" * 8 message.ClientMachineName.blobData.value = self._hostname + "\x00" message.ClientUserName.blobData.value = self._username + "\x00" self._transport.sendFlagged(sec.SecurityFlag.SEC_LICENSE_PKT, LicPacket(message))
def encodeDERTRequest(negoTypes = [], authInfo = None, pubKeyAuth = None): """ @summary: create TSRequest from list of Type @param negoTypes: {list(Type)} @param authInfo: {str} authentication info TSCredentials encrypted with authentication protocol @param pubKeyAuth: {str} public key encrypted with authentication protocol @return: {str} TRequest der encoded """ negoData = NegoData().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)) #fill nego data tokens i = 0 for negoType in negoTypes: s = Stream() s.writeType(negoType) negoToken = NegoToken() negoToken.setComponentByPosition(0, s.getvalue()) negoData.setComponentByPosition(i, negoToken) i += 1 request = TSRequest() request.setComponentByName("version", univ.Integer(2).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))) if i > 0: request.setComponentByName("negoTokens", negoData) if not authInfo is None: request.setComponentByName("authInfo", univ.OctetString(authInfo).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))) if not pubKeyAuth is None: request.setComponentByName("pubKeyAuth", univ.OctetString(pubKeyAuth).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))) return der_encoder.encode(request)
def macData(macSaltKey, data): """ @see: http://msdn.microsoft.com/en-us/library/cc241995.aspx @param macSaltKey: {str} mac key @param data: {str} data to sign @return: {str} signature """ sha1Digest = sha.new() md5Digest = md5.new() #encode length dataLength = Stream() dataLength.writeType(UInt32Le(len(data))) sha1Digest.update(macSaltKey) sha1Digest.update("\x36" * 40) sha1Digest.update(dataLength.getvalue()) sha1Digest.update(data) sha1Sig = sha1Digest.digest() md5Digest.update(macSaltKey) md5Digest.update("\x5c" * 48) md5Digest.update(sha1Sig) return md5Digest.digest()
def sendConnectResponse(self): """ @summary: Send connect response """ ccReq = gcc.writeConferenceCreateResponse(self._serverSettings) ccReqStream = Stream() ccReqStream.writeType(ccReq) tmp = (ber.writeEnumerated(0), ber.writeInteger(0), self.writeDomainParams(22, 3, 0, 0xfff8), ber.writeOctetstring(ccReqStream.getvalue())) self._transport.send((ber.writeApplicationTag(Message.MCS_TYPE_CONNECT_RESPONSE, sizeof(tmp)), tmp))
def MIC(ExportedSessionKey, negotiateMessage, challengeMessage, authenticateMessage): """ @summary: Compute MIC signature @param negotiateMessage: {NegotiateMessage} @param challengeMessage: {ChallengeMessage} @param authenticateMessage: {AuthenticateMessage} @return: {str} signature @see: https://msdn.microsoft.com/en-us/library/cc236676.aspx """ s = Stream() s.writeType((negotiateMessage, challengeMessage, authenticateMessage)) return HMAC_MD5(ExportedSessionKey, s.getvalue())
def GSS_WrapEx(self, data): """ @summary: Encrypt function for NTLMv2 security service @param data: data to encrypt @return: {str} encrypted data """ encryptedData = rc4.crypt(self._encryptHandle, data) signature = MAC(self._encryptHandle, self._signingKey, self._seqNum, data) self._seqNum += 1 s = Stream() s.writeType(signature) return s.getvalue() + encryptedData
def getTargetInfoAsAvPairArray(self): """ @summary: Parse Target info field to retrieve array of AvPair @return: {map(AvId, str)} """ result = {} s = Stream(self.getTargetInfo()) while(True): avPair = AvPair() s.readType(avPair) if avPair.AvId.value == AvId.MsvAvEOL: return result result[avPair.AvId.value] = avPair.Value.value
def writeConferenceCreateRequest(userData): """ @summary: Write conference create request structure @param userData: Settings for client @return: GCC packet """ userDataStream = Stream() userDataStream.writeType(userData) return (per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid), per.writeLength(len(userDataStream.getvalue()) + 14), per.writeChoice(0), per.writeSelection(0x08), per.writeNumericString("1", 1), per.writePadding(1), per.writeNumberOfSet(1), per.writeChoice(0xc0), per.writeOctetStream(h221_cs_key, 4), per.writeOctetStream(userDataStream.getvalue()))
def macSaltedData(macSaltKey, data, encryptionCount): """ @see: https://msdn.microsoft.com/en-us/library/cc240789.aspx @param macSaltKey: {str} mac key @param data: {str} data to sign @param encryptionCount: nb encrypted packet @return: {str} signature """ sha1Digest = sha.new() md5Digest = md5.new() #encode length dataLengthS = Stream() dataLengthS.writeType(UInt32Le(len(data))) encryptionCountS = Stream() encryptionCountS.writeType(UInt32Le(encryptionCount)) sha1Digest.update(macSaltKey) sha1Digest.update("\x36" * 40) sha1Digest.update(dataLengthS.getvalue()) sha1Digest.update(data) sha1Digest.update(encryptionCountS.getvalue()) sha1Sig = sha1Digest.digest() md5Digest.update(macSaltKey) md5Digest.update("\x5c" * 48) md5Digest.update(sha1Sig) return md5Digest.digest()
def writeConferenceCreateResponse(serverData): """ @summary: Write a conference create response packet @param serverData: Settings for server @return: gcc packet """ serverDataStream = Stream() serverDataStream.writeType(serverData) return (per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid), per.writeLength(len(serverDataStream.getvalue()) + 14), per.writeChoice(0x14), per.writeInteger16(0x79F3, 1001), per.writeInteger(1), per.writeEnumerates(0), per.writeNumberOfSet(1), per.writeChoice(0xc0), per.writeOctetStream(h221_sc_key, 4), per.writeOctetStream(serverDataStream.getvalue()))
def sendConnectInitial(self): """ @summary: Send connect initial packet client automata function """ ccReq = gcc.writeConferenceCreateRequest(self._clientSettings) ccReqStream = Stream() ccReqStream.writeType(ccReq) tmp = (ber.writeOctetstring("\x01"), ber.writeOctetstring("\x01"), ber.writeBoolean(True), self.writeDomainParams(34, 2, 0, 0xffff), self.writeDomainParams(1, 1, 1, 0x420), self.writeDomainParams(0xffff, 0xfc17, 0xffff, 0xffff), ber.writeOctetstring(ccReqStream.getvalue())) self._transport.send((ber.writeApplicationTag(Message.MCS_TYPE_CONNECT_INITIAL, sizeof(tmp)), tmp))
def readEncryptedPayload(self, s, saltedMacGeneration): """ @summary: decrypt basic RDP security payload @param s: {Stream} encrypted stream @param saltedMacGeneration: {bool} use salted mac generation @return: {Stream} decrypted """ #if update is needed if self._nbDecryptedPacket == 4096: log.debug("update decrypt key") self._currentDecrytKey = updateKey( self._initialDecrytKey, self._currentDecrytKey, self.getGCCServerSettings().SC_SECURITY.encryptionMethod.value) self._decryptRc4 = rc4.RC4Key(self._currentDecrytKey) self._nbDecryptedPacket = 0 signature = String(readLen=CallableValue(8)) encryptedPayload = String() s.readType((signature, encryptedPayload)) decrypted = rc4.crypt(self._decryptRc4, encryptedPayload.value) #ckeck signature if not saltedMacGeneration and macData( self._macKey, decrypted)[:8] != signature.value: raise InvalidExpectedDataException("bad signature") if saltedMacGeneration and macSaltedData( self._macKey, decrypted, self._nbDecryptedPacket)[:8] != signature.value: raise InvalidExpectedDataException("bad signature") #count self._nbDecryptedPacket += 1 return Stream(decrypted)
def recvConnectInitial(self, data): """ @summary: Receive MCS connect initial from client Send Connect Response Wait Erect Domain Request @param data: {Stream} """ ber.readApplicationTag(data, UInt8(Message.MCS_TYPE_CONNECT_INITIAL)) ber.readOctetString(data) ber.readOctetString(data) if not ber.readBoolean(data): log.info("invalid expected BER boolean tag") pass self.readDomainParams(data) self.readDomainParams(data) self.readDomainParams(data) self._clientSettings = gcc.readConferenceCreateRequest( Stream(ber.readOctetString(data))) if not self._clientSettings.CS_NET is None: i = 1 for channelDef in self._clientSettings.CS_NET.channelDefArray._array: self._serverSettings.SC_NET.channelIdArray._array.append( UInt16Le(i + Channel.MCS_GLOBAL_CHANNEL)) #if channel can be handle by serve add it for serverChannelDef, layer in self._virtualChannels: if channelDef.name == serverChannelDef.name: self._channels[i + Channel.MCS_GLOBAL_CHANNEL] = layer i += 1 self.sendConnectResponse() self.setNextState(self.recvErectDomainRequest)
def rec(self, event): """ @summary: save event in file @param event: {UpdateEvent} """ now = timeMs() #wrap around event message e = Event(event) #timestamp is time since last event e.timestamp.value = now - self._lastEventTimer self._lastEventTimer = now s = Stream() s.writeType(e) self._file.write(s.getvalue())
def sendConnectInitial(self): """ @summary: Send connect initial packet client automata function """ ccReq = gcc.writeConferenceCreateRequest(self._clientSettings) ccReqStream = Stream() ccReqStream.writeType(ccReq) tmp = (ber.writeOctetstring("\x01"), ber.writeOctetstring("\x01"), ber.writeBoolean(True), self.writeDomainParams(34, 2, 0, 0xffff), self.writeDomainParams(1, 1, 1, 0x420), self.writeDomainParams(0xffff, 0xfc17, 0xffff, 0xffff), ber.writeOctetstring(ccReqStream.getvalue())) self._transport.send( (ber.writeApplicationTag(Message.MCS_TYPE_CONNECT_INITIAL, sizeof(tmp)), tmp))
class FileReader(object): """ @summary: RSR File reader """ def __init__(self, f): """ @param f: {file} file pointer use to read """ self._s = Stream(f.read()) def nextEvent(self): """ @summary: read next event and return it """ if self._s.dataLen() == 0: return None e = Event() self._s.readType(e) return e
def MAC(handle, SigningKey, SeqNum, Message): """ @summary: generate signature for application message @param handle: {rc4.RC4Key} handle on crypt @param SigningKey: {str} Signing key @param SeqNum: {int} Sequence number @param Message: Message to sign @see: https://msdn.microsoft.com/en-us/library/cc422952.aspx """ signature = MessageSignatureEx() signature.SeqNum.value = SeqNum #write the SeqNum s = Stream() s.writeType(signature.SeqNum) signature.Checksum.value = rc4.crypt(handle, HMAC_MD5(SigningKey, s.getvalue() + Message)[:8]) return signature
def encodeDERTRequest(negoTypes=[], authInfo=None, pubKeyAuth=None): """ @summary: create TSRequest from list of Type @param negoTypes: {list(Type)} @param authInfo: {str} authentication info TSCredentials encrypted with authentication protocol @param pubKeyAuth: {str} public key encrypted with authentication protocol @return: {str} TRequest der encoded """ negoData = NegoData().subtype( explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)) #fill nego data tokens i = 0 for negoType in negoTypes: s = Stream() s.writeType(negoType) negoToken = NegoToken() negoToken.setComponentByPosition(0, s.getvalue()) negoData.setComponentByPosition(i, negoToken) i += 1 request = TSRequest() request.setComponentByName( "version", univ.Integer(2).subtype(explicitTag=tag.Tag( tag.tagClassContext, tag.tagFormatConstructed, 0))) if i > 0: request.setComponentByName("negoTokens", negoData) if not authInfo is None: request.setComponentByName( "authInfo", univ.OctetString(authInfo).subtype(explicitTag=tag.Tag( tag.tagClassContext, tag.tagFormatConstructed, 2))) if not pubKeyAuth is None: request.setComponentByName( "pubKeyAuth", univ.OctetString(pubKeyAuth).subtype(explicitTag=tag.Tag( tag.tagClassContext, tag.tagFormatConstructed, 3))) return der_encoder.encode(request)
def getAuthenticateMessage(self, challenge, authMessage): """ @summary: Client last handshake message @param s: {Stream} challenge message stream @return: {(AuthenticateMessage, NTLMv2SecurityInterface)} Last handshake message and security interface use to encrypt @see: https://msdn.microsoft.com/en-us/library/cc236676.aspx """ self._challengeMessage = ChallengeMessage() challenge.readType(self._challengeMessage) ServerChallenge = self._challengeMessage.ServerChallenge.value ClientChallenge = random(64) computeMIC = False ServerName = self._challengeMessage.getTargetInfo() infos = self._challengeMessage.getTargetInfoAsAvPairArray() if infos.has_key(AvId.MsvAvTimestamp): Timestamp = infos[AvId.MsvAvTimestamp] computeMIC = False else: Timestamp = CurrentFileTimes() NtChallengeResponse, LmChallengeResponse, SessionBaseKey = ComputeResponsev2( self._ResponseKeyNT, self._ResponseKeyLM, ServerChallenge, ClientChallenge, Timestamp, ServerName) KeyExchangeKey = KXKEYv2(SessionBaseKey, LmChallengeResponse, ServerChallenge) ExportedSessionKey = random(128) EncryptedRandomSessionKey = RC4K(KeyExchangeKey, ExportedSessionKey) domain, user = self._domain, self._user if self._challengeMessage.NegotiateFlags.value & Negotiate.NTLMSSP_NEGOTIATE_UNICODE: self._enableUnicode = True domain, user = UNICODE(domain), UNICODE(user) self._authenticateMessage = AuthenticateMessage() ss = Stream(type.String(authMessage)) self._authenticateMessage.read(ss) if computeMIC: self._authenticateMessage.MIC.value = MIC( ExportedSessionKey, self._negotiateMessage, self._challengeMessage, self._authenticateMessage) else: self._authenticateMessage.MIC._conditional = lambda: False ClientSigningKey = SIGNKEY(ExportedSessionKey, True) ServerSigningKey = SIGNKEY(ExportedSessionKey, False) ClientSealingKey = SEALKEY(ExportedSessionKey, True) ServerSealingKey = SEALKEY(ExportedSessionKey, False) interface = NTLMv2SecurityInterface(rc4.RC4Key(ClientSealingKey), rc4.RC4Key(ServerSealingKey), ClientSigningKey, ServerSigningKey) return self._authenticateMessage, interface
def sendClientNewLicenseRequest(self, licenseRequest): """ @summary: Create new license request in response to server license request @param licenseRequest: {ServerLicenseRequest} @see: http://msdn.microsoft.com/en-us/library/cc241989.aspx @see: http://msdn.microsoft.com/en-us/library/cc241918.aspx """ #get server information serverRandom = licenseRequest.serverRandom.value if self._transport.getGCCServerSettings( ).SC_SECURITY.serverCertificate._is_readed: serverCertificate = self._transport.getGCCServerSettings( ).SC_SECURITY.serverCertificate else: s = Stream(licenseRequest.serverCertificate.blobData.value) serverCertificate = gcc.ServerCertificate() s.readType(serverCertificate) #generate crypto values clientRandom = rsa.random(256) preMasterSecret = rsa.random(384) masterSecret = sec.masterSecret(preMasterSecret, clientRandom, serverRandom) sessionKeyBlob = sec.masterSecret(masterSecret, serverRandom, clientRandom) self._macSalt = sessionKeyBlob[:16] self._licenseKey = sec.finalHash(sessionKeyBlob[16:32], clientRandom, serverRandom) #format message message = ClientNewLicenseRequest() message.clientRandom.value = clientRandom message.encryptedPreMasterSecret.blobData.value = rsa.encrypt( preMasterSecret[::-1], serverCertificate.certData.getPublicKey())[::-1] + "\x00" * 8 message.ClientMachineName.blobData.value = self._hostname + "\x00" message.ClientUserName.blobData.value = self._username + "\x00" self._transport.sendFlagged(sec.SecurityFlag.SEC_LICENSE_PKT, LicPacket(message))
def writeEncryptedPayload(self, data, saltedMacGeneration): """ @summary: sign and crypt data @param data: {Type} raw stream @param saltedMacGeneration: {bool} use salted mac generation @return: {Tuple} (signature, encryptedData) """ if self._nbEncryptedPacket == 4096: log.debug("update encrypt key") self._currentEncryptKey = updateKey( self._initialEncryptKey, self._currentEncryptKey, self.getGCCServerSettings().SC_SECURITY.encryptionMethod.value) self._encryptRc4 = rc4.RC4Key(self._currentEncryptKey) self._nbEncryptedPacket = 0 self._nbEncryptedPacket += 1 s = Stream() s.writeType(data) if saltedMacGeneration: return (String(macSaltedData(self._macKey, s.getvalue(), self._nbEncryptedPacket - 1)[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue()))) else: return (String(macData(self._macKey, s.getvalue())[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue())))
def sendClientChallengeResponse(self, platformChallenge): """ @summary: generate valid challenge response @param platformChallenge: {ServerPlatformChallenge} """ serverEncryptedChallenge = platformChallenge.encryptedPlatformChallenge.blobData.value #decrypt server challenge #it should be TEST word in unicode format serverChallenge = rc4.crypt(rc4.RC4Key(self._licenseKey), serverEncryptedChallenge) if serverChallenge != "T\x00E\x00S\x00T\x00\x00\x00": raise InvalidExpectedDataException("bad license server challenge") #generate hwid s = Stream() s.writeType((UInt32Le(2), String(self._hostname + self._username + "\x00" * 16))) hwid = s.getvalue()[:20] message = ClientPLatformChallengeResponse() message.encryptedPlatformChallengeResponse.blobData.value = serverEncryptedChallenge message.encryptedHWID.blobData.value = rc4.crypt(rc4.RC4Key(self._licenseKey), hwid) message.MACData.value = sec.macData(self._macSalt, serverChallenge + hwid) self._transport.sendFlagged(sec.SecurityFlag.SEC_LICENSE_PKT, LicPacket(message))
def dataReceived(self, data): """ @summary: Inherit from twisted.protocol class main event of received data @param data: string data receive from twisted """ #add in buffer self._buffer += data #while buffer have expected size call local callback while self._expectedLen > 0 and len(self._buffer) >= self._expectedLen: #expected data is first expected bytes expectedData = Stream(self._buffer[0:self._expectedLen]) #rest is for next event of automata self._buffer = self._buffer[self._expectedLen:] #call recv function self.recv(expectedData)
def GSS_UnWrapEx(self, data): """ @summary: decrypt data with key exchange in Authentication protocol @param data: {str} """ signature = MessageSignatureEx() message = String() s = Stream(data) s.readType((signature, message)) #decrypt message plaintextMessage = rc4.crypt(self._decryptHandle, message.value) checksum = rc4.crypt(self._decryptHandle, signature.Checksum.value) #recompute checksum t = Stream() t.writeType(signature.SeqNum) verify = HMAC_MD5(self._verifyKey, t.getvalue() + plaintextMessage)[:8] if verify != checksum: raise error.InvalidExpectedDataException("NTLMv2SecurityInterface : Invalid checksum") return plaintextMessage
def writeEncryptedPayload(self, data): """ @summary: sign and crypt data @param s: {Stream} raw stream @return: {Tuple} (signature, encryptedData) """ if self._nbEncryptedPacket == 4096: log.debug("update encrypt key") self._currentEncryptKey = updateKey( self._initialEncryptKey, self._currentEncryptKey, self.getGCCServerSettings().SC_SECURITY.encryptionMethod.value) self._encryptRc4 = rc4.RC4Key(self._currentEncryptKey) self._nbEncryptedPacket = 0 self._nbEncryptedPacket += 1 s = Stream() s.writeType(data) return (String(macData(self._macKey, s.getvalue())[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue())))
def writeEncryptedPayload(self, data, saltedMacGeneration): """ @summary: sign and crypt data @param data: {Type} raw stream @param saltedMacGeneration: {bool} use salted mac generation @return: {Tuple} (signature, encryptedData) """ if self._nbEncryptedPacket == 4096: log.debug("update encrypt key") self._currentEncryptKey = updateKey( self._initialEncryptKey, self._currentEncryptKey, self.getGCCServerSettings().SC_SECURITY.encryptionMethod.value) self._encryptRc4 = rc4.RC4Key(self._currentEncryptKey) self._nbEncryptedPacket = 0 self._nbEncryptedPacket += 1 self._nbEncMacCount += 1 s = Stream() s.writeType(data) if saltedMacGeneration: return (String(macSaltedData(self._macKey, s.getvalue(), self._nbEncMacCount - 1)[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue()))) else: return (String(macData(self._macKey, s.getvalue())[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue())))
def computeSignatureHash(self): """ @summary: compute hash """ s = Stream() s.writeType(UInt32Le(self.__class__._TYPE_)) s.writeType(self.dwSigAlgId) s.writeType(self.dwKeyAlgId) s.writeType(self.wPublicKeyBlobType) s.writeType(self.wPublicKeyBlobLen) s.writeType(self.PublicKeyBlob) md5Digest = md5.new() md5Digest.update(s.getvalue()) return md5Digest.digest() + "\x00" + "\xff" * 45 + "\x01"
def __init__(self, f): """ @param f: {file} file pointer use to read """ self._s = Stream(f.read())
def getNegoTokens(tRequest): negoData = tRequest.getComponentByName("negoTokens") return [Stream(negoData.getComponentByPosition(i).getComponentByPosition(0).asOctets()) for i in range(len(negoData))]