TeamViewer authentication protocol (part 2 of 3)
January 31, 2013
KeepAlive and Outgoing connections
As mentioned previously, the KeepAlive server is used to maintain an online presence, so that when a client connects, the KeepAlive server can communicate with the target host and negotiate the connection details. Outgoing connections use the CMD_MasterCommand (as used in Login) through the Master server.
Once the device connects to the KeepAlive server (which it does immediately after Login), it performs some additional negotiation, which appears to serve two purposes:
- Router ping
- Server-driven dialog string synchronization
The router ping is a special kind of ping that operates over Buddy commands with the KeepAlive server. I believe it simulates triggering an incoming network connection, and confirms that the device is reachable. Unlike the Master server, the KeepAlive server seems to have a TeamViewer Network ID of its own: when Router Pings are returned, they contain the list of network hops through which the Ping traveled (which generally just contain the initial sender’s ID, and the KeepAlive server’s ID).
The dialog string synchronization is also performed over Buddy commands using a command type of 38, using several nearly identical messages. The returned dialog strings seem mostly relevant to license issues; for example, when a client is determined to be violating the Free License terms, the client is blacklisted and the user is notified that their usage pattern matches Commercial usage. Surprisingly, I never triggered this, despite fairly heavy usage during testing. I suspect it is triggered by connections to a large number of remote systems, whereas I primarily tested against a single target, or locally using a fake server.
Once the client is connected to the KeepAlive server, and has finished Login with the Master server, it is fully connected. Note that no key exchange or encryption has been performed at this point, and all communication with both servers is in the clear (though often obfuscated using the bit-rotation scheme described above). Ironically, at this point, the TeamViewer status bar will state that the client is “Ready to Connect (secure connection)”.
Status bar after KeepAlive negotatiation
Now we’re getting into one of the more interesting aspects of the protocol: outgoing connections. Users make connections to remote systems using their Client ID, which is a 32-bit integer. The Client ID is generated server-side based on hardware-specific data sent by your system, so it should be unique, but constant across installations on the same machine. It is generated from the MID value (as sent to the Master server during master commands) during a one-time Registration phase, which contains your primary network interface’s (en0) MAC address and your computer’s serial number.
Outgoing connections are initiated with a RequestRoute2 CMD_MasterCommand to the Master server. The request parameters include the following:
client = TV
connectionMode = 5
MID = system unique ID (described above)
ID = client ID
ID2 = destination ID
v = client version
ic = unknown, perhaps another unique identifier f = RequestRoute2
The server will respond with a response string which indicates the result of the route request. Possible values include CONNECT, NOROUTE_KeepAliveLost, and NOROUTE_IdNotFound. Note however that many of these identifying parameters can be omitted, and the command will still function properly. Omitting MID, ic, and spoofing the sending ID still results in a successfulRequestRoute2 command—there is no server-side validation of the parameters.
If the result is CONNECT, this means that the destination is valid and currently connected to a KeepAlive server. At this point, the KeepAlive server will send a CMD_RequestConnect to the destination to initiate a connection. A CONNECT response will also contain the destination endpoint’s RSA public key. NOROUTE_KeepAliveLost means that the ID was valid at some point, but the system is no longer connected to the KeepAlive server (i.e. TeamViewer is not currently running). NOROUTE_IdNotFound means that the ID was never valid.
Using this information, it’s fairly straightforward to write a TeamViewer ID scanner, which I have already done and attached here: tv_scanner.py
. The scanner uses a spoofed client ID, and omits the other identifying parameters. However, the Master server detects ID scanning after about 50RequestRoute2 commands from a single client ID, and starts returning the special error codeNOROUTE_ExcessiveUsd. This makes scanning the entire ID space prohibitive from a single ID.
Even with a single ID, the blacklisting does eventually wear off. Attempting to make a connection while blacklisted in the official client results in the following warning:
I initially thought blacklisting occurred based on IP address, as attempting to change the spoofed client ID parameter (or the other omitted identifying parameters such as MID, and ic) did not bypass the blacklisting. However, registering a new valid client ID based on spoofed unique parameters will bypass the blacklisting, and allow scanning to resume again, even during blacklisting.
If you start with a valid Client ID and scan in a direction, you find far more valid IDs than a random distribution would suggest— about 50% of Client IDs I saw near my valid ID were also valid. I confirmed, via multiple ID registrations with spoofed unique parameters, that the server hands out monotonically increasing ID values (which also matches with why my Mac had a significantly lower ID than my Windows VM).
The overall connection (incoming and outgoing) process involves both the Master server, the KeepAlive server (on the incoming side), and a gateway server to which they both connect. Once they are both connected, and a session is established, it’s possible to route peer-to-peer Data4packets between devices.