I am working on implementing the MSNP15 protocol in Python. I have verified that my hashing and encryption functions are working (or at least, they match up with examples I found online), however I am always receiving a 911 error back from the server.
Thanks for any help.
Python code is as follows;
msntest.py:
import socket
import httplib
from encryption import GetSSOTicket
username = "[email protected]"
password = "password"
def ReadAll(sock):
data = ""
while 1:
try:
r = sock.recv(4096)
data += r
except socket.timeout:
break
return data
def SOAPRequest(xml):
url = "login.live.com"
con = httplib.HTTPSConnection(url)
headers = {"Host": "login.live.com",
"Accept": "text/plain"}
con.request("POST", "/RST.srf", xml, headers)
response = con.getresponse().read()
con.close()
return response
def GetTicket(policy, nonce):
xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
xml += "<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\"><Header>";
xml += "<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">";
xml += "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>";
xml += "<ps:BinaryVersion>4</ps:BinaryVersion>";
xml += "<ps:UIVersion>1</ps:UIVersion>";
xml += "<ps:Cookies></ps:Cookies>";
xml += "<ps:RequestParams>AQAAAAIAAABsYwQAAAAxMDMz</ps:RequestParams>";
xml += "</ps:AuthInfo>";
xml += "<wsse:Security><wsse:UsernameToken Id=\"user\">";
xml += "<wsse:Username>" + username + "</wsse:Username>";
xml += "<wsse:Password>" + password + "</wsse:Password>";
xml += "</wsse:UsernameToken></wsse:Security></Header><Body>";
xml += "<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">";
xml += "<wst:RequestSecurityToken Id=\"RST0\">";
xml += "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>";
xml += "<wsp:AppliesTo><wsa:EndpointReference><wsa:Address>http://Passport.NET/tb";
xml += "</wsa:Address></wsa:EndpointReference></wsp:AppliesTo></wst:RequestSecurityToken>";
xml += "<wst:RequestSecurityToken Id=\"RST1\">";
xml += "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType><wsp:AppliesTo><wsa:EndpointReference>";
xml += "<wsa:Address>messengerclear.live.com</wsa:Address></wsa:EndpointReference></wsp:AppliesTo>";
xml += "<wsse:PolicyReference URI=\"" + policy + "\"></wsse:PolicyReference></wst:RequestSecurityToken>";
xml += "<wst:RequestSecurityToken Id=\"RST2\">";
xml += "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>";
xml += "<wsp:AppliesTo>";
xml += "<wsa:EndpointReference>";
xml += "<wsa:Address>contacts.msn.com</wsa:Address>";
xml += "</wsa:EndpointReference>";
xml += "</wsp:AppliesTo>";
xml += "<wsse:PolicyReference URI=\"MBI\">";
xml += "</wsse:PolicyReference>";
xml += "</wst:RequestSecurityToken>";
xml += "</ps:RequestMultipleSecurityTokens></Body></Envelope>";
xmlDoc = SOAPRequest(xml)
start = xmlDoc.find("<wst:BinarySecret>")+len("<wst:BinarySecret>")
end = xmlDoc.find("</wst:BinarySecret>")
secret = xmlDoc[start:end]
print "secret:"
print secret
start = xmlDoc.find('<wsse:BinarySecurityToken Id="Compact1">')+len('<wsse:BinarySecurityToken Id="Compact1">')
end = xmlDoc.find("</wsse:BinarySecurityToken>")
ticket = xmlDoc[start:end].replace("&", "&")
SSOTicket = GetSSOTicket(secret, nonce)
return ticket + " " + SSOTicket
def LogIntoNS():
address = ("64.4.61.219", 1863)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(address)
s.settimeout(3)
s.send("VER 1 MSNP15 CVR0\r\n")
ReadAll(s)
s.send("CVR 2 0x0407 win 6.0 i386 MSNMSGR 8.5 MSMSGS " + username + "\r\n")
ReadAll(s)
s.send("USR 3 SSO I " + username + "\r\n")
recvbuf = ReadAll(s)
recvbuf = recvbuf[recvbuf.find("USR"):]
policy = recvbuf.split()[4]
print "policy:"
print policy
nonce = recvbuf.split()[5]
print "nonce:"
print nonce
ticket = GetTicket(policy, nonce)
print "ticket:"
print ticket
s.send("USR 4 SSO S " + ticket + "\r\n")
print "Sent"
print s.recv(4096)
LogIntoNS()
encryption.py:
import hashlib, hmac
import base64
import pyDes
def Combine(a, b):
aBytes = bytes(a)
bBytes = bytes(b)
combinedBytes = aBytes + bBytes
return combinedBytes
def DeriveKey(key, magic):
hash1 = hmac.new(key, magic, hashlib.sha1).digest()
combined = str(Combine(hash1, magic))
hash2 = hmac.new(key, combined, hashlib.sha1).digest()
hash3 = hmac.new(key, hash1, hashlib.sha1).digest()
combined = str(Combine(hash3, magic))
hash4 = hmac.new(key, combined, hashlib.sha1).digest()
retKey = str(Combine(hash2, hash4[:4]))
return retKey
def GetBeginning():
Beginning = [chr(0)]*28
# StructHeaderSize = 28
Beginning[0] = 0x1c
Beginning[1] = 0x00
Beginning[2] = 0x00
Beginning[3] = 0x00
# CryptMode = 1
Beginning[4] = 0x01
Beginning[5] = 0x00
Beginning[6] = 0x00
Beginning[7] = 0x00
# CipherType = 0x6603
Beginning[8] = 0x03
Beginning[9] = 0x66
Beginning[10] = 0x00
Beginning[11] = 0x00
# HashType = 0x8004
Beginning[12] = 0x04
Beginning[13] = 0x80
Beginning[14] = 0x00
Beginning[15] = 0x00
# IV length = 8
Beginning[16] = 0x08
Beginning[17] = 0x00
Beginning[18] = 0x00
Beginning[19] = 0x00
# hash length = 20
Beginning[20] = 0x14
Beginning[21] = 0x00
Beginning[22] = 0x00
Beginning[23] = 0x00
# cipher length = 72
Beginning[24] = 0x48
Beginning[25] = 0x00
Beginning[26] = 0x00
Beginning[27] = 0x00
asd = "".join([chr(x) for x in Beginning])
return asd
def GetSSOTicket(key, nonce):
key1 = base64.b64decode(key)
key2 = DeriveKey(key1, "WS-SecureConversationSESSION KEY HASH")
key3 = DeriveKey(key1, "WS-SecureConversationSESSION KEY ENCRYPTION")
nonceHash = hmac.new(key2, nonce, hashlib.sha1).digest()
iv = [chr(0)]*8
iv[0] = 0x75
iv[1] = 0x95
iv[2] = 0x85
iv[3] = 0x61
iv[4] = 0x38
iv[5] = 0x85
iv[6] = 0xEF
iv[7] = 0x5C
iv = "".join([chr(x) for x in iv])
encryptor = pyDes.triple_des(key3, pyDes.CBC, iv)
restOfNonce = chr(0x08) * 8
fullNonce = Combine(nonce, restOfNonce)
output = encryptor.encrypt(fullNonce)
beginning = GetBeginning()
struc = beginning + iv + nonceHash + output
value = base64.b64encode(struc)
return value
Modified your msntest.py a little and now it should work: