📜 ⬆️ ⬇️

We understand WeChat - the second most popular messenger in the world





Messenger WeChat from the Chinese company Tencent


WeChat is the second most popular messenger in the world. Official data on the number of users is very difficult to find, but you can make a rough estimate.
We are talking about about 800 million users worldwide, 90% of which are in China.

In China, almost every smartphone owner uses WeChat (Chinese self-Weixin), since it is not only the instant messenger in the classical sense, but the whole system, including a mobile wallet, an integrated browser, an online store, etc. It represents all Chinese government agencies. Pay for a receipt or make an appointment with a doctor through an instant messenger.
')
An urgent task was the integration of CRM systems of customers actively working in China with WeChat. This was facilitated by the prevalence of WeChat in China, as well as the lack of an official API. SMS information in China is expensive and, most importantly, it is unstable, besides there is no “read” status. The customer, using the API, will be able through his CRM system to notify WeChat users (subscribed to receive information from the customer number, we will tell about it below) about the delivery of goods, new orders and other service information.

Protocol study


It was decided to study the messenger "from the inside", to understand the code of the 32-bit version of the messenger for iOS. We have an old, old-fashioned, iPhone 4S with iOS 7.2.1.

As MITM we use Burp Suite Free Edition .
We download the application and with the help of the wonderful utility dumpdecrypted we decrypt the executable file.
At the time of the beginning of the reverse engineering WeChat version 6.3.13 was relevant.

Now it remains to copy the file from the device, disassemble it into IDA, and you can start.

Consider the key exchange algorithm on the example of registration.
Run the application and see the offer to enter the phone number for registration.

Enter the phone number and see the HTTP request to MITM at hkshort.weixin.qq.com/bindopmobileforreg .



The request body consists of:


After a very long static code analysis, we managed to find out that the client communicates with the server using serialized objects. Objects are serialized using the Protocol Buffers library.

The first message is the following data:


The message is serialized and encrypted with the server's public key using the RSA algorithm. The server response is decrypted by the AES-key transmitted in the request. The response states that everything is all right, or an error is indicated.

We receive SMS and enter the code. The same request is formed, only with the code from SMS, and in the answer we get the so-called ticket. Now, having a ticket, you can send a request for registration. Enter the name and click OK.

The key exchange takes place according to the Diffie-Hellman algorithm using an elliptic curve over a finite field “secp224r1”. The private and public keys are generated and a request is sent to hkshort.weixin.qq.com/newreg . The server generates its keys, and also gives us the so-called CryptUin and ServerID, which will be discussed later. In response, the server sends us its public key and session key.

Now we have the public key of the server, and we calculate the common key with which we decrypt the session key. From this point on, client-server communication is performed using the AES symmetric algorithm with a key length of 128 bits.

In general, the algorithm for establishing connections and key exchange is nothing supernatural. Properly encrypting data and exchanging keys is half the task; you also need to correctly create a header for each message. Even if you serialize the data correctly and encrypt it, then if the header is incorrect, the server will send a response with an error. The headline looks like this:

bfa65f16050520252cb6b770021001754cc8fd5e57e085457800fb0242420001aeb890f40b010a0080



Now we will tell more about each field:

1. Protocol identifier. Each packet starts with this byte.

2. Flags. Stores information about the length of the SrvID, the length of the header itself and the compression of the original message.



The compression flag is set to 0b10, if the message is not compressed, otherwise set to 0b01.

3. Application Version. No comments.

4. CryptUin. After registration, each account is assigned a unique identifier of four bytes.

5. SrvID. ID of the current session. Changes with each new connection.

6. uiCgi. Command code Each team has its own uiCgi and url. For example, for the bindopmobileforreg command, uiCgi is 0x91, and for newreg it is 0x7e. Most numbers are packed using the following algorithm:

 private static void Write7BitEncodedInt(BinaryWriter store, int value) { Debug.Assert(store != null); // Write out an int 7 bits at a time. The high bit of the byte, // when on, tells reader to continue reading more bytes. uint v = (uint)value; // support negative numbers while (v >= 0x80) { store.Write((byte)(v | 0x80)); v >>= 7; } store.Write((byte)v); } 


In this example, uiCgi is equal to 0x17b, and in packaged form - fb02.

7. The length of the original message. The length of the serialized data. The number is also packed, but since it is less than 0x80, it remains unchanged.

8. The length of the compressed message. Compression was not made, so it does not differ from the previous one.

9. Flag.

10. Hash.

Calculated as follows:

hash1 = md5(cryptUin.shareKey);
hash2 = md5( strlen(data).shareKey.hash1.data)
resultHash = adler32(hash2)


sharedKey is a shared key obtained during a handshake.
The hash is also packed.

11. Flags. The meaning of these flags remains a mystery, but they are static, so there was no sense to study them separately.

Now another protocol is being used, which we will write about in subsequent publications. In fact, it is a wrapper over the above. The old protocol is still supported - for this you need to clear the MmtlsCtrlFlag flag in the debugger.

Spam protection.
To protect against spam, the user can enable the "confirmation of friendship" option. In this case, you can write a message to him only after he confirms that you are friends. A request for confirmation of friendship may contain a welcome message.

Send a lot of welcome messages will not work. After sending fifteen requests, all the rest stop sending and enter the queue. The sixteenth request will be sent only when one of the previous fifteen adds you as a friend. But the user does not know this, and the application interface does not report about it either. We managed to figure this out with the help of traffic analysis and experiments.

In the process, an interesting vulnerability was also discovered. The application has the ability to find the user by phone number. The server either responds that there is no such user, or returns information about it (name, gender, city, photo, etc.). But if you send these requests too often, the server responds with the message “Too many attempts. Try again later. ” This can be used, because if the user does not exist, the server will always inform about this, and if the answer comes “Too many attempts. Try again later „- this means that the user exists. Using this, you can build a user base. By the way, there were very “interesting” users who use WeChat, but they cannot be detected in the usual way, and it is even impossible to send them an invitation, most likely they are the “special” people of China. Even if you request registration for an “interesting” number, the server will inform you that this user is already registered and offers to restore the account, but not via SMS.

Using 20,000 streams it is possible to collect the entire WeChat database in China from one account per day, account lockdown does not occur.

Also separately I would like to inform you that End-to-End encryption between users does not occur. Messages are encrypted only with a symmetric key, the server decrypts them and re-encrypts them with the symmetric key of the recipient and sends them to the recipient.

This article is introductory, if there is interest from the Habr community, the following WeChat publications may appear, since any event in WeChat (for example, object serialization) is worthy of separate articles.

Source: https://habr.com/ru/post/338940/


All Articles