Messenger Hacking Remotely Compromising an Iphone Over Imessage

Messenger Hacking Remotely Compromising an Iphone Over Imessage

Messenger Hacking Remotely Compromising an iPhone over iMessage Samuel Groß (@5aelo), Project Zero Message coming from iMessage unknown sender ● Messaging service by Apple ● Enabled by default when signed in to iPhone with an Apple account ● Anyone can send messages ● Will popup a notification => Some kind of message processing must happen! => Default-enabled “0-Click” attack surface iMessage Architecture Apple Cloud Servers ● iMessages are sent via Apple’s push services ● Server mostly only sees sender and receiver ● Content is End2End Type: iMessage encrypted (good!) To: [email protected] Content: <e2e encrypted ● Also means Apple’s servers data> can hardly detect or block Sender exploits though... Receiver iMessage Exploit ● Prerequisites ○ Attacker knows phone number or email address ○ iPhone is in default configuration (iMessage not explicitly disabled) ○ iPhone is connected to Internet Type: iMessage To: [email protected] ● Outcome Content: <e2e encrypted ○ Attacker has full control over device data exploit> after few minutes ○ Possible without any visual indicator to user as well Reverse Engineering ● What process is handling iMessages? Make a guess, SIGSTOP that process => imagent seems important, also has an “iMessage” library loaded ● Search for interesting method names, set breakpoint to see if used => Main handler: -[MessageServiceSession handler:incomingMessage:...] ● Hook with frida (great tool!) to dump all messages as they come in ● From there, combination of static and dynamic analysis to figure out where what part of a message is processed iMessage Data Format { ● iMessages are just PLists gid = "008412B9-A4F7-4B96-96C3-70C4276CB2BE"; gv = 8; (Property Lists) p = ( ○ Something like json, but supports "mailto:[email protected]", "mailto:[email protected]" binary and XML encoding ); ● Many fields fairly self-explanatory pv = 0; r = "6401430E-CDD3-4BC7-A377-7611706B431F"; ● Contains pseudo-html in x key, t = "Hello 36C3!"; actually parsed as XML though v = 1; x = "<html><body>Hello 36C3!</body></html>"; ● Looks kind of complex already? } Enumerating Attack Surface { "$objects" => [ 0 => "$null" 1 => { "$class" => <CFKeyedArchiverUID>{value =7 } "NS.count" => 0 "NS.sideDic" => <CFKeyedArchiverUID>{value =0 } "NS.skkeyset" => <CFKeyedArchiverUID>{value =2 } ● “ATI” and “BP” keys of an iMessage } 2 => ... contain NSKeyedUnarchiver data ... 7 => { ● Had numerous bugs in the past "$classname" => "NSSharedKeyDictionary" } ● NSKeyedUnarchiver is now 0-Click ... Attack Surface... } An NSKeyedArchiver archive printed with plutil -p NSKeyedUnarchiver ● Serialization format to serialize rather complex datastructures ○ Dictionaries, arrays, strings, selectors, arrays of c-strings, … ● Extremely complex ● Even supports cyclic object relationships ● Read Natalie’s blog post to appreciate the complexity Vulnerability - Timeline ● Found during joint research project with Natalie Silvanovich (@natashenka) ● Reported July 29 ○ PoC Exploit sent on August 9 ● Mitigated in iOS 12.4.1, August 26 ○ Vulnerable code no longer reachable via iMessage ● Fully fixed in iOS 13.2, October 28 ● Seemed most convenient to exploit… ● Bug: object used before it is fully initialized due to reference cycle ● Vulnerable class: SharedKeyDictionary, subclass of NSDictionary and so implicitly allowed to be decoded… SharedKeyDictionary SharedKeyDictionary SharedKeyDictionary (pseudocode, simplified) - values: [“v1”, “v2”, ”v3”] - keyset: SharedKeyDictionary::lookup(key): idx = keyset.lookup(key, 0) SharedKeySet1 return values[idx] - numKey: 2 - rankTable: [1, 0] SharedKeySet::lookup(key, start): - keys: [“k1”, “k2”] khash = hash(key) - subskset: idx = rankTable[khash % len(rankTable)] if idx < numKey and key == keys[idx]: SharedKeySet2 return start + idx if subskset: - numKey: 1 - rankTable: [0] return subskset.lookup(key, start + numKey) - keys: [“k3”] return -1; - subskset: nullptr CVE-2019-8641 SharedKeySet::initWithCoder(c): numKey = c.decode('NS.numKey') rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') if len(keys) != numKey: raise DecodingError() for k in keys: if lookup(k) == -1: raise DecodingError() CVE-2019-8641 SharedKeySet::initWithCoder(c): numKey = c.decode('NS.numKey') rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: raise DecodingError() - numKey: 0 - rankTable: nullptr for k in keys: - subskset: nullptr - keys = nullptr if lookup(k) == -1: raise DecodingError() CVE-2019-8641 SharedKeySet::initWithCoder(c): numKey = c.decode('NS.numKey') rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: raise DecodingError() - numKey: 0xffffffff - rankTable: nullptr for k in keys: - subskset: nullptr - keys = nullptr if lookup(k) == -1: raise DecodingError() CVE-2019-8641 SharedKeySet::initWithCoder(c): numKey = c.decode('NS.numKey') rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: raise DecodingError() - numKey: 0xffffffff - rankTable: [0x41414141] for k in keys: - subskset: nullptr - keys = nullptr if lookup(k) == -1: raise DecodingError() CVE-2019-8641 SharedKeySet2 - numKey: 0 SharedKeySet::initWithCoder(c): - rankTable: nullptr numKey = c.decode('NS.numKey') - subskset: nullptr - keys: nullptr rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: - numKey: 0xffffffff raise DecodingError() - rankTable: [0x41414141] for k in keys: - subskset: SKS2 if lookup(k) == -1: - keys = nullptr raise DecodingError() CVE-2019-8641 SharedKeySet2 - numKey: 0 SharedKeySet::initWithCoder(c): - rankTable: nullptr numKey = c.decode('NS.numKey') - subskset: nullptr - keys: nullptr rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: - numKey: 0xffffffff Start raise DecodingError() - rankTable: decoding [0x41414141] SKS2 now for k in keys: - subskset: SKS2 if lookup(k) == -1: - keys = nullptr raise DecodingError() CVE-2019-8641 SharedKeySet2 - numKey: 1 SharedKeySet::initWithCoder(c): - rankTable: nullptr - subskset: nullptr numKey = c.decode('NS.numKey') - keys: nullptr rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: - numKey: 0xffffffff raise DecodingError() - rankTable: [0x41414141] for k in keys: - subskset: SKS2 if lookup(k) == -1: - keys = nullptr raise DecodingError() CVE-2019-8641 SharedKeySet2 - numKey: 1 SharedKeySet::initWithCoder(c): - rankTable: [42] numKey = c.decode('NS.numKey') - subskset: nullptr - keys: nullptr rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: - numKey: 0xffffffff raise DecodingError() - rankTable: [0x41414141] for k in keys: - subskset: SKS2 if lookup(k) == -1: - keys = nullptr raise DecodingError() CVE-2019-8641 SharedKeySet2 - numKey: 1 SharedKeySet::initWithCoder(c): - rankTable: [42] numKey = c.decode('NS.numKey') - subskset: SKS1 - keys: nullptr rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: - numKey: 0xffffffff raise DecodingError() - rankTable: [0x41414141] NSKeyedUnarachiver for k in keys: - subskset: SKS2 has special logic to handle this case if lookup(k) == -1: - keys = nullptr correctly (i.e not raise DecodingError() create a third object) CVE-2019-8641 SharedKeySet2 - numKey: 1 SharedKeySet::initWithCoder(c): - rankTable: [42] numKey = c.decode('NS.numKey') - subskset: SKS1 - keys: [“key1”] rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: - numKey: 0xffffffff raise DecodingError() - rankTable: [0x41414141] for k in keys: - subskset: SKS2 if lookup(k) == -1: - keys = nullptr raise DecodingError() CVE-2019-8641 SharedKeySet2 - numKey: 1 SharedKeySet::initWithCoder(c): - rankTable: [42] numKey = c.decode('NS.numKey') - subskset: SKS1 - keys: [“key1”] rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: - numKey: 0xffffffff raise DecodingError() - rankTable: [0x41414141] for k in keys: - subskset: SKS2 if lookup(k) == -1: - keys = nullptr raise DecodingError() CVE-2019-8641 SharedKeySet2 - numKey: 1 SharedKeySet::initWithCoder(c): - rankTable: [42] numKey = c.decode('NS.numKey') - subskset: SKS1 - keys: [“key1”] rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: - numKey: 0xffffffff raise DecodingError() - rankTable: for k in keys: [0x41414141] - subskset: SKS2 if lookup(k) == -1: - keys = nullptr raise DecodingError() CVE-2019-8641 SharedKeySet2 - numKey: 1 SharedKeySet::initWithCoder(c): - rankTable: [42] numKey = c.decode('NS.numKey') - subskset: SKS1 - keys: [“key1”] rankTable = c.decode('NS.rankTable') subskset = c.decode('NS.subskset') keys = c.decode('NS.keys') SharedKeySet1 if len(keys) != numKey: - numKey: 0xffffffff raise DecodingError() - rankTable: for k in keys: [0x41414141] - subskset: SKS2 if lookup(k) == -1: - keys = nullptr raise DecodingError() CVE-2019-8641 SharedKeySet2 - numKey: 1 SharedKeySet::initWithCoder(c):

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    78 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us