def send_message(self, username, body, groupchat=False):
        self._log('[+] Sending message "{}" to {}...'.format(body, username))

        jid = username if groupchat else self._resolve_username(username)
        group_type = "groupchat" if groupchat else "chat"
        unix_timestamp = str(int(round(time.time() * 1000)))
        cts = "1494428808185"
        uuid = CryptographicUtils.make_kik_uuid()

        packet = ('<message type="{0}" to="{1}" id="{2}" cts="{3}">'
                  '<body>{4}</body>'
                  '{5}'
                  '<preview>{6}</preview>'
                  '<kik push="true" qos="true" timestamp="{7}" />'
                  '<request xmlns="kik:message:receipt" r="true" d="true" />'
                  '<ri></ri>'
                  '</message>'
                  ).format(group_type, jid, uuid, cts, body,
                           ("<pb></pb>" if groupchat else ""), body, unix_timestamp).encode('UTF-8')
        self._send_packet(packet)

        is_acked, is_delivered, receipt_id = False, False, ""

        while True:
            info = self.get_next_event(1)
            if info is None:
                break
            if info["type"] == "acknowledgement":
                is_acked = info["id"] == uuid
            elif info["type"] == "message_delivered":
                is_delivered = info["message_id"] == uuid
                receipt_id = info["xml_element"]["id"]
            if is_acked and is_delivered and receipt_id != "":
                break

        if not is_acked:
            self._log("[-] Failed, message was not acknowledged", DebugLevel.ERROR)
            return False
        elif not is_delivered or receipt_id == "":
            self._log("[+] Message '" + uuid + "' seems to be sent but not delivered", DebugLevel.WARNING)
        else:
            self._log("[+] Message receipt id: " + receipt_id)

            data = ('<iq type="set" id="{}" cts="1494351900281">'
                    '<query xmlns="kik:iq:QoS">'
                    '<msg-acks>'
                    '<sender jid="{}">'
                    '<ack-id receipt="false">{}</ack-id>'
                    '</sender>'
                    '</msg-acks>'
                    '<history attach="false" />'
                    '</query>'
                    '</iq>').format(CryptographicUtils.make_kik_uuid(), jid, receipt_id)
            self._make_request(data)
            self._log("[+] Sent")
        return True
    def get_info_for_username(self, username):
        self._log("[+] Getting info for username '" + username + "'...")
        data = ('<iq type="get" id="{}">'
                '<query xmlns="kik:iq:friend">'
                '<item username="******" />'
                '</query>'
                '</iq>').format(CryptographicUtils.make_kik_uuid(), username)
        self._make_request(data)
        response = self._get_response()

        if response.error:
            if response.error.text == "User not found":
                self._log("[-] No users were found for username '" + username + "'")
                return None
            else:
                self._log("[-] Failed to get user info: " + response.error.text, DebugLevel.WARNING)
                raise KikErrorException(response.error.text)

        jid_info = dict()
        jid_info["jid"] = response.contents[0].contents[0]['jid']
        jid_info["display_name"] = response.find('display-name').text
        jid_info["username"] = response.find('username').text
        jid_info["picture_url"] = response.find('pic').text if response.find('pic') is not None else None

        self._log("[+] Okay")

        return jid_info
    def get_info_for_group(self, group_hashtag):
        # essentially doing a group search
        if not group_hashtag.startswith("#"):
            group_hashtag = "#" + group_hashtag

        self._log("[+] Getting info for group (code: " + str(group_hashtag) + ")...")
        data = ('<iq type="get" id="{}">'
                '<query xmlns="kik:groups:admin">'
                '<g action="search">'
                '<code>{}</code>'
                '</g>'
                '</query>'
                '</iq>').format(CryptographicUtils.make_kik_uuid(), group_hashtag)
        self._make_request(data)
        response = self._get_response()
        if response.error:
            self._log("[-] Error when trying to get group info:", DebugLevel.ERROR)
            self._log(response.error.prettify(), DebugLevel.ERROR)
            raise KikErrorException(response.error, "Unable to get info for group, code: " + str(group_hashtag))

        if response.find("g") is None:
            self._log("[-] No groups found for hashtag " + group_hashtag)
            return None

        groups_info = []
        for group in response.findAll("g"):
            groups_info.append(self._parse_group_element(group))

        self._log("[+] Okay")

        return groups_info
    def add_friend(self, username):
        self._log("[+] Adding {} as a friend...".format(username))
        jid = self._resolve_username(username)

        uuid = CryptographicUtils.make_kik_uuid()
        data = '<iq type="set" id="{}">' \
               '<query xmlns="kik:iq:friend">' \
               '<add jid="{}" />' \
               '</query>' \
               '</iq>'.format(uuid, jid)

        self._make_request(data)
        response = self._get_response()

        if response.find('error'):
            self._log("[-] Could not add '" + username + "' as a friend.", DebugLevel.ERROR)
            self._log(response.prettify(), DebugLevel.ERROR)
            return False

        jid_info = dict()
        jid_info["node"] = username[username.find("@")] if "@" in username else username
        jid_info["display_name"] = response.find('display-name').text
        jid_info["username"] = response.find('username').text
        self._log("[+] Okay")
        return jid_info
    def find_groups_suggestions(self, search_query):
        if search_query.startswith("#"):
            search_query = search_query[1:]
        self._log("[+] Searching groups with query '{}'...".format(search_query))

        encoded_search_query = base64.b64encode(("\x0a" + chr(len(search_query)) + search_query).encode(), b"-_").decode()
        if encoded_search_query.endswith("="):
            encoded_search_query = encoded_search_query[:encoded_search_query.index("=")]

        data = ('<iq type="set" id="{}">'
                '<query xmlns="kik:iq:xiphias:bridge" service="mobile.groups.v1.GroupSearch" method="FindGroups">'
                '<body>{}</body></query></iq>') \
            .format(CryptographicUtils.make_kik_uuid(), encoded_search_query)
        self._make_request(data)

        response = self._get_response()
        if response.error:
            self._log("[-] Error when trying to get groups suggestions:", DebugLevel.ERROR)
            self._log(response.error.prettify(), DebugLevel.ERROR)
            raise KikErrorException(response.error, "Unable to get group suggestions. query: " + str(search_query))

        if response.find("body") is None:
            self._log("[-] Can't find results")
            return None

        encoded_results = base64.b64decode(response.find("body").text.encode(), b"-_")
        results = group_search_service_pb2.FindGroupsResponse()
        results.ParseFromString(encoded_results)

        if len(results.match) == 0:
            self._log("[!] Found no matching groups")
        else:
            self._log("[+] Okay")

        return results
 def get_info_for_node(self, node):
     jid = node if "@" in node else node + "@talk.kik.com"
     data = ('<iq type="get" id="{}">'
             '<query xmlns="kik:iq:friend:batch">'
             '<item jid="{}" />'
             '</query>'
             '</iq>').format(CryptographicUtils.make_kik_uuid(), jid)
     self._make_request(data)
     response = self._get_response()
     return self._parse_user_jid_element(response.query.success.item)
    def get_history(self):
        uuid = CryptographicUtils.make_kik_uuid()

        data = ('<iq type="set" id="af0811f1-446f-4103-ba04-2eedf8397008" cts="1513349802685">'
                '<query xmlns="kik:iq:QoS">'
                '<msg-acks />'
                '<history attach="true" />'
                '</query>'
                '</iq>'
                ).format(uuid)
        self._make_request(data)
        element = self._get_response()
        print(element.prettify())
    def get_chat_partners(self):
        self._log("[+] Getting roster (chat partners list)...")
        data = ('<iq type="get" id="{}">'
                '<query p="8" xmlns="jabber:iq:roster" />'
                '</iq>').format(CryptographicUtils.make_kik_uuid())
        self._make_request(data)
        response = self._get_full_response()

        chat_partners = list(map(self._parse_chat_partner, list(response.query.children)))
        chat_partner_dict = {user['jid']: user for user in chat_partners}
        self._log("[+] Fine.")

        return chat_partner_dict
    def validate_username_for_registration(self, username):
        uuid = CryptographicUtils.make_kik_uuid()

        data = ('<iq type="get" id="{}">'
                '<query xmlns="kik:iq:check-unique">'
                ' <username>{}</username>'
                '</query>'
                '</iq>').format(uuid, username)
        self._make_request(data)
        element = self._get_response()
        is_unique = element.find("username")["is-unique"] == "true"

        return is_unique
Example #10
0
    def serialize(self):
        can = 'CAN'  # XmppSocketV2.java line 180,

        device = self.device_id_override if self.device_id_override else device_id
        timestamp = str(CryptographicUtils.make_kik_timestamp())
        sid = CryptographicUtils.make_kik_uuid()

        signature = rsa.sign(
            "{}:{}:{}:{}".format(can + device, kik_version, timestamp,
                                 sid).encode(), private_key, 'SHA-256')
        signature = base64.b64encode(signature,
                                     '-_'.encode()).decode().rstrip('=')

        hmac_data = timestamp + ":" + can + device
        hmac_secret_key = CryptographicUtils.build_hmac_key()
        cv = binascii.hexlify(
            hmac.new(hmac_secret_key, hmac_data.encode(),
                     hashlib.sha1).digest()).decode()

        the_map = {
            'signed': signature,
            'lang': 'en_US',
            'sid': sid,
            'anon': '1',
            'ts': timestamp,
            'v': kik_version,
            'cv': cv,
            'conn': 'WIFI',
            'dev': can + device,
        }

        # Test data to confirm the sort_kik_map function returns the correct result.
        # the_map = {
        #     'signed': 'signature',
        #     'lang': 'en_US',
        #     'sid': 'sid',
        #     'anon': '1',
        #     'ts': 'timestamp',
        #     'v': 'kik_version',
        #     'cv': 'cv',
        #     'conn': 'WIFI',
        #     'dev': 'can+device',
        # }

        if self.n > 0:
            the_map['n'] = self.n

        packet = CryptographicUtils.make_connection_payload(
            *CryptographicUtils.sort_kik_map(the_map))
        return packet.encode()
    def sign_up(self, email, username, password, first_name, last_name, birthday="1974-11-20", captcha_result=None):
        uuid = CryptographicUtils.make_kik_uuid()
        passkey_e = CryptographicUtils.key_from_password(email, password)
        passkey_u = CryptographicUtils.key_from_password(username, password)
        data = ('<iq type="set" id="{}">'
                '<query xmlns="jabber:iq:register">'
                '<email>{}</email>'
                '<passkey-e>{}</passkey-e>'
                '<passkey-u>{}</passkey-u>'
                '<device-id>{}</device-id>'
                '<username>{}</username>'
                '<first>{}</first>'
                '<last>{}</last>'
                '<birthday>{}</birthday>'
                '{}'
                '<version>{}</version>'
                '<device-type>android</device-type>'
                '<model>Nexus 7</model>'
                '<android-sdk>25</android-sdk>'
                '<registrations-since-install>1</registrations-since-install>'
                '<install-date>unknown</install-date>'
                '<logins-since-install>0</logins-since-install>'
                '<prefix>CAN</prefix>'
                '<lang>en_US</lang>'
                '<brand>google</brand>'
                '<android-id>{}</android-id>'
                '</query>'
                '</iq>').format(uuid, email, passkey_e, passkey_u, self.device_id, username, first_name, last_name,
                                birthday, '<challenge><response>{}</response></challenge>'
                                .format(captcha_result) if captcha_result else '', self.kik_version, self.android_id)

        self._log("[+] Registering...")
        self._make_request(data)
        response = self._get_response()
        if response.error:
            captcha = response.find('captcha-url')
            if captcha:
                self._log("[-} Encountered a captcha. URL: " + captcha.string, DebugLevel.ERROR)
                raise KikCaptchaException(response.error, "Captcha when trying to sign up! URL: " + captcha.string,
                                          captcha.string)
            else:
                self._log("[-] Kik error code: {}".format(response.error['code']), DebugLevel.ERROR)
                self._log(response.error.prettify(), DebugLevel.ERROR)
                raise KikLoginException(response.error, "Kik error code: {}".format(response.error['code']))

        if not response.find('node'):
            raise KikErrorException(response, "No node in registration response")
        node = response.find('node').text
        self._log("[+] Registration seems successful, node: {}".format(node))
Example #12
0
    def searlize(self) -> bytes:
        """
        Generates/Gets the generated public key and builds an auth stanza
        """
        UUID = CryptographicUtils.make_kik_uuid()
        der = self.get_public_key_base64()
        signature = self.get_signature()
        urlattr = f' url="{self.cert_url}"' if self.cert_url else ''

        query = ('<iq type="set" id="{}"><query xmlns="kik:auth:cert"{}>'
                 '<key type="rsa">'
                 '<der>{}</der><signature>{}</signature>'
                 '</key>'
                 '</query></iq>').format(UUID, urlattr, der, signature)
        return query.encode()
    def validate_name_for_registration(self, first_name, last_name):
        uuid = CryptographicUtils.make_kik_uuid()

        data = ('<iq type="get" id="{}">'
                '<query xmlns="kik:iq:check-unique">'
                '<first>{}</first>'
                '<last>{}</last>'
                '</query>'
                '</iq>').format(uuid, first_name, last_name)
        self._make_request(data)
        element = self._get_response()
        is_first_name_valid = element.find("first")["is-valid"] == "true"
        is_last_name_valid = element.find("last")["is-valid"] == "true"

        return is_first_name_valid and is_last_name_valid
    def send_read_confirmation(self, username, message_id):
        self._log("[+] Sending read confirmation for message " + message_id + "...")

        jid = self._resolve_username(username)
        uuid = CryptographicUtils.make_kik_uuid()
        unix_timestamp = str(int(time.time() * 1000))

        data = ('<message type="receipt" id="{}" to="{}" cts="{}">'
                '<kik push="false" qos="true" timestamp="{}" />'
                '<receipt xmlns="kik:message:receipt" type="read">'
                '<msgid id="{}" />'
                '</receipt>'
                '</message>').format(uuid, jid, unix_timestamp, unix_timestamp, message_id)
        self._make_request(data)
        self._log("[+] Okay")
    def join_group(self, group_hashtag):
        if not group_hashtag.startswith("#"):
            group_hashtag = "#" + group_hashtag

        groups_suggestions = self.find_groups_suggestions(group_hashtag)
        if groups_suggestions is None or len(groups_suggestions.match) == 0:
            return None

        group_to_join = groups_suggestions.match[0]
        group_to_join_name = group_to_join.display_data.hashtag

        if group_to_join_name.lower() != group_hashtag.lower():
            self._log("[!] The group '{}' does not match exactly to the requested group '{}', so not joining."
                      .format(group_to_join_name, group_hashtag))
            return None

        self._log("[+] Joining group '{}' with {} members...".format(group_to_join_name, group_to_join.member_count))

        join_token = group_to_join.group_join_token.token
        join_token = base64.b64encode(join_token, b"-_").decode()
        if join_token.endswith("="):
            join_token = join_token[:join_token.index("=")]

        data = ('<iq type="set" id="{}">'
                '<query xmlns="kik:groups:admin">'
                '<g jid="{}" action="join">'
                '<code>{}</code>'
                '<token>{}</token>'
                '</g></query></iq>') \
            .format(CryptographicUtils.make_kik_uuid(),
                    self._resolve_group(group_to_join.jid.local_part),
                    group_hashtag,
                    join_token)
        self._make_request(data)

        response = self._get_response()
        if response.error:
            self._log("[-] Error when trying to join group:", DebugLevel.ERROR)
            self._log(response.error.prettify(), DebugLevel.ERROR)
            raise KikErrorException(response.error, "Unable to join group '{}'".format(group_hashtag))

        if response.find("type") is None:
            self._log("[-] Can't find results")
            return None

        self._log("[+] Joined to group '{}'".format(group_hashtag))

        return group_to_join
    def send_is_typing(self, username, is_typing, groupchat=False):
        self._log('[+] Sending is_typing = {}...'.format(is_typing))

        jid = username if groupchat else self._resolve_username(username)
        unix_timestamp = str(int(time.time() * 1000))
        uuid = CryptographicUtils.make_kik_uuid()
        group_type = "groupchat" if groupchat else "is-typing"

        data = '<message type="{}" to="{}" id="{}">' \
               '{}' \
               '<kik push="false" qos="false" timestamp="{}" />' \
               '<is-typing ' \
               'val="{}" />' \
               '</message>'.format(group_type, jid, uuid, "<pb></pb>" if groupchat else "", unix_timestamp, is_typing)
        self._make_request(data)
        self._log("[+] Okay")
    def establish_session(self, username, node, password):
        self._log("[+] Establishing session...")
        # reset the socket
        self.wrappedSocket.send_chat_message("</k>".encode('UTF-8'))
        self.wrappedSocket.close()
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.settimeout(10)
        self.wrappedSocket = ssl.wrap_socket(self.sock)
        self.wrappedSocket.connect((HOST, PORT))

        jid = node + "@talk.kik.com"
        jid_with_resource = jid + "/CAN" + self.device_id
        timestamp = "1496333389122"
        sid = CryptographicUtils.make_kik_uuid()
        version = "11.1.1.12218"

        # some super secret cryptographic stuff
        private_key_pem = "-----BEGIN RSA PRIVATE KEY-----\nMIIBPAIBAAJBANEWUEINqV1KNG7Yie9GSM8t75ZvdTeqT7kOF40kvDHIp" \
                          "/C3tX2bcNgLTnGFs8yA2m2p7hKoFLoxh64vZx5fZykCAwEAAQJAT" \
                          "/hC1iC3iHDbQRIdH6E4M9WT72vN326Kc3MKWveT603sUAWFlaEa5T80GBiP/qXt9PaDoJWcdKHr7RqDq" \
                          "+8noQIhAPh5haTSGu0MFs0YiLRLqirJWXa4QPm4W5nz5VGKXaKtAiEA12tpUlkyxJBuuKCykIQbiUXHEwzFYbMHK5E" \
                          "/uGkFoe0CIQC6uYgHPqVhcm5IHqHM6/erQ7jpkLmzcCnWXgT87ABF2QIhAIzrfyKXp1ZfBY9R0H4pbboHI4uatySKc" \
                          "Q5XHlAMo9qhAiEA43zuIMknJSGwa2zLt/3FmVnuCInD6Oun5dbcYnqraJo=\n-----END RSA PRIVATE KEY----- "
        private_key = rsa.PrivateKey.load_pkcs1(private_key_pem, format='PEM')
        signature = rsa.sign("{}:{}:{}:{}".format(jid, version, timestamp, sid).encode('UTF-8'), private_key, 'SHA-256')
        signature = base64.b64encode(signature, '-_'.encode('UTF-8')).decode('UTF-8')[:-2]
        hmac_data = timestamp + ":" + jid
        hmac_secret_key = CryptographicUtils.build_hmac_key()
        cv = binascii.hexlify(hmac.new(hmac_secret_key, hmac_data.encode('UTF-8'), hashlib.sha1).digest()).decode(
            'UTF-8')

        password_key = CryptographicUtils.key_from_password(username, password)

        the_map = {'from': jid_with_resource, 'to': 'talk.kik.com', 'p': password_key, 'cv': cv, 'v': version,
                   'sid': sid, 'n': '1', 'conn': 'WIFI', 'ts': timestamp, 'lang': 'en_US', 'signed': signature}
        packet = CryptographicUtils.make_connection_payload(CryptographicUtils.sort_kik_map(the_map)).encode(
            'UTF-8')

        # send session request
        self.wrappedSocket.send_chat_message(packet)
        response = self.wrappedSocket.recv(16384).decode('UTF-8')
        if "ok" not in response:
            raise KikErrorException(response, "Could not init session: " + response)
        self._log("[+] Session established.")
Example #18
0
    def serialize(self):
        jid = self.node + "@talk.kik.com"
        jid_with_resource = jid + "/CAN" + (
            self.device_id_override if self.device_id_override else device_id)
        timestamp = str(CryptographicUtils.make_kik_timestamp())
        sid = CryptographicUtils.make_kik_uuid()

        # some super secret cryptographic stuff

        signature = rsa.sign(
            "{}:{}:{}:{}".format(jid, kik_version, timestamp, sid).encode(),
            private_key, 'SHA-256')
        signature = base64.b64encode(signature,
                                     '-_'.encode()).decode().rstrip('=')
        hmac_data = timestamp + ":" + jid
        hmac_secret_key = CryptographicUtils.build_hmac_key()
        cv = binascii.hexlify(
            hmac.new(hmac_secret_key, hmac_data.encode(),
                     hashlib.sha1).digest()).decode()

        password_key = CryptographicUtils.key_from_password(
            self.username, self.password)

        the_map = {
            'from': jid_with_resource,
            'to': 'talk.kik.com',
            'p': password_key,
            'cv': cv,
            'v': kik_version,
            'sid': sid,
            'n': '1',
            'conn': 'WIFI',
            'ts': timestamp,
            'lang': 'en_US',
            'signed': signature
        }
        packet = CryptographicUtils.make_connection_payload(
            *CryptographicUtils.sort_kik_map(the_map))
        return packet.encode()
    def login(self, username, password, establish_session_on_success=True):
        self._log("[+] Logging in (username: "******", password: "******")...")

        device_id = self.device_id
        password_key = CryptographicUtils.key_from_password(username, password)
        data = ('<iq type="set" id="{}">'
                '<query xmlns="jabber:iq:register">'
                '<username>{}</username>'
                '<passkey-u>{}</passkey-u>'
                '<device-id>{}</device-id>'
                '<install-referrer>utm_source=google-play&amp;utm_medium=organic</install-referrer>'
                '<operator>310260</operator>'
                '<install-date>1494078709023</install-date>'
                '<device-type>android</device-type>'
                '<brand>generic</brand>'
                '<logins-since-install>1</logins-since-install>'
                '<version>{}</version>'
                '<lang>en_US</lang>'
                '<android-sdk>19</android-sdk>'
                '<registrations-since-install>0</registrations-since-install>'
                '<prefix>CAN</prefix>'
                '<android-id>c10d47ba7ee17193</android-id>'
                '<model>Samsung Galaxy S5 - 4.4.4 - API 19 - 1080x1920</model>'
                '</query>'
                '</iq>').format(CryptographicUtils.make_kik_uuid(), username, password_key, device_id,
                                self.kik_version)
        self._make_request(data)
        response = self._get_response()

        if response.error:
            if response.find('password-mismatch'):
                self._log("[-] Password mismatch, can't login", DebugLevel.ERROR)
                raise KikLoginException(response.error, "Password mismatch")
            elif response.error.find('not-registered'):
                self._log("[-] User not registered, can't login", DebugLevel.ERROR)
                raise KikLoginException(response.error, "Not registered")
            else:
                captcha = response.find('captcha-url')
                if captcha:
                    self._log("[-} Encountered a captcha. URL: " + captcha.string, DebugLevel.ERROR)
                    raise KikCaptchaException(response.error, "Captcha when trying to log in! URL: " + captcha.string,
                                              captcha.string)
                else:
                    self._log("[-] Kik error code: {}".format(response.error['code']), DebugLevel.ERROR)
                    self._log(response.error.prettify(), DebugLevel.ERROR)
                    raise KikLoginException(response.error, "Kik error code: {}".format(response.error['code']))

        if response.find("kik:error"):
            captcha = response.find('captcha-type')
            if captcha:
                self._log("[-} Encountered a captcha. URL: " + captcha.string, DebugLevel.ERROR)
                raise KikLoginException(response, "Captcha! URL:" + captcha.string)

        user_info = dict()
        user_info["node"] = response.find('node').text
        user_info["username"] = response.find('username').text
        user_info["email"] = response.find('email').text
        user_info["first"] = response.find('first').text
        user_info["last"] = response.find('last').text
        pubkey = response.find('record', {'pk': 'messaging_pub_key'})
        if pubkey:
            user_info["public_key"] = pubkey.text
            user_info["private_key"] = response.find('record', {'pk': 'enc_messaging_priv_key'}).text
            if response.find('record', {'pk': 'chat_list_bins'}):
                user_info["chat_list"] = self._parse_chat_list_bin(
                    Utilities.decode_base64(response.find('record', {'pk': 'chat_list_bins'}).text.encode('UTF-8')))

        self._log("[+] Logged in.")
        if self.debug_level == DebugLevel.VERBOSE:
            Utilities.print_dictionary(user_info)

        self.user_info = user_info
        if establish_session_on_success:
            self.establish_session(self.user_info["username"], self.user_info["node"], password)

        return self.user_info
Example #20
0
 def __init__(self):
     self.message_id = CryptographicUtils.make_kik_uuid()
     self.content_id = CryptographicUtils.make_kik_uuid() #Creating a seprate uuid for content as kik does the same.