In recent weeks, there have been quite a few security disclosures for Apple. Some of these have even been pretty significant. Not to pile on, but here’s some detail behind another security issue that I stumbled across last fall.

Apple had just restricted the availability of the Add Site feature on Apple TVs, and I was trying to determine whether alternate methods existed to enable the feature. If you couldn’t install the required configuration profile directly, maybe it’d work via MDM? Nope, that didn’t work. Wait, what about the Touch Setup feature? That’s obviously allowed to make changes to the Apple TV system.

Briefly, Touch Setup allows a user to wirelessly transfer network and Apple credentials from an iPhone to a new Apple TV. When booting the Apple TV for the first time, the user simply touches an unlocked iPhone to the device, it asks if they want to set up the device, and if so, the Wi-Fi password and Apple ID account and password are copied to the Apple TV. I was hoping that the data was transferred using some kind of special Configuration Profile that I could then modify and install through normal means to re-enable the Add Site feature.

Since a public jailbreak does not yet exist for Apple TV 6.0, I was kind of limited in what I could try. The first thing I checked was to see whether anything interesting is revealed in log files. Collecting log data from an iPhone is pretty easy: Connect the phone via USB and use an application like iPhone Configuration Utility (IPCU) or Xcode to read and save the console log. Can we do that on an Apple TV?

Sure we can, but there’s a slight problem: the micro-USB port and HDMI port on the Apple TV are right next to each other. They’re so close that you usually can’t plug both in at the same time. However, this problem may be solved with a sharp utility knife – and a little bit of luck.

Be careful you don't slice too deep or you'll cut the wires!

Be careful you don't slice too deep or you'll cut the wires!

Okay, now that I’ve got the hardware issues solved… Connect the laptop, go into the Apple TV, select factory reset, reboot, and… Damn. It launches iTunes and goes into “Device Restore” mode. You have to disconnect the USB, reboot the Apple TV, and then connect the USB sometime after it’s started booting. For the purposes of this test, there’s no need to connect until we actually start the Touch Setup process.

After collecting logs from both iPhone and Apple TV, I then went looking for useful log entries. Several items appeared interesting, including multiple “Data arrived” and “Sending back” lines related to the AppleTV binary and TouchRemote framework. One sequence in particular appeared intriguing (you may have to scroll sideways to see the fun bits):

Oct 10 19:47:12 Apple-TV AppleTV[24] <Warning>: Data arrived: <bcc254e0 27de2466 6bda2549 d2c46db7 9892a153 eba53073 dc0df4a7 0cbac8cf 811d0437 18d843a3 c822de94 1436a154 d0954f09 75c407ff 0e289a2d 46230016 259ed996 0f208470 a5cbdb39 94791034 9c> - sending to client
Oct 10 19:47:12 Apple-TV AppleTV[24] <Warning>: [TRTransferServer] Received a full packet: <bcc254e0 27de2466 6bda2549 d2c46db7 9892a153 eba53073 dc0df4a7 0cbac8cf 811d0437 18d843a3 c822de94 1436a154 d0954f09 75c407ff 0e289a2d 46230016 259ed996 0f208470 a5cbdb39 94791034 9c>, state: 3
Oct 10 19:47:12 Apple-TV AppleTV[24] <Warning>: [TRDeviceSetupServer] Server got data of length 81
Oct 10 19:47:12 Apple-TV AppleTV[24] <Warning>: [TRDeviceSetupServer] Compressed data: <1f8b0800 00000000 00034b2a c8c92c2e 3130b8c4 c8c4cc12 98185810 92585a92 7191952d 3025ce25 b12c3345 bd582133 20233f2f 9583975f 504c529a 010c1819 2134033b 032ad002 00102051 82510000 00>
Oct 10 19:47:12 Apple-TV AppleTV[24] <Warning>: [TRDeviceSetupServer] Decompressed data: <62706c69 73743030 d2010203 04516151 70546175 7468d105 0651645e 44617669 64277320 6950686f 6e65080d 0f111619 1b000000 00000001 01000000 00000000 07000000 00000000 00000000 00000000 2a>

The AppleTV process receives data over Bluetooth (starting here with “bcc254e0…”) and passes that to the TRTransferServer, which also logs the same data packet. Then it logs data of exactly the same length, with the note “Compressed data.” So the data was sent compressed, and probably encrypted, and now we’ve seen both the encrypted and decrypted versions of it. Woohoo, all we need to do now is decompress it. But wait, TRDeviceSetupServer is very helpful in its debug logging, as the very next line is annotated “Decompressed data” and contains the actual, decrypted, decompressed data sent by the iPhone. It’s a binary property list, which turned into JSON, looks like this:

{
  "a" : "auth",
  "p" : {
    "d" : "David's iPhone"
  }
} 

So far, so good, but really nothing special. It’s the result of the next transaction that’s interesting. The phone sends 1636 bytes of encrypted and compressed data, which the TRDeviceSetupServer conveniently decrypts, decompresses, and dumps to the log (as 3439 bytes of hex). This, again, is a property list, with considerably more content:

{
  "a" : "setup",
  "p" : {
    "au" : {
      "h" : {
        "x-apple-orig-url" : "https:\/\/p44-buy.itunes.apple.com\/WebObjects\/MZFinance.woa\/wa\/authenticate",
        "edge-control" : "no-store, cache-maxage=0",
        "x-set-apple-store-front" : "143441-1,19",
        "Expires" : "Thu, 10 Oct 2013 22:47:49 GMT",
        "apple-timing-app" : "402 ms",
        "pod" : "44",
        "Cache-Control" : "private, no-cache, no-store, no-transform, must-revalidate, max-age=0",
        "x-apple-lokamai-no-cache" : "true",
        "Content-Type" : "text\/xml; charset=UTF-8",
        "x-apple-translated-wo-url" : "\/WebObjects\/MZFinance.woa\/wa\/authenticate",
        "x-apple-jingle-correlation-key" : "--redacted--",
        "Content-Encoding" : "gzip",
        "x-apple-date-generated" : "Thu, 10 Oct 2013 22:47:48 GMT",
        "x-apple-application-site" : "ST13",
        "x-apple-application-instance" : "440051",
        "x-apple-asset-version" : "0",
        "Date" : "Thu, 10 Oct 2013 22:47:49 GMT",
        "Set-Cookie" : --really-large-cookie-jar-goes-here--; domain=.apple.com; httponly"
        "x-webobjects-loadaverage" : "23",
        "x-apple-request-store-front" : "143441-1,19 t:6",
        "Content-Length" : "522",
        "itspod" : "44"
      },
      "b" : {
        "status" : 0,
        "password" : "--redacted--",
        "m-allowed" : true,
        "creditBalance" : "1311811",
        "freeSongBalance" : "1311811",
        "clearToken" : "--redacted--",
        "is-cloud-enabled" : "true",
        "passwordToken" : "--redacted--",
        "dsPersonId" : "--redacted--",
        "creditDisplay" : "",
        "accountInfo" : {
          "address" : {
            "firstName" : "David",
            "lastName" : "Schuetz"
          },
          "accountKind" : "0",
          "appleId" : "--redacted--"
        }
      }
    },
    "np" : "--redacted--",
    "c" : "US",
    "l" : "en",
    "ns" : "--redacted--",
    "ha" : "--redacted--",
    "rp" : true,
    "hg" : "--redacted--",
    "di" : true
  }
}

(I’ve redacted anything that looked, you know, sensitive.) (and, no, I don’t have $1.3 million in iTunes credits. I have no idea what that number means.) The structure I’ll refer to here as p->b (the last big block, which starts with “status” and “password”) contained my Apple ID and password. The Apple ID was also repeated in the “ha” value a few lines later, and the Wi-Fi network name and password are passed in the ns and np values.

Naturally, we expect all this data to be present in the packet, as that’s the whole point of the Touch Setup: to transfer your Apple ID and Wi-Fi credentials to a new Apple TV so it’s immediately up and running on the network. The problem is that the credentials got saved to the log.

Here’s the affected code, in the original version (the two NSLog entries are where the data is written to the log):

// TRDeviceSetupServer - (id)server:(id) didReceiveData:(id)
  // v6 contains the decrypted data 
  if ( _TRLogEnabled == 1 )
    NSLog("Compressed data: %s", v6);   

  v18 = objc_msgSend(v6, "TR_decompressedGzipData");
  v19 = objc_retainAutoreleasedReturnValue(v18);
  objc_release(v6);
  if ( _TRLogEnabled == 1 )
    NSLog("Decompressed data: %s", v19); 
  }

And the new version. The NSLog entry for compressed data has been removed, and the log entry for uncompressed data has been replaced with a log simply recording the length of the decompressed data:

  v16 = objc_msgSend(v6, "TR_decompressedGzipData");
  v17 = (void *)objc_retainAutoreleasedReturnValue(v16);
  objc_release(v6);
  v6 = v17;
  if ( _TRLogEnabled == 1 )
  {
    v18 = objc_msgSend(v17, "length");
    NSLog(CFSTR("[TRDeviceSetupServer] Decompressed data length: %li"), v18);
  }

Is this really a big problem? Well, one should never write any kind of credentials to a system log, even in the case of the Apple TV, where the log is only available by physically connecting to the device. As far as I know, these logs aren’t stored on the system, but since I don’t have a jailbroken 6.0 Apple TV I can’t say for certain that they aren’t on disk somewhere. And if they’re on disk, they’re at risk.

Armed with this information, I wrote up a nice formal security advisory (Full Disclosure, see also CVE-2014-1279), and sent it off to Apple. Well, it took a little while – I had to verify what I’d done, get it written up, send it through our internal disclosure process, and, well, find the time to do it all. So I didn’t get the bug reported until November 8. Then we waited. I exchanged emails with Apple a couple of times, but still didn’t know when the fix would be released. Finally, on February 19, Apple wrote asking how I’d like to be credited for the find, and we knew the fix would be released soon. So even though it took a while, the “Coordinated Disclosure” process seemed to work pretty well.

This isn’t the first time that passwords were written to a system log, and it probably won’t be the last. But hopefully Apple can learn from these mistakes and work on their QA and code review processes to minimize similar vulnerabilities in the future.