Are You From The Mac App Store Synack validccshoponline, ccshoponlineru

Aloha it’s Patrick, Director of R&D at Synack. In my free time, I also run a small OS X security website , where I share my personal OS X security tools and blog about OS X security and coding topics. Below is one such post originally published on my site, which discusses one of my tools and more generally once way to monitor processing creation on OS X. Read & enjoy!
Let’s discuss how to use receipt verification to determine if an application is from Apple’s Mac App Store. While this has been covered elsewhere, such resources are somewhat outdated, require external dependencies (openssl), are iOS specific, or are copyrighted. To follow along in code, grab the complete source code from GitHub.
ERROR: could not find app store receipt url, or file (_MASReceipt/receipt)
ERROR: failed to init/decode/parse app’s receipt is *not* from the Mac App Store
Recently I released version 1.0 of RansomWhere? – a tool that attempts to generically thwart OS X ransomware. One of the improvements that will be present in version 1.1 is the reduction of false positives. As mentioned in “Towards Generic Ransomware Detection” , RansomWhere? flags untrusted processes that are generating encrypted files. A key component of this design, is correctly classifying processes as being ‘untrusted’ or not.
To reduce false-positives, version 1.1 will trust process instances that are backed by applications from Apple’s Mac App Store. In other words, such processes will be trusted (i.e. not flagged even if they rapidly create encrypted files). The current version of RansomWhere? does not contain logic to determine if an application is from the App Store, and as such, currently does not classify such applications as trusted.
While classifying such applications as trusted will reduce false positives, this begs the question, will this reduction come at the cost of higher false negatives? That is to say, what if ransomware makes it into the App store, it will (no longer) be detected by RansomWhere?
I’m fairly confident that this is unlikely to happen, or technically is somewhat unfeasible. Why? First, Apple attempts to verify that all applications submitted and hosted in their store are not malicious. Thus, ransomware showing up in the App Store is unlikely. And yes, I know, I know; malicious code could sneak in (it’s happened somewhat regularly in the iOS App Store). Which brings up the second point; applications from the App Store are heavily sandboxed. What does this have to do with ransomware? Well, due to the constrictive constraints of the Mac App sandbox, applications from the App Store cannot readily access arbitrary user files. In other words, even if ransomware made it into the App Store, on an end user’s machine it would not unable to arbitrary encrypt user files (such as photos, documents etc) – unless it contained some 0day sandbox escape. At least this is my understanding of App Sandbox…if I’m wrong, I’d love to be corrected
Programmatically Verifying App Receipts
Apple states; “Validating [an application receipt] locally requires code to read and validate a PKCS #7 signature, and code to parse and validate the signed payload.” …let’s dive in, and look how this is accomplished in code!
When determining if an application is from the App Store, and in an untampered state, the first thing to do is simply verify its digital signature. Specifically, check that it’s signed by a legitimate Apple Developer ID. In code; one can do this via the SecStaticCodeCheckValidity() function with the requirement reference “anchor apple generic“.
//is app signed with apple dev id?
// note: error checking (other than on signature) is omitted
//create static code
SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:appPath]), kSecCSDefaultFlags, &staticCode);
//create req string w/ ‘anchor apple generic’
SecRequirementCreateWithString(CFSTR(“anchor apple generic”), kSecCSDefaultFlags, &requirementRef);
//check if file is signed w/ apple dev id by checking if it conforms to req string
status = SecStaticCodeCheckValidity(staticCode, kSecCSDefaultFlags, requirementRef);
if(noErr != status)
   //err msg
   NSLog(@”ERROR: SecStaticCodeCheckValidity() failed with %d”, status);
   goto bail;
//hooray, app signed with apple dev id
However, just because an application is signed with an Apple Developer ID, doesn’t mean it’s from the App Store. In fact, the OS X ransomware KeRanger was signed with a legitimate developer ID! So, now one has to verify the application’s receipt. If the application contains a valid receipt; it is from the App Store.
The first step in application receipt validation is locating the receipt. On OS X 10.7+ one can simply call the NSBundle’s appStoreReceiptURL method to locate a url to the application’s receipt. Also make sure to check that the receipt file actually exists on disk.
//does app have a receipt?
if( (nil == bundle.appStoreReceiptURL)||
   (YES != [[NSFileManager defaultManager] fileExistsAtPath:bundle.appStoreReceiptURL.path]) )
   //err msg
   NSLog(@”ERROR: couldn’t find app store receipt url/file (%@)”, bundle.appStoreReceiptURL);
   goto bail;
//app has a receipt
Once the application’s receipt is located and loaded into memory, it must be decoded. Decoding begins with various functions provided by Apple’s implementation of the “Cryptographic Message Syntax” (see CMSDecoder.h /RFC 3852).
Basically, create a decoder, a X509 policy, add the encoded message to the decoder, then begin decoding! This is most clearly illustrated in code, shown below. Note that the code performs various initial validations on the receipt, such as ensuring the encoded data was signed, etc.
//begin receipt decoding
// note: error checking (other than on signer validations) is omitted
//create decoder
//add encoded data to message
CMSDecoderUpdateMessage(decoder, self.encodedData.bytes, self.encodedData.length);
//create policy
policy = SecPolicyCreateBasicX509();
//CHECK 1:
// ->make sure there is a signer
status = CMSDecoderGetNumSigners(decoder, &signers);
if( (noErr != status) ||
   (0 == signers) )
   goto bail;
//CHECK 2:
// ->make sure signer status is ok
status = CMSDecoderCopySignerStatus(decoder, 0, policy, TRUE, &signerStatus, &trust, &certVerifyResult);
if( (noErr != status) ||
   (kCMSSignerValid != signerStatus) )
   goto bail;
//grab message content
CMSDecoderCopyContent(decoder, &data);
//convert to NSData
decoded = [NSData dataWithData:(__bridge NSData *)data];
Now, we have decoded ‘message’ data. Time to finalize decoding and parse out various components that will be used in receipt validation.
To parse the decoded ‘message’ receipt data, as shown in RVNReceiptValidation.m , one can utilize Apple’s SecAsn1Coder APIs (see SecAsn1Coder.h ). Once a coder is created, invoke SecAsn1Decode() to finalize decoding:
//finalize decoding
// note: error checking is omitted
//create decoder
SecAsn1Decode(decoder, self.decodedData.bytes, self.decodedData.length, kSetOfReceiptAttributeTemplate, &payload);
Then, simply iterate over attributes in the decoded receipt data to extract attributes of interest. For receipt validation, we’re interested in the following attributes (and values) from the receipt:
//extract attributes of interest
for(int i = 0; (attribute = payload.attrs[i]); i++)
   //process each type
      //bundle id
      // ->save bundle id and data
         //save bundle id
         items[KEY_BUNDLE_ID] = decodeUTF8StringFromASN1Data(decoder, attribute->value);
         //save bundle id data
         items[KEY_BUNDLE_DATA] = [NSData dataWithBytes:attribute->
With the receipt located, decoded and parsed, finally it can be validated.
» check 0x1
The first check is to make sure the application’s bundle id matches the application bundle id that was embedded in the receipt:
//CHECK 0x1:
// ->app’s bundle ID should match receipt’s bundle ID
if(YES != [receipt.bundleIdentifier isEqualToString:appBundle.bundleIdentifier])
   //err msg
   NSLog(@”ERROR: receipt’s bundle ID (%@) != app’s bundle ID (%@)”,
   goto bail;
//continue checks…
» check 0x2
The second check is to make sure the application’s version matches the application version that was embedded in the receipt:
//CHECK 0x2:
// ->app’s version should match receipt’s version
if(YES != [receipt.appVersion isEqualToString:appBundle.infoDictionary[@”CFBundleShortVersionString”]])
   //err msg
   NSLog(@”ERROR: receipt’s app version (%@) != app’s version (%@)”,
      receipt.appVersion, appBundle.infoDictionary[@”CFBundleShortVersionString”]);
   goto bail;
//continue checks…
» check 0x3
The final check is to verify that a computed hash, matches the receipt’s embedded hash.
This step is a little more involved, specifically in terms of computing the hash. In order to compute the hash (to check it against the one that’s embedded in the receipt), first get the computer’s MAC address.
Apple provides code to retrieve this (snippet):
//get computer’s MAC address (snippet)
//iterate over services, looking for ‘IOMACAddress’
while((service = IOIteratorNext(iterator)) != 0)
   io_object_t parentService = 0;
   //get parent
   kernResult = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parentService);
   if(KERN_SUCCESS == kernResult)
      //release prev
      if(NULL != registryProperty)
      //get registry property for ‘IOMACAddress’
      registryProperty = (CFDataRef) IORegistryEntryCreateCFProperty(parentService,
         CFSTR(“IOMACAddress”), kCFAllocatorDefault, 0);
      //release parent
   //release service
Once the MAC address is retrieved, create a buffer that contains this MAC address, then the ‘opaque value’ attributed that was extracted from the receipt, and finally the data associated with the bundle id attribute. Hash this via SHA1:
//add guid (MAC) to data obj
[digestData appendData:guid];
//add receipt’s ‘opaque value’ to data obj
[digestData appendData:receipt.opaqueValue];
//add receipt’s bundle id data to data obj
[digestData appendData:receipt.bundleIdentifierData];
//init SHA 1 hash
CC_SHA1(digestData.bytes, (CC_LONG)digestData.length, digestBuffer);
Finally, to complete the third check, compare this computed hash against the hash that was embedded in the receipt:
//CHECK 0x3:
// ->ensure computed and embedded hash are equal
if(0 != memcmp(digestBuffer, receipt.receiptHash.bytes, CC_SHA1_DIGEST_LENGTH))
   //err msg
   NSLog(@”ERROR: receipt’s hash does not match computed one”);
   //hash check failed
   goto bail;
//hooray, receipt is valid!
Assuming all three checks pass, according to Apple, one can be ‘sure’ that the application is from the App Store and is in its original (untampered) state. Mission (finally) accomplished.
Now we can quickly check such thing as whether the (signed) OS X ransomware KeRanger is from the Mac App Store (it’s not):
$ ./fromAppStore /Volumes/Transmission/
checking if is from the Mac App Store
app is signed with an Apple Dev. ID
ERROR: could not find app store receipt url, or file (_MASReceipt/receipt)
ERROR: failed to init/decode/parse app’s receipt is *not* from the Mac App Store
Of course legitimate applications from the App Store are classified as such:
$ ./fromAppStore /Applications/
checking if is from the OS X App Store
app is signed with an Apple Dev. ID
found receipt at: /Applications/
check 1 passed: bundle ID’s match
check 2 passed: app versions match
check 3 passed: hashes match is from the Mac App Store
In order to reduce false positives, I plan on having RansomWhere? version 1.1 trust (i.e. ignore) untampered applications from the official Mac App Store. Turns out determining if an arbitrary application originated from the App Store, was a little more involved than I would have thought. But I learned a lot, and hopefully via this blog, so did you! Remember; check out the complete code – and stay tuned for RansomWhere? version 1.1.
validccshoponline ccshoponlineru