FORCEDENTRY: Sandbox Escape
Follow-up to the December post which covered an int overflow in the CoreGraphics PDF parser for the JBIG2 image format, which implemented a weird machine / mini architecture to execute code. This post covers the sandbox escape that was chained with it, which unlike the first bug, is a logic issue rather than a memory corruption.
Background
A bit of background is necessary to understand the sandbox escape, because it’s a very intricate and complex bug. First, objects in obj-c have a metadata field called the isa
field, which stores a pointer to the object’s class along with other stuff. Prior to iOS 14.5, this field was not protected by Pointer Authentication Codes (PAC). This allowed the exploit authors to fake different types of obj-c objects.
One critical type of object for this exploit is the NSPredicate
object, which can be used to query and filter other objects such as NSArray
s. These predicates can be created in the form of expressions through keywords, such as NSFunctionExpressions
with the “FUNCTION” keyword to invoke an arbitrary method. With some tricks, this can be effectively be used to execute arbitrary obj-c code.
Sandbox escape
Once arbitrary code can be ran, the sandbox escape comes into play via attacking a service over NSXPC (obj-c’s RPC mechanism). Basically with NSXPC, a service can export an object with a protocol
attached which defines which methods and argument types can be used by the client. What’s noteworthy is, the type enforcement is pretty loose by design. Not only will that type be permitted and deserialized by the service, but any sub-class of that type will also be accepted and deserialized. In an extreme case, any protocol that accepts an NSObject
somewhere can effectively receive almost any object, since most objects inherit from it.
The evaluateMobileSubscriberIdentity()
method of the CoreTelephonyClient for the CommCenter service accepted NSObject
types in it’s protocol. In theory, an attacker can pass an NSPredicate
object here, which when deserialized will execute arbitrary obj-c in the CommCenter service context. In practice, there’s some defense in depth onNSPredicate
objects where it won’t be evaluated until allowEvaluation()
is called. Since evaluateMobileSubscriberIdentity()
doesn’t expect predicates, this will never get called.
Fortunately for the attackers, there’s another object from the PrototypeTools
framework called PTSection
, which has a child NSArray
of PTRow
objects. These PTRow
objects have conditions, which can be evaluated as predicates. By passing a PTSection
with a PTRow
that has a malicious NSPredicate
, code execution in the CommCenter service can be achieved when the object is deserialized.
Fix
The primary fix was introduced by Apple in iOS 15.1. They now forbid NSExpression
s from performing operations with significant side-effects like creation and destruction of objects, neutering the ability to execute arbitrary obj-c.