Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use of Unsafe Serialization API Exposes App to Remote Code Execution #14424

Open
achoudhari-csod opened this issue Feb 4, 2025 · 2 comments · May be fixed by #14457
Open

Use of Unsafe Serialization API Exposes App to Remote Code Execution #14424

achoudhari-csod opened this issue Feb 4, 2025 · 2 comments · May be fixed by #14457
Assignees

Comments

@achoudhari-csod
Copy link

Description

We are using firebase ios sdk for our ios app. Our NowSecure dynamic analysis security team have reported the security issue regarding Use of Unsafe Serialization API Exposes App to Remote Code Execution.

Following are the details of the issue
This application was found to use deprecated nscoding functionalities for serialization/deserialization of data.
Caution should be taken when an application has logic to receive arbitrary data and to then deserialize the data into an object. Remote code execution is possible if raw data is permitted to choose an arbitrary class as the object it becomes deserialized to.
In iOS applications, object deserialization/serialization is usually implemented using the NSCoding protocol, which allows the developer to implement the serialization logic for their own classes, or the NSSecureCoding protocol which extends the NSCoding protocol. An implementation which uses the NSCoding protocol is vulnerable to data being deserialized to a different object than what was expected by the developer, also referred to as an "object substitution attack" in Apple's documentation. For more information, watch https://developer.apple.com/videos/play/wwdc2018/222/.

FirebaseMessaging.framework still has usage of NSKeyedUnarchiver unarchiveObjectWithData which is causing this issue .

Recommended Fix
Make sure you have adopted NSSecureCoding in the data you decode. When writing a class that supports secure coding, ensure that the + (BOOL)supportsSecureCoding class property getter returns true. Ensure that all - (id)decodeObjectForKey:(NSString_)key calls are replaced with - (id)decodeObjectOfClass:(Class)c forKey:(NSString_)key.
Also avoid using the deprecated unarchive_ObjectWithData and unarchive_ObjectWithFile classes and instead implement unarchive*OfClass classes. Refer to NSSecureCoding for further details.
It should be noted that third party libraries may be the cause of this finding. In cases where a third party library is the source of this issue, make sure that versions of the library are up-to-date and that the library is necessary.

Code Samples
Good Code Example (.swift)

class Post: NSSecureCoding
{
static var supportsSecureCoding: Bool {
get { return true }
}

// Later on down the road, you might do something like this...
func updatePostsCache()
{
let saveURL = URL(fileURLWithPath: "someDestination")
let archiver = NSKeyedArchiver.archivedData(withRootObject: posts)
try? archiver.write(to: saveURL)
}

// And eventually get it back out...
let postCache:[Data] = /* Data loaded up */
let posts = try postCache.map { postData in
guard let postBlob = try NSKeyedUnarchiver.unarchiveTopLevelObject(with: postData), let post = postBlob as? Post else { throw /* Error handling */ }
return post
}
//Interacting with Object Class
decoder.decodeObject(of:Post.self, forKey: "Posts")
Good Code Example (.objc)

// Inside @interface
@interface Post : NSObject <NSSecureCoding> {

// Add support for secure coding
(BOOL) supportsSecureCoding {
return YES;
}
//...other data
}

//Interacting with Object Class
id obj = [decoder decodeObjectOfClass:Post.class forKey:@"Posts"];
if (![obj isKindOfClass:[MyClass class]]) { /* ...fail... */ }

Additional Guidance
This article describes the NSCoding protocol which may be insecure if an attacker injects an object of different type(s https://developer.apple.com/documentation/foundation/nscoding
This article introduces the NSSecureCoding protocol which allows secure encoding and decoding of objects (checking types before creating the object https://developer.apple.com/documentation/foundation/nssecurecoding

Reproducing the issue

No response

Firebase SDK Version

11.7.0

Xcode Version

16

Installation Method

CocoaPods

Firebase Product(s)

All

Targeted Platforms

iOS

Relevant Log Output

If using Swift Package Manager, the project's Package.resolved

Expand Package.resolved snippet
Replace this line with the contents of your Package.resolved.

If using CocoaPods, the project's Podfile.lock

Expand Podfile.lock snippet
- Alamofire (5.10.1)
  - AmplitudeSwift (1.9.4):
    - AnalyticsConnector (~> 1.0.1)
  - AnalyticsConnector (1.0.3)
  - CocoaLumberjack/Core (3.8.5)
  - CocoaLumberjack/Swift (3.8.5):
    - CocoaLumberjack/Core
  - CSCoursePlayer (0.0.1):
    - GCDWebServer
  - CSOD-Tracker (2.1.7):
    - AmplitudeSwift (~> 1.9.4)
  - DeviceKit (5.5.0)
  - Firebase/AnalyticsWithoutAdIdSupport (11.7.0):
    - Firebase/CoreOnly
    - FirebaseAnalytics/WithoutAdIdSupport (~> 11.7.0)
  - Firebase/CoreOnly (11.7.0):
    - FirebaseCore (~> 11.7.0)
  - FirebaseABTesting (11.7.0):
    - FirebaseCore (~> 11.7.0)
  - FirebaseAnalytics/WithoutAdIdSupport (11.7.0):
    - FirebaseCore (~> 11.7.0)
    - FirebaseInstallations (~> 11.0)
    - GoogleAppMeasurement/WithoutAdIdSupport (= 11.7.0)
    - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
    - GoogleUtilities/MethodSwizzler (~> 8.0)
    - GoogleUtilities/Network (~> 8.0)
    - "GoogleUtilities/NSData+zlib (~> 8.0)"
    - nanopb (~> 3.30910.0)
  - FirebaseCore (11.7.0):
    - FirebaseCoreInternal (~> 11.7.0)
    - GoogleUtilities/Environment (~> 8.0)
    - GoogleUtilities/Logger (~> 8.0)
  - FirebaseCoreExtension (11.7.0):
    - FirebaseCore (~> 11.7.0)
  - FirebaseCoreInternal (11.7.0):
    - "GoogleUtilities/NSData+zlib (~> 8.0)"
  - FirebaseCrashlytics (11.7.0):
    - FirebaseCore (~> 11.7.0)
    - FirebaseInstallations (~> 11.0)
    - FirebaseRemoteConfigInterop (~> 11.0)
    - FirebaseSessions (~> 11.0)
    - GoogleDataTransport (~> 10.0)
    - GoogleUtilities/Environment (~> 8.0)
    - nanopb (~> 3.30910.0)
    - PromisesObjC (~> 2.4)
  - FirebaseInstallations (11.7.0):
    - FirebaseCore (~> 11.7.0)
    - GoogleUtilities/Environment (~> 8.0)
    - GoogleUtilities/UserDefaults (~> 8.0)
    - PromisesObjC (~> 2.4)
  - FirebaseMessaging (11.7.0):
    - FirebaseCore (~> 11.7.0)
    - FirebaseInstallations (~> 11.0)
    - GoogleDataTransport (~> 10.0)
    - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
    - GoogleUtilities/Environment (~> 8.0)
    - GoogleUtilities/Reachability (~> 8.0)
    - GoogleUtilities/UserDefaults (~> 8.0)
    - nanopb (~> 3.30910.0)
  - FirebaseRemoteConfig (11.7.0):
    - FirebaseABTesting (~> 11.0)
    - FirebaseCore (~> 11.7.0)
    - FirebaseInstallations (~> 11.0)
    - FirebaseRemoteConfigInterop (~> 11.0)
    - FirebaseSharedSwift (~> 11.0)
    - GoogleUtilities/Environment (~> 8.0)
    - "GoogleUtilities/NSData+zlib (~> 8.0)"
  - FirebaseRemoteConfigInterop (11.7.0)
  - FirebaseSessions (11.7.0):
    - FirebaseCore (~> 11.7.0)
    - FirebaseCoreExtension (~> 11.7.0)
    - FirebaseInstallations (~> 11.0)
    - GoogleDataTransport (~> 10.0)
    - GoogleUtilities/Environment (~> 8.0)
    - GoogleUtilities/UserDefaults (~> 8.0)
    - nanopb (~> 3.30910.0)
    - PromisesSwift (~> 2.1)
  - FirebaseSharedSwift (11.7.0)
  - GCDWebServer (3.5.4):
    - GCDWebServer/Core (= 3.5.4)
  - GCDWebServer/Core (3.5.4)
  - GoogleAppMeasurement/WithoutAdIdSupport (11.7.0):
    - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
    - GoogleUtilities/MethodSwizzler (~> 8.0)
    - GoogleUtilities/Network (~> 8.0)
    - "GoogleUtilities/NSData+zlib (~> 8.0)"
    - nanopb (~> 3.30910.0)
  - GoogleDataTransport (10.1.0):
    - nanopb (~> 3.30910.0)
    - PromisesObjC (~> 2.4)
  - GoogleUtilities/AppDelegateSwizzler (8.0.2):
    - GoogleUtilities/Environment
    - GoogleUtilities/Logger
    - GoogleUtilities/Network
    - GoogleUtilities/Privacy
  - GoogleUtilities/Environment (8.0.2):
    - GoogleUtilities/Privacy
  - GoogleUtilities/Logger (8.0.2):
    - GoogleUtilities/Environment
    - GoogleUtilities/Privacy
  - GoogleUtilities/MethodSwizzler (8.0.2):
    - GoogleUtilities/Logger
    - GoogleUtilities/Privacy
  - GoogleUtilities/Network (8.0.2):
    - GoogleUtilities/Logger
    - "GoogleUtilities/NSData+zlib"
    - GoogleUtilities/Privacy
    - GoogleUtilities/Reachability
  - "GoogleUtilities/NSData+zlib (8.0.2)":
    - GoogleUtilities/Privacy
  - GoogleUtilities/Privacy (8.0.2)
  - GoogleUtilities/Reachability (8.0.2):
    - GoogleUtilities/Logger
    - GoogleUtilities/Privacy
  - GoogleUtilities/UserDefaults (8.0.2):
    - GoogleUtilities/Logger
    - GoogleUtilities/Privacy
  - Introspect (0.1.4)
  - KeychainSwift (24.0.0)
  - Kingfisher (8.1.0)
  - mobileSharedLib (1.0.0.95)
  - Mockingjay (3.0.0-alpha.1):
    - Mockingjay/Core (= 3.0.0-alpha.1)
    - Mockingjay/XCTest (= 3.0.0-alpha.1)
  - Mockingjay/Core (3.0.0-alpha.1):
    - URITemplate (~> 3.0)
  - Mockingjay/XCTest (3.0.0-alpha.1):
    - Mockingjay/Core
  - nanopb (3.30910.0):
    - nanopb/decode (= 3.30910.0)
    - nanopb/encode (= 3.30910.0)
  - nanopb/decode (3.30910.0)
  - nanopb/encode (3.30910.0)
  - Nimble (11.2.0)
  - ObjectMapper (4.4.2)
  - PINCache (3.0.4):
    - PINCache/Arc-exception-safe (= 3.0.4)
    - PINCache/Core (= 3.0.4)
  - PINCache/Arc-exception-safe (3.0.4):
    - PINCache/Core
  - PINCache/Core (3.0.4):
    - PINOperation (~> 1.2.3)
  - PINOperation (1.2.3)
  - PromiseKit (8.1.2):
    - PromiseKit/CorePromise (= 8.1.2)
    - PromiseKit/Foundation (= 8.1.2)
    - PromiseKit/UIKit (= 8.1.2)
  - PromiseKit/CorePromise (8.1.2)
  - PromiseKit/Foundation (8.1.2):
    - PromiseKit/CorePromise
  - PromiseKit/UIKit (8.1.2):
    - PromiseKit/CorePromise
  - PromisesObjC (2.4.0)
  - PromisesSwift (2.4.0):
    - PromisesObjC (= 2.4.0)
  - Quick (5.0.0)
  - Realm (10.34.0):
    - Realm/Headers (= 10.34.0)
  - Realm/Headers (10.34.0)
  - RealmSwift (10.34.0):
    - Realm (= 10.34.0)
  - SwiftLint (0.57.0)
  - SwiftSoup (2.7.3)
  - Toast-Swift (5.1.1)
  - TPKeyboardAvoiding (1.3.5)
  - UICircularProgressRing (8.0.0)
  - URITemplate (3.0.1)
  - ViewInspector (0.10.0)
  - youtube-ios-player-helper (1.0.4)
  - ZIPFoundation (0.9.19)

DEPENDENCIES:
  - Alamofire
  - CocoaLumberjack/Swift
  - CSCoursePlayer (from `CSCoursePlayer`)
  - CSOD-Tracker (from `https://bitbucket.csod.com/scm/csod/csod-tracker.git`, commit `de1c6be6369e7294410bb3d88530f972715ace48`)
  - DeviceKit
  - Firebase/AnalyticsWithoutAdIdSupport (~> 11.7.0)
  - FirebaseCore (~> 11.7.0)
  - FirebaseCrashlytics (~> 11.7.0)
  - FirebaseMessaging (~> 11.7.0)
  - FirebaseRemoteConfig (~> 11.7.0)
  - Introspect
  - KeychainSwift
  - Kingfisher
  - mobileSharedLib (from `https://artifacts.saba.com/mobile-cocoapods-devqa-hq/mobileSharedLib/1.0.0.95/mobileSharedLib.podspec`)
  - Mockingjay (from `https://github.com/kylef/Mockingjay.git`, branch `master`)
  - Nimble
  - ObjectMapper
  - PINCache
  - PromiseKit
  - Quick (= 5.0.0)
  - RealmSwift (= 10.34.0)
  - SwiftLint
  - SwiftSoup
  - Toast-Swift
  - TPKeyboardAvoiding
  - UICircularProgressRing
  - ViewInspector (= 0.10.0)
  - youtube-ios-player-helper
  - ZIPFoundation

SPEC REPOS:
  https://github.com/CocoaPods/Specs.git:
    - Alamofire
    - AmplitudeSwift
    - AnalyticsConnector
    - CocoaLumberjack
    - DeviceKit
    - Firebase
    - FirebaseABTesting
    - FirebaseAnalytics
    - FirebaseCore
    - FirebaseCoreExtension
    - FirebaseCoreInternal
    - FirebaseCrashlytics
    - FirebaseInstallations
    - FirebaseMessaging
    - FirebaseRemoteConfig
    - FirebaseRemoteConfigInterop
    - FirebaseSessions
    - FirebaseSharedSwift
    - GCDWebServer
    - GoogleAppMeasurement
    - GoogleDataTransport
    - GoogleUtilities
    - Introspect
    - KeychainSwift
    - Kingfisher
    - nanopb
    - Nimble
    - ObjectMapper
    - PINCache
    - PINOperation
    - PromiseKit
    - PromisesObjC
    - PromisesSwift
    - Quick
    - Realm
    - RealmSwift
    - SwiftLint
    - SwiftSoup
    - Toast-Swift
    - TPKeyboardAvoiding
    - UICircularProgressRing
    - URITemplate
    - ViewInspector
    - youtube-ios-player-helper
    - ZIPFoundation

EXTERNAL SOURCES:
  CSCoursePlayer:
    :path: CSCoursePlayer
  CSOD-Tracker:
    :commit: de1c6be6369e7294410bb3d88530f972715ace48
    :git: https://bitbucket.csod.com/scm/csod/csod-tracker.git
  mobileSharedLib:
    :podspec: https://artifacts.saba.com/mobile-cocoapods-devqa-hq/mobileSharedLib/1.0.0.95/mobileSharedLib.podspec
  Mockingjay:
    :branch: master
    :git: https://github.com/kylef/Mockingjay.git

CHECKOUT OPTIONS:
  CSOD-Tracker:
    :commit: de1c6be6369e7294410bb3d88530f972715ace48
    :git: https://bitbucket.csod.com/scm/csod/csod-tracker.git
  Mockingjay:
    :commit: b88c9dce2b7561cccbf35e2882b3c71a2efa387a
    :git: https://github.com/kylef/Mockingjay.git

SPEC CHECKSUMS:
  Alamofire: 840d2a1ad82355b536ec6ba5f97e5bfa54600ca3
  AmplitudeSwift: d10ae6afdb0740e4ae843866bce8ab1119a53d74
  AnalyticsConnector: a53214d38ae22734c6266106c0492b37832633a9
  CocoaLumberjack: 6a459bc897d6d80bd1b8c78482ec7ad05dffc3f0
  CSCoursePlayer: ff8c764c47858027b2aad24e2c4e2bf1e66e1343
  CSOD-Tracker: 2c0e66c4c905a92a4a5cbcea0fcb60264f783313
  DeviceKit: d83e38ca196a4ebf0cc5f37d6f0316a24b794d5b
  Firebase: a64bf6a8546e6eab54f1c715cd6151f39d2329f4
  FirebaseABTesting: 08b3e19b28504632a9cd03e7a796b355c5d39b27
  FirebaseAnalytics: bc9e565af9044ba8d6c6e4157e4edca8e5fdf7ec
  FirebaseCore: 3227e35f4197a924206fbcdc0349325baf4f5de4
  FirebaseCoreExtension: 206c1b399f0d103055207c16f299b28e3dbd1949
  FirebaseCoreInternal: d6c17dafc8dc33614733a8b52df78fcb4394c881
  FirebaseCrashlytics: 785a73b624715bbc09a40bb56cdc3829a801cc98
  FirebaseInstallations: 9347e719c3d52d8d7b9074b2c32407dd027305e9
  FirebaseMessaging: 00ece041b71ddb52a2862ffdee73fb6e9824bd0c
  FirebaseRemoteConfig: aa1d4cb05ef4caad203448dfc87842de12f1ea8d
  FirebaseRemoteConfigInterop: ca12abf9da0003efd3a476b2dff4f7a04fd31b4f
  FirebaseSessions: 32ed7a9387ae71efe3a35a7f20f3a7292950957b
  FirebaseSharedSwift: a45efd84d60ebbfdcdbaebc66948af3630459e62
  GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4
  GoogleAppMeasurement: 0471a5b5bff51f3a91b1e76df22c952d04c63967
  GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
  GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
  Introspect: b62c4dd2063072327c21d618ef2bedc3c87bc366
  KeychainSwift: 007c4647486e4563adca839cf02cef00deb3b670
  Kingfisher: dfbf20b6249ed4ef6f18d6a96c847bce860bdb95
  mobileSharedLib: 97862f3704b84fe9abc5eb6012be6a4dd78b6584
  Mockingjay: 97656c6f59879923976a0a52ef09da45756cca82
  nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
  Nimble: cab2cc29436a378f595e8babd231440dfcb0a358
  ObjectMapper: e6e4d91ff7f2861df7aecc536c92d8363f4c9677
  PINCache: d9a87a0ff397acffe9e2f0db972ac14680441158
  PINOperation: fb563bcc9c32c26d6c78aaff967d405aa2ee74a7
  PromiseKit: e057b5b3c0ce9a0145674d633930924234104ee3
  PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
  PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
  Quick: f58aae30d750b27918005b93d870c187353a7bf0
  Realm: 991e7c4d6d37f1d6470a48bb072782ef00b91b67
  RealmSwift: 11e77934e4af6d011d2970645fe56e11fa0e3c2c
  SwiftLint: eb47480d47c982481592c195c221d11013a679cc
  SwiftSoup: e3849c3293b1efee9cf892f91f6ae5c22bfeb5f7
  Toast-Swift: 7a03a532afe3a560d4044bc7c237e2864d295173
  TPKeyboardAvoiding: d55b3ea7b362540af8fcf36aa3ed2e87bf210cc6
  UICircularProgressRing: 19927375b2b21b5fa5fd9582f15ccdef9659da16
  URITemplate: 5f5a79f3e384884102c4e6b3325d159c20a8035a
  ViewInspector: 2ec5f7d3c572956c560f29a3fd757e5c59a44788
  youtube-ios-player-helper: e9b97535e816db3152179d84d999bc1807ecd689
  ZIPFoundation: b8c29ea7ae353b309bc810586181fd073cb3312c

PODFILE CHECKSUM: 07a5c439f003aa3d772e960aa1401492ffc716dc

COCOAPODS: 1.15.2
@google-oss-bot
Copy link

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

@paulb777
Copy link
Member

paulb777 commented Feb 4, 2025

See also previous report at #13834

leojaygoogle added a commit that referenced this issue Feb 14, 2025
unarchiveObjectWithData is deprecated. Move the codebase to use the new new more secure NSKeyedUnarchiver APIs.

This is expected to fix #14424
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants