/* * 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 #include #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(Skype_Inst *pInst, 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; pInst->pfLog(pInst->pLogStream, "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) { pInst->pfLog(pInst->pLogStream, "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; pInst->pfLog(pInst->pLogStream, "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) { pInst->pfLog(pInst->pLogStream, "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) { pInst->pfLog(pInst->pLogStream, "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) { pInst->pfLog(pInst->pLogStream, "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) { pInst->pfLog(pInst->pLogStream, "Bad Response..\n"); return (-2); } pInst->pfLog(pInst->pLogStream, "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 (BrowserpfLog(pInst->pLogStream, "Login Successful..\n"); ret = 1; break; default : pInst->pfLog(pInst->pLogStream, "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 && ipfLog(pInst->pLogStream, "Login Server %s OK ! Let's authenticate..\n", LoginServers[i].ip); iRet = SendAuthentificationBlobLS(pInst, &conn, User, Pass); } closesocket(conn.LSSock); } if (!iRet) pInst->pfLog(pInst->pLogStream, "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 #ifdef DEBUG pInst->pfLog = (int (__cdecl *)(void *, const char *, ...))fprintf; pInst->pLogStream = stdout; #endif }