Friday, July 25, 2014

tel: URL scheme in UIWebView vs openURL

What happens if you use [UIApplication sharedApplication] openURL: to handle tel: URL scheme in UIWebViewDelegate instead of letting the UIWebView deal with it? This happens:

<iframe src="tel:+48000000000"></iframe>

Saturday, June 21, 2014

Browser Shredders Challenge #1

For some time now I haven't succeeded in triggering password autofill in any iOS browser from a downloaded HTML file (which would allow another easy way to steal passwords). There are no Same Origin Policy constraints for local HTML files, so it seems easy to just open the target website and read the password, but there are some problems:
- password autofill does not work in cross-domain frames in iOS browsers based on UIWebView
- calling overwrites the calling window, so I cannot control content while having the target website open
-  I didn't find any other way to set or to target domain while still controlling the content

I guess there may be some solution which I overlooked, so here is the challenge for you:

A sample application with the code above - which you may run on iOS simulator - is available on GitHub. The task is to prepare a local HTML file (/tmp/challenge1.html) in such way that "You completed the challenge" line will get executed.

There is no reward unfortunately, apart from a humble "thank you" during our SyScan360 talk :-)

Exploring and Exploiting iOS Web Browsers - local HTML files

A quick summary of the possible methods for preventing UXSS when loading untrusted local HTML files into iOS UIWebView:

1. Load as plain text
This would probably break the planned functionality of the application, but you can always decide to use loadData method with mimeType text/plain and forget about all the HTML problems.

2. Content-Security-Policy headers
By using NSURLProtocol and connection:didReceiveResponse you can inject CSP headers to block JavaScript execution (also for file: URIs).
The only application implementing similar solution that I know of is currently Onion Browser. Cure53 found a way to bypass CSP in this browser, but this was due to the fact that file and data URIs were explicitly skipped before injecting the headers (it is a bit misleading that you can inject HTTP response headers for documents that are not requested through HTTP, but it really works).

3. HTML5 sandbox
Using iframe sandbox instead of CSP seems potentially less prone to bypasses, but it is a bit less convenient to implement. You first use loadHTMLString with baseURL=nil and a sandboxed iframe in content, then you run stringByEvaluatingJavaScriptFromString to point the iframe to the file you want to load.
This way your JavaScript can operate on the loaded file, but the loaded file cannot execute JavaScript (unless you allow-scripts or allow-top-navigation; any of them gives UXSS again).

4. Less-privileged baseURL
This is the most common solution used by many applications. Most of them use baseURL pointing to some domain related to the application, but an even better solution is to use about:blank. I already wrote about it before. This does not prevent JavaScript from running, but restores Same Origin Policy constraints.

Do you know other solutions? Or maybe you know how to break these above? Comments welcome!

Monday, June 16, 2014

Puffin Browser for iOS Server Side File Read Access

# Vulnerability: Puffin Browser Server Side File Read Access for iOS
# Date: 30.04.2014
# Tested on: iOS 7.0.1

# CVE: No assigned yet
# Author: Marek Zmysłowski

1. The Puffin Browser (paid version) processing some of the web content on the server side. The vulnerability exist when the "file:///" URL is processed incorrectly, revealing the content of the server side.

2. Proof of Concept

4. Fix
The issue has been fixed on the server side.

5. Timeline
30.04.2014 - vulnerability reported
01.05.2014 - fix 

30.05.2014 - public disclosure

Thursday, June 12, 2014

Exploring and Exploiting iOS Web Browsers - part 1

After our Hack In The Box talk, I thought it would be a good idea to explain some of the slides in more detail. I am currently playing with iOS8 and WKWebViews, which solve a lot of issues, but not all of them. More on this soon - for now, let's stay on with UIWebViews.

UIWebView is the component used to load web content into iOS applications - basically it's Mobile Safari with the UI stripped off, leaving just the viewport part. Some of the differences:

  1. UIWebView can only view a single document at a time (+ frames)
For example, links with target="_blank" will work as target="_top", and will work   more or less the same as location.assign().

  2. There is also no UI for error events
The user will not be asked for accepting invalid SSL certificate, will not be informed the connection to the given host failed, etc. However, JavaScript-initiated alerts and prompts are shown (and are not controllable through available API).

  3. There is an API to control UIWebView content and behaviour

(By the way, you may want to take a look at this presentation from OWASP Poland meeting.)

Browsers using UIWebViews have to add the user interface - this means at least address bar and error handling. Usually to do this programmers implement UIWebViewDelegate methods:

The last one causes problems usually. The most common issue is lack of address bar update within this method. This may allow an attacker to spoof the address bar by forcing some kind of an error. Apart from events like invalid SSL certificate, NXDOMAIN DNS response or simply response timeout, this method is also called when document.write() function interrupts page load or replaces loaded page.

Lack of address bar update on webView:didFailLoadWithError: was the reason for about a half of the address bar spoofing vulnerabilities we reported to browser authors. Most of the second half was due to updating address bar too early - as soon as the navigation was initiated, before the document actually started loading into UIWebView ("loading loop" from the HITB presentation is an example). By combining both techniques, an attacker can be almost sure the address bar will point to whatever she/he wishes.

See you in the next part soon.

Tuesday, June 10, 2014

Opera Coast SSL Man-in-the-Middle Vulnerability

# Vulnerability: Opera Coast SSL Man-in-the-Middle Vulenerability
# Software Link:
# Vulnerable versions: 3.01 and earlier
# CVE: not yet assigned
# Author: Lukasz Pilorz

1. Vulnerability

Opera Coast browser for iOS was vulnerable to man-in-the-middle attacks against SSL-protected web pages. The validation of the webpage certificate was performed for the domain of the main document only, skipping resources embedded from other domains.

2. Proof of Concept

3. Fix
This specific issue was fixed in version 3.02.

Other potentially unfixed vectors may be related to the fact that for some cases of invalid SSL certificates for the main domain the user is alerted of an error, but the page content is still loaded in background (potentially accessing cookies or performing cache poisoning attacks). These vectors were not retested in detail.

4. Timeline

22.01.2014 - initial contact regarding SSL MITM in Coast (not this specific issue), received detailed response explaining why Opera does not consider it to be a bug
29.01.2014 - public disclosure on OWASP Poland meeting
11.03.2014 - second report with this specific issue presented (with proof-of-concept), received immediate response confirming the bug
24.04.2014 - partially fixed version released
26.05.2014 - version 3.02 with final fix released

[CVE-2014-1315] OSX Safari uncontrolled format string

This one is for OS X Safari, so not exactly in our main field of interest, but it's really funny:
<iframe src="lets-try-format-string:%p%p%p%p%p%p..."></iframe>

CoreServicesUIAgent responsible for the format string vulnerability was fixed in OS X Mavericks 10.9.2 (Mountain Lion and previous were not affected). Exploitability was not confirmed on our side, however Apple states that it could result in arbitrary code execution. Hats off to Erik Kooistra, who reported this vulnerability independently (before I did).

[CVE-2013-7197] Yandex.Browser for iOS - Universal Cross-Site Scripting

# Vulnerability: Yandex.Browser for iOS - Universal Cross-Site Scripting
# Software Link:
# Vulnerable versions: 13.11-13.12
# CVE: CVE-2013-7197
# Author: Lukasz Pilorz

1. Vulnerability

Yandex.Browser for iOS was vulnerable to Universal Cross-Site Scripting attacks, allowing a webpage to execute JavaScript on any other webpage, requiring minimal user interaction.

2. Proof of Concept

<button onclick="'redirect.php?');setTimeout(function(){w.document.write('<script>alert(location)</script>')},5000);">Click</button>

3. Fix

This issue was fixed in version 14.02.

4. Timeline

14.12.2013 - initial contact, multiple issues reported
27.12.2013 - Yandex response, additional data provided proving the issue is in Yandex code and not in Apple's API
10.01.2014 - Yandex confirmation and bug bounty award
24.02.2014 - version 14.02 released
30.05.2014 - public disclosure

[CVE-2013-6893] Mercury Browser for iOS - Universal Cross-Site Scripting

# Vulnerability: Mercury Browser for iOS - Universal Cross-Site Scripting
# Software Link:
# Vulnerable versions: at least 8.1 and newer (not tested on previous versions)
# CVE: CVE-2013-6893
# Author: Lukasz Pilorz

1. Vulnerability

Mercury Browser for iOS is vulnerable to Universal Cross-Site Scripting attacks, including the possibility to hijack passwords saved by the browser.

2. Proof of Concept

<button onclick="'');w.document.write('<script>alert(location)</script>');">Click</button>

3. Fix

No response from the vendor, no fix issued. The vulnerability is partially mitigated by popup blocker not allowing to open new tabs if the user does not whitelist target domain (bypassable with redirects).

4. Timeline

02.12.2013 - initial contact, no response

18.12.2013 - proof-of-concept for UXSS and password hijacking sent, no response
30.05.2014 - public disclosure

Thursday, May 15, 2014

Jailbreak Detection Methods

The purpose of this post is to summary methods used for iOS jailbreak detection.

1. Using the Filesystem

The jailbreak process modifies the filesystem by adding, moving and changing files and directories. These changes can be used to detect if the device is jailbroken or not.
All methods presented in this point can be easily detected (it is very easy to find appropriate string in the application) and can be very easily bypassed (simple file name change can bypass this detection).
  • Existence of file

Some of the files are related to jailbroken device. Detection is achieved by means of checking if these files are accessible. The most popular files are listed below:

  • Size of /etc/fstab file

The /etc/fstab file contains mount points for the system. Many jailbreaking tools modify this file by adding some entries. As a result file size is modified. Even thought it is not possible to read the file, the application can attempt to check the file size.
The size of the file can be changed when new updates are installed.
  • Read/Write permission to the root partition

During the jailbreaking process the access to the root partition is amended. This can be checked in order to detect if device has been jailbroken.
  • Existence of symbolic links

Some of the directories are originally located in the small system partition. During the jailbreak process this partition is overwritten. The data must be relocated to the large, data partition. Because the old file location must be valid, symbolic links are created. The following list contains files/directories which are symbolic links on the jailbroken devices.

  • Directory permissions

Similar to checking existence of files/directories, the permissions can be checked.
  • Writing file

On the jailbroken device the applications are installed the /Applications folder thereby are given root privileges. It can be checked, if the application is able to modify files outside of its sandbox. This can be done by simply creating a file in the /private directory.

2. API Calls detection

Some API calls provided by the iOS system behave differently if run on the jailbroken device.
Appropriate implementation can be very difficult to detect and bypassed.
  • fork()

The sandbox denies process forking on devices in jail. By checking the returned pid on fork(), the application can detect if it has successfully forked or not, at which point it can determine if it is running on a jailbroken device.
  • system()

Calling the system() function with a NULL argument on a device in jail will return 0; doing the same on a jailbroken device will return 1. This is since the function will check whether /bin/sh exists, and this is only the case on jailbroken devices.
  • vm_protect() - obsolete

On the iOS device prior or equal to  iOS 4.3.3 the page of the memory could not be marked as executable if device is not jailbroken. Later versions of iOS have fixed this.
  • dyld functions

By far the hardest to get around. Calling functions like _dyld_image_count() and _dyld_get_image_name() to see which dylibs are currently loaded. Very difficult to patch, as patches are themselves part of dylibs.

3. Services detection

The jailbroken device mainly runs some services. The can be check in order to detect if device is jailbroken.
This method can be very time consuming (if ssh is not installed, the connection must be timeout). It is also very easy to bypass by changing the port for the OpenSSH service.
  • OpenSSH

Due to the very large portion of jailbroken devices that have OpenSSH installed, some rogue apps will attempt to make a connection to on port 22. If the connection succeeds, it should mean that OpenSSH is installed and running on the device, which obviously indicates that it is jailbroken.

4. Scheme detection

It is difficult to change scheme for the iOS however the Cydia can be removed during the testing process.
  • Cydia

Most of the devices that are jailbroken have Cydia installed. Notwithstanding the fact that the hacker can change the location of the Cydia app, he won’t change the URL scheme the Cydia app is registered with.
If calling the Cydia’s URL scheme (cydia://) from your application gives a success, you can be sure that the device is jailbroken.

5. Summary

The more complicated jailbreak detection is, the more difficult is to detect and bypass it. It is important not to create the detection runtime which returns true or false. It is very easy to locate this runtime and modify it.

Monday, March 10, 2014

[CVE-2014-1449] Maxthon Cloud Browser for Android Address Bar Spoofing

# Vulnerability: Maxthon Cloud Browser for Android Address Bar Spoofing
# Date: 10.01.2014
# Software Link:
# Vulnerable version:
# Tested on: Android 4.4
# CVE: CVE-2014-1449
# Author: Pawel Wylecial
1. Background

Description from the vendor website: "Maxthon Cloud Browser for Android is the first multi-tab browser with Maxthon’s innovative Cloud Services, including: Cloud Tabs, Cloud Push, Cloud Download and bookmarks/favorites syncing. With its cool design and out of the box features like Super Gestures, Reader Mode, App Center and more, this browser delivers a fresh and original browsing experience."

2. Vulnerability

Maxthon for Android is vulnerable to Address Bar Spoofing. Using the history API it was possible to spoof the URL in the address bar which could trick the user that he is visiting a different site than he thinks.

3. Proof of Concept

function trigger() {
        w ="");
        w.location = "";
        setTimeout('w.location = "a.html"', 1000);
        setTimeout('w.history.back();', 2000);
        setTimeout('w.history.forward();', 2100);
<a href="javascript:trigger();">click</a>

PoC in action:

4. Fix

No response from the vendor, silent fix applied in (can't confirm here, updated straight to or

5. Timeline

10.01.2014 - vulnerability reported
15.01.2014 - second e-mail
21.01.2014 - third
22.01.2014 - *silent fix applied (?),
29.01.2014 - last try

10.03.2014 - advisory published

Thursday, February 27, 2014

Decrypting iOS Applications (Automatically)

My previous post was about how to decrypt the iOS application manually. It is good to know how does it work but it can be tiring if you want to decrypt many applications. All the mentioned steps are gathered together in one tool - Clutch by KJCracks.


The application and source code are available on the github Clutch automatically decrypts the application and creates the .ipa files.

Using the Clutch

You need only to download the application from the github (the compiled version is available). Running Clutch without parameters shows all available applications that can be decrypted. Running Clutch with the name from the list decrypt the application, running with "-a" decrypts all listed application.

After the application is decrypted it can be installed as the ipa package and analyze.

Monday, February 24, 2014

Hack in the Box Amsterdam 2014

We are very pleased to announce that our presentation "Exploring and Exploiting iOS Web Browsers" has been accepted for the Hack in the Box Security Conference 2014 Amsterdam.

In the presentation, we will discuss how iOS third-party web browsers are built. We will go through the main properties and limitations of UIWebView, common features added by browser developers, and common design or programming flaws that result in security vulnerabilities. While security of the underlying WebKit engine is exposed to continuous research, and the imperfections of mobile browser UI are widely known, the publicly available resources dedicated to secure implementation of web views in iOS applications do not cover the challenges which a browser developer faces. We would like to fill this gap in at least a small part.
Apart from the theory and development advice, our talk will also be an opportunity to disclose a dozen of the most interesting examples of security vulnerabilities and weaknesses which we identified in the most popular iOS third-party web browsers, and in Safari/UIWebView itself. We will explain how did they arise, demonstrate their exploitation, show examples of vulnerable code (Objective C and JavaScript) and – where possible – patches that were issued to address these vulnerabilities. Finally, we will demonstrate a sample test suite which can be used to assess basic security properties of UIWebView implementations in iOS web browsers.
More details can be found here:

See you there :)

Tuesday, February 11, 2014

Decrypting iOS Applications (Manual)

Reversing the iOS application can be interesting and profitable. This short article presents how to decrypt an iOS application for reverse engineering. The example application is Puffin browser.


Before the application can be decrypted, some packages need to be installed.
  • gdb - the GDB available from the Cydia repository is not working properly. The correct version can be downloaded from the Radere repository. One needs to add to the repository (the source setting need to be set to Developer)
  • iOS Toolchain
  • file
  • adv-cmds
  • gawk
All these packages need to be installed with required dependencies.

Finding the code

First thing what we need to check if the code is really encrypted. We can do this using the otool tool and looking for the  LC_ENCRYPTION_INFO section.

otool -arch all -Vl <app name> | grep -A4 LC_ENCRYPTION_INFO

Above command reveals two important information: the begining of the code (cryptoff) and the size of the code (cryptsize). It will be need during the dump of the code

Dumping memory

Because the iOS 7 is using ASLR the decrypted code will be located in different memory address ranges. We need to load it, run and stop after the decryption routine is finished (on the original application entry point). To do this we need to load the application in gdb and set break point on the begining of the application - UIApplicationMain.

When the gdb stops on the break point we can find the appropriate region. Using the info sharedlibrary command we can display all loaded libraries with their base addresses.

The Puffin application (position number 2) has the base address 0x9000. Now we can dump the code. To do this we will need two addresses - begin and end. They are calculated in follows:

Begin address = base address + cryptoff 
                                   0x9000 + 16384    = 0xD000

End address = base address + cryptoff + cryptsize 
                                0x9000 + 16384    + 511808    = 0x4ED000

The dump is made by the following command:
dump binary memory <dump name> <begin address> <end address>

Creating binary

 Now we need to copy the dumped code into the thin version of our application.

dd bs=1 seek=<cryptoff> conv=notrunc if=<dump name> of=<application>

Now the dump is completed and the application can ba analyzed using the IDA Pro or the Hopper Disassembler.

Sunday, February 09, 2014

JavaScript Off for iOS

While testing UIWebView on iOS I found out there is no option to turn off JavaScript for web content. Initially I tried to use HTML5 "sandbox" attribute do achieve this, but in practice Content Security Policy is a much more flexible solution. Injecting CSP headers into NSHTTPURLResponse seems to work even for file: and data: URL schemes.

A sample application testing above solution is available on GitHub, and a similar solution has recently made its way into Onion Browser as an experimental feature. I am looking forward to see how it's going to work in practice.

On a side note, Quick Look is another solution if you need to load a single HTML document with JavaScript turned off.

iOS UIWebView baseURL

UIWebView is one of the most popular components in Cocoa Touch library. It can be used to easily embed web content into iOS applications and - of course - to equally easily introduce Cross-Site Scripting vulnerabilities.

When loading content into webView on iOS, a programmer can choose one of three methods:

  • – loadData:MIMEType:textEncodingName:baseURL:
  • – loadHTMLString:baseURL:
  • – loadRequest:

Did you notice baseURL in the first two? This inconspicuous parameter is quite important when dealing with XSS.

Same Origin Policy works a bit different in iOS than we're used to in desktop browsers, namely file: and applewebdata: URLs have complete cross-origin access to any web resources, in addition to local file access. This means if you save untrusted HTML document locally and then call loadRequest method to load it from its file:/// path into UIWebView, you're simply creating a universal Cross-Site Scripting vulnerability. This document can now read all cookies stored by the application, call JavaScript across domains (including your corporate intranet), and do all that stuff Same Origin Policy usually prevents.

Alternatively to loading untrusted local file with loadRequest, you may first read its content and then use one of the two remaining methods: loadData or loadHTMLString. Unfortunately, by default UIWebView content is loaded with file/applewebdata privileges. This is where the baseURL comes in handy. Simply set the baseURL to "about:blank" URL and Same Origin Policy will prevent cross-origin access (as it probably should do by default, Apple?).

Of course this won't be enough if a webView contains sensitive data and untrusted content at the same time, or if you bridge JavaScript with Objective-C through special URLs catched in webView:shouldStartLoadWithRequest:request. In such cases you should remove all XSS vulnerabilities from your application, one by one.