summaryrefslogtreecommitdiff
path: root/protocols/MSN/src/skylogin/login.c
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/MSN/src/skylogin/login.c')
-rw-r--r--protocols/MSN/src/skylogin/login.c414
1 files changed, 414 insertions, 0 deletions
diff --git a/protocols/MSN/src/skylogin/login.c b/protocols/MSN/src/skylogin/login.c
new file mode 100644
index 0000000000..6e6856ad8e
--- /dev/null
+++ b/protocols/MSN/src/skylogin/login.c
@@ -0,0 +1,414 @@
+/*
+ * Skype Login
+ *
+ * Based on:
+ * FakeSkype : Skype reverse engineering proof-of-concept client
+ * Ouanilo MEDEGAN (c) 2006 http://www.oklabs.net
+ * pyskype : Skype login Python script by uunicorn
+ *
+ * Written by: leecher@dose.0wnz.at (c) 2015
+ *
+ * Module: Skype server login
+ *
+ */
+#include "common.h"
+#include "objects.h"
+#include "random.h"
+#include "platform.h"
+#include "crc.h"
+#ifdef _DEBUG
+#include <time.h>
+#endif
+
+#ifdef USE_RC4
+#include "rc4comm.c"
+#else
+#define RC4Comm_Init(conn) 0
+#define RC4Comm_Send(conn,buf,len) send(conn->LSSock,buf,len,0)
+#define RC4Comm_Recv(conn,buf,len) recv(conn->LSSock,buf,len,0)
+#endif
+
+static Host LoginServers[] = {
+ {"91.190.216.17", 33033},
+ {"91.190.218.40", 33033},
+};
+
+static BOOL SendHandShake2LS(LSConnection *pConn, Host *CurLS)
+{
+ uchar HandShakePkt[HANDSHAKE_SZ] = {0};
+ HttpsPacketHeader *HSHeader, Response;
+ struct sockaddr_in Sender={0};
+
+ HSHeader = (HttpsPacketHeader *)HandShakePkt;
+ memcpy(HSHeader->MAGIC, HTTPS_HSR_MAGIC, sizeof(HSHeader->MAGIC));
+ HSHeader->ResponseLen = 0;
+ DBGPRINT("Sending Handshake to Login Server %s..\n", CurLS->ip);
+ Sender.sin_family = AF_INET;
+ Sender.sin_port = htons((short)CurLS->port);
+ Sender.sin_addr.s_addr = inet_addr(CurLS->ip);
+ if (connect(pConn->LSSock, (struct sockaddr *)&Sender, sizeof(Sender)) < 0)
+ {
+ DBGPRINT("Connection refused..\n");
+ return FALSE;
+ }
+ if (RC4Comm_Init(pConn) < 0 ||
+ RC4Comm_Send(pConn, (const char *)HandShakePkt, HANDSHAKE_SZ)<=0 ||
+ RC4Comm_Recv(pConn, (char*)&Response, sizeof(Response))<=0 ||
+ memcmp(Response.MAGIC, HTTPS_HSRR_MAGIC, sizeof(Response.MAGIC)))
+ return FALSE;
+ return TRUE;
+}
+
+/* If Pass is NULL, User is assumed to be OAuth string and OAuth logon is performed */
+static int SendAuthentificationBlobLS(Skype_Inst *pInst, LSConnection *pConn, const char *User, const char *Pass)
+{
+ int64_t PlatForm;
+ uchar AuthBlob[0xFFFF] = {0};
+ uchar SHAResult[32] = {0};
+ uchar Modulus[MODULUS_SZ * 2] = {0};
+ uchar ivec[AES_BLOCK_SIZE] = {0};
+ uchar ecount_buf[AES_BLOCK_SIZE] = {0};
+ uint MiscDatas[0x05] = {0};
+ uchar SessionKey[SK_SZ];
+ uchar *Browser;
+ uchar *Mark;
+ uchar *MarkObjL;
+ uint Idx, Size, Crc, BSize, ret = 0;
+ HttpsPacketHeader *HSHeader;
+ uchar HSHeaderBuf[sizeof(HttpsPacketHeader)], RecvBuf[0x1000];
+ AES_KEY AesKey;
+ MD5_CTX Context;
+ RSA *SkypeRSA;
+ ObjectDesc Obj2000, ObjSessionKey, ObjZBool1, ObjRequestCode, ObjZBool2, ObjModulus, ObjPlatForm, ObjLang, ObjMiscDatas, ObjVer, ObjPubAddr;
+ SResponse Response={0};
+
+
+ if (!pInst->LoginD.RSAKeys)
+ {
+ BIGNUM *KeyExp;
+
+ DBGPRINT("Generating RSA Keys Pair (Size = %d Bits)..\n", KEYSZ);
+ pInst->LoginD.RSAKeys = RSA_new();
+ KeyExp = BN_new();
+ BN_set_word(KeyExp, RSA_F4);
+ Idx = RSA_generate_key_ex(pInst->LoginD.RSAKeys, KEYSZ * 2, KeyExp, NULL);
+ BN_free(KeyExp);
+ if (Idx == -1)
+ {
+ DBGPRINT("Error generating Keys..\n\n");
+ RSA_free(pInst->LoginD.RSAKeys);
+ pInst->LoginD.RSAKeys = NULL;
+ return (0);
+ }
+ }
+
+ Idx = BN_bn2bin(pInst->LoginD.RSAKeys->n, Modulus);
+ Idx = BN_bn2bin(pInst->LoginD.RSAKeys->d, Modulus + Idx);
+
+ Browser = AuthBlob;
+
+ HSHeader = (HttpsPacketHeader *)Browser;
+ memcpy(HSHeader->MAGIC, HTTPS_HSR_MAGIC, sizeof(HSHeader->MAGIC));
+ HSHeader->ResponseLen = htons(0xCD);
+ Browser += sizeof(HttpsPacketHeader);
+
+ *Browser++ = RAW_PARAMS;
+ *Browser++ = 0x03;
+
+ Obj2000.Family = OBJ_FAMILY_NBR;
+ Obj2000.Id = OBJ_ID_2000;
+ Obj2000.Value.Nbr = 0x2000;
+ WriteObject(&Browser, Obj2000);
+
+ SpecialSHA(pInst->SessionKey, SK_SZ, SHAResult, 32);
+ AES_set_encrypt_key(SHAResult, 256, &AesKey);
+
+ SkypeRSA = RSA_new();
+ BN_hex2bn(&(SkypeRSA->n), SkypeModulus1536[1]);
+ BN_hex2bn(&(SkypeRSA->e), "010001");
+ Idx = RSA_public_encrypt(SK_SZ, pInst->SessionKey, SessionKey, SkypeRSA, RSA_NO_PADDING);
+ RSA_free(SkypeRSA);
+ if (Idx < 0)
+ {
+ DBGPRINT("RSA_public_encrypt failed..\n\n");
+ return (0);
+ }
+
+ ObjSessionKey.Family = OBJ_FAMILY_BLOB;
+ ObjSessionKey.Id = OBJ_ID_SK;
+ ObjSessionKey.Value.Memory.Memory = (uchar *)&SessionKey;
+ ObjSessionKey.Value.Memory.MsZ = SK_SZ;
+ WriteObject(&Browser, ObjSessionKey);
+
+ ObjZBool1.Family = OBJ_FAMILY_NBR;
+ ObjZBool1.Id = OBJ_ID_ZBOOL1;
+ ObjZBool1.Value.Nbr = 0x01;
+ WriteObject(&Browser, ObjZBool1);
+
+ Mark = Browser;
+ HSHeader = (HttpsPacketHeader *)Browser;
+ memcpy(HSHeader->MAGIC, HTTPS_HSRR_MAGIC, sizeof(HSHeader->MAGIC));
+ HSHeader->ResponseLen = 0x00;
+ Browser += sizeof(HttpsPacketHeader);
+
+ MarkObjL = Browser;
+ if (Pass)
+ {
+ ObjectDesc ObjUserName, ObjSharedSecret;
+
+ *Browser++ = RAW_PARAMS;
+ *Browser++ = 0x04;
+
+ ObjRequestCode.Family = OBJ_FAMILY_NBR;
+ ObjRequestCode.Id = OBJ_ID_REQCODE;
+ ObjRequestCode.Value.Nbr = 0x1399;
+ WriteObject(&Browser, ObjRequestCode);
+
+ ObjZBool2.Family = OBJ_FAMILY_NBR;
+ ObjZBool2.Id = OBJ_ID_ZBOOL2;
+ ObjZBool2.Value.Nbr = 0x01;
+ WriteObject(&Browser, ObjZBool2);
+
+ ObjUserName.Family = OBJ_FAMILY_STRING;
+ ObjUserName.Id = OBJ_ID_USERNAME;
+ ObjUserName.Value.Memory.Memory = (uchar *)User;
+ ObjUserName.Value.Memory.MsZ = (uchar)strlen(User);
+ WriteObject(&Browser, ObjUserName);
+
+ MD5_Init(&Context);
+ MD5_Update(&Context, User, (ulong)strlen(User));
+ MD5_Update(&Context, CONCAT_SALT, (ulong)strlen(CONCAT_SALT));
+ MD5_Update(&Context, Pass, (ulong)strlen(Pass));
+ MD5_Final(pInst->LoginD.LoginHash, &Context);
+
+ ObjSharedSecret.Family = OBJ_FAMILY_BLOB;
+ ObjSharedSecret.Id = OBJ_ID_USERPASS;
+ ObjSharedSecret.Value.Memory.Memory = (uchar *)pInst->LoginD.LoginHash;
+ ObjSharedSecret.Value.Memory.MsZ = MD5_DIGEST_LENGTH;
+ WriteObject(&Browser, ObjSharedSecret);
+
+ *Browser++ = RAW_PARAMS;
+ *Browser++ = 0x06;
+
+ ObjModulus.Family = OBJ_FAMILY_BLOB;
+ ObjModulus.Id = OBJ_ID_MODULUS;
+ ObjModulus.Value.Memory.Memory = (uchar *)Modulus;
+ ObjModulus.Value.Memory.MsZ = MODULUS_SZ;
+ WriteObject(&Browser, ObjModulus);
+
+ PlatForm = PlatFormSpecific();
+
+ ObjPlatForm.Family = OBJ_FAMILY_TABLE;
+ ObjPlatForm.Id = OBJ_ID_PLATFORM;
+ memcpy(ObjPlatForm.Value.Table, (uchar *)&PlatForm, sizeof(ObjPlatForm.Value.Table));
+ WriteObject(&Browser, ObjPlatForm);
+
+ ObjLang.Family = OBJ_FAMILY_STRING;
+ ObjLang.Id = OBJ_ID_LANG;
+ ObjLang.Value.Memory.Memory = pInst->Language;
+ ObjLang.Value.Memory.MsZ = sizeof(pInst->Language);
+ WriteObject(&Browser, ObjLang);
+
+ FillMiscDatas(pInst, MiscDatas);
+ ObjMiscDatas.Family = OBJ_FAMILY_INTLIST;
+ ObjMiscDatas.Id = OBJ_ID_MISCD;
+ ObjMiscDatas.Value.Memory.Memory = (uchar *)MiscDatas;
+ ObjMiscDatas.Value.Memory.MsZ = 0x05;
+ WriteObject(&Browser, ObjMiscDatas);
+
+ ObjVer.Family = OBJ_FAMILY_STRING;
+ ObjVer.Id = OBJ_ID_VERSION;
+ ObjVer.Value.Memory.Memory = (uchar *)VER_STR;
+ ObjVer.Value.Memory.MsZ = (uchar)strlen(VER_STR);
+ WriteObject(&Browser, ObjVer);
+
+ ObjPubAddr.Family = OBJ_FAMILY_NBR;
+ ObjPubAddr.Id = OBJ_ID_PUBADDR;
+ ObjPubAddr.Value.Nbr = pInst->PublicIP;
+ WriteObject(&Browser, ObjPubAddr);
+ }
+ else
+ {
+ int64_t PartnerId = 999;
+ ObjectDesc ObjPartnerId, ObjOauth;
+
+ // OAuth logon
+ *Browser++ = RAW_PARAMS;
+ *Browser++ = 0x02;
+
+ ObjRequestCode.Family = OBJ_FAMILY_NBR;
+ ObjRequestCode.Id = OBJ_ID_REQCODE;
+ ObjRequestCode.Value.Nbr = 0x13a3;
+ WriteObject(&Browser, ObjRequestCode);
+
+ ObjZBool2.Family = OBJ_FAMILY_NBR;
+ ObjZBool2.Id = OBJ_ID_ZBOOL2;
+ ObjZBool2.Value.Nbr = 0x3d;
+ WriteObject(&Browser, ObjZBool2);
+
+ *Browser++ = RAW_PARAMS;
+ *Browser++ = 0x08;
+
+ ObjModulus.Family = OBJ_FAMILY_BLOB;
+ ObjModulus.Id = OBJ_ID_MODULUS;
+ ObjModulus.Value.Memory.Memory = (uchar *)Modulus;
+ ObjModulus.Value.Memory.MsZ = MODULUS_SZ;
+ WriteObject(&Browser, ObjModulus);
+
+ PlatForm = PlatFormSpecific();
+
+ ObjPlatForm.Family = OBJ_FAMILY_TABLE;
+ ObjPlatForm.Id = OBJ_ID_PLATFORM;
+ memcpy(ObjPlatForm.Value.Table, (uchar *)&PlatForm, sizeof(ObjPlatForm.Value.Table));
+ WriteObject(&Browser, ObjPlatForm);
+
+ FillMiscDatas(pInst, MiscDatas);
+ ObjMiscDatas.Family = OBJ_FAMILY_INTLIST;
+ ObjMiscDatas.Id = OBJ_ID_MISCD;
+ ObjMiscDatas.Value.Memory.Memory = (uchar *)MiscDatas;
+ ObjMiscDatas.Value.Memory.MsZ = 0x05;
+ WriteObject(&Browser, ObjMiscDatas);
+
+ ObjLang.Family = OBJ_FAMILY_STRING;
+ ObjLang.Id = OBJ_ID_LANG;
+ ObjLang.Value.Memory.Memory = pInst->Language;
+ ObjLang.Value.Memory.MsZ = sizeof(pInst->Language);
+ WriteObject(&Browser, ObjLang);
+
+ ObjPartnerId.Family = OBJ_FAMILY_TABLE;
+ ObjPlatForm.Id = OBJ_ID_PARTNERID;
+ memcpy(ObjPlatForm.Value.Table, (uchar *)&PartnerId, sizeof(ObjPlatForm.Value.Table));
+ WriteObject(&Browser, ObjPlatForm);
+
+ ObjOauth.Family = OBJ_FAMILY_STRING;
+ ObjOauth.Id = OBJ_ID_OAUTH;
+ ObjOauth.Value.Memory.Memory = (uchar *)User;
+ ObjOauth.Value.Memory.MsZ = strlen(User);
+ WriteObject(&Browser, ObjOauth);
+
+ ObjVer.Family = OBJ_FAMILY_STRING;
+ ObjVer.Id = OBJ_ID_VERSION;
+ ObjVer.Value.Memory.Memory = (uchar *)VER_STR;
+ ObjVer.Value.Memory.MsZ = (uchar)strlen(VER_STR);
+ WriteObject(&Browser, ObjVer);
+
+ ObjPubAddr.Family = OBJ_FAMILY_NBR;
+ ObjPubAddr.Id = OBJ_ID_PUBADDR;
+ ObjPubAddr.Value.Nbr = pInst->PublicIP;
+ WriteObject(&Browser, ObjPubAddr);
+ }
+
+ Size = (uint)(Browser - MarkObjL);
+ HSHeader->ResponseLen = htons((u_short)(Size + 0x02));
+
+ Idx = 0;
+ memset(ivec, 0, AES_BLOCK_SIZE);
+ memset(ecount_buf, 0, AES_BLOCK_SIZE);
+ AES_ctr128_encrypt(MarkObjL, MarkObjL, Size, &AesKey, ivec, ecount_buf, &Idx);
+
+ Crc = crc32(MarkObjL, Size, -1);
+ *Browser++ = *((uchar *)(&Crc) + 0);
+ *Browser++ = *((uchar *)(&Crc) + 1);
+
+ Size = (uint)(Browser - AuthBlob);
+
+ if (RC4Comm_Send(pConn, (const char *)AuthBlob, Size)<=0)
+ {
+ DBGPRINT("Sending to LS failed :'(..\n");
+ return (-1);
+ }
+
+ while (!ret && RC4Comm_Recv(pConn, (char *)&HSHeaderBuf, sizeof(HSHeaderBuf))>0)
+ {
+ HSHeader = (HttpsPacketHeader *)HSHeaderBuf;
+ if (strncmp((const char *)HSHeader->MAGIC, HTTPS_HSRR_MAGIC, strlen(HTTPS_HSRR_MAGIC)) ||
+ RC4Comm_Recv(pConn, (char *)RecvBuf, (BSize=htons(HSHeader->ResponseLen)))<=0)
+ {
+ DBGPRINT("Bad Response..\n");
+ return (-2);
+ }
+ DBGPRINT("Auth Response Got..\n\n");
+
+ Idx = 0;
+ memset(ivec, 0, AES_BLOCK_SIZE);
+ memset(ecount_buf, 0, AES_BLOCK_SIZE);
+ BSize-=2;
+ ivec[3] = 0x01;
+ ivec[7] = 0x01;
+ AES_ctr128_encrypt(RecvBuf, RecvBuf, BSize, &AesKey, ivec, ecount_buf, &Idx);
+
+ Browser = RecvBuf;
+ while (Browser<RecvBuf+BSize)
+ ManageObjects(&Browser, BSize, &Response);
+ for (Idx = 0; Idx < Response.NbObj; Idx++)
+ {
+ uint LdIdx = 0;
+
+
+ switch (Response.Objs[Idx].Id)
+ {
+ case OBJ_ID_LOGINANSWER:
+ switch (Response.Objs[Idx].Value.Nbr)
+ {
+ case LOGIN_OK:
+ DBGPRINT("Login Successful..\n");
+ ret = 1;
+ break;
+ default :
+ DBGPRINT("Login Failed.. Bad Credentials..\n");
+ FreeResponse(&Response);
+ return 0;
+ }
+ break;
+ case OBJ_ID_CIPHERDLOGD:
+ if (pInst->LoginD.SignedCredentials.Memory) free(pInst->LoginD.SignedCredentials.Memory);
+ if (!(pInst->LoginD.SignedCredentials.Memory = malloc(Response.Objs[Idx].Value.Memory.MsZ)))
+ {
+ FreeResponse(&Response);
+ return -2;
+ }
+ memcpy (pInst->LoginD.SignedCredentials.Memory, Response.Objs[Idx].Value.Memory.Memory,
+ (pInst->LoginD.SignedCredentials.MsZ = Response.Objs[Idx].Value.Memory.MsZ));
+ break;
+ }
+ }
+ FreeResponse(&Response);
+ }
+
+ return ret;
+}
+
+
+int PerformLogin(Skype_Inst *pInst, const char *User, const char *Pass)
+{
+ uint ReUse = 1;
+ int i;
+ LSConnection conn={0};
+ int iRet = 0;
+
+ for (i=0; !iRet && i<sizeof(LoginServers)/sizeof(LoginServers[0]); i++)
+ {
+ conn.LSSock = socket(AF_INET, SOCK_STREAM, 0);
+ setsockopt(conn.LSSock, SOL_SOCKET, SO_REUSEADDR, (const char *)&ReUse, sizeof(ReUse));
+
+ if (SendHandShake2LS(&conn, &LoginServers[i]))
+ {
+ DBGPRINT("Login Server %s OK ! Let's authenticate..\n", LoginServers[i].ip);
+ iRet = SendAuthentificationBlobLS(pInst, &conn, User, Pass);
+ }
+ closesocket(conn.LSSock);
+ }
+
+ if (!iRet) DBGPRINT("Login Failed..\n");
+ return iRet;
+}
+
+
+void InitInstance(Skype_Inst *pInst)
+{
+ memset(pInst, 0, sizeof(Skype_Inst));
+ GenSessionKey(pInst->SessionKey, sizeof(pInst->SessionKey));
+ InitNodeId(pInst);
+ memcpy(pInst->Language, "en", 2);
+ pInst->PublicIP = 0x7F000001; // 127.0.0.1, we could use hostscan to get real IP, but not necessary for just login
+}