Skip to content

MASTG-DEMO-0125: Implementation Details Exposed in App Logs

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

Sample

This demo uses the sample from Logging APIs Exposing Implementation Details with r2.

../MASTG-DEMO-0124/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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import Foundation
import UIKit
import os.log

// SUMMARY: This sample demonstrates verbose error logging and debugging messages that expose implementation details.

class MastgTest {

    static func mastgTest(completion: @escaping (String) -> Void) {
        // FAIL: [MASTG-TEST-0358] Verbose logging exposes internal API endpoint and request details
        NSLog("[DEBUG] Attempting to connect to API endpoint: https://internal-api.example.com/v2/auth/login")

        let result = performLogin(username: "testuser", password: "testpass")
        completion(result)
    }

    static func performLogin(username: String, password: String) -> String {
        // FAIL: [MASTG-TEST-0358] Debug print exposes function execution flow and internal state
        // FAIL: [MASTG-TEST-0297] Debug print exposes user name
        print("[DEBUG] performLogin() called with username: \(username)")

        // Simulate network request
        let success = validateCredentials(username: username, password: password)

        if success {
            // FAIL: [MASTG-TEST-0358] Verbose success message exposes implementation details
            // FAIL: [MASTG-TEST-0297] Verbose success message exposes authentication token
            debugPrint("✅ [DEBUG] Authentication successful - Session token generated: \(generateMockToken())")
            debugPrint("[DEBUG] User profile loaded from cache, bypassing network call")
            return "Login successful"
        } else {
            // FAIL: [MASTG-TEST-0358] Detailed error logging exposes error handling logic
            NSLog("[ERROR] Authentication failed - Invalid credentials provided")
            NSLog("[DEBUG] Fallback to offline mode initiated")
            NSLog("[DEBUG] Error code: AUTH_001, Module: AuthenticationService.validateCredentials()")
            return "Login failed"
        }
    }

    static func validateCredentials(username: String, password: String) -> Bool {
        // FAIL: [MASTG-TEST-0358] os_log with .debug level exposes validation logic
        if #available(iOS 14.0, *) {
            let logger = Logger(subsystem: "com.example.mastg", category: "Authentication")
            logger.debug("Validating credentials against local database")
            logger.debug("Checking password hash: SHA256 algorithm")
        }

        // Simulate validation
        return username.count > 0 && password.count > 0
    }

    static func generateMockToken() -> String {
        return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
    }

    static func performNetworkRequest() {
        // FAIL: [MASTG-TEST-0358] Verbose logging exposes network configuration
        print("[DEBUG] Network request configuration:")
        print("[DEBUG] - Timeout: 30s")
        print("[DEBUG] - Retry count: 3")
        print("[DEBUG] - SSL pinning: disabled")
        print("[DEBUG] - Certificate validation: relaxed for staging environment")
    }

    static func handleError(_ error: Error) {
        // FAIL: [MASTG-TEST-0358] Dumping error object exposes internal error structure
        dump(error)

        // FAIL: [MASTG-TEST-0358] Verbose error logging with stack trace information
        NSLog("[ERROR] Exception occurred in module: NetworkManager")
        NSLog("[ERROR] Stack trace: \(Thread.callStackSymbols)")
    }

    // PASS: [MASTG-TEST-0358] Properly guarded debug logging (would not appear in release builds if DEBUG flag is set)
    static func properlyGuardedLogging() {
        #if DEBUG
        print("[DEBUG] This message only appears in debug builds")
        NSLog("[DEBUG] Debug configuration active")
        #endif
    }
}

Steps

  1. Install the app on a device ( Installing Apps)
  2. Make sure you have Frida (iOS) installed on your machine and the frida-server running on the device
  3. Make sure you have libimobiledevice suite installed on your machine and the idevicesyslog tool available in your PATH
  4. Run run.sh to spawn your app with Frida and to start monitoring system logs with idevicesyslog as described in Monitoring System Logs
  5. Click the Start button
  6. Stop the script by pressing Ctrl+C
run.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/bin/sh

APP="${APP:-MASTestApp}"
SCRIPT="${SCRIPT:-script.js}"

trap 'trap - INT TERM EXIT, kill 0 2>/dev/null' INT TERM EXIT

idevicesyslog -p "$APP" \
  | awk -v app="$APP" '$0 !~ app "\\((UIKitCore|CoreFoundation|IOKit|FrontBoardServices)\\)" { print; fflush() }' \
  > unified.log 2>&1 &

stdbuf -oL -eL frida -U -n "$APP" -l "$SCRIPT" \
  > frida.log 2>&1 &

wait

The script collects two complementary log sources:

  1. frida.log contains process output captured with Frida, including Swift print, debugPrint, NSLog, and intercepted unified logging calls
  2. unified.log contains rendered iOS unified logging output collected with idevicesyslog, including NSLog and os.Logger messages

Observation

The following output includes both idevicesyslog and Frida results to show how the two collection methods differ. idevicesyslog shows rendered iOS unified logging records, such as NSLog and os.Logger, but may miss stdout based Swift print and debugPrint messages. Therefore, absence from idevicesyslog alone does not prove that the app did not log sensitive data.

unified.log
1
2
3
4
5
[connected:81e43377d6fa9508615173d104e3f739e8c1b252]
Jun  9 10:14:31.806381 MASTestApp(Foundation)[2781] <Notice>: [DEBUG] Attempting to connect to API endpoint: https://internal-api.example.com/v2/auth/login
Jun  9 10:14:31.807542 MASTestApp(MASTestApp.debug.dylib)[2781] <Debug>: Validating credentials against local database
Jun  9 10:14:31.811025 MASTestApp(MASTestApp.debug.dylib)[2781] <Debug>: Checking password hash: SHA256 algorithm
[disconnected:81e43377d6fa9508615173d104e3f739e8c1b252]

Frida captures stdout and stderr based logging by hooking functions such as fwrite and write. In this run, Frida captured all relevant messages, including Swift print, debugPrint, NSLog, and observed unified logging calls. Using both sources helps correlate results and reduces the chance of missing logs that are only visible through one method.

frida.log
 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
     ____
    / _  |   Frida 17.6.2 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
   . . . .
   . . . .   Connected to iPad (id=81e43377d6fa9508615173d104e3f739e8c1b252)
Attaching...
[hooked] write at 0x1d0984f98
[hooked] fwrite at 0x19480a484
[hooked] puts at 0x19485270c
[hooked] printf at 0x194822748
[hooked] NSLog at 0x18c1629b4
[hooked] NSLogv at 0x18c162a98
[hooked] _os_log_impl at 0x1a591e8c0
[hooked] _os_log_debug_impl at 0x1a59232fc
[hooked] _os_log_error_impl at 0x1a591e8a4
[hooked] _os_log_fault_impl at 0x1a5929b9c
[ready] Frida log capture installed
[iPad::MASTestApp ]-> [NSLogv.format] [DEBUG] Attempting to connect to API endpoint: https://internal-api.example.com/v2/auth/login
[fwrite] [DEBUG] performLogin() called with username: testuser
[_os_log_impl.format] Validating credentials against local database
[_os_log_impl.format] Checking password hash: SHA256 algorithm
[fwrite] "✅ [DEBUG] Authentication successful - Session token generated: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
[fwrite] "[DEBUG] User profile loaded from cache, bypassing network call"

Evaluation

The test case fails because runtime log monitoring shows that the application emits internal implementation details through multiple logging mechanisms.

The observed logs reveal the following information.

  1. Internal endpoint details. The app logs the internal authentication endpoint.

log [NSLogv.format] [DEBUG] Attempting to connect to API endpoint: https://internal-api.example.com/v2/auth/login

  1. Authentication flow behavior. The app logs that performLogin() was called and includes the supplied username.
[fwrite] [DEBUG] performLogin() called with username: testuser
  1. Local credential validation behavior. The app logs that credentials are validated against a local database.
[_os_log_impl.format] Validating credentials against local database
  1. Password handling details. The app logs the password hashing algorithm used during validation.
[_os_log_impl.format] Checking password hash: SHA256 algorithm
  1. Cache and network behavior. The app logs that the user profile is loaded from cache and that a network call is bypassed.
[fwrite] "[DEBUG] User profile loaded from cache, bypassing network call"
  1. Session handling details. The app logs that authentication succeeded and exposes a generated session token.
[fwrite] "✅ [DEBUG] Authentication successful - Session token generated: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"

The logs also expose the username testuser and a session token. These values are sensitive data and should be assessed under the appropriate sensitive data logging test, such as Sensitive Data Exposure in Logs or Sensitive Data Exposure Through Logging APIs.