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.
importFoundationimportNetworkstructMastgTest{//SUMMARY:Thissampledemonstratestheuseoflow-levelNetworkframeworkAPIsthatbypassATS.staticfuncmastgTest(completion:@escaping(String)->Void){varresult="Testing Network framework connection (bypasses ATS):\n\n"//FAIL:[MASTG-TEST-0322]UsingNetworkframeworkwithoutTLSbypassesATSlethost=NWEndpoint.Host("httpbin.org")letport=NWEndpoint.Port(integerLiteral:80)//CreatingaTCPconnectionwithoutTLS-thisbypassesATSentirelyletconnection=NWConnection(host:host,port:port,using:.tcp)connection.stateUpdateHandler={stateinswitchstate{case.ready:result+="Connection established to httpbin.org:80 (cleartext)\n"result+="This connection bypasses ATS because it uses Network framework\n"//SendasimpleHTTPGETrequestletrequest="GET /get HTTP/1.1\r\nHost: httpbin.org\r\nConnection: close\r\n\r\n"letrequestData=request.data(using:.utf8)!connection.send(content:requestData,completion:.contentProcessed{errorinifleterror=error{result+="Send error: \(error)\n"}else{result+="HTTP request sent successfully over cleartext connection\n"}connection.cancel()completion(result)})case.failed(leterror):result+="Connection failed: \(error)\n"completion(result)case.cancelled:result+="Connection cancelled\n"default:break}}connection.start(queue:.main)}//PASS:[MASTG-TEST-0322]UsingNetworkframeworkwithTLSissecurestaticfuncsecureNetworkConnection(completion:@escaping(String)->Void){varresult="Testing secure Network framework connection:\n\n"lethost=NWEndpoint.Host("httpbin.org")letport=NWEndpoint.Port(integerLiteral:443)//CreatingaTLSconnection-secureusageofNetworkframeworklettlsParameters=NWParameters.tlsletconnection=NWConnection(host:host,port:port,using:tlsParameters)connection.stateUpdateHandler={stateinswitchstate{case.ready:result+="Secure TLS connection established to httpbin.org:443\n"completion(result)connection.cancel()case.failed(leterror):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.
Unzip the app package and locate the main binary file ( Exploring the App Package), which in this case is ./Payload/MASTestApp.app/MASTestApp.
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 9101112131415161718192021222324
easm.bytes=falseescr.color=falseeasm.var=false?eUsesoftheNetwork.NWEndpoint.Port.integerLiteralfunction:f~Network.NWEndpoint.Port.integerLiteral?e?exrefstoNetwork.NWEndpoint.Port.integerLiteral:axt@0x100006c00?e?eUseofNetwork.NWEndpoint.Port.integerLiteral:# Seek to the function where Network.NWEndpoint.Port.integerLiteral is calledpd--5@0x1000047f4?e?eValuepassedtoNetwork.NWEndpoint.Port.integerLiteral:?0x50~uint32[1]
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:
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.