Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
SensePost Pty Ltd committed Feb 10, 2012
0 parents commit 8ecef1a
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 0 deletions.
140 changes: 140 additions & 0 deletions Manifestor.py
@@ -0,0 +1,140 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-

"""
This utility extracts AndroidManifest.xml file from an apk, converts it into
human readable format and stores in on your hard disk. Additionally, it scans
the AndroidManifest.xml file for grant-uri-permission tag
(http://developer.android.com/guide/topics/manifest/grant-uri-permission-element.html)
and attempts to determine if it is possible for any other installed application
to steal data of target content-provider. In order to use this utility, your
android phone should be rooted and have a find command (via busybox or
terminal)
"""

import os
import re
import subprocess
import sys


AAPT_BIN = 'aapt'
ADB_BIN = 'adb'


def find_apks(path):
#TODO: Implement this
proc = subprocess.Popen(
[ADB_BIN, 'shell', 'find', path, '-name', '*.apk'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
stdout, stderr = proc.communicate()
return [line.strip() for line in stdout.split('\n') if line.strip()]


def check_manifest(apk_path, outdir):
apk_name = os.path.split(apk_path)[-1]

print "Extracting Manifest file..."
manifestfilename = os.path.join(outdir, 'Manifest_%s.txt' % (apk_name))
proc = subprocess.Popen(
[AAPT_BIN, "d", "xmltree", apk_path, "AndroidManifest.xml"],
stdout=subprocess.PIPE
)
stdoutdata, stderrdata = proc.communicate()
open(manifestfilename, 'w').write(stdoutdata)

print 'The AndroidManifest.xml for %s has been saved at location: %s' %(
apk_name, manifestfilename
)

print "Scanning for excessive permissions..."
grant_path = re.findall(
r'grant-uri-permission.*?\n.*?path(|Pattern|Prefix)\([0-9a-fx]*\)="(.*?)"',
stdoutdata, re.MULTILINE
)
print "Found %d instances of grant-uri-permission" % (len(grant_path))
for count, i in enumerate(grant_path):
if i[1] == '/':
print '(%s) Instance %d looks vulnerable. It may be possible for any app to query data of this content provider.' % (i[1], count+1)
else:
print "(%s) Instance %d looks good. Its worth analysing the AndroidManifest.xml manually" % (i[1], count+1)


def download_apk(apk_path, outdir):
"""Downloads an APK from the given Android device path to the given output
directory.
@returns: The path on the local file system to the downloaded APK."""
print "Downloading apk %s..." % (apk_path)
exit_status = subprocess.call(
[ADB_BIN, "pull", apk_path, outdir],
stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
if exit_status == 1:
print "Looks like the device is not connected. Please connect your android device via usb and enable usb debugging"
sys.exit(1)
else:
print "The apk has been saved to: %s" % (os.path.abspath(outdir))

apk_local = os.path.join(outdir, os.path.split(apk_path)[-1])
if not os.path.isfile(apk_local):
raise IOError('APK downloaded, but doesn not exist: %s' % (apk_local))
return apk_local


def main(options, args):
"""Main entry point.
@type options: optparse.Values
@param options: Options parsed from the command-line.
@type args: list
@param args: Residual arguments not parsed by the option parser."""
if len(options.apks) == 1 and options.apks[0].lower() == 'scan_all':
download_apks = find_apks('/system/app') + find_apks('/system/sd/app')
else:
download_apks = list(options.apks)
for apkpath in options.apkpaths:
download_apks.extend(find_apks(apkpath))

all_apks = []

for apk in download_apks:
all_apks.append(download_apk(apk, options.outputdir))

all_apks.extend(options.localfiles)

for apk in all_apks:
check_manifest(apk, options.outputdir)


def create_option_parser():
from optparse import OptionParser
parser = OptionParser(usage='%prog [<options>]\nSaurabh Harit, SensePost')

parser.add_option(
'-o', '--output-dir', dest='outputdir', default=os.path.curdir,
help='Output directory to use. This path will be used to download the apk files to your machine',
)
parser.add_option(
'-a', '--apk', dest='apks', action='append', default=[],
help='Path (on Android device) of APK(s) to scan. Example: /system/app/Gmail.apk. If the value of this switch is set to scan_all, the script will automatically scan all apks in /system/app and /system/sd/app folder'
)
parser.add_option(
'-l', '--local', dest='localfiles', action='append', default=[],
help='Path (on the local machine) to APK(s).'
)
parser.add_option(
'-A', '--apkpath', dest='apkpaths', action='append', default=[],
help='Path (on Android device) to search for APK(s) to scan. Example: /system/app'
)

return parser


if __name__ == '__main__':
parser = create_option_parser()
options, args = parser.parse_args()
if not os.path.isdir(options.outputdir):
parser.error('Invalid output directory: %s' % (options.outputdir))
if not options.apks and not options.apkpaths and not options.localfiles:
parser.error('No APKs or APK paths specified.')
main(options, args)
39 changes: 39 additions & 0 deletions README.markdown
@@ -0,0 +1,39 @@
#1. Name
Manifestor - Android Manifest.xml tool
#2. Author
Saurabh Harit < saurabh(at)sensepost(dot)com >
#3. License, version & release date
License : GPLv3
Version : v0.1
Release Date : 2011/11/01

#4. Description
Android applications may share the data of a content provider with other applications installed on your device. For example, if you receive an image attachment in an email, your mail client will have to share it with an image viewer. One way of sharing a content provider's data with other applications is by using "grant-uri-permission" tag in AndroidManifest.xml. Using this tag, a content provider can specify a path, path pattern or path prefix. However, if this path is mistakenly set to "/", any other installed application would be able to access data of that content provider.
< grant-uri-permission android:pathPrefix="/" />
Manifestor.py extracts AndroidManifest.xml from an Android application package (.apk), decodes it and scans it for such permission flaws. As an output, it will display you the set path and whether or not it could be vulnerable.
#5. Usage
Options:

-h, --help show this help message and exit

-o OUTPUTDIR, --output-dir=OUTPUTDIR
Output directory to use. This path will be used to
download the apk files to your machine

-a APKS, --apk=APKS Path (on Android device) of APK(s) to scan. Example:
/system/app/Gmail.apk. If the value of this switch is
set to scan_all, the script will automatically scan
all apks in /system/app and /system/sd/app folder

-l LOCALFILES, --local=LOCALFILES
Path (on the local machine) to APK(s).

-A APKPATHS, --apkpath=APKPATHS
Path (on Android device) to search for APK(s) to scan.
Example: /system/app

As input, it accepts an apk file path or a folder name on your phone. If you have apk files on your local machine, you can use "-l" switch. "-o" switch lets you specify the folder where the apk files will be downloaded and saved from you android device. If this switch is not specified, the files are saved in the current folder.
#6. Requirements
Python
#7. Additional Resources
Slides, Outsmarting Smartphones - http://www.slideshare.net/sensepost/outsmarting-smartphones
21 changes: 21 additions & 0 deletions readme.txt.old
@@ -0,0 +1,21 @@
Android applications may share the data of a content provider with other applications installed on your device. For example, if you receive an image attachment in an email, your mail client will have to share it with an image viewer. One way of sharing a content provider's data with other applications is by using "grant-uri-permission" tag in AndroidManifest.xml. Using this tag, a content provider can specify a path, path pattern or path prefix. However, if this path is mistakenly set to "/", any other installed application would be able to access data of that content provider.
<grant-uri-permission android:pathPrefix="/" />
Manifestor.py extracts AndroidManifest.xml from an Android application package (.apk), decodes it and scans it for such permission flaws. As an output, it will display you the set path and whether or not it could be vulnerable. Below is the usage:

Options:
-h, --help show this help message and exit
-o OUTPUTDIR, --output-dir=OUTPUTDIR
Output directory to use. This path will be used to
download the apk files to your machine
-a APKS, --apk=APKS Path (on Android device) of APK(s) to scan. Example:
/system/app/Gmail.apk. If the value of this switch is
set to scan_all, the script will automatically scan
all apks in /system/app and /system/sd/app folder
-l LOCALFILES, --local=LOCALFILES
Path (on the local machine) to APK(s).
-A APKPATHS, --apkpath=APKPATHS
Path (on Android device) to search for APK(s) to scan.
Example: /system/app
As input, it accepts an apk file path or a folder name on your phone. If you have apk files on your local machine, you can use "-l" switch. "-o" switch lets you specify the folder where the apk files will be downloaded and saved from you android device. If this switch is not specified, the files are saved in the current folder.
This tool is in early stages of development. You are more than welcome to modify/enhance it.

0 comments on commit 8ecef1a

Please sign in to comment.