├── .gitignore
├── .gitmodules
├── .travis.yml
├── LICENSE
├── README.rst
├── docs
└── qark_diagram.png
├── qark
├── __init__.py
├── apk_builder.py
├── decompiler
│ ├── __init__.py
│ ├── decompiler.py
│ └── external_decompiler.py
├── exploit_apk
│ ├── app
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ ├── .DS_Store
│ │ │ ├── androidTest
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── secbro
│ │ │ │ └── qark
│ │ │ │ └── ApplicationTest.java
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── ic_launcher-web.png
│ │ │ ├── ic_launcher_2-web.png
│ │ │ ├── ic_launcher_droid-web.png
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── secbro
│ │ │ │ └── qark
│ │ │ │ ├── TopLevelActivity.java
│ │ │ │ ├── customintent
│ │ │ │ ├── ChooseIntentUseCaseActivity.java
│ │ │ │ └── CreateCustomIntentActivity.java
│ │ │ │ ├── exportedcomponent
│ │ │ │ ├── ExportedComponentsFragment.java
│ │ │ │ ├── exportedactivity
│ │ │ │ │ ├── ExportedActivityListFragment.java
│ │ │ │ │ ├── IntentParamsFragment.java
│ │ │ │ │ └── IntentSenderActivity.java
│ │ │ │ └── exportedreceiver
│ │ │ │ │ ├── ExportedReceiverListFragment.java
│ │ │ │ │ ├── IntentSenderActivity.java
│ │ │ │ │ └── IntentSenderFragment.java
│ │ │ │ ├── filebrowser
│ │ │ │ ├── FileBrowserActivity.java
│ │ │ │ └── FileBrowserFragment.java
│ │ │ │ ├── intentsniffer
│ │ │ │ ├── BroadcastIntentSnifferActivity.java
│ │ │ │ ├── BroadcastIntentSnifferFragment.java
│ │ │ │ └── services
│ │ │ │ │ ├── BootReceiver.java
│ │ │ │ │ └── BroadcastStealerService.java
│ │ │ │ ├── tapjacking
│ │ │ │ └── TapJackingExploitFragment.java
│ │ │ │ └── webviewtests
│ │ │ │ ├── WebViewTestsActivity.java
│ │ │ │ └── WebViewTestsActivityFragment.java
│ │ │ └── res
│ │ │ ├── .DS_Store
│ │ │ ├── drawable-hdpi
│ │ │ ├── drawer_shadow.9.png
│ │ │ ├── ic_add_black_24dp.png
│ │ │ └── ic_drawer.png
│ │ │ ├── drawable-mdpi
│ │ │ ├── drawer_shadow.9.png
│ │ │ ├── ic_add_black_24dp.png
│ │ │ └── ic_drawer.png
│ │ │ ├── drawable-xhdpi
│ │ │ ├── custom_intent.png
│ │ │ ├── drawer_shadow.9.png
│ │ │ ├── header2.png
│ │ │ ├── ic_add_black_24dp.png
│ │ │ ├── ic_drawer.png
│ │ │ ├── ic_folder_black_24dp.png
│ │ │ ├── ic_launch_black_24dp.png
│ │ │ ├── ic_mouse_black_24dp.png
│ │ │ ├── ic_public_black_24dp.png
│ │ │ ├── ic_visibility_black_24dp.png
│ │ │ ├── qark_512.png
│ │ │ └── web_view.png
│ │ │ ├── drawable-xxhdpi
│ │ │ ├── drawer_shadow.9.png
│ │ │ ├── header3.png
│ │ │ ├── header4.png
│ │ │ ├── ic_add_black_24dp.png
│ │ │ ├── ic_drawer.png
│ │ │ ├── ic_launch_black_24dp.png
│ │ │ ├── ic_mouse_black_24dp.png
│ │ │ ├── ic_public_black_24dp.png
│ │ │ ├── ic_visibility_black_24dp.png
│ │ │ └── qark_drawer.png
│ │ │ ├── drawable
│ │ │ ├── dir_up.png
│ │ │ ├── file_icon.png
│ │ │ ├── folder_icon.png
│ │ │ ├── folder_icon_light.png
│ │ │ ├── ic_one.png
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_2.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_2.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_2.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_2.png
│ │ │ └── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_2.png
│ │ │ ├── layout
│ │ │ ├── activity_choose_intent_use_case.xml
│ │ │ ├── activity_create_custom_intent.xml
│ │ │ ├── activity_exploit_exported_result.xml
│ │ │ ├── activity_file_browser.xml
│ │ │ ├── activity_intent_sender.xml
│ │ │ ├── activity_top_level.xml
│ │ │ ├── activity_web_view_tests.xml
│ │ │ ├── fragment_broadcast_stealer.xml
│ │ │ ├── fragment_exploit_exported_activity_params.xml
│ │ │ ├── fragment_exported_activity_list.xml
│ │ │ ├── fragment_exported_components.xml
│ │ │ ├── fragment_exported_receiver_list.xml
│ │ │ ├── fragment_file_browser.xml
│ │ │ ├── fragment_intent_sender.xml
│ │ │ ├── fragment_navigation_drawer.xml
│ │ │ ├── fragment_tap_jacking_exploit.xml
│ │ │ ├── fragment_top_level.xml
│ │ │ ├── fragment_web_view_tests.xml
│ │ │ ├── nav_header.xml
│ │ │ ├── tap_jacking_toast.xml
│ │ │ ├── toolbar.xml
│ │ │ └── webview.xml
│ │ │ ├── menu
│ │ │ ├── drawer_view.xml
│ │ │ ├── menu_intent_sender.xml
│ │ │ ├── menu_main.xml
│ │ │ └── menu_web_view_tests.xml
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── qark_512.png
│ │ │ ├── values-w820dp
│ │ │ └── dimens.xml
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── extraKeys.xml
│ │ │ ├── intentID.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── issue.py
├── lib
│ ├── apktool
│ │ └── apktool.jar
│ ├── decompilers
│ │ ├── cfr_0_124.jar
│ │ ├── fernflower.jar
│ │ └── procyon-decompiler-1.0.jar
│ └── dex2jar-2.0
│ │ ├── d2j-baksmali.bat
│ │ ├── d2j-baksmali.sh
│ │ ├── d2j-dex-recompute-checksum.bat
│ │ ├── d2j-dex-recompute-checksum.sh
│ │ ├── d2j-dex2jar.bat
│ │ ├── d2j-dex2jar.sh
│ │ ├── d2j-dex2smali.bat
│ │ ├── d2j-dex2smali.sh
│ │ ├── d2j-jar2dex.bat
│ │ ├── d2j-jar2dex.sh
│ │ ├── d2j-jar2jasmin.bat
│ │ ├── d2j-jar2jasmin.sh
│ │ ├── d2j-jasmin2jar.bat
│ │ ├── d2j-jasmin2jar.sh
│ │ ├── d2j-smali.bat
│ │ ├── d2j-smali.sh
│ │ ├── d2j-std-apk.bat
│ │ ├── d2j-std-apk.sh
│ │ ├── d2j_invoke.bat
│ │ ├── d2j_invoke.sh
│ │ └── lib
│ │ ├── antlr-runtime-3.5.jar
│ │ ├── asm-debug-all-4.1.jar
│ │ ├── d2j-base-cmd-2.0.jar
│ │ ├── d2j-jasmin-2.0.jar
│ │ ├── d2j-smali-2.0.jar
│ │ ├── dex-ir-2.0.jar
│ │ ├── dex-reader-2.0.jar
│ │ ├── dex-reader-api-2.0.jar
│ │ ├── dex-tools-2.0.jar
│ │ ├── dex-translator-2.0.jar
│ │ ├── dex-writer-2.0.jar
│ │ └── dx-1.7.jar
├── plugins
│ ├── __init__.py
│ ├── broadcast
│ │ ├── __init__.py
│ │ ├── dynamic_broadcast_receiver.py
│ │ └── send_broadcast_receiver_permission.py
│ ├── cert
│ │ ├── __init__.py
│ │ ├── cert_validation_methods_overriden.py
│ │ └── hostname_verifier.py
│ ├── crypto
│ │ ├── __init__.py
│ │ ├── ecb_cipher_usage.py
│ │ ├── packaged_private_keys.py
│ │ ├── rsa_cipher_usage.py
│ │ └── setting_secure_random_seed.py
│ ├── file
│ │ ├── __init__.py
│ │ ├── android_logging.py
│ │ ├── api_keys.py
│ │ ├── external_storage.py
│ │ ├── file_permissions.py
│ │ ├── http_url_hardcoded.py
│ │ ├── insecure_functions.py
│ │ └── phone_identifier.py
│ ├── generic
│ │ ├── __init__.py
│ │ ├── check_permissions.py
│ │ └── task_affinity.py
│ ├── helpers.py
│ ├── intent
│ │ ├── __init__.py
│ │ └── implicit_intent_to_pending_intent.py
│ ├── manifest
│ │ ├── __init__.py
│ │ ├── allow_backup.py
│ │ ├── android_path.py
│ │ ├── api_keys.py
│ │ ├── custom_permissions.py
│ │ ├── debuggable.py
│ │ ├── exported_tags.py
│ │ ├── min_sdk.py
│ │ ├── single_task_launch_mode.py
│ │ └── task_reparenting.py
│ ├── manifest_helpers.py
│ └── webview
│ │ ├── __init__.py
│ │ ├── add_javascript_interface.py
│ │ ├── helpers.py
│ │ ├── javascript_enabled.py
│ │ ├── load_data_with_base_url.py
│ │ ├── remote_webview_debugging.py
│ │ ├── set_allow_content_access.py
│ │ ├── set_allow_file_access.py
│ │ ├── set_allow_universal_access_from_file_urls.py
│ │ └── set_dom_storage_enabled.py
├── qark.py
├── report.py
├── scanner
│ ├── __init__.py
│ ├── plugin.py
│ └── scanner.py
├── templates
│ ├── csv_report.jinja
│ ├── html_report.jinja
│ ├── json_report.jinja
│ └── xml_report.jinja
├── utils.py
└── xml_helpers.py
├── report
└── .gitignore
├── requirements-test.txt
├── requirements.txt
├── requirements_to_freeze.txt
├── setup.cfg
├── setup.py
└── tests
├── __init__.py
├── conftest.py
├── goatdroid.apk
├── test_apk_builder.py
├── test_decompiler
├── __init__.py
└── test_decompiler.py
├── test_issue.py
├── test_java_files
├── check_permissions.java
├── dynamic_broadcast_receiver.java
├── external_storage.java
├── http_url_hardcoded.java
├── insecure_functions.java
├── phone_identifier.java
├── send_broadcast_receiver_permission.java
├── task_affinity.java
└── test_android_logging.java
├── test_manifest_helpers.py
├── test_plugins
├── __init__.py
├── test_broadcast_plugins
│ ├── __init__.py
│ ├── test_dynamic_broadcast_receiver.py
│ └── test_send_broadcast_receiver_permission.py
├── test_cert_plugins
│ ├── __init__.py
│ ├── testCertMethodsFile.java
│ ├── testHostnameVerifier.java
│ └── test_cert_plugins.py
├── test_crypto_plugins
│ ├── __init__.py
│ ├── java_files
│ │ ├── blank.java
│ │ ├── ecb1.java
│ │ ├── ecb2.java
│ │ ├── ecb3.java
│ │ ├── invalid.java
│ │ ├── no_ecb1.java
│ │ ├── secure_random_args1.java
│ │ ├── secure_random_args2.java
│ │ └── secure_random_no_args1.java
│ ├── keys
│ │ ├── dsa-key
│ │ ├── dsa-key.pub
│ │ ├── ecdsa-key
│ │ ├── ecdsa-key.pub
│ │ ├── ed25519-key
│ │ ├── ed25519-key.pub
│ │ ├── rsa-key
│ │ └── rsa-key.pub
│ ├── test_crypto_plugins.py
│ └── test_ecb.py
├── test_file_plugins
│ ├── __init__.py
│ ├── test_file_permissions.java
│ └── test_file_plugins.py
├── test_generic_plugins
│ ├── __init__.py
│ ├── test_check_permissions.py
│ └── test_task_affinity.py
├── test_intent
│ ├── __init__.py
│ ├── test_implicit_intent.java
│ └── test_intent_plugins.py
├── test_manifest_plugins
│ ├── __init__.py
│ ├── broadcastreceivers
│ │ └── SendSMSNowReceiver.java
│ ├── test_manifest_plugins.py
│ └── test_min_sdk_tapjacking
│ │ └── androidmanifest.xml
└── test_webviews
│ ├── __init__.py
│ ├── test_webviews.py
│ ├── vulnerable_webview.java
│ ├── vulnerable_webview_add_javascript_interface.java
│ ├── vulnerable_webview_content_access.java
│ ├── vulnerable_webview_file_access.java
│ ├── vulnerable_webview_set_dom_storage_enabled.java
│ └── vulnerable_webview_universal_access_from_urls.java
├── test_report.py
├── test_scanner
├── __init__.py
├── test_plugin.py
└── test_scanner.py
└── test_xml_files
├── strings.xml
├── test_androidmanifest.xml
└── test_goatdroid_manifest.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.png
3 | *.jpg
4 | logs
5 | android-sdk*
6 | settings.properties
7 | *.swp
8 | build
9 | run
10 | sampleApps/goatdroid
11 | lib/plyj/lextab.py
12 | test/.coverage
13 | .coverage
14 | parsetab.py
15 | sampleApps
16 | lextab.py
17 | qark/test/testData/*
18 | .idea
19 | .DS_Store
20 | *.iml
21 | lib/
22 | .cache/
23 | dist/
24 | qark.egg-info/
25 | venv/
26 | qark_debug.log
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/.gitmodules
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - "2.7"
4 | - "3.6"
5 | install:
6 | - pip install -r requirements-test.txt
7 | script:
8 | - travis_wait python -m pytest
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2015 LinkedIn Corp. All rights reserved.
2 |
3 | Copyright 2015 LinkedIn Corp. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/ licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6 |
7 | ==============================================================================
8 | Copyrights and Licenses for Third Party Software Distributed with QARK:
9 | ==============================================================================
10 | The QARK software also contains code written by third parties. Such software will
11 | have its own individual LICENSE.TXT file in the directory in which it appears, or
12 | at the top of the files in case the LICENSE.TXT is not present. This file will
13 | describe the copyrights, license, and restrictions which apply to that code.
14 |
15 | The following pieces of software have additional or alternate copyrights,
16 | licenses, and/or restrictions:
17 |
18 | Program Type
19 | ------- ----
20 | six MIT
21 | pluginbase BSD
22 | requests[security] Apache Software License (Apache 2.0)
23 | jinja2 BSD
24 | enum34 BSD
25 | javalang MIT
26 | click BSD
27 | apktool Apache Software License (Apache 2.0) qark/qark/lib/apktool
28 | dex2jar Apache Software License (Apache 2.0) qark/qark/lib/dex2jar-2.0
29 | procyon Apache Software License (Apache 2.0) qark/qark/lib/decompilers/procyon-decompiler-1.0.jar
30 | cfr MIT qark/qark/lib/decompilers/cfr_0_124.jar
31 | fernflower Apache Software License (Apache 2.0) qark/qark/lib/decompilers/fernflower.jar
--------------------------------------------------------------------------------
/docs/qark_diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/docs/qark_diagram.png
--------------------------------------------------------------------------------
/qark/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/__init__.py
--------------------------------------------------------------------------------
/qark/decompiler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/decompiler/__init__.py
--------------------------------------------------------------------------------
/qark/decompiler/external_decompiler.py:
--------------------------------------------------------------------------------
1 | import abc
2 | import os
3 |
4 | LIB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "lib")
5 | PATH_TO_DECOMPILERS = os.path.join(LIB_PATH, "decompilers")
6 |
7 |
8 | class ExternalDecompiler(object):
9 | __meta__ = abc.ABCMeta
10 |
11 | def __init__(self, name, path_to_decompiler, command=None):
12 | self.name = name.lower()
13 | self.path_to_decompiler = path_to_decompiler
14 | self.command = command
15 |
16 |
17 | class CFR(ExternalDecompiler):
18 | def __init__(self):
19 | ExternalDecompiler.__init__(self,
20 | name="cfr",
21 | path_to_decompiler=os.path.join(PATH_TO_DECOMPILERS, "cfr_0_124.jar"),
22 | command="java -jar {path_to_decompiler} {jar} --outputdir {build_directory}/cfr")
23 |
24 |
25 | class Procyon(ExternalDecompiler):
26 | def __init__(self):
27 | ExternalDecompiler.__init__(self,
28 | name="procyon",
29 | path_to_decompiler=os.path.join(PATH_TO_DECOMPILERS,
30 | "procyon-decompiler-1.0.jar"),
31 | command="java -jar {path_to_decompiler} {jar} -o {build_directory}/procyon")
32 |
33 |
34 | class Fernflower(ExternalDecompiler):
35 | def __init__(self):
36 | ExternalDecompiler.__init__(self,
37 | name="fernflower",
38 | path_to_decompiler=os.path.join(PATH_TO_DECOMPILERS,
39 | "fernflower.jar"),
40 | command="java -jar {path_to_decompiler} -ren=1 {jar} {build_directory}/fernflower")
41 |
42 |
43 | DECOMPILERS = (CFR(), Procyon(), Fernflower())
44 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "21.1.2"
6 | defaultConfig {
7 | applicationId 'com.secbro.qark'
8 | minSdkVersion 7
9 | targetSdkVersion 21
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | compileOptions {
14 | sourceCompatibility = JavaVersion.VERSION_1_7
15 | targetCompatibility = JavaVersion.VERSION_1_7
16 | }
17 | buildTypes {
18 | release {
19 | }
20 | }
21 | productFlavors {
22 | }
23 | }
24 |
25 | dependencies {
26 | compile 'com.android.support:appcompat-v7:22.2.1'
27 | compile 'com.android.support:design:22.2.1'
28 | compile 'com.android.support:recyclerview-v7:22.2.1'
29 | }
--------------------------------------------------------------------------------
/qark/exploit_apk/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Applications/android-sdk-macosx/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/exploit_apk/app/src/.DS_Store
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/androidTest/java/com/secbro/qark/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.secbro.qark;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/exploit_apk/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/ic_launcher_2-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/exploit_apk/app/src/main/ic_launcher_2-web.png
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/ic_launcher_droid-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/exploit_apk/app/src/main/ic_launcher_droid-web.png
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/java/com/secbro/qark/intentsniffer/BroadcastIntentSnifferActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 LinkedIn Corp. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
3 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4 | *
5 | * Unless required by applicable law or agreed to in writing, software
6 | * distributed under the License is distributed on an "AS IS" BASIS,
7 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8 | */
9 |
10 | package com.secbro.qark.intentsniffer;
11 |
12 | import android.app.Activity;
13 | import android.content.Context;
14 | import android.content.Intent;
15 | import android.content.SharedPreferences;
16 | import android.os.Bundle;
17 | import android.support.v7.app.AppCompatActivity;
18 | import android.widget.TextView;
19 |
20 | import com.secbro.qark.R;
21 | import com.secbro.qark.intentsniffer.services.BroadcastStealerService;
22 |
23 | public class BroadcastIntentSnifferActivity extends AppCompatActivity {
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.fragment_broadcast_stealer);
28 | SharedPreferences prefs = this.getSharedPreferences(
29 | getPackageName(), Context.MODE_PRIVATE);
30 | TextView textview = (TextView) findViewById(R.id.activity_broadcast_stealer_text_view);
31 | textview.setText(prefs.getString("foo", "Listening..." ));
32 | Intent msgIntent = new Intent(this, BroadcastStealerService.class);
33 | msgIntent.setAction("Start");
34 | startService(msgIntent);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/java/com/secbro/qark/intentsniffer/BroadcastIntentSnifferFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 LinkedIn Corp. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
3 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4 | *
5 | * Unless required by applicable law or agreed to in writing, software
6 | * distributed under the License is distributed on an "AS IS" BASIS,
7 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8 | */
9 |
10 | package com.secbro.qark.intentsniffer;
11 |
12 | import android.content.Context;
13 | import android.content.Intent;
14 | import android.content.SharedPreferences;
15 | import android.os.Bundle;
16 | import android.support.annotation.Nullable;
17 | import android.support.v4.app.Fragment;
18 | import android.view.LayoutInflater;
19 | import android.view.View;
20 | import android.view.ViewGroup;
21 | import android.widget.TextView;
22 |
23 | import com.secbro.qark.R;
24 | import com.secbro.qark.intentsniffer.services.BroadcastStealerService;
25 |
26 | public class BroadcastIntentSnifferFragment extends Fragment {
27 |
28 |
29 | public static BroadcastIntentSnifferFragment newInstance() {
30 | BroadcastIntentSnifferFragment fragment = new BroadcastIntentSnifferFragment();
31 | return fragment;
32 | }
33 |
34 | @Override
35 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
36 | View retVal = inflater.inflate(R.layout.fragment_broadcast_stealer, container, false);
37 |
38 | SharedPreferences prefs = this.getActivity().getSharedPreferences(
39 | getActivity().getPackageName(), Context.MODE_PRIVATE);
40 | TextView textview = (TextView) retVal.findViewById(R.id.activity_broadcast_stealer_text_view);
41 |
42 | textview.setText(prefs.getString("foo", "Listening..." ));
43 | Intent msgIntent = new Intent(this.getActivity(), BroadcastStealerService.class);
44 | msgIntent.setAction("Start");
45 | this.getActivity().startService(msgIntent);
46 |
47 | return retVal;
48 | }
49 |
50 | @Override
51 | public void onResume() {
52 | SharedPreferences prefs = this.getActivity().getSharedPreferences(
53 | getActivity().getPackageName(), Context.MODE_PRIVATE);
54 | TextView textview = (TextView) this.getActivity().findViewById(R.id.activity_broadcast_stealer_text_view);
55 |
56 | textview.setText(prefs.getString("foo", "Listening..." ));
57 | super.onResume();
58 | }
59 |
60 | /**
61 | * Mandatory empty constructor for the fragment manager to instantiate the
62 | * fragment (e.g. upon screen orientation changes).
63 | */
64 | public BroadcastIntentSnifferFragment() {
65 | }
66 |
67 | @Override
68 | public void onCreate(Bundle savedInstanceState) {
69 | super.onCreate(savedInstanceState);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/java/com/secbro/qark/intentsniffer/services/BootReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 LinkedIn Corp. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
3 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4 | *
5 | * Unless required by applicable law or agreed to in writing, software
6 | * distributed under the License is distributed on an "AS IS" BASIS,
7 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8 | */
9 |
10 | package com.secbro.qark.intentsniffer.services;
11 |
12 | import android.content.BroadcastReceiver;
13 | import android.content.Context;
14 | import android.content.Intent;
15 |
16 | public class BootReceiver extends BroadcastReceiver {
17 |
18 | @Override
19 | public void onReceive(Context context, Intent intent) {
20 | Intent service = new Intent(context, BroadcastStealerService.class);
21 | context.startService(service);
22 | }
23 | }
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/java/com/secbro/qark/intentsniffer/services/BroadcastStealerService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 LinkedIn Corp. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
3 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4 | *
5 | * Unless required by applicable law or agreed to in writing, software
6 | * distributed under the License is distributed on an "AS IS" BASIS,
7 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8 | */
9 |
10 | package com.secbro.qark.intentsniffer.services;
11 |
12 | import android.app.IntentService;
13 | import android.app.Service;
14 | import android.content.BroadcastReceiver;
15 | import android.content.Intent;
16 | import android.content.Context;
17 | import android.content.IntentFilter;
18 | import android.content.SharedPreferences;
19 | import android.os.Bundle;
20 | import android.os.IBinder;
21 | import android.util.Log;
22 |
23 | import com.secbro.qark.R;
24 | import com.secbro.qark.TopLevelActivity;
25 |
26 | /**
27 | * An {@link IntentService} subclass for handling asynchronous task requests in
28 | * a service on a separate handler thread.
29 | *
30 | * TODO: Customize class - update intent actions, extra parameters and static
31 | * helper methods.
32 | */
33 | public class BroadcastStealerService extends Service {
34 |
35 | private static final String LOG_TAG = BroadcastStealerService.class.getSimpleName();
36 | private String[] intentNames = {};
37 |
38 |
39 | private final BroadcastReceiver receiver = new BroadcastReceiver() {
40 | @Override
41 | public void onReceive(Context context, Intent intent) {
42 | String action = intent.getAction();
43 | for(int i=0;i
7 |
8 |
14 |
15 |
21 |
22 |
27 |
28 |
29 |
30 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/activity_exploit_exported_result.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/activity_file_browser.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
27 |
28 |
36 |
37 |
47 |
48 |
49 |
57 |
58 |
68 |
69 |
70 |
71 |
76 |
77 |
83 |
84 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/activity_intent_sender.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/activity_top_level.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
13 |
14 |
15 |
19 |
20 |
22 |
26 |
27 |
28 |
29 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/activity_web_view_tests.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
11 |
12 |
17 |
19 |
24 |
25 |
28 |
29 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/fragment_broadcast_stealer.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
14 |
15 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/fragment_exploit_exported_activity_params.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
17 |
18 |
28 |
29 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/fragment_exported_activity_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/fragment_exported_components.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
19 |
20 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/fragment_exported_receiver_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
13 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/fragment_file_browser.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
27 |
28 |
36 |
37 |
47 |
48 |
49 |
57 |
58 |
68 |
69 |
70 |
71 |
76 |
77 |
83 |
84 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/fragment_intent_sender.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
17 |
18 |
28 |
29 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/fragment_navigation_drawer.xml:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/fragment_tap_jacking_exploit.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
14 |
15 |
18 |
19 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/fragment_top_level.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/fragment_web_view_tests.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/nav_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/tap_jacking_toast.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
27 |
28 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/layout/webview.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/menu/drawer_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/menu/menu_intent_sender.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
17 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/menu/menu_web_view_tests.xml:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/mipmap-xxxhdpi/qark_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/exploit_apk/app/src/main/res/mipmap-xxxhdpi/qark_512.png
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #F44336
4 | #D32F2F
5 | #FF5252
6 | #FFFFFF
7 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
8 | 240dp
9 | 25dp
10 | 10dp
11 |
12 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/values/extraKeys.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/values/intentID.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | - "JS_AOSP"
9 | - "JS_CHROME"
10 | - "FS_AOSP"
11 | - "FS_CHROME"
12 | - "BU_AOSP"
13 | - "BU_CHROME"
14 | - "SOP_AOSP"
15 | - "SOP_CHROME"
16 | - "IFRAME_AOSP
17 | - "IFRAME_CHROME
18 |
19 |
20 | - "Coming Soon.."
21 |
22 |
--------------------------------------------------------------------------------
/qark/exploit_apk/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/qark/exploit_apk/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.1.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | maven {
18 | url 'https://maven.google.com'
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/qark/exploit_apk/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/exploit_apk/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/qark/exploit_apk/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Apr 23 20:18:21 PDT 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip
7 |
--------------------------------------------------------------------------------
/qark/exploit_apk/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/qark/exploit_apk/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/qark/lib/apktool/apktool.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/apktool/apktool.jar
--------------------------------------------------------------------------------
/qark/lib/decompilers/cfr_0_124.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/decompilers/cfr_0_124.jar
--------------------------------------------------------------------------------
/qark/lib/decompilers/fernflower.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/decompilers/fernflower.jar
--------------------------------------------------------------------------------
/qark/lib/decompilers/procyon-decompiler-1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/decompilers/procyon-decompiler-1.0.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-baksmali.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM
4 | REM dex2jar - Tools to work with android .dex and java .class files
5 | REM Copyright (c) 2009-2013 Panxiaobo
6 | REM
7 | REM Licensed under the Apache License, Version 2.0 (the "License");
8 | REM you may not use this file except in compliance with the License.
9 | REM You may obtain a copy of the License at
10 | REM
11 | REM http://www.apache.org/licenses/LICENSE-2.0
12 | REM
13 | REM Unless required by applicable law or agreed to in writing, software
14 | REM distributed under the License is distributed on an "AS IS" BASIS,
15 | REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | REM See the License for the specific language governing permissions and
17 | REM limitations under the License.
18 | REM
19 |
20 | REM call d2j_invoke.bat to setup java environment
21 | @"%~dp0d2j_invoke.bat" com.googlecode.d2j.smali.BaksmaliCmd %*
22 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-baksmali.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # dex2jar - Tools to work with android .dex and java .class files
5 | # Copyright (c) 2009-2013 Panxiaobo
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | # copy from $Tomcat/bin/startup.sh
21 | # resolve links - $0 may be a softlink
22 | PRG="$0"
23 | while [ -h "$PRG" ] ; do
24 | ls=`ls -ld "$PRG"`
25 | link=`expr "$ls" : '.*-> \(.*\)$'`
26 | if expr "$link" : '/.*' > /dev/null; then
27 | PRG="$link"
28 | else
29 | PRG=`dirname "$PRG"`/"$link"
30 | fi
31 | done
32 | PRGDIR=`dirname "$PRG"`
33 | #
34 |
35 | # call d2j_invoke.sh to setup java environment
36 | "$PRGDIR/d2j_invoke.sh" "com.googlecode.d2j.smali.BaksmaliCmd" "$@"
37 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-dex-recompute-checksum.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM
4 | REM dex2jar - Tools to work with android .dex and java .class files
5 | REM Copyright (c) 2009-2013 Panxiaobo
6 | REM
7 | REM Licensed under the Apache License, Version 2.0 (the "License");
8 | REM you may not use this file except in compliance with the License.
9 | REM You may obtain a copy of the License at
10 | REM
11 | REM http://www.apache.org/licenses/LICENSE-2.0
12 | REM
13 | REM Unless required by applicable law or agreed to in writing, software
14 | REM distributed under the License is distributed on an "AS IS" BASIS,
15 | REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | REM See the License for the specific language governing permissions and
17 | REM limitations under the License.
18 | REM
19 |
20 | REM call d2j_invoke.bat to setup java environment
21 | @"%~dp0d2j_invoke.bat" com.googlecode.dex2jar.tools.DexRecomputeChecksum %*
22 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-dex-recompute-checksum.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # dex2jar - Tools to work with android .dex and java .class files
5 | # Copyright (c) 2009-2013 Panxiaobo
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | # copy from $Tomcat/bin/startup.sh
21 | # resolve links - $0 may be a softlink
22 | PRG="$0"
23 | while [ -h "$PRG" ] ; do
24 | ls=`ls -ld "$PRG"`
25 | link=`expr "$ls" : '.*-> \(.*\)$'`
26 | if expr "$link" : '/.*' > /dev/null; then
27 | PRG="$link"
28 | else
29 | PRG=`dirname "$PRG"`/"$link"
30 | fi
31 | done
32 | PRGDIR=`dirname "$PRG"`
33 | #
34 |
35 | # call d2j_invoke.sh to setup java environment
36 | "$PRGDIR/d2j_invoke.sh" "com.googlecode.dex2jar.tools.DexRecomputeChecksum" "$@"
37 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-dex2jar.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM
4 | REM dex2jar - Tools to work with android .dex and java .class files
5 | REM Copyright (c) 2009-2013 Panxiaobo
6 | REM
7 | REM Licensed under the Apache License, Version 2.0 (the "License");
8 | REM you may not use this file except in compliance with the License.
9 | REM You may obtain a copy of the License at
10 | REM
11 | REM http://www.apache.org/licenses/LICENSE-2.0
12 | REM
13 | REM Unless required by applicable law or agreed to in writing, software
14 | REM distributed under the License is distributed on an "AS IS" BASIS,
15 | REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | REM See the License for the specific language governing permissions and
17 | REM limitations under the License.
18 | REM
19 |
20 | REM call d2j_invoke.bat to setup java environment
21 | @"%~dp0d2j_invoke.bat" com.googlecode.dex2jar.tools.Dex2jarCmd %*
22 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-dex2jar.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # dex2jar - Tools to work with android .dex and java .class files
5 | # Copyright (c) 2009-2013 Panxiaobo
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | # copy from $Tomcat/bin/startup.sh
21 | # resolve links - $0 may be a softlink
22 | PRG="$0"
23 | while [ -h "$PRG" ] ; do
24 | ls=`ls -ld "$PRG"`
25 | link=`expr "$ls" : '.*-> \(.*\)$'`
26 | if expr "$link" : '/.*' > /dev/null; then
27 | PRG="$link"
28 | else
29 | PRG=`dirname "$PRG"`/"$link"
30 | fi
31 | done
32 | PRGDIR=`dirname "$PRG"`
33 | #
34 |
35 | # call d2j_invoke.sh to setup java environment
36 | "$PRGDIR/d2j_invoke.sh" "com.googlecode.dex2jar.tools.Dex2jarCmd" "$@"
37 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-dex2smali.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM
4 | REM dex2jar - Tools to work with android .dex and java .class files
5 | REM Copyright (c) 2009-2013 Panxiaobo
6 | REM
7 | REM Licensed under the Apache License, Version 2.0 (the "License");
8 | REM you may not use this file except in compliance with the License.
9 | REM You may obtain a copy of the License at
10 | REM
11 | REM http://www.apache.org/licenses/LICENSE-2.0
12 | REM
13 | REM Unless required by applicable law or agreed to in writing, software
14 | REM distributed under the License is distributed on an "AS IS" BASIS,
15 | REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | REM See the License for the specific language governing permissions and
17 | REM limitations under the License.
18 | REM
19 |
20 | REM call d2j_invoke.bat to setup java environment
21 | @"%~dp0d2j_invoke.bat" com.googlecode.d2j.smali.BaksmaliCmd %*
22 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-dex2smali.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # dex2jar - Tools to work with android .dex and java .class files
5 | # Copyright (c) 2009-2013 Panxiaobo
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | # copy from $Tomcat/bin/startup.sh
21 | # resolve links - $0 may be a softlink
22 | PRG="$0"
23 | while [ -h "$PRG" ] ; do
24 | ls=`ls -ld "$PRG"`
25 | link=`expr "$ls" : '.*-> \(.*\)$'`
26 | if expr "$link" : '/.*' > /dev/null; then
27 | PRG="$link"
28 | else
29 | PRG=`dirname "$PRG"`/"$link"
30 | fi
31 | done
32 | PRGDIR=`dirname "$PRG"`
33 | #
34 |
35 | # call d2j_invoke.sh to setup java environment
36 | "$PRGDIR/d2j_invoke.sh" "com.googlecode.d2j.smali.BaksmaliCmd" "$@"
37 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-jar2dex.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM
4 | REM dex2jar - Tools to work with android .dex and java .class files
5 | REM Copyright (c) 2009-2013 Panxiaobo
6 | REM
7 | REM Licensed under the Apache License, Version 2.0 (the "License");
8 | REM you may not use this file except in compliance with the License.
9 | REM You may obtain a copy of the License at
10 | REM
11 | REM http://www.apache.org/licenses/LICENSE-2.0
12 | REM
13 | REM Unless required by applicable law or agreed to in writing, software
14 | REM distributed under the License is distributed on an "AS IS" BASIS,
15 | REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | REM See the License for the specific language governing permissions and
17 | REM limitations under the License.
18 | REM
19 |
20 | REM call d2j_invoke.bat to setup java environment
21 | @"%~dp0d2j_invoke.bat" com.googlecode.dex2jar.tools.Jar2Dex %*
22 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-jar2dex.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # dex2jar - Tools to work with android .dex and java .class files
5 | # Copyright (c) 2009-2013 Panxiaobo
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | # copy from $Tomcat/bin/startup.sh
21 | # resolve links - $0 may be a softlink
22 | PRG="$0"
23 | while [ -h "$PRG" ] ; do
24 | ls=`ls -ld "$PRG"`
25 | link=`expr "$ls" : '.*-> \(.*\)$'`
26 | if expr "$link" : '/.*' > /dev/null; then
27 | PRG="$link"
28 | else
29 | PRG=`dirname "$PRG"`/"$link"
30 | fi
31 | done
32 | PRGDIR=`dirname "$PRG"`
33 | #
34 |
35 | # call d2j_invoke.sh to setup java environment
36 | "$PRGDIR/d2j_invoke.sh" "com.googlecode.dex2jar.tools.Jar2Dex" "$@"
37 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-jar2jasmin.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM
4 | REM dex2jar - Tools to work with android .dex and java .class files
5 | REM Copyright (c) 2009-2013 Panxiaobo
6 | REM
7 | REM Licensed under the Apache License, Version 2.0 (the "License");
8 | REM you may not use this file except in compliance with the License.
9 | REM You may obtain a copy of the License at
10 | REM
11 | REM http://www.apache.org/licenses/LICENSE-2.0
12 | REM
13 | REM Unless required by applicable law or agreed to in writing, software
14 | REM distributed under the License is distributed on an "AS IS" BASIS,
15 | REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | REM See the License for the specific language governing permissions and
17 | REM limitations under the License.
18 | REM
19 |
20 | REM call d2j_invoke.bat to setup java environment
21 | @"%~dp0d2j_invoke.bat" com.googlecode.d2j.jasmin.Jar2JasminCmd %*
22 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-jar2jasmin.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # dex2jar - Tools to work with android .dex and java .class files
5 | # Copyright (c) 2009-2013 Panxiaobo
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | # copy from $Tomcat/bin/startup.sh
21 | # resolve links - $0 may be a softlink
22 | PRG="$0"
23 | while [ -h "$PRG" ] ; do
24 | ls=`ls -ld "$PRG"`
25 | link=`expr "$ls" : '.*-> \(.*\)$'`
26 | if expr "$link" : '/.*' > /dev/null; then
27 | PRG="$link"
28 | else
29 | PRG=`dirname "$PRG"`/"$link"
30 | fi
31 | done
32 | PRGDIR=`dirname "$PRG"`
33 | #
34 |
35 | # call d2j_invoke.sh to setup java environment
36 | "$PRGDIR/d2j_invoke.sh" "com.googlecode.d2j.jasmin.Jar2JasminCmd" "$@"
37 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-jasmin2jar.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM
4 | REM dex2jar - Tools to work with android .dex and java .class files
5 | REM Copyright (c) 2009-2013 Panxiaobo
6 | REM
7 | REM Licensed under the Apache License, Version 2.0 (the "License");
8 | REM you may not use this file except in compliance with the License.
9 | REM You may obtain a copy of the License at
10 | REM
11 | REM http://www.apache.org/licenses/LICENSE-2.0
12 | REM
13 | REM Unless required by applicable law or agreed to in writing, software
14 | REM distributed under the License is distributed on an "AS IS" BASIS,
15 | REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | REM See the License for the specific language governing permissions and
17 | REM limitations under the License.
18 | REM
19 |
20 | REM call d2j_invoke.bat to setup java environment
21 | @"%~dp0d2j_invoke.bat" com.googlecode.d2j.jasmin.Jasmin2JarCmd %*
22 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-jasmin2jar.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # dex2jar - Tools to work with android .dex and java .class files
5 | # Copyright (c) 2009-2013 Panxiaobo
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | # copy from $Tomcat/bin/startup.sh
21 | # resolve links - $0 may be a softlink
22 | PRG="$0"
23 | while [ -h "$PRG" ] ; do
24 | ls=`ls -ld "$PRG"`
25 | link=`expr "$ls" : '.*-> \(.*\)$'`
26 | if expr "$link" : '/.*' > /dev/null; then
27 | PRG="$link"
28 | else
29 | PRG=`dirname "$PRG"`/"$link"
30 | fi
31 | done
32 | PRGDIR=`dirname "$PRG"`
33 | #
34 |
35 | # call d2j_invoke.sh to setup java environment
36 | "$PRGDIR/d2j_invoke.sh" "com.googlecode.d2j.jasmin.Jasmin2JarCmd" "$@"
37 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-smali.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM
4 | REM dex2jar - Tools to work with android .dex and java .class files
5 | REM Copyright (c) 2009-2013 Panxiaobo
6 | REM
7 | REM Licensed under the Apache License, Version 2.0 (the "License");
8 | REM you may not use this file except in compliance with the License.
9 | REM You may obtain a copy of the License at
10 | REM
11 | REM http://www.apache.org/licenses/LICENSE-2.0
12 | REM
13 | REM Unless required by applicable law or agreed to in writing, software
14 | REM distributed under the License is distributed on an "AS IS" BASIS,
15 | REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | REM See the License for the specific language governing permissions and
17 | REM limitations under the License.
18 | REM
19 |
20 | REM call d2j_invoke.bat to setup java environment
21 | @"%~dp0d2j_invoke.bat" com.googlecode.d2j.smali.SmaliCmd %*
22 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-smali.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # dex2jar - Tools to work with android .dex and java .class files
5 | # Copyright (c) 2009-2013 Panxiaobo
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | # copy from $Tomcat/bin/startup.sh
21 | # resolve links - $0 may be a softlink
22 | PRG="$0"
23 | while [ -h "$PRG" ] ; do
24 | ls=`ls -ld "$PRG"`
25 | link=`expr "$ls" : '.*-> \(.*\)$'`
26 | if expr "$link" : '/.*' > /dev/null; then
27 | PRG="$link"
28 | else
29 | PRG=`dirname "$PRG"`/"$link"
30 | fi
31 | done
32 | PRGDIR=`dirname "$PRG"`
33 | #
34 |
35 | # call d2j_invoke.sh to setup java environment
36 | "$PRGDIR/d2j_invoke.sh" "com.googlecode.d2j.smali.SmaliCmd" "$@"
37 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-std-apk.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM
4 | REM dex2jar - Tools to work with android .dex and java .class files
5 | REM Copyright (c) 2009-2013 Panxiaobo
6 | REM
7 | REM Licensed under the Apache License, Version 2.0 (the "License");
8 | REM you may not use this file except in compliance with the License.
9 | REM You may obtain a copy of the License at
10 | REM
11 | REM http://www.apache.org/licenses/LICENSE-2.0
12 | REM
13 | REM Unless required by applicable law or agreed to in writing, software
14 | REM distributed under the License is distributed on an "AS IS" BASIS,
15 | REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | REM See the License for the specific language governing permissions and
17 | REM limitations under the License.
18 | REM
19 |
20 | REM call d2j_invoke.bat to setup java environment
21 | @"%~dp0d2j_invoke.bat" com.googlecode.dex2jar.tools.StdApkCmd %*
22 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j-std-apk.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # dex2jar - Tools to work with android .dex and java .class files
5 | # Copyright (c) 2009-2013 Panxiaobo
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | # copy from $Tomcat/bin/startup.sh
21 | # resolve links - $0 may be a softlink
22 | PRG="$0"
23 | while [ -h "$PRG" ] ; do
24 | ls=`ls -ld "$PRG"`
25 | link=`expr "$ls" : '.*-> \(.*\)$'`
26 | if expr "$link" : '/.*' > /dev/null; then
27 | PRG="$link"
28 | else
29 | PRG=`dirname "$PRG"`/"$link"
30 | fi
31 | done
32 | PRGDIR=`dirname "$PRG"`
33 | #
34 |
35 | # call d2j_invoke.sh to setup java environment
36 | "$PRGDIR/d2j_invoke.sh" "com.googlecode.dex2jar.tools.StdApkCmd" "$@"
37 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j_invoke.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | REM better invocation scripts for windows from lanchon, release in public domain. thanks!
3 | REM https://code.google.com/p/dex2jar/issues/detail?id=192
4 |
5 | setlocal enabledelayedexpansion
6 |
7 | set LIB=%~dp0lib
8 |
9 | set CP=
10 | for %%X in ("%LIB%"\*.jar) do (
11 | set CP=!CP!%%X;
12 | )
13 |
14 | java -Xms512m -Xmx1024m -cp "%CP%" %*
15 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/d2j_invoke.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # dex2jar - Tools to work with android .dex and java .class files
5 | # Copyright (c) 2009-2013 Panxiaobo
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | # copy from $Tomcat/bin/startup.sh
21 | # resolve links - $0 may be a softlink
22 | PRG="$0"
23 | while [ -h "$PRG" ] ; do
24 | ls=`ls -ld "$PRG"`
25 | link=`expr "$ls" : '.*-> \(.*\)$'`
26 | if expr "$link" : '/.*' > /dev/null; then
27 | PRG="$link"
28 | else
29 | PRG=`dirname "$PRG"`/"$link"
30 | fi
31 | done
32 | PRGDIR=`dirname "$PRG"`
33 | #
34 |
35 | _classpath="."
36 | if [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path
37 | for k in "$PRGDIR"/lib/*.jar
38 | do
39 | _classpath="${_classpath};`cygpath -w ${k}`"
40 | done
41 | else
42 | for k in "$PRGDIR"/lib/*.jar
43 | do
44 | _classpath="${_classpath}:${k}"
45 | done
46 | fi
47 |
48 | java -Xms512m -Xmx1024m -classpath "${_classpath}" "$@"
49 |
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/antlr-runtime-3.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/antlr-runtime-3.5.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/asm-debug-all-4.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/asm-debug-all-4.1.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/d2j-base-cmd-2.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/d2j-base-cmd-2.0.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/d2j-jasmin-2.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/d2j-jasmin-2.0.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/d2j-smali-2.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/d2j-smali-2.0.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/dex-ir-2.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/dex-ir-2.0.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/dex-reader-2.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/dex-reader-2.0.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/dex-reader-api-2.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/dex-reader-api-2.0.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/dex-tools-2.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/dex-tools-2.0.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/dex-translator-2.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/dex-translator-2.0.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/dex-writer-2.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/dex-writer-2.0.jar
--------------------------------------------------------------------------------
/qark/lib/dex2jar-2.0/lib/dx-1.7.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/lib/dex2jar-2.0/lib/dx-1.7.jar
--------------------------------------------------------------------------------
/qark/plugins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/plugins/__init__.py
--------------------------------------------------------------------------------
/qark/plugins/broadcast/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/plugins/broadcast/__init__.py
--------------------------------------------------------------------------------
/qark/plugins/broadcast/dynamic_broadcast_receiver.py:
--------------------------------------------------------------------------------
1 | """This plugin detects if a method ``registerReceiver`` is being called with a min_sdk of less than 14.
2 |
3 | ICE_CREAM_SANDWICH properly registers receivers so anything >= API level 14 is not vulnerable."""
4 |
5 | import logging
6 |
7 | from javalang.tree import MethodInvocation
8 |
9 | from qark.issue import Issue, Severity
10 | from qark.scanner.plugin import CoroutinePlugin, ManifestPlugin
11 |
12 | log = logging.getLogger(__name__)
13 |
14 | DYNAMIC_BROADCAST_RECEIVER_DESCRIPTION = (
15 | "Application that register a broadcast receiver dynamically is vulnerable to granting unrestricted access to the "
16 | "broadcast receiver. The receiver will be called with any broadcast Intent that matches filter."
17 | " Reference: https://developer.android.com/reference/android/"
18 | "content/Context.html#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter)"
19 | )
20 |
21 | JAVA_DYNAMIC_BROADCAST_RECEIVER_METHOD = 'registerReceiver'
22 |
23 |
24 | class DynamicBroadcastReceiver(CoroutinePlugin, ManifestPlugin):
25 |
26 | def __init__(self):
27 | super(DynamicBroadcastReceiver, self).__init__(category="broadcast", name="Dynamic broadcast receiver found",
28 | description=DYNAMIC_BROADCAST_RECEIVER_DESCRIPTION)
29 | self.severity = Severity.VULNERABILITY
30 |
31 | def run_coroutine(self):
32 | while True:
33 | _, method_invocation = (yield)
34 | if not isinstance(method_invocation, MethodInvocation):
35 | continue
36 |
37 | if method_invocation.member == JAVA_DYNAMIC_BROADCAST_RECEIVER_METHOD and self.min_sdk < 14:
38 | self.issues.append(Issue(
39 | category=self.category, severity=self.severity, name=self.name,
40 | description=DYNAMIC_BROADCAST_RECEIVER_DESCRIPTION,
41 | file_object=self.file_path,
42 | line_number=method_invocation.position)
43 | )
44 |
45 |
46 | plugin = DynamicBroadcastReceiver()
47 |
--------------------------------------------------------------------------------
/qark/plugins/cert/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/plugins/cert/__init__.py
--------------------------------------------------------------------------------
/qark/plugins/crypto/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/plugins/crypto/__init__.py
--------------------------------------------------------------------------------
/qark/plugins/crypto/ecb_cipher_usage.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import re
3 |
4 | import javalang
5 |
6 | from qark.issue import Severity, Issue
7 | from qark.scanner.plugin import CoroutinePlugin
8 |
9 | log = logging.getLogger(__name__)
10 |
11 |
12 | class ECBCipherCheck(CoroutinePlugin):
13 | def __init__(self):
14 |
15 | super(ECBCipherCheck, self).__init__(category="crypto", name="ECB Cipher Usage",
16 | description="ECB mode is an insecure encryption technique and prone to data leakage")
17 |
18 | self.severity = Severity.VULNERABILITY
19 |
20 | def run_coroutine(self):
21 | while True:
22 | _, method_invocation = (yield)
23 |
24 | if not isinstance(method_invocation, javalang.tree.MethodInvocation):
25 | continue
26 |
27 | try:
28 | method_name = method_invocation.member
29 | encryption_type = method_invocation.arguments[0].value
30 | qualifier = method_invocation.qualifier # the thing that getInstance is called on
31 | if method_name == 'getInstance' and qualifier == 'Cipher' and re.search(r'.*/ECB/.*',
32 | encryption_type):
33 | description = "getInstance should not be called with ECB as the cipher mode, as it is insecure."
34 | self.issues.append(
35 | Issue(self.category, self.name, self.severity, description, file_object=self.file_path))
36 | except Exception:
37 | continue
38 |
39 |
40 | plugin = ECBCipherCheck()
41 |
--------------------------------------------------------------------------------
/qark/plugins/crypto/packaged_private_keys.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import re
3 |
4 | from qark.issue import Severity, Issue
5 | from qark.plugins.helpers import run_regex
6 | from qark.scanner.plugin import FileContentsPlugin
7 |
8 | log = logging.getLogger(__name__)
9 |
10 |
11 | class PackagedPrivateKeys(FileContentsPlugin):
12 | PRIVATE_KEY_REGEXES = (
13 | re.compile(r'PRIVATE\sKEY'),
14 | )
15 |
16 | def __init__(self):
17 | super(PackagedPrivateKeys, self).__init__(category="crypto",
18 | name="Encryption keys are packaged with the application")
19 |
20 | self.severity = Severity.VULNERABILITY
21 |
22 | def run(self):
23 | for regex in PackagedPrivateKeys.PRIVATE_KEY_REGEXES:
24 | if run_regex(self.file_path, regex):
25 | log.debug("It appears there is a private key embedded in your application: %s", self.file_path)
26 | description = "It appears there is a private key embedded in your application in the following file:"
27 | self.issues.append(
28 | Issue(self.category, self.name, self.severity, description, file_object=self.file_path))
29 |
30 |
31 | plugin = PackagedPrivateKeys()
32 |
--------------------------------------------------------------------------------
/qark/plugins/crypto/rsa_cipher_usage.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import re
3 |
4 | import javalang
5 |
6 | from qark.issue import Severity, Issue
7 | from qark.scanner.plugin import CoroutinePlugin
8 |
9 | log = logging.getLogger(__name__)
10 |
11 |
12 | class RSACipherCheck(CoroutinePlugin):
13 | def __init__(self):
14 |
15 | super(RSACipherCheck, self).__init__(category="crypto", name="RSA Cipher Usage",
16 | description="RSA mode without padding is an insecure encryption technique and prone to data leakage")
17 |
18 | self.severity = Severity.VULNERABILITY
19 |
20 | def run_coroutine(self):
21 | while True:
22 | _, method_invocation = (yield)
23 |
24 | if not isinstance(method_invocation, javalang.tree.MethodInvocation):
25 | continue
26 |
27 | try:
28 | method_name = method_invocation.member
29 | encryption_type = method_invocation.arguments[0].value
30 | qualifier = method_invocation.qualifier # the thing that getInstance is called on
31 | if method_name == 'getInstance' and qualifier == 'Cipher' and re.search(r'RSA/.+/NoPadding',
32 | encryption_type):
33 | description = "getInstance should not be called with RSA without padding as the cipher mode, as it is insecure."
34 | self.issues.append(
35 | Issue(self.category, self.name, self.severity, description, file_object=self.file_path))
36 | except Exception:
37 | continue
38 |
39 |
40 | plugin = RSACipherCheck()
41 |
--------------------------------------------------------------------------------
/qark/plugins/crypto/setting_secure_random_seed.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | import javalang
4 |
5 | from qark.issue import Severity, Issue
6 | from qark.scanner.plugin import CoroutinePlugin
7 |
8 | log = logging.getLogger(__name__)
9 |
10 |
11 | class SeedWithSecureRandom(CoroutinePlugin):
12 |
13 | INSECURE_FUNCTIONS = ("setSeed", "generateSeed")
14 |
15 | def __init__(self):
16 |
17 | super(SeedWithSecureRandom, self).__init__(category="crypto",
18 | name="Random number generator is seeded with SecureSeed",
19 | description=(
20 | "Specifying a fixed seed will cause a predictable sequence of numbers. "
21 | "This may be useful for testing, but not for secure use"))
22 |
23 | self.severity = Severity.WARNING
24 |
25 | def _imports_secure_seed(self, tree):
26 | """Checks if a tree imports java.security.SecureRandom, and returns True if the import exists"""
27 | return any(imp.path == "java.security.SecureRandom" for imp in tree.imports)
28 |
29 | def can_run_coroutine(self):
30 | return self._imports_secure_seed(self.java_ast)
31 |
32 | def run_coroutine(self):
33 | while True:
34 | _, method_invocation = (yield)
35 |
36 | if not isinstance(method_invocation, javalang.tree.MethodInvocation):
37 | continue
38 |
39 | if method_invocation.member in SeedWithSecureRandom.INSECURE_FUNCTIONS:
40 | self.issues.append(Issue(self.category, self.name, self.severity, self.description,
41 | file_object=self.file_path))
42 |
43 |
44 | plugin = SeedWithSecureRandom()
45 |
--------------------------------------------------------------------------------
/qark/plugins/file/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/plugins/file/__init__.py
--------------------------------------------------------------------------------
/qark/plugins/file/android_logging.py:
--------------------------------------------------------------------------------
1 | """
2 | Checks if either a method within ``ANDROID_LOGGING_METHODS`` is invoked with `Log.` before it.
3 |
4 | For instance:
5 | Log.d("test")
6 | Log.e("test")
7 |
8 | Both trigger but the following does not:
9 | d("test")
10 | e("test")
11 | """
12 |
13 | import logging
14 |
15 | from javalang.tree import MethodInvocation
16 |
17 | from qark.issue import Severity, Issue
18 | from qark.scanner.plugin import CoroutinePlugin
19 |
20 | log = logging.getLogger(__name__)
21 |
22 | ANDROID_LOGGING_DESCRIPTION = (
23 | "Logs are detected. This may allow potential leakage of information from Android applications. Logs should never be"
24 | " compiled into an application except during development. Reference: "
25 | "https://developer.android.com/reference/android/util/Log.html"
26 | )
27 |
28 | ANDROID_LOGGING_METHODS = ("v", "d", "i", "w", "e")
29 |
30 |
31 | class AndroidLogging(CoroutinePlugin):
32 | def __init__(self):
33 | super(AndroidLogging, self).__init__(category="file", name="Logging found",
34 | description=ANDROID_LOGGING_DESCRIPTION)
35 | self.severity = Severity.WARNING
36 |
37 | def run_coroutine(self):
38 | while True:
39 | _, method_invocation = (yield)
40 |
41 | if not isinstance(method_invocation, MethodInvocation):
42 | continue
43 |
44 | if method_invocation.qualifier == "Log" and method_invocation.member in ANDROID_LOGGING_METHODS:
45 | self.issues.append(Issue(
46 | category=self.category, severity=self.severity, name=self.name,
47 | description=self.description,
48 | file_object=self.file_path,
49 | line_number=method_invocation.position)
50 | )
51 |
52 |
53 | plugin = AndroidLogging()
54 |
--------------------------------------------------------------------------------
/qark/plugins/file/api_keys.py:
--------------------------------------------------------------------------------
1 | """This plugin checks if there are any lines in the file that match the regex ``API_KEY_REGEX`` while
2 | also not matching ``SPECIAL_CHARACTER_REGEX``."""
3 |
4 | import logging
5 | import re
6 |
7 | from qark.issue import Severity, Issue
8 | from qark.scanner.plugin import FileContentsPlugin
9 |
10 | log = logging.getLogger(__name__)
11 |
12 | API_KEY_REGEX = re.compile(r'(?=.{20,})(?=.+\d)(?=.+[a-z])(?=.+[A-Z])(?=.+[-_])')
13 | SPECIAL_CHARACTER_REGEX = re.compile(r'(?=.+[!$%^&*()_+|~=`{}\[\]:<>?,./])')
14 | BLACKLISTED_EXTENSIONS = (".apk", ".dex", ".png", ".jar")
15 |
16 | API_KEY_DESCRIPTION = "Please confirm and investigate the API key to determine its severity."
17 |
18 |
19 | class JavaAPIKeys(FileContentsPlugin):
20 | def __init__(self):
21 | super(JavaAPIKeys, self).__init__(category="file", name="Potential API Key found",
22 | description=API_KEY_DESCRIPTION)
23 | self.severity = Severity.INFO
24 |
25 | def run(self):
26 | if any(self.file_path.endswith(extension) for extension in BLACKLISTED_EXTENSIONS):
27 | return
28 |
29 | for line_number, line in enumerate(self.file_contents.split("\n")):
30 | for word in line.split():
31 | if re.search(API_KEY_REGEX, word) and not re.search(SPECIAL_CHARACTER_REGEX, word):
32 | self.issues.append(Issue(
33 | category=self.category, severity=self.severity, name=self.name,
34 | description=self.description,
35 | file_object=self.file_path,
36 | line_number=(line_number, 0))
37 | )
38 |
39 |
40 | plugin = JavaAPIKeys()
41 |
--------------------------------------------------------------------------------
/qark/plugins/file/external_storage.py:
--------------------------------------------------------------------------------
1 | """
2 | This plugin determines if the following methods are called:
3 |
4 | 1. getExternalFilesDir
5 | 2. getExternalFilesDirs
6 | 3. getExternalMediaDirs
7 | 4. getExternalStoragePublicDirectory
8 |
9 | """
10 |
11 | import logging
12 |
13 | from javalang.tree import MethodInvocation
14 |
15 | from qark.issue import Severity, Issue
16 | from qark.scanner.plugin import CoroutinePlugin
17 |
18 | log = logging.getLogger(__name__)
19 |
20 | EXTERNAL_STORAGE_DESCRIPTION = (
21 | "Reading files stored on {storage_location} makes it vulnerable to data injection attacks. "
22 | "Note that this code does no error checking and there is no security enforced with these files. "
23 | "For example, any application holding WRITE_EXTERNAL_STORAGE can write to these files. "
24 | "Reference: https://developer.android.com/reference/android/content/Context.html"
25 | )
26 |
27 | EXTERNAL_FILES_DIR_METHOD = 'getExternalFilesDir'
28 | EXTERNAL_FILES_DIRS_METHOD = 'getExternalFilesDirs'
29 | EXTERNAL_MEDIA_DIR_METHOD = 'getExternalMediaDirs'
30 | EXTERNAL_STORAGE_PUBLIC_DIR_METHOD = 'getExternalStoragePublicDirectory'
31 |
32 |
33 | class ExternalStorage(CoroutinePlugin):
34 | def __init__(self):
35 | super(ExternalStorage, self).__init__(category="file", name="External storage used",
36 | description=EXTERNAL_STORAGE_DESCRIPTION)
37 | self.severity = Severity.WARNING
38 |
39 | def run_coroutine(self):
40 | while True:
41 | _, method_invocation = (yield)
42 |
43 | if not isinstance(method_invocation, MethodInvocation):
44 | continue
45 |
46 | storage_location = None
47 | if (method_invocation.member == EXTERNAL_FILES_DIR_METHOD
48 | or method_invocation.member == EXTERNAL_FILES_DIRS_METHOD):
49 | storage_location = "External Storage"
50 |
51 | elif method_invocation.member == EXTERNAL_MEDIA_DIR_METHOD:
52 | storage_location = "External Media Directory"
53 |
54 | elif method_invocation.member == EXTERNAL_STORAGE_PUBLIC_DIR_METHOD:
55 | storage_location = "External Storage Public Directory"
56 |
57 | if storage_location:
58 | self.issues.append(Issue(
59 | category=self.category, severity=self.severity, name=self.name,
60 | description=self.description,
61 | file_object=self.file_path,
62 | line_number=method_invocation.position)
63 | )
64 |
65 |
66 | plugin = ExternalStorage()
67 |
--------------------------------------------------------------------------------
/qark/plugins/file/file_permissions.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import re
3 |
4 | from qark.issue import Severity, Issue
5 | from qark.plugins.helpers import run_regex
6 | from qark.scanner.plugin import FileContentsPlugin
7 |
8 | log = logging.getLogger(__name__)
9 |
10 | WORLD_READABLE = re.compile("MODE_WORLD_READABLE")
11 | WORLD_WRITEABLE = re.compile("MODE_WORLD_WRITEABLE")
12 |
13 | WORLD_READABLE_DESCRIPTION = "World readable file found. Any application or file browser can access and read this file"
14 | WORLD_WRITEABLE_DESCRIPTION = "World writeable file found. Any application or file browser can write to this file"
15 |
16 |
17 | class FilePermissions(FileContentsPlugin):
18 | """
19 | This module runs a regex search on every Java file looking for `WORLD_READABLE` and `WORLD_WRITEABLE` modes.
20 | """
21 | def __init__(self):
22 | super(FilePermissions, self).__init__(category="file", name="File Permissions")
23 | self.severity = Severity.WARNING
24 |
25 | def run(self):
26 | if run_regex(self.file_path, WORLD_READABLE):
27 | self.issues.append(Issue(category=self.category, name="World readable file", severity=self.severity,
28 | description=WORLD_READABLE_DESCRIPTION, file_object=self.file_path))
29 | if run_regex(self.file_path, WORLD_WRITEABLE):
30 | self.issues.append(Issue(category=self.category, name="World writeable file", severity=self.severity,
31 | description=WORLD_WRITEABLE_DESCRIPTION, file_object=self.file_path))
32 |
33 |
34 | plugin = FilePermissions()
35 |
--------------------------------------------------------------------------------
/qark/plugins/file/http_url_hardcoded.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import re
3 |
4 | from qark.issue import Severity, Issue
5 | from qark.utils import is_java_file
6 | from qark.scanner.plugin import FileContentsPlugin
7 |
8 | log = logging.getLogger(__name__)
9 |
10 | HARDCODED_HTTP_DESCRIPTION = (
11 | "Application contains hardcoded HTTP url: {http_url}, unless HSTS is implemented, this request can be "
12 | "intercepted and modified by a man-in-the-middle attack."
13 | )
14 |
15 | HTTP_URL_REGEX = re.compile(r'http://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+')
16 |
17 |
18 | class HardcodedHTTP(FileContentsPlugin):
19 | def __init__(self):
20 | super(HardcodedHTTP, self).__init__(category="file", name="Hardcoded HTTP url found",
21 | description=HARDCODED_HTTP_DESCRIPTION)
22 | self.severity = Severity.INFO
23 |
24 | def run(self):
25 | if not is_java_file(self.file_path):
26 | return
27 |
28 | for line_number, line in enumerate(self.file_contents.split('\n')):
29 | http_url_match = re.search(HTTP_URL_REGEX, line)
30 | if http_url_match:
31 | self.issues.append(Issue(
32 | category=self.category, severity=self.severity, name=self.name,
33 | description=self.description.format(http_url=http_url_match.group(0)),
34 | file_object=self.file_path,
35 | line_number=(line_number, 0))
36 | )
37 |
38 |
39 | plugin = HardcodedHTTP()
40 |
--------------------------------------------------------------------------------
/qark/plugins/file/insecure_functions.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from javalang.tree import MethodDeclaration
4 |
5 | from qark.issue import Severity, Issue
6 | from qark.scanner.plugin import CoroutinePlugin
7 |
8 | log = logging.getLogger(__name__)
9 |
10 | INSECURE_FUNCTIONS_DESCRIPTION = (
11 | "The Content provider API provides a method call. The framework does no permission checking on this "
12 | "entry into the content provider besides the basic ability for the application to get access to the provider"
13 | " at all. Any implementation of this method must do its own permission checks on incoming calls to make sure "
14 | "they are allowed. Failure to do so will allow unauthorized components to interact with the content provider. "
15 | "Reference: https://bitbucket.org/secure-it-i/android-app-vulnerability-benchmarks/src/d5305b9481df3502e60e98fa352d5f58e4a69044/ICC/WeakChecksOnDynamicInvocation-InformationExposure/?at=master"
16 | )
17 |
18 | INSECURE_FUNCTIONS_NAMES = ("call",)
19 |
20 |
21 | class InsecureFunctions(CoroutinePlugin):
22 | def __init__(self):
23 | super(InsecureFunctions, self).__init__(category="file", name="Insecure functions found",
24 | description=INSECURE_FUNCTIONS_DESCRIPTION)
25 | self.severity = Severity.WARNING
26 |
27 | def run_coroutine(self):
28 | while True:
29 | _, node = (yield)
30 |
31 | if isinstance(node, MethodDeclaration) and node.name in INSECURE_FUNCTIONS_NAMES:
32 | self.issues.append(Issue(
33 | category=self.category, severity=self.severity, name=self.name,
34 | description=self.description,
35 | file_object=self.file_path,
36 | line_number=node.position)
37 | )
38 |
39 |
40 | plugin = InsecureFunctions()
41 |
--------------------------------------------------------------------------------
/qark/plugins/file/phone_identifier.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import re
3 |
4 | from qark.issue import Severity, Issue
5 | from qark.scanner.plugin import FileContentsPlugin
6 |
7 | log = logging.getLogger(__name__)
8 |
9 | PHONE_IDENTIFIER_DESCRIPTION = (
10 | "Access of phone number or IMEI, is detected. Avoid storing or transmitting this data."
11 | )
12 |
13 | TELEPHONY_MANAGER_VARIABLE_NAMES_REGEX = re.compile(r'(android\.telephony\.)?TelephonyManager\s(\w*?)([,);]|(\s=))')
14 | TELEPHONY_MANAGER_REGEX = re.compile(r'android\.telephony\.TelephonyManager')
15 | TELEPHONY_INLINE_REGEX = re.compile(r'\({2,}(android.telephony.)?TelephonyManager\)\w*?\.getSystemService\([\'\"]phone'
16 | r'[\'\"]\){2,}\.(getLine1Number|getDeviceId)')
17 |
18 |
19 | class PhoneIdentifier(FileContentsPlugin):
20 | def __init__(self):
21 | super(PhoneIdentifier, self).__init__(category="file", name="Phone number or IMEI detected",
22 | description=PHONE_IDENTIFIER_DESCRIPTION)
23 | self.severity = Severity.INFO
24 |
25 | def run(self):
26 | if re.search(TELEPHONY_MANAGER_REGEX, self.file_contents):
27 | if re.search(TELEPHONY_INLINE_REGEX, self.file_contents):
28 | self._add_issue(java_path=self.file_path)
29 |
30 | else:
31 |
32 | for match in re.finditer(TELEPHONY_MANAGER_VARIABLE_NAMES_REGEX, self.file_contents):
33 |
34 | for variable_name in match.group(2):
35 |
36 | if re.search(r'{var_name}\.(getLine1Number|getDeviceId)\(.*?\)'.format(var_name=variable_name),
37 | self.file_contents):
38 | self._add_issue(java_path=self.file_path)
39 |
40 | def _add_issue(self, java_path):
41 | self.issues.append(Issue(
42 | category=self.category, severity=self.severity, name=self.name,
43 | description=self.description,
44 | file_object=java_path)
45 | )
46 |
47 |
48 | plugin = PhoneIdentifier()
49 |
--------------------------------------------------------------------------------
/qark/plugins/generic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/plugins/generic/__init__.py
--------------------------------------------------------------------------------
/qark/plugins/generic/check_permissions.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import re
3 |
4 | from qark.issue import Severity, Issue
5 | from qark.scanner.plugin import JavaASTPlugin
6 |
7 | log = logging.getLogger(__name__)
8 |
9 | CHECK_PERMISSIONS_DESCRIPTION = (
10 | "Be careful with use of {used_permission} permission function\nApp maybe vulnerable to Privilege escalation or "
11 | "Confused Deputy Attack. This function can grant access to malicious application, lacking the "
12 | "appropriate permission, by assuming your applications permissions. This means a malicious application, "
13 | "without appropriate permissions, can bypass its permission check by using your application"
14 | "permission to get access to otherwise denied resources. Use - {recommended_permission}CallingPermission instead. "
15 | "Reference: https://developer.android.com/reference/android/content/Context.html\n"
16 | )
17 | CHECK_PERMISSION_REGEX = re.compile(r'checkCallingOrSelfPermission|checkCallingOrSelfUriPermission|checkPermission')
18 | ENFORCE_PERMISSION_REGEX = re.compile(
19 | 'enforceCallingOrSelfPermission|enforceCallingOrSelfUriPermission|enforcePermission')
20 |
21 |
22 | class CheckPermissions(JavaASTPlugin):
23 | def __init__(self):
24 | super(CheckPermissions, self).__init__(category="manifest",
25 | name="Potientially vulnerable check permission function called",
26 | description=CHECK_PERMISSIONS_DESCRIPTION)
27 | self.severity = Severity.WARNING
28 |
29 | def run(self):
30 | if any("Context" in imp.path for imp in self.java_ast.imports):
31 | if re.search(CHECK_PERMISSION_REGEX, self.file_contents):
32 | self.issues.append(Issue(
33 | category=self.category, severity=self.severity, name=self.name,
34 | description=self.description.format(used_permission="Check", recommended_permission="check"),
35 | file_object=self.file_path)
36 | )
37 | if re.search(ENFORCE_PERMISSION_REGEX, self.file_contents):
38 | self.issues.append(Issue(
39 | category=self.category, severity=self.severity, name=self.name,
40 | description=self.description.format(used_permission="Enforce", recommended_permission="enforce"),
41 | file_object=self.file_path)
42 | )
43 |
44 |
45 | plugin = CheckPermissions()
46 |
--------------------------------------------------------------------------------
/qark/plugins/generic/task_affinity.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import re
3 |
4 | from qark.issue import Severity, Issue
5 | from qark.scanner.plugin import JavaASTPlugin
6 |
7 | log = logging.getLogger(__name__)
8 |
9 | TASK_AFFINITY_DESCRIPTION = (
10 | "FLAG_ACTIVITY_{type}_TASK - intent flag is set. This results in activity being loaded as a part of a new task. "
11 | "This can be abused in the task hijacking attack. "
12 | "Reference: https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-ren-chuangang.pdf"
13 | )
14 | NEW_TASK_REGEX = re.compile(r'FLAG_ACTIVITY_NEW_TASK')
15 | MULTIPLE_TASK_REGEX = re.compile(r'FLAG_ACTIVITY_MULTIPLE_TASK')
16 |
17 |
18 | class TaskAffinity(JavaASTPlugin):
19 | def __init__(self):
20 | super(TaskAffinity, self).__init__(category="generic", name="Potential task hijacking",
21 | description=TASK_AFFINITY_DESCRIPTION)
22 | self.severity = Severity.INFO
23 |
24 | def run(self):
25 | if any("Intent" in import_decl.path for import_decl in self.java_ast.imports):
26 | description = None
27 |
28 | if re.search(NEW_TASK_REGEX, self.file_contents):
29 | description = TASK_AFFINITY_DESCRIPTION.format(type="NEW")
30 | elif re.search(MULTIPLE_TASK_REGEX, self.file_contents):
31 | description = TASK_AFFINITY_DESCRIPTION.format(type="MULTIPLE")
32 |
33 | if description:
34 | self.issues.append(Issue(category=self.category,
35 | severity=self.severity,
36 | name=self.name,
37 | description=description,
38 | file_object=self.file_path))
39 |
40 |
41 | plugin = TaskAffinity()
42 |
--------------------------------------------------------------------------------
/qark/plugins/intent/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/plugins/intent/__init__.py
--------------------------------------------------------------------------------
/qark/plugins/manifest/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/plugins/manifest/__init__.py
--------------------------------------------------------------------------------
/qark/plugins/manifest/allow_backup.py:
--------------------------------------------------------------------------------
1 | from qark.scanner.plugin import ManifestPlugin
2 | from qark.issue import Severity, Issue
3 |
4 | import logging
5 |
6 | log = logging.getLogger(__name__)
7 |
8 |
9 | class ManifestBackupAllowed(ManifestPlugin):
10 | def __init__(self):
11 | super(ManifestBackupAllowed, self).__init__(category="manifest", name="Backup is allowed in manifest",
12 | description=(
13 | "Backups enabled: Potential for data theft via local attacks via adb "
14 | "backup, if the device has USB debugging enabled (not common). "
15 | "More info: "
16 | "http://developer.android.com/reference/android/R.attr.html#allowBackup"))
17 |
18 | self.severity = Severity.WARNING
19 |
20 | def run(self):
21 | application_sections = self.manifest_xml.getElementsByTagName("application")
22 |
23 | for application in application_sections:
24 | if "android:allowBackup" in application.attributes.keys():
25 | self.issues.append(Issue(category=self.category, severity=self.severity,
26 | name=self.name, description=self.description,
27 | file_object=self.manifest_path))
28 |
29 |
30 | plugin = ManifestBackupAllowed()
31 |
--------------------------------------------------------------------------------
/qark/plugins/manifest/android_path.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from qark.issue import Severity, Issue
4 | from qark.scanner.plugin import ManifestPlugin
5 |
6 | log = logging.getLogger(__name__)
7 |
8 | PATH_USAGE_DESCRIPTION = ("android:path means that the permission applies to the exact path declared"
9 | " in android:path. This expression does not protect the sub-directories")
10 |
11 |
12 | class AndroidPath(ManifestPlugin):
13 | def __init__(self):
14 | super(AndroidPath, self).__init__(category="manifest", name="android:path tag used",
15 | description=PATH_USAGE_DESCRIPTION)
16 |
17 | self.severity = Severity.WARNING
18 |
19 | def run(self):
20 | with open(self.manifest_path, "r") as manifest_file:
21 | for line_number, line in enumerate(manifest_file):
22 | if "android:path=" in line:
23 | self.issues.append(Issue(
24 | category=self.category, severity=self.severity, name=self.name,
25 | description=self.description,
26 | file_object=self.manifest_path,
27 | line_number=line_number)
28 | )
29 |
30 |
31 | plugin = AndroidPath()
32 |
--------------------------------------------------------------------------------
/qark/plugins/manifest/api_keys.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import re
3 |
4 | from qark.issue import Severity, Issue
5 | from qark.scanner.plugin import ManifestPlugin
6 |
7 | log = logging.getLogger(__name__)
8 |
9 | API_KEY_REGEX = re.compile(r'(?=.{20,})(?=.+\d)(?=.+[a-z])(?=.+[A-Z])')
10 | SPECIAL_CHARACTER_REGEX = re.compile(r'(?=.+[!$%^~])')
11 | HARDCODED_API_KEY_REGEX = re.compile(r'api_key|api|key', re.IGNORECASE)
12 |
13 | API_KEY_DESCRIPTION = "Please confirm and investigate for potential API keys to determine severity."
14 |
15 |
16 | class APIKeys(ManifestPlugin):
17 | def __init__(self):
18 | super(APIKeys, self).__init__(category="manifest", name="Potential API Key found",
19 | description=API_KEY_DESCRIPTION)
20 | self.severity = Severity.INFO
21 |
22 | def run(self):
23 | with open(self.manifest_path, "r") as manifest_file:
24 | for line_number, line in enumerate(manifest_file):
25 | # TODO: Fix API_KEY_REGEX, there are too many false positives
26 | # if re.search(API_KEY_REGEX, line) and not re.search(SPECIAL_CHARACTER_REGEX, line):
27 | # self.issues.append(Issue(
28 | # category=self.category, severity=self.severity, name=self.name,
29 | # description=self.description,
30 | # file_object=self.manifest_path,
31 | # line_number=line_number)
32 | # )
33 | if re.search(HARDCODED_API_KEY_REGEX, line):
34 | self.issues.append(Issue(
35 | category=self.category, severity=self.severity, name=self.name,
36 | description=self.description,
37 | file_object=self.manifest_path,
38 | line_number=line_number)
39 | )
40 |
41 |
42 | plugin = APIKeys()
43 |
--------------------------------------------------------------------------------
/qark/plugins/manifest/custom_permissions.py:
--------------------------------------------------------------------------------
1 | from qark.scanner.plugin import ManifestPlugin
2 |
3 | import logging
4 |
5 | from qark.issue import Severity, Issue
6 | from qark.plugins.manifest_helpers import get_min_sdk
7 |
8 | log = logging.getLogger(__name__)
9 |
10 | SIGNATURE_OR_SIGNATURE_OR_SYSTEM_DESCRIPTION = (
11 | "This permission can be obtained by malicious apps installed prior to this "
12 | "one, without the proper signature. Applicable to Android Devices prior to "
13 | "L (Lollipop). More info: "
14 | "https://github.com/commonsguy/cwac-security/blob/master/PERMS.md"
15 | )
16 | SIGNATURE_OR_SIGNATURE_OR_SYSTEM_SEVERITY = Severity.WARNING
17 |
18 | DANGEROUS_PERMISSION_DESCRIPTION = (
19 | "This permission can give a requesting application access to private user data or control over the "
20 | "device that can negatively impact the user."
21 | )
22 |
23 |
24 | class CustomPermissions(ManifestPlugin):
25 | def __init__(self):
26 | super(CustomPermissions, self).__init__(category="manifest",
27 | name="Custom permissions are enabled in the manifest",
28 | description=(
29 | "This permission can be obtained by malicious apps installed prior to this "
30 | "one, without the proper signature. Applicable to Android Devices prior to "
31 | "L (Lollipop). More info: "
32 | "https://github.com/commonsguy/cwac-security/blob/master/PERMS.md"))
33 |
34 | self.severity = Severity.WARNING
35 |
36 | def run(self):
37 | permission_sections = self.manifest_xml.getElementsByTagName("permission")
38 | for permission in permission_sections:
39 | try:
40 | protection_level = permission.attributes["android:protectionLevel"].value
41 | except KeyError:
42 | continue
43 |
44 | if protection_level in ("signature", "signatureOrSystem"):
45 | if self.min_sdk < 21:
46 | self.issues.append(Issue(category=self.category,
47 | severity=SIGNATURE_OR_SIGNATURE_OR_SYSTEM_SEVERITY,
48 | name=self.name,
49 | description=SIGNATURE_OR_SIGNATURE_OR_SYSTEM_DESCRIPTION,
50 | file_object=self.manifest_path))
51 |
52 | elif protection_level == "dangerous":
53 | self.issues.append(Issue(category=self.category,
54 | severity=Severity.INFO,
55 | name=self.name,
56 | description=DANGEROUS_PERMISSION_DESCRIPTION,
57 | file_object=self.manifest_path))
58 |
59 |
60 | plugin = CustomPermissions()
61 |
--------------------------------------------------------------------------------
/qark/plugins/manifest/debuggable.py:
--------------------------------------------------------------------------------
1 | from qark.scanner.plugin import ManifestPlugin
2 | from qark.issue import Severity, Issue
3 |
4 | import logging
5 |
6 | log = logging.getLogger(__name__)
7 |
8 |
9 | class DebuggableManifest(ManifestPlugin):
10 | def __init__(self):
11 | super(DebuggableManifest, self).__init__(category="manifest", name="Manifest is manually set to debug",
12 | description=(
13 | "The android:debuggable flag is manually set to true in the"
14 | " AndroidManifest.xml. This will cause your application to be debuggable "
15 | "in production builds and can result in data leakage "
16 | "and other security issues. It is not necessary to set the "
17 | "android:debuggable flag in the manifest, it will be set appropriately "
18 | "automatically by the tools. More info: "
19 | "http://developer.android.com/guide/topics/manifest/application-element.html#debug"))
20 |
21 | self.severity = Severity.VULNERABILITY
22 |
23 | def run(self):
24 | application_sections = self.manifest_xml.getElementsByTagName("application")
25 | for application in application_sections:
26 | try:
27 | if application.attributes["android:debuggable"].value.lower() == "true":
28 | self.issues.append(Issue(category=self.category, severity=self.severity,
29 | name=self.name, description=self.description,
30 | file_object=self.manifest_path))
31 | except (KeyError, AttributeError):
32 | log.debug("Application section does not have debuggable flag, continuing")
33 | continue
34 |
35 |
36 | plugin = DebuggableManifest()
37 |
--------------------------------------------------------------------------------
/qark/plugins/manifest/min_sdk.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from qark.issue import Issue, Severity
4 | from qark.plugins.manifest_helpers import get_min_sdk
5 | from qark.scanner.plugin import ManifestPlugin
6 |
7 | log = logging.getLogger(__name__)
8 |
9 | TAP_JACKING = ("Since the minSdkVersion is less that 9, it is likely this application is vulnerable to TapJacking. "
10 | "QARK made no attempt to confirm, as the protection would have to be custom code, which is difficult for"
11 | " QARK to examine and understand properly. This vulnerability allows a malicious application to lay on "
12 | "top of this app, while letting the key strokes pass through to the application below. This can cause "
13 | "users to take unwanted actions, within the victim application, similar to Clickjacking on websites. "
14 | "Please select the appropriate options in the exploitation menus to verify manually using QARK's "
15 | "exploit APK. Note: The QARK proof-of-concept is transparent, but in real-world attacks, it would "
16 | "likely not be. This is done solely to aid in testing. For more information: "
17 | "https://media.blackhat.com/ad-12/Niemietz/bh-ad-12-androidmarcus_niemietz-WP.pdf")
18 |
19 |
20 | class MinSDK(ManifestPlugin):
21 | """This plugin will create issues depending on the manifest's minimum SDK. For instance
22 | tapjacking is only protected when min_sdk > 9 (or custom code is used)."""
23 | def __init__(self):
24 | super(MinSDK, self).__init__(name="MinSDK checks", category="manifest")
25 |
26 | self.severity = Severity.WARNING
27 |
28 | def run(self):
29 | if self.min_sdk < 9:
30 | self.issues.append(Issue(category=self.category, name="Tap Jacking possible",
31 | severity=Severity.VULNERABILITY, description=TAP_JACKING))
32 |
33 |
34 | plugin = MinSDK()
35 |
--------------------------------------------------------------------------------
/qark/plugins/manifest/single_task_launch_mode.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from qark.issue import Severity, Issue
4 | from qark.scanner.plugin import ManifestPlugin
5 |
6 | log = logging.getLogger(__name__)
7 |
8 | TASK_LAUNCH_MODE_DESCRIPTION = (
9 | "This results in AMS either resuming the earlier activity or loads it in a task with same affinity "
10 | "or the activity is started as a new task. This may result in Task Poisoning. "
11 | "https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-ren-chuangang.pdf"
12 | )
13 |
14 |
15 | class SingleTaskLaunchMode(ManifestPlugin):
16 | def __init__(self):
17 | super(ManifestPlugin, self).__init__(category="manifest", name="launchMode=singleTask found", description=TASK_LAUNCH_MODE_DESCRIPTION)
18 | self.severity = Severity.WARNING
19 |
20 | def run(self):
21 | with open(self.manifest_path, "r") as manifest_file:
22 | for line_number, line in enumerate(manifest_file):
23 | if 'android:launchMode="singleTask"' in line:
24 | self.issues.append(Issue(
25 | category=self.category, severity=self.severity, name=self.name,
26 | description=self.description,
27 | file_object=self.manifest_path,
28 | line_number=line_number)
29 | )
30 |
31 |
32 | plugin = SingleTaskLaunchMode()
33 |
--------------------------------------------------------------------------------
/qark/plugins/manifest/task_reparenting.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from qark.issue import Severity, Issue
4 | from qark.scanner.plugin import ManifestPlugin
5 |
6 | log = logging.getLogger(__name__)
7 |
8 | TASK_REPARENTING_DESCRIPTION = (
9 | "This allows an existing activity to be reparented to a new native task i.e task having the same affinity as the "
10 | "activity. This may lead to UI spoofing attack on this application."
11 | "https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-ren-chuangang.pdf"
12 | )
13 |
14 |
15 | class TaskReparenting(ManifestPlugin):
16 | def __init__(self):
17 | super(TaskReparenting, self).__init__(category="manifest", name="android:allowTaskReparenting='true' found",
18 | description=TASK_REPARENTING_DESCRIPTION)
19 | self.severity = Severity.WARNING
20 |
21 | def run(self):
22 | with open(self.manifest_path, "r") as manifest_file:
23 | for line_number, line in enumerate(manifest_file):
24 | if 'android:allowTaskReparenting="true"' in line:
25 | self.issues.append(Issue(
26 | category=self.category, severity=self.severity, name=self.name,
27 | description=self.description,
28 | file_object=self.manifest_path,
29 | line_number=line_number)
30 | )
31 |
32 |
33 | plugin = TaskReparenting()
34 |
--------------------------------------------------------------------------------
/qark/plugins/manifest_helpers.py:
--------------------------------------------------------------------------------
1 | from xml.etree import ElementTree
2 | from xml.dom import minidom
3 | import logging
4 |
5 | from qark.xml_helpers import get_manifest_out_of_files
6 |
7 | log = logging.getLogger(__name__)
8 |
9 |
10 | def get_package_from_manifest(manifest_path):
11 | """
12 | Gets the package name from an AndroidManifest.xml file path
13 |
14 | :param manifest_path: path to android manifest
15 | :return: package name if exists
16 | """
17 | try:
18 | manifest_xml = ElementTree.parse(manifest_path)
19 | except IOError:
20 | raise
21 |
22 | return manifest_xml.getroot().attrib.get("package")
23 |
24 |
25 | def get_min_sdk(manifest_xml, files=None):
26 | """
27 | Given the manifest as a `minidom.parse`'d object or path to manifest,
28 | try to get the minimum SDK the manifest specifies.
29 |
30 | :param manifest_xml: object after parsing the XML
31 | :param Set[str] files: list of files received from Scanner
32 | :return: int of the version if it exists, else 1 (the default)
33 | """
34 | if manifest_xml is None and files:
35 | manifest_xml = get_manifest_out_of_files(files)
36 |
37 | if isinstance(manifest_xml, str):
38 | manifest_xml = minidom.parse(manifest_xml)
39 |
40 | # TODO: try to get SDK from gradle file
41 | try:
42 | sdk_section = manifest_xml.getElementsByTagName("uses-sdk")[0]
43 | except IndexError:
44 | log.debug("Unable to get uses-sdk section")
45 | return 1
46 |
47 | try:
48 | return int(sdk_section.attributes["android:minSdkVersion"].value)
49 | except (KeyError, AttributeError):
50 | log.debug("Unable to get minSdkVersion from manifest")
51 | return 1
52 |
53 |
54 | def get_target_sdk(manifest_xml, files=None):
55 | """
56 | Given the manifest as a `minidom.parse`'d object, try to get the target SDK the manifest specifies.
57 |
58 | :param manifest_xml: object after parsing the XML
59 | :param Set[str] files: list of files received from Scanner
60 | :return: int of the version if it exists, else 1 (the default)
61 | """
62 | if manifest_xml is None and files:
63 | manifest_xml = get_manifest_out_of_files(files)
64 |
65 | if isinstance(manifest_xml, str):
66 | manifest_xml = minidom.parse(manifest_xml)
67 |
68 | # TODO: try to get SDK from gradle file
69 | try:
70 | sdk_section = manifest_xml.getElementsByTagName("uses-sdk")[0]
71 | except IndexError:
72 | log.debug("Unable to get uses-sdk section")
73 | return 1
74 |
75 | try:
76 | return int(sdk_section.attributes["android:targetSdkVersion"].value)
77 | except (KeyError, AttributeError):
78 | log.debug("Unable to get targetSdkVersion from manifest")
79 | return 1
80 |
81 |
--------------------------------------------------------------------------------
/qark/plugins/webview/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/plugins/webview/__init__.py
--------------------------------------------------------------------------------
/qark/plugins/webview/add_javascript_interface.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from qark.issue import Issue, Severity
4 | from qark.plugins.helpers import valid_method_invocation
5 | from qark.scanner.plugin import CoroutinePlugin, ManifestPlugin
6 |
7 | log = logging.getLogger(__name__)
8 |
9 | ADD_JAVASCRIPT_INTERFACE_DESCRIPTION = (
10 | "This webview uses the addJavascriptInterface method in a pre-API 17 app, which exposes all public methods to "
11 | "Javascript running in the WebView. If this webview loads untrusted content or trusted content over plain-text "
12 | "HTTP, this represents a MAJOR issue! Reference: "
13 | "https://labs.mwrinfosecurity.com/blog/2013/09/24/webview-addjavascriptinterface-remote-code-execution/. "
14 | "To validate this vulnerability, load the following local file in this WebView: "
15 | "file://qark/poc/html/BAD_JS_INT.html"
16 | )
17 |
18 |
19 | class AddJavascriptInterface(CoroutinePlugin, ManifestPlugin):
20 | """This plugin checks if the `addJavaScriptInterface` method is called with a min_sdk of below 17."""
21 | def __init__(self):
22 | super(AddJavascriptInterface, self).__init__(category="webview",
23 | name="Webview uses addJavascriptInterface pre-API 17",
24 | description=ADD_JAVASCRIPT_INTERFACE_DESCRIPTION)
25 | self.severity = Severity.WARNING
26 | self.java_method_name = "addJavascriptInterface"
27 |
28 | def can_run_coroutine(self):
29 | return self.min_sdk <= 16
30 |
31 | def run_coroutine(self):
32 | while True:
33 | _, method_invocation = (yield)
34 | if valid_method_invocation(method_invocation, method_name=self.java_method_name, num_arguments=2):
35 | self.issues.append(Issue(category=self.category, name=self.name, severity=self.severity,
36 | description=self.description, line_number=method_invocation.position,
37 | file_object=self.file_path))
38 |
39 |
40 | plugin = AddJavascriptInterface()
41 |
--------------------------------------------------------------------------------
/qark/plugins/webview/javascript_enabled.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from javalang.tree import MethodInvocation
4 |
5 | from qark.issue import Severity, Issue
6 | from qark.plugins.webview.helpers import valid_set_method_bool
7 | from qark.scanner.plugin import CoroutinePlugin
8 |
9 | log = logging.getLogger(__name__)
10 |
11 | JAVASCRIPT_ENABLED_DESCRIPTION = (
12 | "While not a vulnerability by itself, it appears this app has JavaScript enabled in "
13 | "the WebView: If this is not expressly necessary, you should disable "
14 | "it, to prevent the possibility of XSS (cross-site scripting) attacks. More info: "
15 | "http://developer.android.com/guide/practices/security.html To validate this "
16 | "vulnerability, load the following local file in this "
17 | "WebView: qark/poc/html/JS_WARNING.html"
18 | )
19 |
20 |
21 | class JavascriptEnabled(CoroutinePlugin):
22 | """This plugin checks if the `setJavaScriptEnabled` method is called with a value of `true`"""
23 | def __init__(self):
24 | super(JavascriptEnabled, self).__init__(category="webview", name="Javascript enabled in Webview",
25 | description=JAVASCRIPT_ENABLED_DESCRIPTION)
26 |
27 | def run_coroutine(self):
28 | while True:
29 | _, method_invocation = (yield)
30 | if not isinstance(method_invocation, MethodInvocation):
31 | continue
32 |
33 | if valid_set_method_bool(method_invocation, str_bool="true", method_name="setJavaScriptEnabled"):
34 | self.issues.append(Issue(category=self.category, name=self.name, severity=Severity.WARNING,
35 | description=self.description, line_number=method_invocation.position,
36 | file_object=self.file_path))
37 |
38 |
39 | plugin = JavascriptEnabled()
40 |
--------------------------------------------------------------------------------
/qark/plugins/webview/load_data_with_base_url.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from javalang.tree import MethodInvocation
4 |
5 | from qark.issue import Severity, Issue
6 | from qark.scanner.plugin import CoroutinePlugin
7 |
8 | log = logging.getLogger(__name__)
9 |
10 | LOAD_DATA_WITH_BASE_URL_DESCRIPTION = (
11 | "This webView sets the BaseURL. You should verify that this is only loading content "
12 | "from this domain. Loading content from a domain you do not control, or using "
13 | "plain-text HTTP, leaves this vulnerable to injection attacks against the BaseURL "
14 | "domain."
15 | )
16 |
17 |
18 | class LoadDataWithBaseURL(CoroutinePlugin):
19 | """This plugin checks if the `loadDataWithBaseURL` method is called."""
20 | def __init__(self):
21 | super(LoadDataWithBaseURL, self).__init__(category="webview", name="BaseURL set for Webview",
22 | description=LOAD_DATA_WITH_BASE_URL_DESCRIPTION)
23 |
24 | def run_coroutine(self):
25 | while True:
26 | _, method_invocation = (yield)
27 | if not isinstance(method_invocation, MethodInvocation):
28 | continue
29 |
30 | if method_invocation.member == "loadDataWithBaseURL" and len(method_invocation.arguments) == 5:
31 | self.issues.append(Issue(category=self.category, name=self.name, severity=Severity.WARNING,
32 | description=self.description, line_number=method_invocation.position,
33 | file_object=self.file_path))
34 |
35 |
36 | plugin = LoadDataWithBaseURL()
37 |
--------------------------------------------------------------------------------
/qark/plugins/webview/remote_webview_debugging.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from javalang.tree import MethodInvocation
4 |
5 | from qark.issue import Severity, Issue
6 | from qark.plugins.webview.helpers import valid_set_method_bool
7 | from qark.scanner.plugin import CoroutinePlugin
8 |
9 | log = logging.getLogger(__name__)
10 |
11 | JAVASCRIPT_REMOTE_DEBUGGING = (
12 | "Enabling webview remote debugging is insecure."
13 | )
14 |
15 |
16 | class RemoteDebugging(CoroutinePlugin):
17 | """This plugin checks if the `setWebContentsDebuggingEnabled` method is called with a value of `true`"""
18 | def __init__(self):
19 | super(RemoteDebugging, self).__init__(category="webview", name="Remote debugging enabled in Webview",
20 | description=JAVASCRIPT_REMOTE_DEBUGGING)
21 |
22 | def run_coroutine(self):
23 | while True:
24 | _, method_invocation = (yield)
25 | if not isinstance(method_invocation, MethodInvocation):
26 | continue
27 | if valid_set_method_bool(method_invocation, str_bool="true", method_name="setWebContentsDebuggingEnabled"):
28 | self.issues.append(Issue(category=self.category, name=self.name, severity=Severity.WARNING,
29 | description=self.description, line_number=method_invocation.position,
30 | file_object=self.file_path))
31 |
32 | plugin = RemoteDebugging()
33 |
--------------------------------------------------------------------------------
/qark/plugins/webview/set_allow_content_access.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from qark.issue import Severity
4 | from qark.plugins.webview.helpers import webview_default_vulnerable
5 | from qark.scanner.plugin import JavaASTPlugin
6 |
7 | log = logging.getLogger(__name__)
8 |
9 | SET_ALLOW_CONTENT_ACCESS_DESCRIPTION = (
10 | "While not a vulnerability by itself, it appears this app does not explicitly disable Content Provider access "
11 | "from WebViews. If the WebViews take in untrusted input, this can allow for data theft. To validate this "
12 | "vulnerability, load the following local file in this WebView: "
13 | "file://qark/poc/html/WV_CPA_WARNING.html"
14 | )
15 |
16 |
17 | class SetAllowContentAccess(JavaASTPlugin):
18 | """This plugin checks if the webview calls setAllowContentAccess(false), otherwise the webview is vulnerable
19 | (defaults to true)."""
20 | def __init__(self):
21 | super(SetAllowContentAccess, self).__init__(category="webview", name="Webview enables content access",
22 | description=SET_ALLOW_CONTENT_ACCESS_DESCRIPTION)
23 | self.severity = Severity.WARNING
24 |
25 | def run(self):
26 | self.issues.extend(webview_default_vulnerable(self.java_ast, method_name="setAllowContentAccess",
27 | issue_name=self.name,
28 | description=self.description, file_object=self.file_path,
29 | severity=self.severity))
30 |
31 |
32 | plugin = SetAllowContentAccess()
33 |
--------------------------------------------------------------------------------
/qark/plugins/webview/set_allow_file_access.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from qark.issue import Severity
4 | from qark.plugins.webview.helpers import webview_default_vulnerable
5 | from qark.scanner.plugin import JavaASTPlugin
6 |
7 | log = logging.getLogger(__name__)
8 |
9 | SET_ALLOW_FILE_ACCESS_DESCRIPTION = (
10 | "File system access is enabled in this WebView. If untrusted data is used to specify the URL opened by this "
11 | "WebView, a malicious app or site may be able to read your app's private files, if it returns the response to "
12 | "them. To validate this vulnerability, load the following local file in this "
13 | "WebView: qark/poc/html/FILE_SYS_WARN.html"
14 | )
15 |
16 |
17 | class SetAllowFileAccess(JavaASTPlugin):
18 | """This plugin checks if the webview calls setAllowFileAccess(false), otherwise the webview is vulnerable
19 | (defaults to true)."""
20 | def __init__(self):
21 | super(SetAllowFileAccess, self).__init__(category="webview", name="Webview enables file access",
22 | description=SET_ALLOW_FILE_ACCESS_DESCRIPTION)
23 | self.severity = Severity.WARNING
24 |
25 | def run(self):
26 | self.issues.extend(webview_default_vulnerable(self.java_ast, method_name="setAllowFileAccess", issue_name=self.name,
27 | description=self.description, file_object=self.file_path,
28 | severity=self.severity))
29 |
30 |
31 | plugin = SetAllowFileAccess()
32 |
--------------------------------------------------------------------------------
/qark/plugins/webview/set_allow_universal_access_from_file_urls.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from javalang.tree import MethodInvocation
4 |
5 | from qark.issue import Issue, Severity
6 | from qark.plugins.webview.helpers import webview_default_vulnerable, valid_set_method_bool
7 | from qark.scanner.plugin import CoroutinePlugin, ManifestPlugin
8 |
9 | log = logging.getLogger(__name__)
10 |
11 | SET_ALLOW_UNIVERSAL_ACCESS_FROM_FILE_URLS_DESCRIPTION = (
12 | "JavaScript running in a file scheme context can access content from any origin. This is an insecure default "
13 | "value for minSdkVersion < 16 or may have been overridden (setAllowUniversalAccessFromFileURLs) in later versions. "
14 | "To validate this vulnerability, load the following local file in this WebView: "
15 | "file://qark/poc/html/UNIV_FILE_WARNING.html"
16 | )
17 |
18 |
19 | class SetAllowUniversalAccessFromFileURLs(CoroutinePlugin, ManifestPlugin):
20 | """This plugin checks if the `setAllowUniversalAccessFromFileURLs` method is called with a value of `true`, or
21 | if the default is vulnerable."""
22 | def __init__(self):
23 | super(SetAllowUniversalAccessFromFileURLs, self).__init__(category="webview",
24 | name="Webview enables universal access for JavaScript",
25 | description=SET_ALLOW_UNIVERSAL_ACCESS_FROM_FILE_URLS_DESCRIPTION)
26 | self.severity = Severity.WARNING
27 | self.java_method_name = "setAllowUniversalAccessFromFileURLs"
28 |
29 | def can_run_coroutine(self):
30 | if self.min_sdk <= 15:
31 | self.issues.extend(webview_default_vulnerable(self.java_ast, method_name=self.java_method_name,
32 | issue_name=self.name, description=self.description,
33 | file_object=self.file_path, severity=self.severity))
34 | return False
35 |
36 | return True
37 |
38 | def run_coroutine(self):
39 | while True:
40 | _, method_invocation = (yield)
41 | if not isinstance(method_invocation, MethodInvocation):
42 | continue
43 |
44 | if valid_set_method_bool(method_invocation, str_bool="true", method_name=self.java_method_name):
45 | self.issues.append(Issue(category=self.category, name=self.name, severity=self.severity,
46 | description=self.description, line_number=method_invocation.position,
47 | file_object=self.file_path))
48 |
49 |
50 | plugin = SetAllowUniversalAccessFromFileURLs()
51 |
--------------------------------------------------------------------------------
/qark/plugins/webview/set_dom_storage_enabled.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from javalang.tree import MethodInvocation
4 |
5 | from qark.issue import Issue, Severity
6 | from qark.plugins.webview.helpers import valid_set_method_bool
7 | from qark.scanner.plugin import CoroutinePlugin
8 |
9 | log = logging.getLogger(__name__)
10 |
11 | SET_DOM_STORAGE_ENABLED_DESCRIPTION = (
12 | "DOM Storage enabled for this WebView, there is a potential for caching sensitive information."
13 | )
14 |
15 |
16 | class SetDomStorageEnabled(CoroutinePlugin):
17 | """This plugin checks if the `setDomStorageEnabled` method is called with a value of `true`."""
18 | def __init__(self):
19 | super(SetDomStorageEnabled, self).__init__(category="webview", name="Webview enables DOM Storage",
20 | description=SET_DOM_STORAGE_ENABLED_DESCRIPTION)
21 | self.severity = Severity.WARNING
22 | self.java_method_name = "setDomStorageEnabled"
23 |
24 | def run_coroutine(self):
25 | while True:
26 | _, method_invocation = (yield)
27 | if not isinstance(method_invocation, MethodInvocation):
28 | continue
29 | if valid_set_method_bool(method_invocation, str_bool="true", method_name=self.java_method_name):
30 | self.issues.append(Issue(category=self.category, name=self.name, severity=self.severity,
31 | description=self.description, line_number=method_invocation.position,
32 | file_object=self.file_path))
33 |
34 |
35 | plugin = SetDomStorageEnabled()
36 |
--------------------------------------------------------------------------------
/qark/report.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 |
3 | from os import path
4 |
5 | from jinja2 import Environment, PackageLoader, select_autoescape, Template
6 |
7 | from qark.issue import (Issue, Severity, issue_json) # noqa:F401 These are expected to be used later.
8 | from qark.utils import create_directories_to_path
9 |
10 | DEFAULT_REPORT_PATH = path.join(path.dirname(path.realpath(__file__)), 'report', '')
11 |
12 |
13 | jinja_env = Environment(
14 | loader=PackageLoader('qark', 'templates'),
15 | autoescape=select_autoescape(['html', 'xml'])
16 | )
17 |
18 | jinja_env.filters['issue_json'] = issue_json
19 |
20 |
21 | class Report(object):
22 | """An object to store issues against and to generate reports in different formats.
23 |
24 | There is one instance created per QARK run and it uses a classic Singleton pattern
25 | to make it easy to get a reference to that instance anywhere in QARK.
26 | """
27 |
28 | # The one instance to rule them all
29 | # http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Singleton.html#the-singleton
30 | __instance = None
31 |
32 | def __new__(cls, issues=None, report_path=None, keep_report=False):
33 | if Report.__instance is None:
34 | Report.__instance = object.__new__(cls)
35 |
36 | return Report.__instance
37 |
38 | def __init__(self, issues=None, report_path=None, keep_report=False):
39 | """This will give you an instance of a report, with a default report path which is local
40 | to where QARK is on the file system.
41 |
42 | :param report_path: The path to the report directory where all generated report files will be written.
43 | :type report_path: str or None
44 |
45 | """
46 | self.issues = issues if issues else []
47 | self.report_path = report_path or DEFAULT_REPORT_PATH
48 | self.keep_report = keep_report
49 |
50 | def generate(self, file_type='html', template_file=None):
51 | """This method uses Jinja2 to generate a standalone HTML version of the report.
52 |
53 | :param str file_type: The type of file for the report. Defaults to 'html'.
54 | :param str template_file: The path to an optional template file to override the default.
55 | :return: Path to the written report
56 | :rtype: str
57 | """
58 | create_directories_to_path(self.report_path)
59 |
60 | full_report_path = path.join(self.report_path, 'report.{file_type}'.format(file_type=file_type))
61 |
62 | open_flag = 'w'
63 | if self.keep_report:
64 | open_flag = 'a'
65 | with open(full_report_path, mode=open_flag) as report_file:
66 | if not template_file:
67 | template = jinja_env.get_template('{file_type}_report.jinja'.format(file_type=file_type))
68 | else:
69 | template = Template(template_file)
70 | report_file.write(template.render(issues=list(self.issues)))
71 | report_file.write('\n')
72 |
73 | return full_report_path
74 |
--------------------------------------------------------------------------------
/qark/scanner/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/qark/scanner/__init__.py
--------------------------------------------------------------------------------
/qark/templates/csv_report.jinja:
--------------------------------------------------------------------------------
1 | {% for issue in issues %}
2 | {{ issue.severity.name }},{{ issue.name }}
3 | {% endfor %}
--------------------------------------------------------------------------------
/qark/templates/html_report.jinja:
--------------------------------------------------------------------------------
1 |
2 | Temporary Report Template
3 |
4 | Issues
5 | {% for issue in issues %}
6 | {{ issue.severity.name }} {{ issue.name }}
7 | {{ issue.description }}
8 | File: {{ issue.file_object }}{% if issue.line_number %}:{{ issue.line_number[0] }}:{{ issue.line_number[1] }} {% endif %}
9 | {% endfor %}
10 |
11 |
--------------------------------------------------------------------------------
/qark/templates/json_report.jinja:
--------------------------------------------------------------------------------
1 | {{ issues|issue_json|safe }}
--------------------------------------------------------------------------------
/qark/templates/xml_report.jinja:
--------------------------------------------------------------------------------
1 |
2 | {% for issue in issues %}
3 |
4 | {{ issue.severity.name }}
5 | {{ issue.name }}
6 |
7 | {% endfor %}
--------------------------------------------------------------------------------
/qark/utils.py:
--------------------------------------------------------------------------------
1 | import os
2 | from functools import partial
3 |
4 |
5 | def create_directories_to_path(path):
6 | """Create directories to a path if they don't exist."""
7 |
8 | try:
9 | os.makedirs(os.path.dirname(path))
10 | except Exception:
11 | # directory already exists
12 | pass
13 |
14 |
15 | def file_has_extension(extension, file_path):
16 | return os.path.splitext(file_path.lower())[1] == extension.lower()
17 |
18 |
19 | is_java_file = partial(file_has_extension, ".java")
20 |
21 |
22 | def environ_path_variable_exists(variable_name):
23 | """Determines if the os.environ variable exists and is a valid path.
24 |
25 | :rtype: bool
26 | """
27 | try:
28 | return os.path.exists(os.environ[variable_name])
29 | except KeyError:
30 | return False
31 |
--------------------------------------------------------------------------------
/qark/xml_helpers.py:
--------------------------------------------------------------------------------
1 | from xml.etree import ElementTree
2 |
3 | import logging
4 |
5 | log = logging.getLogger(__name__)
6 |
7 |
8 | def write_key_value_to_xml(key, value, path):
9 | """
10 | Checks if `key` exists in the parsed XML `path`, if it does not it creates a new
11 | element and appends it to the XML tree and then updates the file.
12 |
13 | :param key:
14 | :param value:
15 | :param path: Union[str, pathlib.Path, FileObject]
16 | :return:
17 | """
18 | try:
19 | xml_to_write = ElementTree.parse(path)
20 | except IOError:
21 | log.exception("Strings file for exploit APK does not exist")
22 | raise SystemExit("Strings file for exploit APK does not exist")
23 |
24 | if not xml_to_write.find(key):
25 | new_element = ElementTree.SubElement(xml_to_write.getroot(), "string", attrib={"name": key})
26 | new_element.text = value
27 |
28 | xml_to_write.write(path)
29 |
30 |
31 | def write_key_value_to_string_array_xml(array_name, value, path, add_id=True):
32 | """
33 | Checks if `array_name` is name of a `string-array`, if it does not exist it creates a new
34 | element and appends it to the XML tree and then updates the file, if it exists it updates the existing element.
35 |
36 | :param str array_name:
37 | :param str value:
38 | :param Union[str, pathlib.Path, FileObject] path:
39 | :param bool add_id: Whether or not to create an id like `value{id}` where `id` is an int
40 | """
41 | try:
42 | strings_xml = ElementTree.parse(path)
43 | except IOError:
44 | log.exception("Extra keys file for exploit APK does not exist")
45 | raise SystemExit("Extra keys file for exploit APK does not exist")
46 |
47 | if add_id:
48 | last_id = 0
49 |
50 | # attempt to update the entry if it exists
51 | for string_array in strings_xml.findall("string-array"):
52 | if string_array.attrib.get("name") == array_name:
53 | if add_id:
54 | for child in string_array.getchildren():
55 | last_id = child.text.split(value)[1]
56 | value = "{value}{id}".format(value=value, id=int(last_id)+1)
57 |
58 | sub_element_item = ElementTree.SubElement(string_array, "item")
59 | sub_element_item.text = value
60 |
61 | strings_xml.write(path)
62 | return value
63 |
64 | if add_id:
65 | value = "{value}{id}".format(value=value, id=last_id+1)
66 |
67 | # write the entry as it does not exist
68 | new_string_array = ElementTree.SubElement(strings_xml.getroot(), "string-array", attrib={"name": array_name})
69 | sub_element_item = ElementTree.SubElement(new_string_array, "item")
70 | sub_element_item.text = value
71 |
72 | strings_xml.write(path)
73 | return value
74 |
75 |
76 | def get_manifest_out_of_files(files):
77 | """
78 | Parses `files` for a file that ends with `androidmanifest.xml`.
79 | :param Set[str] files: list of paths to files as absolute paths
80 | :return: manifest string if in `files`, else None
81 | """
82 | for file_name in files:
83 | if file_name.lower().endswith("androidmanifest.xml"):
84 | return file_name
85 | return None
86 |
--------------------------------------------------------------------------------
/report/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
5 |
--------------------------------------------------------------------------------
/requirements_to_freeze.txt:
--------------------------------------------------------------------------------
1 | requests[security]
2 | pluginbase
3 | jinja2
4 | enum34; python_version < '3.4'
5 | javalang
6 | click
7 | six
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [flake8]
2 | ignore = E121,E123,E226,E266
3 | max-line-length = 160
4 |
5 | [tool:pytest]
6 | addopts = -m "not long" --cov=qark --cov-report term-missing -x --durations 0
7 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 | import os
3 | import io
4 |
5 | QARK_DIR = "qark"
6 | LIB_DIR = os.path.join(QARK_DIR, "lib")
7 |
8 |
9 | exploit_apk_files = [os.path.join(dir_path, filename).replace(os.path.join(QARK_DIR, ""), "")
10 | for dir_path, _, files in os.walk(os.path.join(QARK_DIR, "exploit_apk"))
11 | for filename in files]
12 |
13 |
14 | with io.open('README.rst', 'rt', encoding='utf8') as f:
15 | long_description = f.read()
16 |
17 | setup(
18 | name="qark",
19 | version="4.0.0",
20 | packages=find_packages(exclude=["tests*"]),
21 | package_dir={QARK_DIR: QARK_DIR},
22 | package_data={
23 | QARK_DIR: [
24 | os.path.join("lib", "decompilers", "*.jar"), # include any decompiler jar files
25 | os.path.join("lib", "apktool", "*.jar"), # include apktool
26 | os.path.join("lib", "dex2jar-2.0", "*"), # include dex2jar
27 | os.path.join("lib", "dex2jar-2.0", "lib", "*"), # include dex2jar
28 | os.path.join("templates", "*.jinja"), # include the reporting template files
29 | ] + exploit_apk_files, # include all the java files required for creating an exploit APK
30 | },
31 | install_requires=[
32 | "requests[security]",
33 | "pluginbase",
34 | "jinja2",
35 | "enum34; python_version < '3.4'",
36 | "javalang",
37 | "click",
38 | "six",
39 | ],
40 | # metadata for upload to PyPI
41 | author="Tushar Dalvi & Tony Trummer",
42 | author_email="tushardalvi@gmail.com, tonytrummer@hotmail.com",
43 | description="Android static code analyzer",
44 | long_description=long_description,
45 | license="Apache 2.0",
46 | keywords="android security qark exploit",
47 | url="https://www.github.com/linkedin/qark",
48 | entry_points="""
49 | [console_scripts]
50 | qark=qark.qark:cli""",
51 | classifiers=[
52 | "Development Status :: 4 - Beta",
53 | "Environment :: Console",
54 | "License :: OSI Approved :: Apache Software License",
55 | "Operating System :: MacOS",
56 | "Operating System :: Microsoft :: Windows",
57 | "Operating System :: Unix",
58 | "Programming Language :: Python :: 2.7",
59 | "Programming Language :: Python :: 3.6",
60 | ]
61 | )
62 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/__init__.py
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 |
3 | import pytest
4 |
5 | import os
6 |
7 | from qark.decompiler.decompiler import Decompiler
8 | from qark.scanner.scanner import Scanner
9 | from qark.scanner.plugin import JavaASTPlugin, ManifestPlugin
10 |
11 |
12 | DECOMPILER_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "qark", "lib", "decompilers")
13 |
14 |
15 | @pytest.fixture(scope="session")
16 | def path_to_source():
17 | return os.path.join(os.path.dirname(os.path.abspath(__file__)), "goatdroid.apk")
18 |
19 |
20 | @pytest.fixture(scope="session")
21 | def build_directory():
22 | return os.path.join(os.path.dirname(os.path.abspath(__file__)), "build_directory")
23 |
24 |
25 | @pytest.fixture()
26 | def decompiler(path_to_source, build_directory):
27 | return Decompiler(path_to_source=path_to_source, build_directory=build_directory)
28 |
29 |
30 | @pytest.fixture(scope="module")
31 | def module_decompiler(path_to_source, build_directory):
32 | return Decompiler(path_to_source=path_to_source, build_directory=build_directory)
33 |
34 |
35 |
36 | @pytest.fixture()
37 | def scanner(decompiler):
38 | return Scanner(decompiler.manifest_path, decompiler.build_directory)
39 |
40 |
41 | @pytest.fixture(scope="session")
42 | def vulnerable_manifest_path():
43 | return os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_xml_files",
44 | "test_androidmanifest.xml")
45 |
46 |
47 | @pytest.fixture(scope="session")
48 | def goatdroid_manifest_path():
49 | return os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_xml_files",
50 | "test_goatdroid_manifest.xml")
51 |
52 |
53 | @pytest.fixture(scope="session")
54 | def test_java_files():
55 | return os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_java_files")
56 |
57 |
58 | @pytest.fixture(scope="session")
59 | def vulnerable_broadcast_path(test_java_files):
60 | return os.path.join(test_java_files,
61 | "send_broadcast_receiver_permission.java")
62 |
63 |
64 | @pytest.fixture(scope="session")
65 | def vulnerable_receiver_path():
66 | return os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_plugins", "test_manifest_plugins",
67 | "broadcastreceivers", "SendSMSNowReceiver.java")
68 |
69 |
70 | @pytest.fixture(autouse=True)
71 | def reset_plugins():
72 | """Reset all plugins in between each function. `JavaASTPlugin` currently will reset every other plugin type."""
73 | JavaASTPlugin.reset()
74 |
75 | ManifestPlugin.manifest_xml = None
76 | ManifestPlugin.manifest_path = None
77 | ManifestPlugin.min_sdk = -1
78 | ManifestPlugin.target_sdk = -1
79 | ManifestPlugin.package_name = "PACKAGE_NOT_FOUND"
80 |
--------------------------------------------------------------------------------
/tests/goatdroid.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/goatdroid.apk
--------------------------------------------------------------------------------
/tests/test_apk_builder.py:
--------------------------------------------------------------------------------
1 | import os
2 | import shutil
3 |
4 | import pytest
5 |
6 | from qark.apk_builder import APKBuilder
7 | from qark.plugins.manifest.exported_tags import ExportedTags
8 |
9 | # Path to SDK is required, so these are commented out
10 | # def test_gradle_build(build_directory, vulnerable_manifest_path):
11 | # if os.path.exists(build_directory):
12 | # shutil.rmtree(build_directory)
13 | #
14 | # builder = APKBuilder(exploit_apk_path=build_directory,
15 | # issues=[],
16 | # apk_name="test_apk",
17 | # manifest_path=vulnerable_manifest_path,
18 | # sdk_path="/Users/nwalsh/IdeaProjects/qark/android-sdk_r24.0.2-macosx/android-sdk-macosx")
19 | # builder._build_apk()
20 | #
21 | #
22 | # def test_apk_build(build_directory, vulnerable_manifest_path):
23 | # if os.path.exists(build_directory):
24 | # shutil.rmtree(build_directory)
25 | #
26 | # builder = APKBuilder(exploit_apk_path=build_directory,
27 | # issues=[],
28 | # apk_name="test_apk",
29 | # manifest_path=vulnerable_manifest_path,
30 | # sdk_path="/Users/nwalsh/IdeaProjects/qark/android-sdk_r24.0.2-macosx/android-sdk-macosx")
31 | # builder.build()
32 |
--------------------------------------------------------------------------------
/tests/test_decompiler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_decompiler/__init__.py
--------------------------------------------------------------------------------
/tests/test_issue.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from qark.issue import Issue, Severity, issue_json
4 |
5 |
6 | def test_convert_severity():
7 | issue = Issue(category='Test', name='Test Issue', severity='INFO', description='Test')
8 | assert issue.severity == Severity.INFO
9 | issue = Issue(category='Test', name='Test Issue', severity='VULNERABILITY', description='Test')
10 | assert issue.severity == Severity.VULNERABILITY
11 | issue = Issue(category='Test', name='Test Issue', severity='ERROR', description='Test')
12 | assert issue.severity == Severity.ERROR
13 | issue = Issue(category='Test', name='Test Issue', severity='WARNING', description='Test')
14 | assert issue.severity == Severity.WARNING
15 | issue = Issue(category='Test', name='Test Issue', severity='', description='Test')
16 | assert issue.severity == Severity.WARNING
17 | issue = Issue(category='Test', name='Test Issue', severity=4, description='Test')
18 | assert issue.severity == Severity.WARNING
19 |
20 |
21 | def test_issue_json_single():
22 | issue = Issue(category='Test', name='Test Issue', severity=Severity.VULNERABILITY, description='Test')
23 | json_output = issue_json(issue)
24 | json_issue = json.loads(json_output)
25 | assert json_issue['severity'] == issue.severity.name
26 | assert json_issue['name'] == issue.name
27 |
28 |
29 | def test_issue_json_list():
30 | issue = Issue(category='Test', name='Test Issue', severity=Severity.VULNERABILITY, description='Test')
31 | json_output = issue_json([issue])
32 | json_issue = json.loads(json_output)
33 | assert json_issue[0]['severity'] == issue.severity.name
34 | assert json_issue[0]['name'] == issue.name
35 |
--------------------------------------------------------------------------------
/tests/test_java_files/check_permissions.java:
--------------------------------------------------------------------------------
1 | import android.content.Context;
2 |
3 | class Test {
4 | public static void Test(Context context) {
5 | context.checkCallingOrSelfPermission();
6 | context.enforceCallingOrSelfPermission();
7 | }
8 | }
--------------------------------------------------------------------------------
/tests/test_java_files/dynamic_broadcast_receiver.java:
--------------------------------------------------------------------------------
1 | class RegisterReceiver {
2 | public void Test(Context context, Calendar c) {
3 | final String SOME_ACTION = "com.android.action.MyAction.SomeAction";
4 | IntentFilter intentFilter = new IntentFilter(SOME_ACTION);
5 | Receiver mReceiver = new Receiver();
6 | context.registerReceiver(mReceiver, intentFilter);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tests/test_java_files/external_storage.java:
--------------------------------------------------------------------------------
1 | class Test {
2 | public static File[] Test(Context context) {
3 | File[] roots = context.getExternalFilesDirs("external");
4 | File roots = context.getExternalFilesDir("external");
5 | File roots = context.getExternalMediaDirs("external");
6 | File roots = context.getExternalStoragePublicDirectory("external");
7 | return roots;
8 | }
9 | }
--------------------------------------------------------------------------------
/tests/test_java_files/http_url_hardcoded.java:
--------------------------------------------------------------------------------
1 | class Test {
2 | public static void TestMethod() {
3 | final TextView mTextView = (TextView) findViewById(R.id.text);
4 | // ...
5 |
6 | // Instantiate the RequestQueue.
7 | RequestQueue queue = Volley.newRequestQueue(this);
8 | String url ="http://www.google.com";
9 |
10 | // Request a string response from the provided URL.
11 | StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
12 | new Response.Listener() {
13 | @Override
14 | public void onResponse(String response) {
15 | // Display the first 500 characters of the response string.
16 | mTextView.setText("Response is: "+ response.substring(0,500));
17 | }
18 | }, new Response.ErrorListener() {
19 | @Override
20 | public void onErrorResponse(VolleyError error) {
21 | mTextView.setText("That didn't work!");
22 | }
23 | });
24 |
25 | // Add the request to the RequestQueue.
26 | queue.add(stringRequest);
27 | }
28 | }
--------------------------------------------------------------------------------
/tests/test_java_files/insecure_functions.java:
--------------------------------------------------------------------------------
1 | class Test {
2 | @Override
3 | public Bundle call(String method, String arg, Bundle extras) {
4 | pass;
5 | }
6 | }
--------------------------------------------------------------------------------
/tests/test_java_files/phone_identifier.java:
--------------------------------------------------------------------------------
1 | import android.telephony.TelephonyManager;
2 |
3 | class Test {
4 | public static void Test(Context context) {
5 | TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
6 |
7 | //Calling the methods of TelephonyManager the returns the information
8 | String IMEINumber=tm.getDeviceId();
9 | }
10 | }
--------------------------------------------------------------------------------
/tests/test_java_files/task_affinity.java:
--------------------------------------------------------------------------------
1 | import android.app.Activity;
2 | import android.content.Intent;
3 | import android.os.Bundle;
4 | import android.view.Menu;
5 | import android.widget.Toast;
6 |
7 | public class MyActivity extends Activity {
8 |
9 | protected void Test() {
10 | Intent intent = new Intent(this, BPSplashActivity.class);
11 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
12 |
13 | startActivity(intent);
14 |
15 | }
16 |
17 | protected void Test2() {
18 | Intent intent = new Intent(this, BPSplashActivity.class);
19 | intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
20 |
21 | startActivity(intent);
22 |
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/tests/test_java_files/test_android_logging.java:
--------------------------------------------------------------------------------
1 | class Test {
2 | public void Test() {
3 | Log.d("test");
4 | Log.v("test");
5 | }
6 | public void Test2() {
7 | d("test");
8 | v("test");
9 | }
10 | }
--------------------------------------------------------------------------------
/tests/test_manifest_helpers.py:
--------------------------------------------------------------------------------
1 | from qark.plugins.manifest_helpers import get_min_sdk, get_target_sdk
2 |
3 | from xml.dom import minidom
4 |
5 |
6 | def test_get_min_sdk(vulnerable_manifest_path):
7 | assert 9 == get_min_sdk(minidom.parse(vulnerable_manifest_path))
8 |
9 |
10 | def test_get_target_sdk(vulnerable_manifest_path):
11 | assert 15 == get_target_sdk(minidom.parse(vulnerable_manifest_path))
12 |
--------------------------------------------------------------------------------
/tests/test_plugins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_plugins/__init__.py
--------------------------------------------------------------------------------
/tests/test_plugins/test_broadcast_plugins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_plugins/test_broadcast_plugins/__init__.py
--------------------------------------------------------------------------------
/tests/test_plugins/test_broadcast_plugins/test_dynamic_broadcast_receiver.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import javalang
4 |
5 | from qark.plugins.broadcast.dynamic_broadcast_receiver import DynamicBroadcastReceiver
6 | from qark.scanner.plugin import ManifestPlugin
7 |
8 |
9 | def test_vulnerable_dynamic_broadcast_receiver(test_java_files):
10 | plugin = DynamicBroadcastReceiver()
11 | path_to_vuln_file = os.path.join(test_java_files,
12 | "dynamic_broadcast_receiver.java")
13 |
14 | ManifestPlugin.min_sdk = 5
15 | plugin.update(file_path=path_to_vuln_file)
16 | plugin.run()
17 |
18 | assert len(plugin.issues) == 1 # vulnerable manifest
19 | assert plugin.issues[0].name == plugin.name
20 | assert plugin.issues[0].severity == plugin.severity
21 | assert plugin.issues[0].category == plugin.category
22 |
23 |
24 | def test_nonvulnerable_dynamic_broadcast_receiver(test_java_files):
25 | plugin = DynamicBroadcastReceiver()
26 | path_to_vuln_file = os.path.join(test_java_files,
27 | "dynamic_broadcast_receiver.java")
28 | plugin.update(file_path=path_to_vuln_file)
29 | ManifestPlugin.min_sdk = 14
30 | plugin.run()
31 |
32 | assert len(plugin.issues) == 0
33 |
34 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_broadcast_plugins/test_send_broadcast_receiver_permission.py:
--------------------------------------------------------------------------------
1 | from qark.plugins.broadcast.send_broadcast_receiver_permission import SendBroadcastReceiverPermission
2 | from qark.scanner.plugin import ManifestPlugin
3 |
4 |
5 | def test_send_broadcast_receiver_permission(vulnerable_broadcast_path):
6 | ManifestPlugin.min_sdk = 25
7 | plugin = SendBroadcastReceiverPermission()
8 | plugin.update(file_path=vulnerable_broadcast_path)
9 | plugin.run()
10 | assert 8 == len(plugin.issues)
11 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_cert_plugins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_plugins/test_cert_plugins/__init__.py
--------------------------------------------------------------------------------
/tests/test_plugins/test_cert_plugins/testCertMethodsFile.java:
--------------------------------------------------------------------------------
1 | class VulnerableCheckServerTrusted {
2 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
3 | }
4 | class VulnerableCheckServerTrustedEmptyReturn {
5 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {return;}
6 | }
7 | class VulnerableOnReceivedSslError {
8 | public void onReceivedSslError(Webview view, SslErrorHandler handler, SslError error) throws CertificateException {
9 | handler.proceed();
10 | }
11 | }
12 | class NonVulnerableOnReceivedSslError {
13 | public void onReceivedSslError(Webview view, SslErrorHandler handler, SslError error) throws CertificateException {
14 | // this one has more logic than just handler.proceed even though it is just as vulnerable
15 | if( 1 > 0 ) {
16 | handler.proceed();
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/tests/test_plugins/test_cert_plugins/testHostnameVerifier.java:
--------------------------------------------------------------------------------
1 | package test_plugins.test_cert_plugins;
2 |
3 | public class testHostnameVerifier {
4 | public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER = new AllowAllHostnameVerifier();
5 | }
6 |
7 | public class testSetHostnameVerifier {
8 | public static void vulnerableMethod() {
9 | URL url = new URL("https://example.org/");
10 | HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
11 | urlConnection.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
12 | }
13 | public static void nonVulnerableMethod() {
14 | URL url = new URL("https://example.org/");
15 | HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
16 | urlConnection.setHostnameVerifier(SSLSocketFactory.SOMETHING_ELSE);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_cert_plugins/test_cert_plugins.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from qark.issue import Severity
4 | from qark.plugins.cert.cert_validation_methods_overriden import CertValidation
5 | from qark.plugins.cert.hostname_verifier import HostnameVerifier, ALLOW_ALL_HOSTNAME_VERIFIER_DESC
6 |
7 |
8 | def test_cert_validation_methods():
9 | path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "testCertMethodsFile.java")
10 |
11 | plugin = CertValidation()
12 | plugin.update(path)
13 | plugin.run()
14 | assert 3 == len(plugin.issues)
15 |
16 |
17 | def test_hostname_verifier():
18 | plugin = HostnameVerifier()
19 | path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "testHostnameVerifier.java")
20 |
21 | plugin.update(path)
22 | plugin.run()
23 | assert 2 == len(plugin.issues)
24 | assert "Allow all hostname verifier used" == plugin.issues[0].name
25 | assert "setHostnameVerifier set to ALLOW_ALL" == plugin.issues[1].name
26 | assert plugin.issues[1].line_number
27 |
28 | for issue in plugin.issues:
29 | assert Severity.WARNING == issue.severity
30 | assert plugin.category == issue.category
31 | assert ALLOW_ALL_HOSTNAME_VERIFIER_DESC == issue.description
32 | assert os.path.join(os.path.dirname(os.path.abspath(__file__)),
33 | "testHostnameVerifier.java") == issue.file_object
34 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_plugins/test_crypto_plugins/__init__.py
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/java_files/blank.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_plugins/test_crypto_plugins/java_files/blank.java
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/java_files/ecb1.java:
--------------------------------------------------------------------------------
1 | class Example{
2 | public static void main(){
3 | Cipher.getInstance("AES/ECB/PKCS5Padding", "SunJCE");
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/java_files/ecb2.java:
--------------------------------------------------------------------------------
1 | class Example{
2 | public static void main(){
3 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "SunJCE");
4 | Key skeySpec = KeyGenerator.getInstance("AES").generateKey();
5 | cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
6 | System.out.println(Arrays.toString(cipher.doFinal(new byte[] { 0, 1, 2, 3 })));
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/java_files/ecb3.java:
--------------------------------------------------------------------------------
1 | class Example{
2 | public static void main(){
3 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "SunJCE");
4 | Key skeySpec = KeyGenerator.getInstance("AES").generateKey();
5 | cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
6 | System.out.println(Arrays.toString(cipher.doFinal(new byte[] { 0, 1, 2, 3 })));
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/java_files/invalid.java:
--------------------------------------------------------------------------------
1 | THIS IS AN INVALID JAVA FILE
2 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/java_files/no_ecb1.java:
--------------------------------------------------------------------------------
1 | class Example{
2 | private static String decrypt_data(String encData)
3 | throws NoSuchAlgorithmException, NoSuchPaddingException,
4 | InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
5 | String key = "bad8deadcafef00d";
6 | SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
7 | Cipher cipher = Cipher.getInstance("AES");
8 |
9 | cipher.init(Cipher.DECRYPT_MODE, skeySpec);
10 |
11 | System.out.println("Base64 decoded: "
12 | + Base64.decode(encData.getBytes()).length);
13 | byte[] original = cipher
14 | .doFinal(Base64.decode(encData.getBytes()));
15 | return new String(original).trim();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/java_files/secure_random_args1.java:
--------------------------------------------------------------------------------
1 | import java.security.SecureRandom;
2 |
3 | class Aoeu{
4 | public String generate(){
5 | SecureRandom random = new SecureRandom();
6 | Random r = new Random();
7 | int seed = r.nextInt();
8 | random.setSeed(seed);
9 | return new BigInteger(130, random).toString(32);
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/java_files/secure_random_args2.java:
--------------------------------------------------------------------------------
1 | import java.security.SecureRandom;
2 | import java.math.BigInteger;
3 |
4 | class Aoeu{
5 | public BigInteger generate(){
6 | SecureRandom random = new SecureRandom();
7 | Random r = new Random();
8 | int seed = r.nextInt();
9 | random.setSeed(seed);
10 | return new BigInteger(130, random).toString(32);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/java_files/secure_random_no_args1.java:
--------------------------------------------------------------------------------
1 | import java.security.SecureRandom;
2 | import java.util.Random;
3 |
4 | public final class mfo {
5 | public static final SecureRandom a;
6 | private static final Random b;
7 |
8 | static {
9 | b = new mfp();
10 | SecureRandom secureRandom = new SecureRandom();
11 | secureRandom.nextLong();
12 | a = secureRandom;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/keys/dsa-key:
--------------------------------------------------------------------------------
1 | -----BEGIN DSA PRIVATE KEY-----
2 | MIIBugIBAAKBgQDU3Di8U44kfgMgCib7CzWyZV638QW2a8ipOamnHPYxDjTop5OA
3 | 3UrKiQcGAQA+0ahe5bk973PvJ8j85MUfchvjidVgMaAXSQbPHsNfOCvDXtCaOko9
4 | L5L9hUms6en/perQZF3b8niLsJOJ/SsvksFQkAg8qieWCgfl+HIb5M5MyQIVAJxG
5 | fBuN9vbqfMtW5XoE2ldL6OT/AoGAfHn8zIjUGJ5ocTBJUud3Tkl9O4IYL5isklUz
6 | 9EuTJv8XZWeVWt06WK/QGCQVq9nQavj48hTeU7/F/V7SC5BDsZv8zLMdlTortHzU
7 | o+bhV8MWIZvsqS8gl9BgAm7N/TpW/N5cqhsLSGMAYl1tY7ZRXUOQM2x45H4DjcQu
8 | kYJvhegCgYAkqv1WdLA24/BwGf0CcGqX+ORKV1ymjU3x43WJH/0mR8cs4wDt1v76
9 | vkBj/Vrv8C6X7x4eU1ZG8TvqIq4eRJl2vk4wG5rHZ1ttNwQHDW1InsxRQYGaio4a
10 | YVEC2kJHrKA/CoMsPuNaC8ZeaTNFoyG6ne7uB0RyyuS0z49cq/YNAgIUNjBp1uIS
11 | mUY3/DtA71KX7j1gnuI=
12 | -----END DSA PRIVATE KEY-----
13 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/keys/dsa-key.pub:
--------------------------------------------------------------------------------
1 | ssh-dss AAAAB3NzaC1kc3MAAACBANTcOLxTjiR+AyAKJvsLNbJlXrfxBbZryKk5qacc9jEONOink4DdSsqJBwYBAD7RqF7luT3vc+8nyPzkxR9yG+OJ1WAxoBdJBs8ew184K8Ne0Jo6Sj0vkv2FSazp6f+l6tBkXdvyeIuwk4n9Ky+SwVCQCDyqJ5YKB+X4chvkzkzJAAAAFQCcRnwbjfb26nzLVuV6BNpXS+jk/wAAAIB8efzMiNQYnmhxMElS53dOSX07ghgvmKySVTP0S5Mm/xdlZ5Va3TpYr9AYJBWr2dBq+PjyFN5Tv8X9XtILkEOxm/zMsx2VOiu0fNSj5uFXwxYhm+ypLyCX0GACbs39Olb83lyqGwtIYwBiXW1jtlFdQ5AzbHjkfgONxC6Rgm+F6AAAAIAkqv1WdLA24/BwGf0CcGqX+ORKV1ymjU3x43WJH/0mR8cs4wDt1v76vkBj/Vrv8C6X7x4eU1ZG8TvqIq4eRJl2vk4wG5rHZ1ttNwQHDW1InsxRQYGaio4aYVEC2kJHrKA/CoMsPuNaC8ZeaTNFoyG6ne7uB0RyyuS0z49cq/YNAg==
2 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/keys/ecdsa-key:
--------------------------------------------------------------------------------
1 | -----BEGIN EC PRIVATE KEY-----
2 | MHcCAQEEIMY3laspkmscOBAABbwhxLJniUTF2WC4DHkglmKfqKJkoAoGCCqGSM49
3 | AwEHoUQDQgAEPeTxJR2+B5cFpKRW7E+mKZWH70Bx2v/15EI7O08G0vqd2vTzf7AX
4 | wP1o6P5sgkfBt2kuar1tpTcM+Ui05fxb2Q==
5 | -----END EC PRIVATE KEY-----
6 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/keys/ecdsa-key.pub:
--------------------------------------------------------------------------------
1 | ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBD3k8SUdvgeXBaSkVuxPpimVh+9Acdr/9eRCOztPBtL6ndr083+wF8D9aOj+bIJHwbdpLmq9baU3DPlItOX8W9k=
2 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/keys/ed25519-key:
--------------------------------------------------------------------------------
1 | -----BEGIN EC PRIVATE KEY-----
2 | MHcCAQEEIJhyICkPbYqs6JHfCLTwg24lb06lGpZcdN9ffhgVg3OcoAoGCCqGSM49
3 | AwEHoUQDQgAE+HacvOZW+V2vsE+z5+7m9e+FgDV7+xSj5osvB2VT1rxiTPrlGDPw
4 | PmyQb/bwWn1AOpGAZ4XhP6AIeVQGhw9X7g==
5 | -----END EC PRIVATE KEY-----
6 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/keys/ed25519-key.pub:
--------------------------------------------------------------------------------
1 | ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPh2nLzmVvldr7BPs+fu5vXvhYA1e/sUo+aLLwdlU9a8Ykz65Rgz8D5skG/28Fp9QDqRgGeF4T+gCHlUBocPV+4=
2 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/keys/rsa-key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEpAIBAAKCAQEA4Yb7Oa6aPqcGIyOCtYkbmgPjGCOpJ0Lc+j/Hlp4Ai9wBeExI
3 | /cYSAZETcLRiFLdnDKYcTGzLBJyl0KcjkOzWy2k6ooQO88vqljUZ80fKAgZMKhxf
4 | Go3XFE9M/nASvcGcUdjMSaf36N4xFOn5Zoyp/gHIPFBXJq7P+sJnZ/leUGUdFIh0
5 | pG1NlUcUGBFG29KW3QhsWM7Wkl8uo2ufb/V97nlmFuFlP0752UvAJnqqQzz1gnkW
6 | 22kD2X5kjnmTJj8inVD5jzL9uVtfHk/SK26IK3eXmaeRHa2Pe1J7yp77vsMiNBCH
7 | o5RnQcWnEKIsSCXcCmJx6zdFZMEBDNyuFGF/fwIDAQABAoIBAHBQhsC9Qbe9+oJ5
8 | Ztj9hS94jBozeERDOkWuiblqyp7cXCcK5rbrc4AwPdw9GTNz+vADscglzh1n3fRB
9 | qKa+LGJ072yME946SYOwwlG0CNhlRn0aUAqrZNeKfq+gJNU3nJ/uNh7gdcgVD6B4
10 | vWni163WOWBAKobrPEyHkHPpbpzeLuAbiIyAkc7oZLCXRPMRVdlwGORIKOCA1j0o
11 | AALSpioswDCvBsISuEztcgPVeDmSB0Is6mtqJdqFYluyKuLqn+hW+K+qLUp+huYk
12 | 0T7fJtb0gPc5JbHZKl9jPhM59w5qoVXk0NXjHKJq3bIZDxpYNKimIEH0gjH1ESh9
13 | N0PGvJECgYEA+BW1FBRggsYXdWVhrjWgW7bjBJMnOI8infK6r0YUrnDjDw0VM+ub
14 | SksPBWIitDeYil0WRXm74paoUHKE5a5bdNAvwKzxaI7925m6p4jlzHR8HvSpEf1e
15 | SbMPkFuO3zXdKurfXP7zUSEtN+xpM1CrxSELQjWQ6gxPhiq1wFhHEzsCgYEA6LkH
16 | rFz2q7ioVhr9nM290xbqCtJ+jf2jc7NDEj7YyV24JKO+HCP8RIY9HUXUgGoX1rY5
17 | kkzy8aEfXMeZ9CmFEA7+W2wP0LV/Lu1UHcocIf6lkY7XxfZC2Lhjkar03ErjnWTY
18 | 85dPqmQeApQJBd3FXVstO0k+uctvvuQcK0ylOI0CgYEAvFjerWv7Cc4TKVHbI0Qb
19 | hwYGvQZrlIk3IuuRyFhQg0+5U0f/fPe3YmQx90hWSLSc3w9lRUHy30i6aLlJJIeH
20 | b9xPJN0oOtW07fB8wY0xylP1mBrv8XSHDTUg79xTUCu4ykifZB8747BogDjAdfEd
21 | OACqZ437g3XtOlNawblD3NkCgYEAo9yMg5edc8H8fUxZ4EuZagVLW71ksJOzwCar
22 | hjBMMlTT8LB+jo/j81fVtkPR4W1SRbNfDB00PmBllc1RIHMPpwP3ouWOqTTyTVd8
23 | D9GcR29movvCADhqTvBd41ZNPMNaSxuUCsgyptYBr20OgVvquNYXHhRvnyCYGP/C
24 | udYoy40CgYB+8lHXcs9WP3z59zH7Fi7bDDFNF9/q0vXm4T+KdnE7RV4X8f60CBJN
25 | 9EPOPcizebjNBB2pgF1D1zM4/3AJ4m+nUYxy5/aRUnvFSceWoaD1MFzk9KSU/4Tc
26 | o4euPH+8XL2GmMOYcuNQUebPmC5sC0pEg+bpJ/erYvZV3I5yXdyQww==
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/keys/rsa-key.pub:
--------------------------------------------------------------------------------
1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDhhvs5rpo+pwYjI4K1iRuaA+MYI6knQtz6P8eWngCL3AF4TEj9xhIBkRNwtGIUt2cMphxMbMsEnKXQpyOQ7NbLaTqihA7zy+qWNRnzR8oCBkwqHF8ajdcUT0z+cBK9wZxR2MxJp/fo3jEU6flmjKn+Acg8UFcmrs/6wmdn+V5QZR0UiHSkbU2VRxQYEUbb0pbdCGxYztaSXy6ja59v9X3ueWYW4WU/TvnZS8AmeqpDPPWCeRbbaQPZfmSOeZMmPyKdUPmPMv25W18eT9Irbogrd5eZp5EdrY97UnvKnvu+wyI0EIejlGdBxacQoixIJdwKYnHrN0VkwQEM3K4UYX9/
2 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/test_crypto_plugins.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from qark.plugins.crypto.ecb_cipher_usage import ECBCipherCheck
4 | from qark.plugins.crypto.packaged_private_keys import PackagedPrivateKeys
5 | from qark.plugins.crypto.setting_secure_random_seed import SeedWithSecureRandom
6 |
7 | curr_dir = os.path.dirname(__file__)
8 | java_dir = os.path.join(curr_dir, 'java_files')
9 |
10 |
11 | def test_blank_file():
12 | files = ('invalid.java', 'blank.java')
13 | files = tuple(os.path.join(java_dir, file) for file in files)
14 | plugins = (SeedWithSecureRandom(), ECBCipherCheck(), PackagedPrivateKeys())
15 | for plugin in plugins:
16 | for file in files:
17 | plugin.update(file_path=file, call_run=True)
18 | assert plugin.issues == []
19 |
20 |
21 | def test_seeding_secure_random():
22 | no_bug_files = ['secure_random_no_args1.java']
23 | buggy_files = ['secure_random_args1.java', 'secure_random_args2.java']
24 | plugin = SeedWithSecureRandom()
25 | for curr_file in no_bug_files:
26 | curr_file = os.path.join(java_dir, curr_file)
27 |
28 | plugin.update(file_path=curr_file, call_run=True)
29 |
30 | plugin.run()
31 | assert not plugin.issues
32 |
33 | plugin.reset()
34 |
35 | for i, curr_file in enumerate(buggy_files):
36 | curr_file = os.path.join(java_dir, curr_file)
37 |
38 | assert i == len(plugin.issues)
39 | plugin.update(file_path=curr_file)
40 | plugin.run()
41 | assert i + 1 == len(plugin.issues)
42 |
43 |
44 | def test_packaged_private_keys():
45 | key_dir = os.path.join(curr_dir, 'keys')
46 | plugin = PackagedPrivateKeys()
47 | assert 0 == len(plugin.issues)
48 |
49 | private_key_files = ['rsa-key', 'dsa-key', 'ed25519-key', 'ecdsa-key']
50 | for i, file_path in enumerate(private_key_files):
51 | absolute_path = os.path.join(key_dir, file_path)
52 | assert i == len(plugin.issues)
53 | plugin.reset()
54 | plugin.update(file_path=absolute_path)
55 | plugin.run()
56 | assert i + 1 == len(plugin.issues)
57 |
58 | public_key_files = [path + '.pub' for path in private_key_files]
59 | num_issues = len(plugin.issues)
60 | for file_path in public_key_files:
61 | plugin.reset()
62 | plugin.update(file_path=os.path.join(key_dir, file_path))
63 | plugin.run()
64 | assert num_issues == len(plugin.issues)
65 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_crypto_plugins/test_ecb.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import javalang
4 |
5 | from qark.plugins.crypto.ecb_cipher_usage import ECBCipherCheck
6 |
7 | curr_dir = os.path.dirname(__file__)
8 | java_dir = os.path.join(curr_dir, 'java_files')
9 |
10 |
11 | def test_ecb_cipher_usage():
12 | plugin = ECBCipherCheck()
13 | files_with_ecb = ['ecb1.java', 'ecb2.java']
14 | files_without_ecb = ['no_ecb1.java']
15 |
16 | for file in files_without_ecb:
17 | file = os.path.join(java_dir, file)
18 | plugin.update(file_path=file)
19 | plugin.run()
20 |
21 | assert not plugin.issues
22 |
23 | plugin.reset()
24 |
25 | for i, file in enumerate(files_with_ecb):
26 | file = os.path.join(java_dir, file)
27 | plugin.update(file_path=file)
28 | assert len(plugin.issues) == i
29 | plugin.run()
30 | assert len(plugin.issues) == i + 1
31 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_file_plugins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_plugins/test_file_plugins/__init__.py
--------------------------------------------------------------------------------
/tests/test_plugins/test_file_plugins/test_file_permissions.java:
--------------------------------------------------------------------------------
1 | class ExampleReadable{
2 | public static void main(){
3 | SharedPreferences preference = context.getContext()
4 | .getSharedPreferences(Context.MODE_WORLD_READABLE);
5 | }
6 | }
7 | class ExampleWritable{
8 | public static void main(){
9 | SharedPreferences preference = context.getContext()
10 | .getSharedPreferences(Context.MODE_WORLD_WRITEABLE);
11 | }
12 | }
13 | class ExampleNonVulnerable{
14 | public static void main(){
15 | SharedPreferences preference = context.getContext()
16 | .getSharedPreferences(Context.MODE_WRITEABLE);
17 | }
18 | }
19 | class ExampleCommented{
20 | public static void main(){
21 | /* SharedPreferences preference = context.getContext()
22 | .getSharedPreferences(Context.MODE_WRITEABLE);
23 | */
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_generic_plugins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_plugins/test_generic_plugins/__init__.py
--------------------------------------------------------------------------------
/tests/test_plugins/test_generic_plugins/test_check_permissions.py:
--------------------------------------------------------------------------------
1 | from qark.plugins.generic.check_permissions import CheckPermissions
2 |
3 | import os
4 |
5 |
6 | def test_check_permissions(test_java_files):
7 | plugin = CheckPermissions()
8 | path = os.path.join(test_java_files,
9 | "check_permissions.java")
10 | plugin.update(file_path=path)
11 | plugin.run()
12 | assert 2 == len(plugin.issues)
13 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_generic_plugins/test_task_affinity.py:
--------------------------------------------------------------------------------
1 | from qark.plugins.generic.task_affinity import TaskAffinity
2 |
3 | import os
4 |
5 | def test_task_affinity(test_java_files):
6 | plugin = TaskAffinity()
7 | path = os.path.join(test_java_files,
8 | "task_affinity.java")
9 | plugin.update(file_path=path)
10 | plugin.run()
11 | assert 1 == len(plugin.issues)
12 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_intent/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_plugins/test_intent/__init__.py
--------------------------------------------------------------------------------
/tests/test_plugins/test_intent/test_implicit_intent.java:
--------------------------------------------------------------------------------
1 | package android.support.v4.content;
2 |
3 | import android.app.PendingIntent;
4 | import android.content.BroadcastReceiver;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.IntentFilter;
8 | import android.os.Handler;
9 | import android.os.Looper;
10 | import android.os.Message;
11 | import java.util.ArrayList;
12 | import java.util.HashMap;
13 |
14 |
15 | public class VulnerableTest {
16 | public void vulnerableMethodGetActivity() {
17 | PendingIntent b = PendingIntent.getActivity("context", "requestcode", new Intent(), "flags");
18 | }
19 | public void vulnerableMethodGetActivities() {
20 | PendingIntent b = PendingIntent.getActivities("context", "requestcode", new Intent[]{new Intent()}, "flags");
21 | }
22 | public void vulnerableMethodGetService() {
23 | PendingIntent b = PendingIntent.getService("context", "requestcode", new Intent(), "flags");
24 | }
25 | public void vulnerableMethodGetBroadcast() {
26 | PendingIntent b = PendingIntent.getBroadcast("context", "requestcode", new Intent(), "flags");
27 | }
28 | public void nonVulnerableMethodGetBroadcast() {
29 | PendingIntent b = PendingIntent.getBroadcast("context", "requestcode", new Intent(this, VulnerableTest.class), "flags");
30 | }
31 | }
--------------------------------------------------------------------------------
/tests/test_plugins/test_intent/test_intent_plugins.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from qark.plugins.intent.implicit_intent_to_pending_intent import ImplicitIntentToPendingIntent
4 |
5 |
6 | vuln_java_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_implicit_intent.java")
7 |
8 |
9 | def test_empty_intent():
10 | plugin = ImplicitIntentToPendingIntent()
11 | plugin.update(file_path=vuln_java_file)
12 | plugin.run()
13 | assert len(plugin.issues) == 4
14 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_manifest_plugins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_plugins/test_manifest_plugins/__init__.py
--------------------------------------------------------------------------------
/tests/test_plugins/test_manifest_plugins/broadcastreceivers/SendSMSNowReceiver.java:
--------------------------------------------------------------------------------
1 | package test_plugins.test_manifest_plugins.broadcastreceivers;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.telephony.SmsManager;
8 | import org.owasp.goatdroid.fourgoats.misc.Utils;
9 |
10 | public class SendSMSNowReceiver
11 | extends BroadcastReceiver
12 | {
13 | Context context;
14 |
15 | public SendSMSNowReceiver() {}
16 |
17 | public void onReceive(Context paramContext, Intent paramIntent)
18 | {
19 | this.context = paramContext;
20 | paramContext = SmsManager.getDefault();
21 | paramIntent = paramIntent.getExtras();
22 | paramContext.sendTextMessage(paramIntent.getString("phoneNumber"), null, paramIntent.getString("message"), null, null);
23 | Utils.makeToast(this.context, "Your text message has been sent!", 1);
24 | }
25 | }
--------------------------------------------------------------------------------
/tests/test_plugins/test_webviews/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_plugins/test_webviews/__init__.py
--------------------------------------------------------------------------------
/tests/test_plugins/test_webviews/vulnerable_webview.java:
--------------------------------------------------------------------------------
1 | class WebviewJavascript extends WebViewClient {
2 | public void vulnerableMethodJavascriptEnabled() {
3 | WebView web = (WebView) findViewById(R.id.webview);
4 | web.setWebChromeClient(new MyCustomChromeClient(this));
5 | web.setWebViewClient(new MyCustomWebViewClient(this));
6 | web.clearCache(true);
7 | web.clearHistory();
8 | web.getSettings().setJavaScriptEnabled(true);
9 | }
10 | public void nonVulnerableMethodJavascriptEnabled() {
11 | WebView web = (WebView) findViewById(R.id.webview);
12 | web.setWebChromeClient(new MyCustomChromeClient(this));
13 | web.setWebViewClient(new MyCustomWebViewClient(this));
14 | web.clearCache(true);
15 | web.clearHistory();
16 | web.getSettings().setJavaScriptEnabled();
17 | }
18 | public void nonVulnerableMethod2JavascriptEnabled() {
19 | WebView web = (WebView) findViewById(R.id.webview);
20 | web.setWebChromeClient(new MyCustomChromeClient(this));
21 | web.setWebViewClient(new MyCustomWebViewClient(this));
22 | web.clearCache(true);
23 | web.clearHistory();
24 | web.getSettings().setJavaScriptEnabled(false);
25 | }
26 | public void vulnerableMethodLoadDataWithBaseURL() {
27 | WebView web = (WebView) findViewById(R.id.webview);
28 | web.setWebChromeClient(new MyCustomChromeClient(this));
29 | web.setWebViewClient(new MyCustomWebViewClient(this));
30 | web.clearCache(true);
31 | web.clearHistory();
32 | web.loadDataWithBaseURL("file:///android_res/drawable/", "", "text/html", "UTF-8", null);
33 | }
34 | public void nonVulnerableMethodLoadDataWithBaseURL() {
35 | WebView web = (WebView) findViewById(R.id.webview);
36 | web.setWebChromeClient(new MyCustomChromeClient(this));
37 | web.setWebViewClient(new MyCustomWebViewClient(this));
38 | web.clearCache(true);
39 | web.clearHistory();
40 | web.loadDataWithBaseURL();
41 | }
42 | public void vulnerableMethodSetAllowFileAccessSetAllowContentAccess() {
43 | WebView web = (WebView) findViewById(R.id.webview);
44 | web.setWebChromeClient(new MyCustomChromeClient(this));
45 | web.setWebViewClient(new MyCustomWebViewClient(this));
46 | web.clearCache(true);
47 | web.clearHistory();
48 | WebSettings webSettings = web.getSettings();
49 | }
50 | public void nonVulnerableMethodSetAllowFileAccessSetAllowContentAccess() {
51 | WebView web = (WebView) findViewById(R.id.webview);
52 | web.setWebChromeClient(new MyCustomChromeClient(this));
53 | web.setWebViewClient(new MyCustomWebViewClient(this));
54 | web.clearCache(true);
55 | web.clearHistory();
56 | WebSettings webSettings = web.getSettings();
57 | webSettings.setAllowFileAccess(false);
58 | webSettings.setAllowContentAccess(false);
59 | }
60 | }
--------------------------------------------------------------------------------
/tests/test_plugins/test_webviews/vulnerable_webview_add_javascript_interface.java:
--------------------------------------------------------------------------------
1 | class JsObject {
2 | @JavascriptInterface
3 | public String toString() { return "injectedObject"; }
4 | }
5 |
6 | class vulnerable_webview_add_javascript_interface extends WebViewClient {
7 | public void vulnerableMethodSetAllowFileAccess() {
8 | WebView web = (WebView) findViewById(R.id.webview);
9 | web.addJavascriptInterface(new JsObject(), "injectedObject");
10 | }
11 | public void vulnerableMethodSetAllowFileAccess2(WebView web) {
12 | web.addJavascriptInterface(new JsObject(), "injectedObject");
13 | }
14 | public void nonVulnerableMethodSetAllowFileAccess(WebView web) {
15 | pass;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_webviews/vulnerable_webview_content_access.java:
--------------------------------------------------------------------------------
1 | class WebviewJavascript extends WebViewClient {
2 | public void vulnerableMethodSetAllowContentAccess() {
3 | WebView web = (WebView) findViewById(R.id.webview);
4 | }
5 | public void vulnerableMethodSetAllowContentAccess2() {
6 | WebView web = (WebView) findViewById(R.id.webview);
7 | WebSettings webSettings = web.getSettings();
8 | webSettings.setAllowContentAccess(true);
9 | }
10 | public void nonVulnerableMethodSetAllowFileAccess() {
11 | WebView web = (WebView) findViewById(R.id.webview);
12 | web.getSettings().setAllowContentAccess(false);
13 | }
14 | public void nonVulnerableMethodSetAllowFileAccess2() {
15 | WebView web = (WebView) findViewById(R.id.webview);
16 | WebSettings web_settings = web.getSettings();
17 | web_settings.setAllowContentAccess(false);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_webviews/vulnerable_webview_file_access.java:
--------------------------------------------------------------------------------
1 | class WebviewJavascript extends WebViewClient {
2 | public void vulnerableMethodSetAllowFileAccess() {
3 | WebView web = (WebView) findViewById(R.id.webview);
4 | }
5 | public void vulnerableMethodSetAllowFileAccess2() {
6 | WebView web = (WebView) findViewById(R.id.webview);
7 | WebSettings webSettings = web.getSettings();
8 | webSettings.setAllowFileAccess(true);
9 | }
10 | public void nonVulnerableMethodSetAllowFileAccess() {
11 | WebView web = (WebView) findViewById(R.id.webview);
12 | web.getSettings().setAllowFileAccess(false);
13 | }
14 | public void nonVulnerableMethodSetAllowFileAccess2() {
15 | WebView web = (WebView) findViewById(R.id.webview);
16 | WebSettings web_settings = web.getSettings();
17 | web_settings.setAllowFileAccess(false);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_webviews/vulnerable_webview_set_dom_storage_enabled.java:
--------------------------------------------------------------------------------
1 | class vulnerable_webview_set_dom_storage_enabled extends WebViewClient {
2 | public void vulnerableMethodSetDomStorageEnabled() {
3 | WebView web = (WebView) findViewById(R.id.webview);
4 | web.getSettings().setDomStorageEnabled(true);
5 | }
6 | public void vulnerableMethodSetAllowFileAccess2(WebView web) {
7 | web.setDomStorageEnabled(true);
8 | }
9 | public void nonVulnerableMethodSetAllowFileAccess() {
10 | WebView web = (WebView) findViewById(R.id.webview);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/tests/test_plugins/test_webviews/vulnerable_webview_universal_access_from_urls.java:
--------------------------------------------------------------------------------
1 | class vulnerable_webview_universal_access_from_urls extends WebViewClient {
2 | public void vulnerableMethodSetAllowUniversalAccessFromURLs() {
3 | WebView web = (WebView) findViewById(R.id.webview);
4 | }
5 | public void vulnerableMethodSetAllowUniversalAccessFromURLs2() {
6 | WebView web = (WebView) findViewById(R.id.webview);
7 | WebSettings webSettings = web.getSettings();
8 | webSettings.setAllowUniversalAccessFromFileURLs(true);
9 | }
10 | public void nonVulnerableMethodSetAllowUniversalAccessFromURLs() {
11 | WebView web = (WebView) findViewById(R.id.webview);
12 | web.getSettings().setAllowUniversalAccessFromFileURLs(false);
13 | }
14 | public void nonVulnerableMethodSetAllowUniversalAccessFromURLs2() {
15 | WebView web = (WebView) findViewById(R.id.webview);
16 | WebSettings web_settings = web.getSettings();
17 | web_settings.setAllowUniversalAccessFromFileURLs(false);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/test_scanner/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linkedin/qark/ba1b26562507d631389b111e5033dad4128a8541/tests/test_scanner/__init__.py
--------------------------------------------------------------------------------
/tests/test_scanner/test_plugin.py:
--------------------------------------------------------------------------------
1 | from qark.scanner.plugin import get_plugins, get_plugin_source
2 |
3 | import pytest
4 |
5 |
6 | @pytest.mark.parametrize("category, num_plugins", [
7 | (None, 0),
8 | ("manifest", 0),
9 | ])
10 | def test_get_plugins(category, num_plugins):
11 | assert len(get_plugins(category=category)) > num_plugins
12 | assert len(get_plugins(category="non_existant_category")) == 0
13 |
14 |
15 | def test_get_plugin_source():
16 | assert 0 < len(get_plugin_source(category="manifest").list_plugins())
17 | assert 0 < len(get_plugin_source().list_plugins())
18 | assert 0 == len(get_plugin_source(category="does_not_exist").list_plugins())
19 |
--------------------------------------------------------------------------------
/tests/test_scanner/test_scanner.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | SCANNER_ISSUES = 10
4 |
5 |
6 | @pytest.mark.long
7 | def test_run(scanner, decompiler):
8 | decompiler.run()
9 |
10 | scanner.issues = []
11 | scanner.decompiler = decompiler
12 | scanner.run()
13 | assert 0 < len(scanner.issues)
14 |
--------------------------------------------------------------------------------