Skip to content

MASTG-DEMO-0085: Uses of Network Framework Bypassing ATS

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

Sample

The code sample code uses the Network framework to establish a connection to httpbin.org on port 80. The demo doesn't send any data over the connection, but for the purposes of this demo, assume that it does.

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
import Foundation
import Network

struct MastgTest {
    // SUMMARY: This sample demonstrates the use of low-level Network framework APIs that bypass ATS.

    static func mastgTest(completion: @escaping (String) -> Void) {
        var result = "Testing Network framework connection (bypasses ATS):\n\n"

        // FAIL: [MASTG-TEST-0322] Using Network framework without TLS bypasses ATS
        let host = NWEndpoint.Host("httpbin.org")
        let port = NWEndpoint.Port(integerLiteral: 80)

        // Creating a TCP connection without TLS - this bypasses ATS entirely
        let connection = NWConnection(host: host, port: port, using: .tcp)

        connection.stateUpdateHandler = { state in
            switch state {
            case .ready:
                result += "Connection established to httpbin.org:80 (cleartext)\n"
                result += "This connection bypasses ATS because it uses Network framework\n"

                // Send a simple HTTP GET request
                let request = "GET /get HTTP/1.1\r\nHost: httpbin.org\r\nConnection: close\r\n\r\n"
                let requestData = request.data(using: .utf8)!

                connection.send(content: requestData, completion: .contentProcessed { error in
                    if let error = error {
                        result += "Send error: \(error)\n"
                    } else {
                        result += "HTTP request sent successfully over cleartext connection\n"
                    }
                    connection.cancel()
                    completion(result)
                })

            case .failed(let error):
                result += "Connection failed: \(error)\n"
                completion(result)

            case .cancelled:
                result += "Connection cancelled\n"

            default:
                break
            }
        }

        connection.start(queue: .main)
    }

    // PASS: [MASTG-TEST-0322] Using Network framework with TLS is secure
    static func secureNetworkConnection(completion: @escaping (String) -> Void) {
        var result = "Testing secure Network framework connection:\n\n"

        let host = NWEndpoint.Host("httpbin.org")
        let port = NWEndpoint.Port(integerLiteral: 443)

        // Creating a TLS connection - secure usage of Network framework
        let tlsParameters = NWParameters.tls
        let connection = NWConnection(host: host, port: port, using: tlsParameters)

        connection.stateUpdateHandler = { state in
            switch state {
            case .ready:
                result += "Secure TLS connection established to httpbin.org:443\n"
                completion(result)
                connection.cancel()
            case .failed(let error):
                result += "Connection failed: \(error)\n"
                completion(result)
            default:
                break
            }
        }

        connection.start(queue: .main)
    }
}

Note that we do not modify ATS so such a connection should be blocked. However, ATS does not apply to the Network framework so the connection will succeed.

Steps

  1. Unzip the app package and locate the main binary file ( Exploring the App Package), which in this case is ./Payload/MASTestApp.app/MASTestApp.
  2. Run radare2 (iOS) with the script to search for low-level networking APIs in the binary. In this case, we'll focus on NWEndpoint.Port.integerLiteral, which is used to specify the port number when creating a network endpoint, but you could also look for NWConnection and NWParameters.
low_level_network.r2
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
e asm.bytes=false
e scr.color=false
e asm.var=false

?e Uses of the Network.NWEndpoint.Port.integerLiteral function:
f~Network.NWEndpoint.Port.integerLiteral

?e

?e xrefs to Network.NWEndpoint.Port.integerLiteral:
axt @ 0x100006c00

?e

?e Use of Network.NWEndpoint.Port.integerLiteral:

# Seek to the function where Network.NWEndpoint.Port.integerLiteral is called
pd-- 5 @ 0x1000047f4

?e

?e Value passed to Network.NWEndpoint.Port.integerLiteral:

? 0x50~uint32[1]
run.sh
1
2
#! /bin/bash
r2 -q -i low_level_network.r2 -A MASTestApp > output.asm

Observation

The output contains references to the NWEndpoint.Port.integerLiteral function, including the locations where it is used in the binary and the value passed to it:

output.asm
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
Uses of the Network.NWEndpoint.Port.integerLiteral function:
0x100006c00 12 sym.imp.Network.NWEndpoint.Port.integerLiteral.UInt16...V_tcfC
0x10000c0c8 8 reloc.Network.NWEndpoint.Port.integerLiteral.UInt16...V_tcfC

xrefs to Network.NWEndpoint.Port.integerLiteral:
sym.func.1000046c4 0x1000047f4 [CALL:--x] bl sym.imp.Network.NWEndpoint.Port.integerLiteral.UInt16...V_tcfC

Use of Network.NWEndpoint.Port.integerLiteral:
           0x1000047e0      movk x1, 0xeb00, lsl 48
           0x1000047e4      mov x8, x23
           0x1000047e8      bl sym.imp.Network.NWEndpoint.Host.stringLiteral.__String_...cfC_
           0x1000047ec      mov x8, x21
           0x1000047f0      mov w0, 0x50                              ; 'P'
           0x1000047f4      bl sym.imp.Network.NWEndpoint.Port.integerLiteral.UInt16...V_tcfC
           0x1000047f8      mov x0, 0
           0x1000047fc      bl sym.imp.Network.NWConnection.allocator_...a_ ; Network.NWConnection.allocator(...a)
           0x100004800      mov x26, x0
           0x100004804      ldr x8, [x19, 0x10]

Value passed to Network.NWEndpoint.Port.integerLiteral:
80

Evaluation

The test fails because the app uses NWEndpoint.Port.integerLiteral to specify port 80 for a network connection by loading the value 0x50 (which is 80 in decimal) into register w0 before calling the function.