TL;DR — Apple built a super secure door, left the key on the door and forgot to build the wall around the door.

Ever since the existence of connected home accessories, security is always something people worried about. So many things that can go wrong with your fancy new BTLE lock with software running on it, compared to old mechanical locks. There was a period of time where the market of connected home accessories is really chaotic, manufacturer shipping poorly implemented accessories with terrible security. I was really happy when Apple announced HomeKit back in 2014, promising to offer a secure and private way to control connected home accessories.

The thing is, a lot of time there is really no way for people to check whether a thing is really secure or not. And for HomeKit, it turned out not to be so secure after all. HomeKit didn’t check the sender of remote message before processing the request, which ended up allowing potentially anyone to remotely control HomeKit accessories in the home.

HomeKit is actually an umbrella term covering both the software on your iOS device and a communication protocol. The software on your device provides a centralized place for you to manage home and accessories (daemon), and the communication protocol (HAP) used by the software on iOS to talk to your HomeKit accessories. The security issues with watchOS 4 and iOS 11.2 were on daemon side, the underlying HAP exchange is not breached.

So, what went wrong with HomeKit?

A not too technical version

Imagine HomeKit as the butler for your home, and when you are not at home, you can send iMessage to it asking it to do things for you. Say you want to unlock the front door, you would send a message to HomeKit asking it to unlock the front door. Once HomeKit receive the message, it should check that the message is sent by you and then unlock the door as you have asked. Except that in reality, HomeKit doesn’t check who sent the message and it will happily unlock the door whenever someone ask it to do so.

In order for HomeKit to do something, the message needs to contain a unique identifier that identifies the object (accessory, scene, or room) in the home. Normally it should be impossible for anyone to figure out the unique identifier for those objects unless you are actually authorized to access that home in HomeKit. However, there are two separate bugs, one in watchOS 4 - 4.1, and another in iOS 11.2 and watchOS 4.2, allow someone to figure out those unique identifiers without authorizing the person to access the home in first place. With those unique identifiers, remote attacker can ask HomeKit to do almost anything.

Apple disabled the ability for people to send HomeKit message to others on December 7th as a temporary solution while it works on a proper fix for future iOS release. As a result of that, sharing home to new users and remote access for existing shared users are not longer available for users on iOS before 11.2.1.

A more technical version

HomeKit daemon is built upon the request-response pattern. Each action you do in your favorite HomeKit app is being translated to a request, sent to daemon. The daemon processes the request, perform the operation, and then reply to the request. For HomeKit app running on iOS device, all of the communication is done over XPC and the access permission is enforced by TCC (the permission popup in iOS). All information discussed in this article are based on disassembling HomeKit daemon binary bundled with iOS SDK. Hopper is a great tool for this kind of task ;)

To allow you to securely access your accessories when you are not at home, and share your home with other users, Apple built a remote cloud messaging platform (same one behind iMessage). Messages across users, devices, and apps over multiple transports are processed by the HomeKit daemon with a centralized message dispatcher.

Fun things happen when someone try to design a system that’s too flexible. For XPC messages, HomeKit daemon doesn’t really need to perform extra validation for messages since TCC and iOS in general have already done all the hard work (Entitlements 😉). For normal daemon to daemon remote communication, the actual message is encrypted by HomeKit secure session, and the encrypted packet is then sent over the remote cloud messaging platform. The issue with HomeKit is how the daemon handles remote message without a secure session. Instead of having daemon discard the message that doesn’t make sense with the state machine, the daemon treat the message as a normal request and processed it anyway. Apple addressed the issue with iOS 11.2.1 and tvOS 11.2.1 by improving message handling on the daemon side.

Since HomeKit daemon handles request without secure session as a normal request, we can send messages to home manager and have it leak information about the home and its accessories. Those information could then be used to instruct HomeKit to perform actions it shouldn’t do in the normal situation. There are two ways we could gather the required information from home manager, one was available with watchOS 4 and 4.1, and the other one was introduced in iOS 11.2 and watchOS 4.2 🙃. Both are now patched as of iOS 11.2.1.

For watchOS 4 and 4.1

Of all the messages you can send to HomeKit daemon, there are some really interesting ones. There is one message that will let HomeKit on watchOS to reply with a list of home identifiers, along with the public and private key that used to encrypt home data and communicate with accessories to the sender. Once an attacker got the reply, it’s game over for HomeKit. With pairing identity and private key, the attacker can trick HomeKit into thinking him as the owner of the home, even after Apple fixed the messaging issue.

A small tool for verifying the vulnerability

But yeah, now we have all the information we need to tell HomeKit daemon to do things, we can just send messages targeting the right home, and control every thing in user’s home (including IP cameras 😅).