TeamViewer authentication protocol (part 3 of 3)
January 31, 2013
By default, peers will attempt to initiate encryption with each other using the public key handed out by the Master server in the RequestRoute2 response. The connecting device will initiate encryption using a CMD_RequestEncryption command, which is routed peer-to-peer, containing a session key (either AES or RC4, based on version) encrypted with the remote peer’s public key, and signed with the sender’s private key for verification.
Keep in mind that the initial RequestRoute2 response, containing the public key of the destination, is not authenticated in any way (e.g. with a cryptographic signature), so it can be trivially man-in- the-middled, and the RSA key replaced with a key of the attacker’s choosing. Since a newRequestRoute2 is performed on every new connection, and the public key is always respected (there is no “pinning” for previous clients), an attacker can always MITM a MasterResponse, and replace the public key with one of their own.
If peer-to-peer encryption negotiation fails for any reason, one of the clients (usually the one that is unable to decrypt the peer-to-peer traffic) will send a CMD_RequestNoEncryption command, which will turn off all peer-to-peer encryption for the session. Turning off encryption is silent, with no user-noticeable effect. An attacker could likely also inject such a command to disable encryption for the session.Another interesting point to note is that encryption is negotiated and confirmed asynchronously, so any peer-to-peer communication that occurs before encryption has been confirmed will automatically be in the clear, and any that occurs after will automatically be encrypted. There are often several peer-to-peer packets communicated prior to encryption being confirmed, though likely indefinitely delaying the RequestEncryption command would result in a successful connection and authentication without any encryption (not tested!).
Understanding and potentially subverting the authentication protocol was the goal of this reverse engineering experiment. Authentication takes place peer-to-peer, and by default, uses a 4 digit numeric passcode. Brute-force protection takes the form of a back-off timer that increases on subsequent bad authentications.
Shown above is the ideal case where peer-to-peer encryption succeeds. As mentioned above, anyData4 peer-to-peer packet that is sent after ConfirmEncryption will be encrypted, but encryption proceeds asynchronously, and may not be finished until after several Data4 packets have been exchanged. Data4 is the most recent kind of peer-to-peer data command, though I have also seenData3 used. The only difference between Data3 and Data4 is that Data4 can support both encrypted and clear text payloads, using an additional byte indicating encryption. Data3 instead has two different command varieties depending on whether it is encrypted (Data3 andData3_Encrypted).
If the brute-force protection is activated due to excessive authentication attempts, the remote client will respond to the Authenticate message with an error code, and another parameter indicating the number of seconds before Authentication may be retried, otherwise, a code is returned indicating whether authentication was successful. Finally, Data4 messages are also compressed (prior to encryption) using a zlib stream, but only starting with messages after the initial version handshake, and the first Handshake (ID 49) peer-to-peer message has already been sent.Given the default weak passcode, and the flaws in Encryption, it’s fairly straightforward to MITM the encryption and brute-force the passcode as it is sent on the wire. An exploit has been developed to do that: divert_teamviewer_and_mitm.py. The exploit builds off an old framework that I have used more times than I can recall, that diverts TCP traffic using an ipfw divert socket, possibly modifies it, and re-injects it. I’ve never really done extensive testing of the included TCP implementation, so it more than likely contains bugs, but it works well enough to keep using. The exploit should work on any traffic coming from your Mac, or being routed through your Mac (sysctl net.inet.ip.forwarding FTW here).
The exploit works by performing two of the attacks described here. First, it modifies theMasterResponse to swap out the public key of the intended target. I originally did this intending to fully MITM the encrypted traffic, decrypting and re-encrypting it on the fly, but once I noticed that encryption was transparently abandoned using a CMD_RequestNoEncryption when theCMD_RequestEncryption’s session key couldn’t be decrypted, I decided it wasn’t necessary. Since the peer-to-peer traffic is all in the clear, after encryption has been silently abandoned, it’s easy to look for the Authenticate message and quickly brute-force the 9999 possible passwords offline against the MD5(challenge | passcode), outputting the clear text passcode.
In addition to the offline bruteforce of passcodes entered by legitimate users, an online bruteforce is also possible, with some caveats. Performing an online bruteforce from a single ID, as previously mentioned, is not possible due to the increasing backoff timer. Nevertheless, by repeatedly generating new client IDs with spoofed parameters using the Registration process, thenRequestRoute2 to connect to the target, the attacker gets 5 immediate authentication attempts before the backoff timer kicks in. At that point, they may abandon the ID and begin Registration again.
When I attempted this, I found that after about 250 requests (2.5% of default passcode search space), I started receiving a new error from RequestRoute2 that I had not seen before:NOROUTE_ExcessiveUse (note that the spelling is slightly different fromNOROUTE_ExcessiveUsd, the error that indicates excessive requests from a single ID). I originally assumed that this blacklisting was based on source IP address. In any case, after routing my requests through Tor, I found that the blacklisting is actually based on the victim’s client ID—which is in itself a denial of service. Just by requesting a route to a system repeatedly, it will eventually become impossible to connect to. I observed that the destination blacklisting seems to last somewhere between 15 and 30 minutes, so a patient attacker could perform a successful online brute-force in less than 24 hours.
It is my recommendation that TeamViewer not be used on an untrusted network, or with the default password settings. TeamViewer does support increasing the password strength to a configurable length, and using alphanumeric passcodes, but it’s unlikely that casual users will have changed this setting.Keep in mind that there is a substantial attack surface in TeamViewer that needs more analysis such as the unauthenticated, plaintext communication between client to server (over 100 commands are supported and parsed on the client side), as well as many peer-to-peer commands, routed through the gateway server. Despite the danger to this much exposed attack surface, the risk is somewhat mitigated by an extensive use of std::string and std::vector instead of C-style strings and arrays.