// // Created by wolverindev on 08.10.17. // #include #include #include #include "Connection.h" #include "misc/base64.h" #include "misc/endianness.h" using namespace std; using namespace std::chrono; using namespace ts; using namespace ts::connection; using namespace ts::protocol; const int InitVersionLength = 4; const uint8_t InitVersion[InitVersionLength] = {0x09, 0x83, 0x8C, 0xCF}; /** * Maybe memset to 0 for security? */ #define RESET_DATA \ bufferIndex = 0; \ delete pkt; \ pkt = nullptr; inline ClientPacket *solvePuzzle(shared_ptr response, Identity *, std::string &); inline std::string toString(mp_int* num){ char buffer[2048]; memset(buffer, 0, 2048); auto len = mp_todecimal(num, buffer); return string(buffer); } extern void hexdump(std::ostream& outs, const std::string& s, size_t line_len = 16); bool ServerConnection::handshake(std::string &errorMessage) { //setup the init mac /** * Low level */ ts::protocol::ClientPacket *pkt; shared_ptr response; int maxBufferSize = 512; size_t bufferIndex = 0; uint8_t buffer[maxBufferSize]; memset(buffer, 0, maxBufferSize); int err = 0; string error = "success"; beginCoocie: memcpy(buffer, InitVersion, InitVersionLength); bufferIndex += InitVersionLength; buffer[bufferIndex++] = 0x00; //Login state auto millis = duration_cast(system_clock::now().time_since_epoch()).count(); memcpy(&buffer[bufferIndex], &millis, 4); bufferIndex += 4; //generate the alpha key for (int i = 0; i < 4; i++) buffer[bufferIndex++] = (uint8_t) std::rand(); bufferIndex += 8; //Reserved bytes pkt = new ts::protocol::ClientPacket(ts::protocol::PacketTypeInfo::Init1, pipes::buffer_view((void *) buffer, bufferIndex)); pkt->clientId(0); pkt->toggle(ts::protocol::PacketFlag::Unencrypted, true); pkt->applyPacketId(101, 0); this->sendPacket(*pkt); RESET_DATA; response = readNextPacket(); if (!response) { errorMessage = "could not get a valid response!"; return false; } if (response->type() != protocol::PacketTypeInfo::Init1) { errorMessage = "invalid response type. Got: " + response->type().name(); return false; } if (response->data()[0] != 1) { errorMessage = "iInvalid requested login type (" + to_string((int) response->data()[0]) + " == 1)"; return false; } //the second request of the manager memcpy(buffer, InitVersion, InitVersionLength); bufferIndex += InitVersionLength; buffer[bufferIndex++] = 0x02; //Login state if(response) memcpy(&buffer[bufferIndex], response->data().string().substr(1, 16).data(), 16); bufferIndex += 16; //Servers 16 bytes if(response) memcpy(&buffer[bufferIndex], response->data().string().substr(17, 4).data(), 4); bufferIndex += 4; //My own 16 bytes, reversed pkt = new ts::protocol::ClientPacket(ts::protocol::PacketTypeInfo::Init1, pipes::buffer_view((void *) buffer, bufferIndex)); pkt->clientId(0); pkt->toggle(ts::protocol::PacketFlag::Unencrypted, true); pkt->applyPacketId(101, 0); this->sendPacket(*pkt); RESET_DATA; //We got the RSA challenge response = readNextPacket(); if (!response) { errorMessage = "could not get a valid response!"; return false; } if (response->type() != protocol::PacketTypeInfo::Init1) { errorMessage = "invalid response type"; return false; } if (response->data()[0] != 3) { if(response->data()[0] == 127) { cout << "COOCIE RESET!" << endl; goto beginCoocie; } hexdump(cout, response->data().string()); errorMessage = "Invalid requested login type (" + to_string((int) response->data()[0]) + " == 3 | unencripted -> " + (response->hasFlag(PacketFlag::Unencrypted) ? "true" : "false") + ")"; return false; } //Generate puzzel response std::string alpha; pkt = solvePuzzle(response, this->clientIdentity, alpha); pkt->applyPacketId(101, 0); this->sendPacket(*pkt); RESET_DATA; cout << "manager init done" << endl; this->encriptAck = true; response = readNextPacket(); if (!response) { errorMessage = "could not get a valid response!"; return false; } if (response->type() != protocol::PacketTypeInfo::Command) { errorMessage = "invalid response type: " + response->type().name(); return false; } auto command = response->asCommand(); if (command.getCommand().compare("initivexpand") != 0) { // errorMessage = "invalid response command. Got: " + command.getCommand() + " Expected: initivexpand"; return this->handshakeNew(command, alpha, errorMessage); } //std::string alpha = base64::decode(command[0]["alpha"]); std::string beta = base64::decode(command[0]["beta"]); std::string omega = base64::decode(command[0]["omega"]); //Remotes public key cout << "RESPONSE! -> " << command.build() << endl; //Read public key ecc_key remotePublicKey{}; if ((err = ecc_import((const unsigned char *) omega.data(), omega.length(), &remotePublicKey)) != CRYPT_OK) { errorMessage = "ecc_import(...) returned " + to_string(err) + "/" + error_to_string(err); return false; } if(strcmp(remotePublicKey.dp->name, "ECC-256") != 0){ errorMessage = "invalid imported public key! Curve found " + string(remotePublicKey.dp->name); return false; } size_t sharedSecretLength = 32; char sharedSecret[sharedSecretLength]; if ((err = ecc_shared_secret(clientIdentity->getKeyPair(), &remotePublicKey, (unsigned char *) sharedSecret, &sharedSecretLength)) != CRYPT_OK) { errorMessage = "ecc_shared_secret(...) returned " + to_string(err) + "/" + error_to_string(err); return false; } if (!setupSharedSecret(alpha, beta, string(sharedSecret, sharedSecretLength), error)) { errorMessage = "setupSharedSecret(...) failed: " + error; return false; } //this->readQueue[PacketType::Command.type()]->reset(); //TS 3.1 /* response = readNextPacket(); if (!response) { errorMessage = "could not get a valid response!"; return false; } if (response->type() != protocol::PacketType::Command) { errorMessage = "invalid response type: " + response->type().name(); return false; } command = response->asCommand(); cout << "Having initiv2 -> " << response->data() << endl; */ this->idManager.nextPacketId(PacketTypeInfo::Command); Command clientinit("clientinit"); //94ec66de-5940-4e38-b002-970df0cf6c94,62444179-0d99-42ba-a45c-c6b1557d079a,d95f9901-c42d-4bac-8849-7164fd9e2310 //clientinit["client_badges"] = "badges=450f81c1-ab41-4211-a338-222fa94ed157,c9e97536-5a2d-4c8e-a135-af404587a472,94ec66de-5940-4e38-b002-970df0cf6c94"; //,62444179-0d99-42ba-a45c-c6b1557d079a clientinit["client_nickname"] = "Wolf C++ XXXX"; clientinit["client_version"] = "3.1 [Build: 1471417187]"; clientinit["client_platform"] = "Windows"; clientinit["client_version_sign"] = "Vr9F7kbVorcrkV5b/Iw+feH9qmDGvfsW8tpa737zhc1fDpK5uaEo6M5l2DzgaGqqOr3GKl5A7PF9Sj6eTM26Aw=="; clientinit["client_input_hardware"] = true; clientinit["client_output_hardware"] = true; clientinit["client_default_channel"] = ""; clientinit["client_default_channel_password"] = ""; string password; if(!password.empty()){ char passwordBuffer[SHA_DIGEST_LENGTH]; SHA1((const unsigned char *) password.data(), password.length(), (unsigned char *) passwordBuffer); password = base64_encode(string(passwordBuffer, SHA_DIGEST_LENGTH)); } clientinit["client_server_password"] = password; clientinit["client_meta_data"] = ""; clientinit["client_key_offset"] = this->clientIdentity->lastValidKeyOffset(); clientinit["client_nickname_phonetic"] = ""; clientinit["client_default_token"] = ""; clientinit["hwid"] = "123,456123123123"; sendCommand(clientinit); while(true){ response = readNextPacket(); if (!response) { errorMessage = "could not get a valid response!"; return false; } if(response->type() == PacketTypeInfo::Ack) continue; break; } //TODO check ack id if (!response) { errorMessage = "could not get a valid response!"; return false; } if (response->type() != protocol::PacketTypeInfo::Command) { errorMessage = "invalid response type: " + response->type().name(); return false; } if(response->asCommand().getCommand() == "initserver"){ //Got success this->handleQueueLock.lock(); this->handleQueue.push_front(response); this->handleQueueLock.unlock(); this->setClientId(response->asCommand()["aclid"]); this->autoHandle = true; cout << "Successfull connected!" << endl; /* std::thread([&](){ usleep(1000 * 1000); cout << " -> send extra command" << endl; //this->sendCommand(Command("channelsubscribeall return_code=1:i")); while(true){ //this->sendCommand(Command("getconnectioninfo clid=320 return_code=1:112")); //this->sendCommand(Command("ftgetfilelist cid=0 cpw path=\\/icons return_code=1:z0")); this->sendCommand(Command("servergrouppermlist sgid=6 return_code=1:112")); usleep(10 * 1000 * 1000); } //Command cmd("channelgetdescription cid=1 return_code=1:3o"); //Command cmd("clientupdate client_nickname=WolverinDEV22 return_code=__1_"); //Command cmd("clientdisconnect reasonid=8 reasonmsg=leaving"); //this->sendCommand(Command("permissionlist return_code=__1_")); //this->sendCommand(Command("clientgetvariables clid=" + to_string(this->clientId))); }).detach(); */ return true; } cout << "Invalid connect: " << response->data() << endl; //TODO error handling return true; } inline ClientPacket* solvePuzzle(shared_ptr response, Identity *identity, std::string &alpha) { uint32_t puzzelLength = be2le32(&((char*) response->data().data_ptr())[1 + 128]); //1 for the first byte (the state byte) auto buffer = (char*) response->data().data_ptr(); char alphaBuffer[10]; for (int index = 0; index < 10; index++) alphaBuffer[index] = 0; //rand(); alpha = string(alphaBuffer, 10); //Generating command auto pkey = identity->publicKey(); ts::Command command("clientinitiv", { {"alpha", base64_encode(alphaBuffer, 10)}, {"omega", pkey}, {"ip", ""}, {"ot", 1} //Required by 3.1 }); std::string cmd = command.build(); //Sloving puzzel mp_int x{}; mp_int n{}; mp_int result{}; //mp_init_multi(&x, &n, &result); mp_init(&x); mp_init(&n); mp_init(&result); char numBuffer[2048]; mp_read_unsigned_bin(&x, (const unsigned char *) &response->data()[1], 64); //One offset mp_read_unsigned_bin(&n, (const unsigned char *) &response->data()[1 + 64], 64); //1 + 64 offset cout << "X: " << toString(&x) << endl; cout << "N: " << toString(&n) << endl; cout << "Length: " << puzzelLength << endl; mp_int exp{}; mp_init(&exp); mp_2expt(&exp, puzzelLength); //x ** (2 ** puzzelLength) mod n int err = 0; if ((err = mp_exptmod(&x, &exp, &n, &result)) != CRYPT_OK) { cerr << "Invalid crypt: " << err << "/" << error_to_string(err) << endl; } int resultBufferLength = mp_unsigned_bin_size(&result); char resultBuffer[resultBufferLength]; mp_to_unsigned_bin(&result, (unsigned char *) resultBuffer); //mp_clear_multi(&x, &n, &exp, &result); mp_clear(&x); mp_clear(&n); mp_clear(&exp); mp_clear(&result); size_t packetBufferLength = InitVersionLength + 1 + 232 + 64 + cmd.length(); char packetBuffer[packetBufferLength]; memset(packetBuffer, 0, packetBufferLength); memcpy(packetBuffer, InitVersion, InitVersionLength); packetBuffer[InitVersionLength] = 0x04; //Copy old data memcpy(&packetBuffer[InitVersionLength + 1], &response->data()[1], 232); memcpy(&packetBuffer[InitVersionLength + 1 + 232 + (64 - resultBufferLength)], resultBuffer, resultBufferLength); memcpy(&packetBuffer[InitVersionLength + 1 + 232 + 64], cmd.data(), cmd.length()); cout << "sending puzzel sulution" << endl; auto pkt = new ts::protocol::ClientPacket(ts::protocol::PacketTypeInfo::Init1, pipes::buffer_view((void *) packetBuffer, packetBufferLength)); pkt->clientId(0); pkt->toggle(ts::protocol::PacketFlag::Unencrypted, true); return pkt; }