Skip to content

MASTG-DEMO-0067: Runtime Tracking of Files Eligible for Backup with Frida

Download MASTG-DEMO-0067 IPA Open MASTG-DEMO-0067 Folder Build MASTG-DEMO-0067 IPA

Sample

The code snippet below shows sample code that writes files to storage at different locations.

MastgTest.swift
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import SwiftUI
import os
import Darwin

struct MastgTest {

  static func mastgTest(completion: @escaping (String) -> Void) {
    let filename = "secret.json"
    let secret = "secret_token"

    let fm = FileManager.default

    let types: [FileManager.SearchPathDirectory] = [
        .documentDirectory,
        .cachesDirectory,
        .libraryDirectory,
        .applicationSupportDirectory,
    ]

    for type in types{
      guard let docDir = fm.urls(for: type, in: .userDomainMask).first else { continue }
        try? secret.write(to: docDir.appendingPathComponent(filename), atomically: false, encoding: .utf8)
    }
    completion("Successfully stored files to the storage")
  }
}

Steps

  1. Install the app on a device ( Installing Apps)
  2. Make sure you have Frida for iOS installed on your machine and the frida-server running on the device
  3. Run run.sh to spawn your app with Frida
  4. Click the Start button
  5. Stop the script by pressing Ctrl+C
1
2
#!/bin/bash
frida -U -f org.owasp.mastestapp.MASTestApp-iOS -l ./script.js -o output.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
const CONTAINER_PATH_LEN = "/var/mobile/Containers/Data/Application/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/".length

Interceptor.attach(Module.getGlobalExportByName("open"), {
  onEnter(args) {
      let path = args[0].readCString()
      if(path.indexOf("/var/mobile/Containers/Data/Application") != -1 &&
        ((path.indexOf("tmp") != CONTAINER_PATH_LEN && path.indexOf("Library/Caches") != CONTAINER_PATH_LEN ))){
        console.log(`\nopen(${path})`);
        // Use an arrow function so that `this` remains the same as in onEnter
        const printBacktrace = (maxLines = 8) => {
            console.log("Backtrace:");
            let backtrace = Thread.backtrace(this.context, Backtracer.ACCURATE)
                .map(DebugSymbol.fromAddress);

            for (let i = 0; i < Math.min(maxLines, backtrace.length); i++) {
                console.log(backtrace[i]);
            }
        }
        printBacktrace();  
      }
  }
});

Observation

output.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
open(/var/mobile/Containers/Data/Application/976DB6BA-3AE8-483D-9CE7-0207049BB3B5/Documents/secret.json)
Backtrace:
0x19a8dfd68 Foundation!_NSOpenFileDescriptor_Protected
0x19a8cb884 Foundation!_NSWriteDataToFileWithExtendedAttributes
0x19a92336c Foundation!writeStringToURLOrPath
0x19abeb294 Foundation!StringProtocol.write(to:atomically:encoding:)
0x104ab0418 MASTestApp!specialized static MastgTest.mastgTest(completion:)
0x104ab122c MASTestApp!closure #1 in closure #1 in closure #1 in ContentView.body.getter
0x1a417e9e8 SwiftUI!0x7199e8 (0x18a8f29e8)
0x1a417ece8 SwiftUI!0x719ce8 (0x18a8f2ce8)

open(/var/mobile/Containers/Data/Application/976DB6BA-3AE8-483D-9CE7-0207049BB3B5/Library/secret.json)
Backtrace:
0x19a8dfd68 Foundation!_NSOpenFileDescriptor_Protected
0x19a8cb884 Foundation!_NSWriteDataToFileWithExtendedAttributes
0x19a92336c Foundation!writeStringToURLOrPath
0x19abeb294 Foundation!StringProtocol.write(to:atomically:encoding:)
0x104ab0418 MASTestApp!specialized static MastgTest.mastgTest(completion:)
0x104ab122c MASTestApp!closure #1 in closure #1 in closure #1 in ContentView.body.getter
0x1a417e9e8 SwiftUI!0x7199e8 (0x18a8f29e8)
0x1a417ece8 SwiftUI!0x719ce8 (0x18a8f2ce8)

open(/var/mobile/Containers/Data/Application/976DB6BA-3AE8-483D-9CE7-0207049BB3B5/Library/Application Support/secret.json)
Backtrace:
0x19a8dfd68 Foundation!_NSOpenFileDescriptor_Protected
0x19a8cb884 Foundation!_NSWriteDataToFileWithExtendedAttributes
0x19a92336c Foundation!writeStringToURLOrPath
0x19abeb294 Foundation!StringProtocol.write(to:atomically:encoding:)
0x104ab0418 MASTestApp!specialized static MastgTest.mastgTest(completion:)
0x104ab122c MASTestApp!closure #1 in closure #1 in closure #1 in ContentView.body.getter
0x1a417e9e8 SwiftUI!0x7199e8 (0x18a8f29e8)
0x1a417ece8 SwiftUI!0x719ce8 (0x18a8f2ce8)

The output contains all calls to open including the paths of the files being accessed and backtraces. In this case the app is writing a file named secret.json to multiple locations.

Evaluation

The test fails because the secret.json file exists in multiple directories that are eligible for backup:

open(.../Documents/secret.json)
open(.../Library/secret.json)
open(.../Library/Application Support/secret.json)