Now Reading
Reverse Engineering the Apple MultiPeer Connectivity Framework

Reverse Engineering the Apple MultiPeer Connectivity Framework

2023-08-08 12:17:58

A while in the past I used to be utilizing Logic Pro to report a few of my music and I wanted a approach to begin and cease the recording from an iPhone, so I discovered about Logic Remote and was fairly proud of it.
After the session, the hacker in me turned interested by how the instruments had been speaking with one another, so I shortly began Wireshark whereas establishing a connection and noticed one thing that tickled my curiosity much more: among the information, such because the shopper and server names, had been transmitted in cleartext on what it appeared a customized (and as typical of Apple, undocumented) TCP protocol (“stevie” being the hostname of my Mac):

cleartext packets

Utilizing lsof confirmed that this was certainly the communication between the shopper cellphone and Logic listening on port 56076:


Initially I tought this was just a few Logic Professional particular protocol and really lazily began trying into it, with out a lot success principally as a result of lack of motivation given the very restricted scope of the analysis. After some time I tweeted asking if anybody had ever seen something prefer it. @isComputerOn pointed out that this seemed so much like a protocol that has been partially reversed and introduced by Alban Diquet again in 2014. Sadly, nevertheless good, this analysis covers the protocol at a really excessive degree and doesn’t actually doc the packets, their fields and set up a connection from something however a shopper utilizing the Apple framework. Nonetheless, this helped me so much in two methods: first it helped me understand this was not simply Logic Professional particular, however that it was a part of the Multipeer Connectivity Framework, and gave me a couple of hints in regards to the normal logic of the protocol itself.

With renewed curiosity and motivation then I jumped into this rabbit gap and managed to reverse engineer all community packets. This allowed me to put in writing a Python proof of concept client that routinely discovers any MPC servers, initializes the connection and succesfully exchanges software particular information packets.

Furthermore, whereas sending crafted packets and making an attempt all types of issues, I’ve found a number of vulnerabilities within the Apple customized made parsers. I’ll not talk about them right here (exception made for the session spoofing) however on the identical time I’m not fascinated by reporting them to Apple, I’ve heard approach too many unfavourable tales about their disclosure program and usually how they mistreat researchers.


Let’s see how this entire factor works! 🙂

MultipeerConnectivity Framework

Apple’s documentation describes the framework like so:

The Multipeer Connectivity framework helps the invention of companies supplied by close by units and helps speaking with these companies by means of message-based information, streaming information, and assets (corresponding to information). In iOS, the framework makes use of infrastructure Wi-Fi networks, peer-to-peer Wi-Fi, and Bluetooth private space networks for the underlying transport. In macOS and tvOS, it makes use of infrastructure Wi-Fi, peer-to-peer Wi-Fi, and Ethernet.

The doc principally describes how they abstracted the protocol in a number of courses whereas being extraordinarily imprecise about how the factor really works on the packet degree. In actuality they principally reused current protocols corresponding to MDNS and a personalized STUN implementation (in Logic Professional particular case, this doesn’t all the time apply to apps utilizing this framework), plus a customized TCP primarily based protocol for which they closely relied on customized (and intensely badly) written parsers.

Discovery Part: Multicast DNS

The very very first thing that I’ve seen was that, regardless of the server port being randomized at every software startup, the shopper software by no means requested me for the server ip deal with nor tcp port. This was a robust indicator that one thing else was taking place on the community earlier than the TCP session was being established, as if the server (and presumably the shopper as properly) broadcasted this data in such a approach to be routinely discoverable, as additionally hinted by the wording used within the documentation.

My knowledgeable guess was multicast DNS as I’ve seen this protocol being (ab)used so much from Apple (Bonjour as an example), and Wireshark confirmed my guess. Each the server and the shopper are broadcasting their hostnames and peer identifiers (extra on this later) on the community in order that they will discover one another with out consumer interplay.

Right here’s how the server commercial seems to be like on Spycast:

mdns server

We are able to see which TCP port is getting used (57219), some software particular data within the textual content report and a bizarre string “1tvdkfvihbru6”, the PeerID.

On the identical time, the shopper is broadcasting some data corresponding to its hostname:

mdns client

Understand that all this information is seen by anybody on the identical community, this is a vital element as we’ll see shortly once I’ll describe how the spoofing works.

How a PeerID is made

Earlier than continuing to the following half, let’s cease for a second to see how a peer is recognized on this protocol and what that “1tvdkfvihbru6” string is.

Upon startup, every peer is represented by a MCPeerID object. Lengthy story brief, a random 64bit integer is generated and transformed to base36.

In order that 1tvdkfvihbru6 in base36 is 8670129607084362000 in base 10. This quantity is used to uniquely establish the host through the session, whatever the hostname itself and it’s current in varied types in many of the packets we’re about to see.

Handshake Part: Hellos and Acks

After the shopper discovers the server peer by way of MDNS the connection is initiated to the TCP port indicated within the commercial. That is when issues began being sophisticated because the protocol is fully customized and undocumented.

I wanted to work my approach from one thing like this:

hex data

To one thing like this.

For this process I’ve carried out dozens of assessments corresponding to:

  • See if comparable packets all began with the identical signature bytes (they did).
  • See if by altering the hostname of the shopper, another fields (presumably string size fields) modified reflecting the brand new size (they did).
  • See if there was any checksum happening by 2 bytes and 4 bytes phrases that modified relying on the contents (there are).
  • See if packets had been encapsulated with a typical header plus a packet-specific payload, which size ought to be indicated within the header (it’s).

After a couple of days of testing I’ve managed to know that each one the packets began with a header that appears like this:

  • The primary 2 bytes are the packet signature and decide the packet kind (Hiya, Ack, Invite, …).
  • The following 4 bytes are a sequence quantity plus flags which might be used just for some particular payloads.
  • We then have 2 bytes indicating the payload dimension after the header.
  • Following 4 bytes are the CRC32 of the entire packet (i wasn’t positive which checksum was, so I bruteforced it :D)
  • The final 4 bytes of the header are unknown to me however they all the time appear to include the identical worth.

With this new information I began trying into the payload of the primary packets and recognized how the connection handshake works:

  1. The shopper sends an Hello packet made from the header and its PeerID.
  2. The server responds with an Ack packet, made from simply the header and no payload.
  3. The server then sends its personal Hiya packet containing its PeerID (which appears redundant given its already broadcasted by way of MDNS, however no matter …).
  4. The shopper sends an Ack to the server Hiya.
  5. Lastly the shopper sends an Accept packet additionally solely made from the header and no payload, indicating that the primary a part of the handshake is full. The explanation why the shopper is liable for this and never the server will all the time stay a thriller to me 😀

You’ll find the implementation of this handshake course of here.

Authorization Part: Spoofable Invitations and BPlist inside BPlist inside TCP

After this mutual introduction, the shopper will ship an Invitation packet and that is the place issues begin getting covoluted (a la Apple): as we will see from the following image, the Invite packet is made from the header plus a Binary Property List as indicated by the “bplist00” signature seen in cleartext within the packet:

client invite

A BPlist is principally a binary encoded XML doc, on this case containing the next fields:

  • MCNearbyServiceInviteContextKey: a bplist encoded (sure it’s a bplist inside a bplist …) integer, all the time 0x2.
  • MCNearbyServiceInviteIDKey: an integer all the time set to 0x0.
  • MCNearbyServiceMessageIDKey: an integer message identifier, all the time 0x1 for invitations.
  • MCNearbyServiceRecipientPeerIDKey: the message recipient (the server on this case) PeerID, encoded as described subsequent.
  • MCNearbyServiceSenderPeerIDKey: the message sender (the shopper) PeerID.

Within the final two fields, the peer identifiers are encoded as:

  • 8 bytes containing the numeric peer identifier, large endian.
  • 1 byte containing the peer hostname size.
  • N bytes containing the unicode peer hostname.

The server responds with an Ack and at this level two issues can occur: if the shopper is unknown to the server, a immediate shall be proven with the intention to let the consumer determine wether to authorize it or not:

server prompt

Nonetheless, if the shopper has been beforehand approved, no immediate shall be proven and the communication will silently proceed to the following information change step.

At this level you may ask, how does the server retailer this authorization data? Is it some form of session cookie? A extra superior cryptographic problem mechanism? Black magic? Effectively my pals, typically actuality is approach duller and dumber than what you may think 😀

They simply don’t give a rattling and preserve a “string peer_hostname -> bool approved” affiliation … sure, you learn that proper, shopper authorization solely depends on the (spoofable) shopper hostname, they don’t even care in regards to the peer identifier quantity.

Bear in mind how all this data (and extra) is being broadcasted in cleartext by way of MDNS for everybody to get pleasure from? Yep that’s proper, an attacker can look forward to a legit shopper to be approved after which use its hostname (not on the community, simply within the MCNearbyServiceSenderPeerIDKey subject) with the intention to both hijack the legit session, or simply create a brand new one in every of its personal and fully bypass the authorization immediate ????????????


See Also

Anyhow … if approved, the server will conclude this part by sending an InviteResponse, which is an identical to the shopper Invite packet, again to the shopper. You’ll find the shopper invite logic here and the wait loop for the server response here.

Let’s proceed.

Knowledge Trade Part

After the server accepted the invite, the shopper will proceed by sending a ClientData packet, one other bplist encoded payload containing the next fields:

  • MCNearbyServiceInviteIDKey: the invite key obtained with the server InviteResponse.
  • MCNearbyServiceMessageIDKey: an incremental integer being InviteResponse.MCNearbyServiceMessageIDKey + 1.
  • MCNearbyServiceRecipientPeerIDKey: shopper peer id encoded as beforehand described.
  • MCNearbyServiceSenderPeerIDKey: server peer id encoded as beforehand described.
  • MCNearbyServiceConnectionDataKey: connection information as bplist (once more, a bplist inside a bplist …), described subsequent.

The fascinating half right here is the MCNearbyServiceConnectionDataKey subject, which accommodates a bplist encoded binary payload made from:

  1. A header composed of:
    • 1 signature byte (0x80).
    • 1 byte bitmask of safety flags indicating if encryption is enabled (not on this case, LOL).
    • 2 bytes indicating the entire dimension of the payload.
    • 1 byte indicating the variety of segments / entries within the payload.
  2. An inventory of IPv4 and IPv6 addresses, one for every community interface of each friends.
  3. A variable variety of segments describing each network interface of both peers, made from:
    • 1 signature byte (0x61).
    • 4 bytes of the numeric peer id (both the shopper or the server one) trimmed all the way down to 32bits.
    • 4 bytes of a random identifier, my guess is that this creates a brand new distinctive identifier along with the earlier subject.
    • 1 byte indicating the interface kind ( ipv4=0x5A ipv6=0x0A ).
    • 3 bytes of padding.
    • 1 byte containing the interface IP index bit-masked with its kind.
    • 2 bytes containing an UDP port.

Because the software particular a part of the protocol works on UDP, by exchanging this information each endpoints grow to be conscious of on which potential IP and UDP ports the following a part of the communication can occur.

STUN a la Facetime

After the earlier step, an Apple customized implementation of STUN is used to find out NAT kind and which IP:PORT pair is finest suited to the communication. Apparently, whereas digging onerous into this rabbit gap and reversing different frameworks that had been referenced right here and there, I discovered this is identical actual mechanism that Apple Facetime additionally makes use of.

I’ve applied a really primary STUN processor here, what occurs is:

  1. The server will decide one of many IP:UDP_PORT pairs despatched within the ClientData and sends a STUN Binding Request containing these STUN attributes:
    • USERNAME: containing the server and shopper integer peer identifiers.
    • ADDRESS_ERROR_CODE: all the time 0x6.
    • ALTERNATE_DOMAIN: all the time 0x03f2.
    • APPLE_NTP_DELAY: you’ll see this labled as ICMP by Wireshark, nevertheless Apple is utilizing this particular attribute identifier to point the NTP delay, as I discovered by Ghidra-ing the s*it out of it 😀
    • ICE_CONTROLLING: randomly generate STUN tie breaker / session id.
  2. The shopper will reply with its personal Binding Request, changing ICE_CONTROLLING with ICE_CONTROLLED and its tie breaker.
  3. The server will ship a Binding Response with a MAPPED-ADDRESS attribute indicating the ultimate IP:UDP_PORT pair for the communication.
  4. The shopper will ship its personal Binding Response with its UDP MAPPED-ADDRESS.

From this level on, an UDP connection is established between the 2 MAPPED-ADDRESSes and software particular information is exchanged.

Transient be aware on OSPF

Regardless of the Logic Professional particular protocol taking place in spite of everything these steps is out of the scope of this submit, I wish to briefly point out the way it works.

Apparently, this protocol is referenced as OSPF from the framework:


Howver it has virtually nothing in widespread with the Open Shortest Path First protocol. Regardless of a few of these operate names reference legitimate OSPF messages corresponding to LSA, LSAACK and so forth, the Apple implementation is fully totally different.

You’ll find a partial python implementation here that shall be used after the earlier step with the intention to appropriately begin the “OSPF” session and begin receiving information from the server.

On this case, every packet is made from this header:

  • 1 byte of protocol kind signature (0xc1).
  • 1 byte of packet kind signature.
  • 2 bytes of packet dimension.
  • 2 bytes indicating OSPF channel, principally unused.
  • 2 bytes with the packet CRC16/ARC checksum (once more, bruteforcing the kind of checksum helped so much).
  • 4 bytes of the sender peer id.
  • 4 bytes of the receiver peer id.

Following, the packet particular payload.

You’ll find the definitions of a few of the Logic Pro packets here and the OSPF server code that may initialize the session and begin getting server updates here.


This has undoubtedly been a enjoyable trip throughout which I’ve realized a number of new stuff about how Apple frameworks deal with community communications. I wish to reiterate my gratitude to Alban Diquet for its analysis and to @isComputerOn for pointing me to the appropriate route once I was about to surrender on what it appeared one thing fully irrelevant, thanks you a lot guys! <3

I additionally wish to touch upon one thing i’ve heard throughout a chat introduced on the final 0x41 conference.
The researcher who was presenting and who specialised in fuzzing Apple merchandise, talked about how initially of his path, somebody who’s extremely revered and acknowledged within the infosec group and business, instructed him that “fuzzing Apple’s community protocols was a dumb thought”, which sadly satisfied the researcher to look elsewhere.

Effectively, my extremely revered and acknowledged dude, I can let you know it’s not a dumb thought, in any respect, there’s so much of unexplored assault floor there. What was dumb, very close-minded and ignorant, is your take about it.

Anyhow … you can find the project on my github as regular, get pleasure from!

Source Link

What's Your Reaction?
In Love
Not Sure
View Comments (0)

Leave a Reply

Your email address will not be published.

2022 Blinking Robots.
WordPress by Doejo

Scroll To Top