├── LEEME.md
├── README.md
├── client
├── Analyzer.py
├── CommonComponent
│ ├── AnalyzerDecorator.py
│ ├── FuzzingTrigger.py
│ ├── InsecureTransmissionAnalyzer.py
│ ├── ZIPPathTraversalAnalyzer.py
│ └── __init__.py
├── Dispatcher.py
├── DummyFilter
│ ├── DummyAnalyzer.py
│ ├── DummyReporter.py
│ ├── DummyTrigger.py
│ └── __init__.py
├── Emulator.py
├── FileSchemeFilter
│ ├── FileSchemeAnalyzer.py
│ ├── FileSchemeReporter.py
│ ├── FileSchemeTrigger.py
│ └── __init__.py
├── JavascriptInterfaceFilter
│ ├── JavascriptInterfaceAnalyzer.py
│ ├── JavascriptInterfaceReporter.py
│ ├── JavascriptInterfaceTrigger.py
│ └── __init__.py
├── PhonegapFilter
│ ├── PhonegapAnalyzerCVE3500.py
│ ├── PhonegapAnalyzerJSInjection.py
│ ├── PhonegapReporter.py
│ ├── PhonegapTriggerCVE3500.py
│ ├── PhonegapTriggerJSInjection.py
│ └── __init__.py
├── Reporter.py
├── SSLFilter
│ ├── SSLAnalyzer.py
│ ├── SSLReporter.py
│ ├── SSLTrigger.py
│ └── __init__.py
├── StorageAnalyzer.py
├── Trigger.py
├── Utils.py
├── VMClient.py
├── client.sh
├── client_setup.sh
├── mitmproxy_setup.sh
└── settings.py
├── emulator
├── emulator_setup.sh
└── emulator_support_files
│ ├── Android-SSL-TrustKiller.apk
│ ├── Android-x86-RootScript-4.3
│ ├── install-device.sh
│ └── system
│ │ ├── app
│ │ └── Superuser.apk
│ │ ├── bin
│ │ ├── .ext
│ │ │ └── .su
│ │ └── README
│ │ ├── etc
│ │ └── init.sh
│ │ └── xbin
│ │ ├── daemonsu
│ │ └── su
│ ├── Marvin-toqueton.apk
│ ├── busybox
│ ├── com.saurik.substrate.apk
│ └── eu.chainfire.supersu_preferences.xml
├── images
└── architecture.jpg
└── server
├── DBCache_django.py
├── DBManager_django.py
├── ONE-API
├── NetworkInfo.java
├── SnapshotRestore.java
├── lib
│ ├── org.opennebula.client.jar
│ ├── ws-commons-util-1.0.2.jar
│ ├── xmlrpc-client-3.1.2.jar
│ └── xmlrpc-common-3.1.2.jar
├── network_info.jar
└── restore.jar
├── Utils.py
├── VMManager.py
├── django_support
├── __init__.py
├── models.py
├── myindices.py
└── settings.py
└── settings.py
/LEEME.md:
--------------------------------------------------------------------------------
1 | # Marvin Dynamic Analyzer #
2 |
3 | Analizador dinámico de vulnerabilidades de aplicaciones Android utilzando OpenNebula y emuladores Android-x86.
4 |
5 | Version: 0.01
6 |
7 | ## Arquitectura general ##
8 |
9 | 
10 |
11 | Las vulnerabilidades analizadas dinámicamente son:
12 |
13 | * JAVASCRIPT_INTERFACE
14 | * PHONEGAP_JS_INJECTION
15 | * PHONEGAP_CVE_3500_URL
16 | * SSL_CUSTOM_TRUSTMANAGER
17 | * SSL_CUSTOM_HOSTNAMEVERIFIER
18 | * SSL_ALLOWALL_HOSTNAMEVERIFIER
19 | * SSL_INSECURE_SOCKET_FACTORY
20 | * SSL_WEBVIEW_ERROR
21 | * WEBVIEW_FILE_SCHEME
22 |
23 | Además, intenta analizar por otro tipo de vulnerabilidades mientras analizando las anteriores:
24 |
25 | * ZIP_PATH_TRAVERSAL
26 | * INSECURE_TRANSMISSION
27 | * INSECURE_STORAGE
28 |
29 | El VMManager esta encargado de buscar nuevas vulnerabilidades en la base de datos de Marvin para analizar dinámicamente.
30 |
31 | Los VMClient reciben las aplicaciones y los tipos de vulnerabilidades a analizar del VMManager. Luego, usa ADB para conectarse al emulador y comenzar el análisis. Además configura al emulador para que él pueda actuar de router para interceptar los pedidos HTTP/HTTPS. Utilizan un fuzzer personalizado [MarvinToqueton](https://github.com/programastic/Marvin-toqueton/) cuyo objetivo es interactuar con la aplicación para disparar las vulnerabilidades.
32 |
33 | Los emuladores corren Android 4.3 x86 para soportar Cydia Substrate. Las próximas versiones soportaran Xposed.
34 | El proyecto está utilizando las imágenes de [Android-x86](www.android-x86.org).
35 |
36 | Hay 3 tipos de emuladores:
37 | * Emuladores sin ningún tipo de verificación SSL
38 | * Emuladores con verificación SSL normal (utilizados para ver si las aplicaciones realizan verificaciones SSL)
39 | * Emuladores corriendo ICS 4.0 (usados para explotar la vulnerabilidad de interfaces Javascript/Java )
40 |
41 | ## Configuraciones ##
42 |
43 | Las configuraciones de VMManager se encuentran en el archivo settings.py:
44 |
45 | ```
46 | NET_ID = 1 #ID used de la red Virtual OpenNebula
47 | # IP RPC OpenNebula
48 | ONE_IP = "http://IP:2633/RPC2"
49 | ONE_CREDS = "" #Credenciales OpenNebula xml RPC
50 | ELASTIC_SEARCH_SERVER = "ELASTIC_SEARCH_IP_ADDRESS"
51 | DOWNLOAD_APK_SITE = "http://FRONTEND_IP_ADDRESS/frontpage/"
52 | ANDROID_VM_POOL = {"NONSSL":{"NON_SSL_EMULATOR_IP"},"SSL":{"EMULATOR_IP"},"JAVASCRIPTINTERFACE":{"ICS_EMULATOR_IP"}}
53 | ```
54 |
55 | **IMPORTANTE:** Bajo el directorio django_support, configurar el archivo settings.py con los SECRET_KEY, contraseñas de la base de datos y URL de BungieSearch correspondientes a la configuración de Marvin-frontend.
56 |
57 | El cliente de VMClient también incluye configuraciones en settings.py:
58 |
59 | ```
60 | VM_MANAGER_IP = 'VMMANAGER_IP_ADDRESS:8082'
61 | REPORTER_IP = 'localhost:8081'
62 | DEBUG_MODE = False
63 |
64 | #Algunas configuraciones del Fuzzer que pueden ser modificadas en el proyecto Marvin-toqueton.
65 | ```
66 |
67 | ## Para correrlo ##
68 |
69 | Comenzar el servidor con:
70 |
71 | ```
72 | python VMManager.py
73 | ```
74 |
75 | Y los clientes con:
76 |
77 | ```
78 | ./client.sh
79 | ```
80 |
81 | ## Análisis de una aplicación ##
82 |
83 | El analizador dinámico obtiene la siguiente aplicación a analizar del conjunto de vulnerabilidades no verificadas en la base de datos de Marvin. Para hacer análisis de una sola aplicación, cambiar DEBUG_MODE a True en settings.py del cliente. Y luego correr el cliente de la siguiente forma:
84 |
85 | ```
86 | python VMClient.py [VULNERABILITY_ID] [NOMBRE-PAQUETE/NOMBRE ARCHIVO APK] '''{"emulator":"IP_DEL_EMULADOR_A_USAR","count":0}'''
87 | ```
88 |
89 | En el caso de la vulnerabilidad PHONEGAP_CVE_3500_URL se debe además agregar como parámetro el campo "activity" que referencia a la Activity inicial de la aplicación. Si sólo querés corroborar vulnerabilidades no encontradas estáticamente como ZIP Path Traversal o transmisión y almacenamiento inseguro, utiliza "dummy" como ID de la vulnerabilidad.
90 |
91 | **IMPORTANTE:** El nombre del archivo APK debe coincidir con el nombre del paquete de la aplicación.
92 |
93 | ## Deployment ##
94 |
95 | VMManager y VMClient pueden utilizar cualquier VM hosteada en OpenNebula. Los autores utilizaron ttylinux - kvm del Marketstore de OpenNebula como template.
96 |
97 | ### Dependencias de VMManager ###
98 |
99 | Correr los siguientes comandos para instalar las dependencias:
100 |
101 | ```
102 | pip install bungiesearch
103 |
104 | sudo apt-get install python-mysqldb
105 |
106 | apt-get install default-jre
107 |
108 | apt-get install python-django
109 | ```
110 |
111 | ### Dependencias de VMClient ###
112 |
113 | Correr los siguientes comandos para instalar las dependencias:
114 |
115 | ```
116 | apt-get install mitmproxy
117 | ```
118 | ### Crear un emulador ###
119 |
120 | Descargar desde el sitio de Android-x86 el ISO para el release 4.3 o 4.0. Instalar en un disco con una herramienta de virtualización. Los autores utilizamos VirtualBox para ello.
121 |
122 | Convierte la imagen instalada del disco a formato qemu de KVM para soportar snapshots en OpenNebula. Puedes utilizar el siguiente comando:
123 |
124 | ```
125 | qemu-img convert -O qcow2 original-image image-converted.qcow
126 | ```
127 | Sube la imagen a OpenNebula y create un nuevo template para el emulador.
128 |
129 | Ejemplo de template:
130 |
131 | ```
132 | CONTEXT=[NETWORK="YES",SSH_PUBLIC_KEY="$USER[SSH_PUBLIC_KEY]"]
133 |
134 | CPU="2"
135 |
136 | DISK=[DRIVER="qcow2",IMAGE="Image Name",IMAGE_UNAME="Your user"]
137 |
138 | GRAPHICS=[LISTEN="0.0.0.0",TYPE="VNC"]
139 |
140 | HYPERVISOR="kvm"
141 |
142 | MEMORY="512"
143 |
144 | NIC=[MODEL="pcnet",NETWORK="Your Virtual Network Name",NETWORK_UNAME="Your user"]
145 |
146 | SUNSTONE_CAPACITY_SELECT="YES"
147 |
148 | SUNSTONE_NETWORK_SELECT="YES"
149 | ```
150 |
151 | **IMPORTANTE:** COnfigurar QCOW2 como el driver de disco para soportar snapshots.
152 |
153 | **IMPORTANTE:** Al crear un dispositivo Android ICS, configurar el driver de red a pcnet.
154 |
155 | Crear una VM utilizando el template creado anteriormente y prende el dispositivo.
156 |
157 | **IMPORTANT:** Iniciar la primera vez en modo Debug y editar el archivo /mnt/grub/menu.lst. Agregar "quiet nomodeset vga=788" antes de video=-16 a los argumentos del kernel.
158 |
159 | Por ahora no hay soporte de contextualización para las VMs de Android corriendo en OpenNebula así que las interfaces de red deben ser configuradas manualmente para poder conectarse remotamente desde ADB. Para correr comandos como root desde la aplicación Terminal utilizar:
160 |
161 | ```
162 | adb root
163 |
164 | adb kill-server
165 |
166 | adb start-server
167 |
168 | adb shell
169 | ```
170 |
171 | Los siguientes comandos deberían funcionar para configurar la red corriendo en la aplicación de Terminal como root:
172 |
173 | ```
174 | ifconfig eth0 [IP] netmask [NETMASK]
175 |
176 | busybox route add default gw [GATEWAY] dev eth0
177 | ```
178 |
179 |
180 | Una vez terminada la configuración de la red, **salir de la terminal en modo root** e utilizar ADB para permitir depuración remota con:
181 |
182 | ```
183 | adb tcpip 5556
184 | ```
185 |
186 | Manualmente configurar:
187 | * Deshabilitar el sonido en el Emulador (Settings->Sound)
188 | * Destildar la verificación de las aplicaciones en Settings->Security->Uncheck Verify Apps
189 |
190 | Correr android_setup_client.sh en un host con los siguientes parámetros:
191 |
192 | ```
193 | emulator_setup.sh {SSL/NOSSL} {IP-EMULADOR} {ROUTER-PARA-EMULADOR}
194 | ```
195 |
196 | Seleccionar {SSL/NOSSL} para desplegar un emulador de tipo 1 o 2.
197 |
198 | El script:
199 | * Rootea el emulador
200 | * Agrega una configuración de red estática
201 | * Instala SuperUser y CydiaSubstrate, linkea Substrate y le permite correr como root.
202 | * Si es de tipo NOSSL, instala Android-SSL-TrustKiller para dejar de validar la verificación SSL.
203 | * Instala el fuzzer Marvin-toqueton.
204 | * Deshabilita el bloqueo de pantalla y la suspensión.
205 |
206 |
207 | Por último, crear un snapshot de la VM corriendo con el nombre que prefieras.
208 |
209 | ### Requerimientos ###
210 |
211 | * Marvin-frontend instalado en alguna VM de OpenNebula.
212 | * Python 2.7.x (No usar Python 3.X)
213 |
214 | ### Créditos ###
215 | * Joaquín Rinaudo ([@xeroxnir](https://www.twitter.com/xeroxnir))
216 | * Juan Heguiabehere ([@jheguia](https://www.twitter.com/jheguia))
217 |
218 | ### Contacto ###
219 | * Mandar un correo a stic en el dominio fundacionsadosky.org.ar
220 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Marvin Dynamic Analyzer #
2 |
3 | Dynamic android vulnerability scanner using OpenNebula and Android-x86 emulators.
4 |
5 | Version: 0.01
6 |
7 | ## General architecture ##
8 |
9 | 
10 |
11 | Vulnerabilities analyzed dynamically are:
12 |
13 | * JAVASCRIPT_INTERFACE
14 | * PHONEGAP_JS_INJECTION
15 | * PHONEGAP_CVE_3500_URL
16 | * SSL_CUSTOM_TRUSTMANAGER
17 | * SSL_CUSTOM_HOSTNAMEVERIFIER
18 | * SSL_ALLOWALL_HOSTNAMEVERIFIER
19 | * SSL_INSECURE_SOCKET_FACTORY
20 | * SSL_WEBVIEW_ERROR
21 | * WEBVIEW_FILE_SCHEME
22 |
23 | Also it checks for new vulnerabilities that might be found while searching for others:
24 |
25 | * ZIP_PATH_TRAVERSAL
26 | * INSECURE_TRANSMISSION
27 | * INSECURE_STORAGE
28 |
29 | VMManager is in charge of searching new vulnerabilities to be analyzed in Marvin's Django database.
30 |
31 | VMClients receive the app and type of vulnerability to analyze and emulator to use from VMManager. It uses ADB to connect to the emulator and start the analysis. It also configures the emulator to act as its gateway to intercept HTTP/HTTPS requests.
32 |
33 | VMClients uses a custom fuzzer [MarvinToqueton](https://github.com/programastic/Marvin-toqueton/) developed for interacting with the application to try triggering the vulnerabilities.
34 |
35 | The emulators are running Android 4.3 x86 because of Cydia Substrate support. The project is using [Android-x86](www.android-x86.org) images.
36 |
37 | There are 3 types of emulator:
38 | * Emulators with no SSL verification
39 | * Emulators with normal SSL verification (They are used to check if an application does proper SSL verification)
40 | * Emulators running ICS 4.0 (Used for exploiting Javascript Interface vulnerability)
41 |
42 | ## Configurations ##
43 |
44 | VMManager configurations are in settings.py:
45 |
46 | ```
47 | NET_ID = 1 #ID used for OpenNebula virtual network
48 | #credentials for RPC
49 | ONE_IP = "http://IP:2633/RPC2"
50 | ONE_CREDS = "" #OpenNebula xml RPC credentials
51 | ELASTIC_SEARCH_SERVER = "ELASTIC_SEARCH_IP_ADDRESS"
52 | DOWNLOAD_APK_SITE = "http://FRONTEND_IP_ADDRESS/frontpage/"
53 | ANDROID_VM_POOL = {"NONSSL":{"NON_SSL_EMULATOR_IP"},"SSL":{"EMULATOR_IP"},"JAVASCRIPTINTERFACE":{"ICS_EMULATOR_IP"}}
54 | ```
55 |
56 | **IMPORTANT:** Under the django_support directory, also configure the settings.py file with the corresponding SECRET_KEY, database password and BungieSearch URL from Marvin-frontend configuration.
57 |
58 | VMClient configurations are also in the settings.py file:
59 |
60 | ```
61 | VM_MANAGER_IP = 'VMMANAGER_IP_ADDRESS:8082'
62 | REPORTER_IP = 'localhost:8081'
63 | DEBUG_MODE = False
64 |
65 | #Some fuzzer configurations that can be modified in Marvin-toqueton project.
66 | ```
67 |
68 | ## Running ##
69 |
70 | Start the server with:
71 |
72 | ```
73 | python VMManager.py
74 | ```
75 |
76 | And VMClients with:
77 |
78 | ```
79 | ./client.sh
80 | ```
81 | ## Running a single analysis ##
82 |
83 | Marvin dynamic analyzer obtains the next app to analyze from the pool of unverified vulnerabilities on Marvin's database. If you want to run an analysis on a single app you can change the variable DEBUG_MODE to True in settings.py of the client. Then you can run an analysis with:
84 |
85 |
86 | ```
87 | python VMClient.py [VULNERABILITY_ID] [PACKAGE-NAME/FILE-NAME] '''{"emulator":"EMULATOR_IP_ADDRESS","count":0}'''
88 | ```
89 | In the case of PHONEGAP_CVE_3500_URL, you must also include the parameter "activity" with a reference to the initial application activity. If you only want to run checks against vulnerabilities not found statically such as ZIP path traversal, insecure storage and insecure transmission use "dummy" as the vulnerability ID.
90 |
91 |
92 | **IMPORTANT:** The filename of the APK must be the same as the package name.
93 |
94 | ## Deployment ##
95 |
96 | VMManager and VMClient can use any Linux virtual machine hosted in OpenNebula. Authors used ttylinux - kvm from OpenNebula Marketstore as template.
97 |
98 | ### VMManager dependencies ###
99 |
100 | Run to install dependencies:
101 |
102 | ```
103 | pip install bungiesearch
104 |
105 | sudo apt-get install python-mysqldb
106 |
107 | apt-get install default-jre
108 |
109 | apt-get install python-django
110 | ```
111 |
112 | ### VMClient dependencies ###
113 |
114 | Run to install dependencies:
115 |
116 | ```
117 | apt-get install mitmproxy
118 | ```
119 | ### Creating an emulator ###
120 |
121 | Download from the Android-x86 site the ISO for 4.3 or 4.0 release. Install it in a disk with your favorite virtualization tool. Authors used VirtualBox.
122 |
123 | Convert the installed image to KVM qemu's format in order to support OpenNebula's snapshot feature. You can use the following command:
124 |
125 | ```
126 | qemu-img convert -O qcow2 original-image image-converted.qcow
127 | ```
128 |
129 | Upload the image to OpenNebula and create a new template for the emulator.
130 |
131 | Example of template:
132 |
133 | ```
134 | CONTEXT=[NETWORK="YES",SSH_PUBLIC_KEY="$USER[SSH_PUBLIC_KEY]"]
135 |
136 | CPU="2"
137 |
138 | DISK=[DRIVER="qcow2",IMAGE="Image Name",IMAGE_UNAME="Your user"]
139 |
140 | GRAPHICS=[LISTEN="0.0.0.0",TYPE="VNC"]
141 |
142 | HYPERVISOR="kvm"
143 |
144 | MEMORY="512"
145 |
146 | NIC=[MODEL="pcnet",NETWORK="Your Virtual Network Name",NETWORK_UNAME="Your user"]
147 |
148 | SUNSTONE_CAPACITY_SELECT="YES"
149 |
150 | SUNSTONE_NETWORK_SELECT="YES"
151 | ```
152 |
153 | **IMPORTANT:** Set QCOW2 as the image mapping driver for snapshot support.
154 |
155 | **IMPORTANT:** When creating a ICS Android device, set the network interface driver to pcnet.
156 |
157 | Create a VM using the previous template and boot the device.
158 |
159 | **IMPORTANT:** Start the kernel in debug mode the first time and edit the file /mnt/grub/menu.lst. Add "quiet nomodeset vga=788" before the option video=-16 to kernel arguments.
160 |
161 | So far there is no contextualization support for Android VMs running in OpenNebula so the network interfaces have to be configured manually. First to run commands as root run in Terminal application the following commands:
162 |
163 | ```
164 | adb root
165 |
166 | adb kill-server
167 |
168 | adb start-server
169 |
170 | adb shell
171 | ```
172 |
173 | The following commands should work to set the network if run using the Terminal application as root.
174 |
175 | ```
176 | ifconfig eth0 [IP] netmask [NETMASK]
177 |
178 | busybox route add default gw [GATEWAY] dev eth0
179 | ```
180 |
181 | Once the network configuration is set,**exit the Terminal in root mode** and use adb to allow remote debugging with:
182 |
183 | ```
184 | adb tcpip 5556
185 | ```
186 |
187 | Manually configure:
188 |
189 | * Disable all sound in emulator (Settings->Sound)
190 | * Unverify appplications with Settings->Security->Uncheck Verify Apps
191 |
192 | Then run android_setup_client.sh in a host with the following parameters:
193 |
194 | ```
195 | emulator_setup.sh {SSL/NOSSL} {EMULATOR-IP} {GATEWAY-IP-FOR-EMULATOR}
196 | ```
197 |
198 | Choose {SSL/NOSSL} to emulator deploy type 1 or 2.
199 |
200 | This script:
201 |
202 | * Roots the emulator
203 | * Adds network static configuration
204 | * Installs SuperUser and CydiaSubstrate, links Substrate and allows it to run as root.
205 | * If it's NOSSL type, install Android-SSL-TrustKiller to skip SSL verification
206 | * Install the Marvin-toqueton fuzzer.
207 | * Disables lockscreen and suspension
208 |
209 | Lastly, create a snapshot of the VM running with any name you refer.
210 |
211 | ### Requirements ###
212 |
213 | * Deployed Marvin-frontend
214 | * Python 2.7.x (DO NOT USE Python 3.X)
215 |
216 | ### Credits ###
217 | * Joaquín Rinaudo ([@xeroxnir](https://www.twitter.com/xeroxnir))
218 | * Juan Heguiabehere ([@jheguia](https://www.twitter.com/jheguia))
219 |
220 | ### Who do I talk to? ###
221 | * Send an email to stic at fundacionsadosky.org.ar
222 |
223 |
--------------------------------------------------------------------------------
/client/Analyzer.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import os
27 | import sys
28 | import json
29 | import abc
30 | import traceback
31 | import threading
32 | sys.path.append(os.getcwd())
33 | import Utils
34 | from Dispatcher import *
35 | from StorageAnalyzer import StorageAnalyzer
36 | from Emulator import Emulator
37 | from libmproxy import controller, proxy
38 | from libmproxy.proxy.server import ProxyServer
39 | from libmproxy.flow import FlowWriter
40 | import logging
41 |
42 | class Analyzer(controller.Master):
43 | acting_component = None
44 |
45 | def __init__(self, filter_id, package_name, description):
46 | self.report = {}
47 | self.filter_id = filter_id
48 | self.package_name = package_name
49 | self.description = description
50 | config = proxy.ProxyConfig(port=8080,mode="transparent")
51 | server = ProxyServer(config)
52 | controller.Master.__init__(self, server)
53 | flow_dump_file = open(self.get_package_name()+"_network_traffic", "wb")
54 | self.network_flow = FlowWriter(flow_dump_file)
55 | self.should_exit = None
56 | self.extra_analyzers = [InsecureTransmissionAnalyzer(self),ZIPPathTraversalAnalyzer(self)]
57 | logging.debug("Init analyzer")
58 |
59 | def get_extra_analyzers(self):
60 | return self.extra_analyzers
61 |
62 | def get_package_name(self):
63 | return self.package_name
64 |
65 | def get_filter_id(self):
66 | return self.filter_id
67 |
68 | def get_description(self):
69 | return self.description
70 |
71 | def start_analyzer(self, error_message_queue, signal_init, signal_close):
72 | try:
73 | signal_init.set()
74 | self.should_exit = signal_close
75 | controller.Master.run(self)
76 | StorageAnalyzer(self).analyze_storage()
77 | self.send_report()
78 | except Exception:
79 | print traceback.format_exc()
80 | error_message_queue.put(traceback.format_exc())
81 | finally:
82 | self.shutdown()
83 |
84 | @staticmethod
85 | def get_analyzer():
86 | if not Analyzer.acting_component:
87 | logging.error("Analyzer: analyzer not initialized")
88 | raise Exception("Analyzer not initialized")
89 | return Analyzer.acting_component
90 |
91 |
92 | @staticmethod
93 | def get_analyzer_for(filter_id, package_name, description):
94 | if not Analyzer.acting_component:
95 | analyzer_class = Dispatcher.get_component_for(filter_id, Analyzer)
96 | logging.debug("Analyzer class: "+ repr(analyzer_class))
97 | Analyzer.acting_component = analyzer_class(filter_id, package_name, description)
98 | logging.debug("Analyzer acting component: "+ repr(Analyzer.acting_component))
99 | return Analyzer.acting_component
100 |
101 | @staticmethod
102 | def is_for(FILTER_ID):
103 | return False
104 |
105 | def add_to_report(self, key, value):
106 | self.report[key] = value
107 |
108 | def get_report(self):
109 | return self.report
110 |
111 | def handle_request(self, flow):
112 | for analyzer in self.get_extra_analyzers():
113 | analyzer.handle_request(flow)
114 | self.network_flow.add(flow)
115 | flow.reply()
116 |
117 | def handle_response(self, flow):
118 | logging.debug("Analyzer: analyzing "+ str(flow))
119 | for analyzer in self.get_extra_analyzers():
120 | try:
121 | analyzer.handle_response(flow)
122 | except Exception:
123 | print traceback.format_exc()
124 | self.network_flow.add(flow)
125 | flow.reply()
126 |
127 | def send_report(self):
128 | Utils.notify(Utils.get_reporter(), 'analyzer', Analyzer.get_analyzer().get_report())
129 |
130 |
131 | from CommonComponent.ZIPPathTraversalAnalyzer import ZIPPathTraversalAnalyzer
132 | from CommonComponent.InsecureTransmissionAnalyzer import InsecureTransmissionAnalyzer
133 | from DummyFilter.DummyAnalyzer import *
134 | from SSLFilter.SSLAnalyzer import *
135 | from PhonegapFilter.PhonegapAnalyzerJSInjection import *
136 | from PhonegapFilter.PhonegapAnalyzerCVE3500 import *
137 | from FileSchemeFilter.FileSchemeAnalyzer import *
138 | from JavascriptInterfaceFilter.JavascriptInterfaceAnalyzer import *
139 |
140 |
141 |
--------------------------------------------------------------------------------
/client/CommonComponent/AnalyzerDecorator.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 |
27 | # DummyAnalyzer for testing
28 | class AnalyzerDecorator():
29 |
30 | def __init__(self,analyzer):
31 | self.analyzer = analyzer
32 |
33 | def handle_request(self, flow):
34 | return
35 |
36 | def handle_response(self, flow):
37 | return
38 |
39 | def add_to_report(self, key, value):
40 | self.analyzer.add_to_report(key,value)
41 |
--------------------------------------------------------------------------------
/client/CommonComponent/FuzzingTrigger.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import subprocess
27 | import random
28 | from Trigger import Trigger
29 | import logging
30 |
31 | THROTTLE = 1000
32 | EVENTS_PER_TEST = 100
33 |
34 |
35 | class FuzzingTrigger(Trigger):
36 | def __init__(self, filter_id, package_name, description):
37 | Trigger.__init__(self, filter_id, package_name, description)
38 | self.throttle = 1000
39 | self.event_per_test = 100
40 |
41 | def set_throttle(self, delay):
42 | self.throttle = delay
43 |
44 | def set_events_per_test(self, event):
45 | self.event_per_test = event
46 |
47 | def trigger(self):
48 | print "Running FuzzingTrigger"
49 | seed = int(random.SystemRandom().getrandbits(32))
50 | logging.debug ("Lanzando shell monkey -p %s -v --throttle %d -s %d %d" % (
51 | self.get_package_name(), self.throttle, seed, self.event_per_test))
52 | self.get_emulator().run_adb_command('shell monkey -p %s -v --throttle %d -s %d %d' % (
53 | self.get_package_name(), self.throttle, seed, self.event_per_test))
54 | # add events to notify to server
55 |
56 |
--------------------------------------------------------------------------------
/client/CommonComponent/InsecureTransmissionAnalyzer.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from AnalyzerDecorator import AnalyzerDecorator
27 | import settings
28 |
29 |
30 | # DummyAnalyzer for testing
31 | class InsecureTransmissionAnalyzer(AnalyzerDecorator):
32 |
33 | def sensitiveValues(self):
34 | return settings.FUZZER_VALUES
35 |
36 | def privateValues(self):
37 | merged = {}
38 | for values in settings.FUZZER_PRIVACY_VALUES.values():
39 | merged.update(values)
40 | return merged
41 |
42 | def keywords(self):
43 | values = self.sensitiveValues()
44 | values.update(self.privateValues())
45 | return values
46 |
47 | def requestContains(self, flow, keyword_value):
48 | inPath = keyword_value in flow.request.path
49 | inContent =flow.request.content is not None and keyword_value in flow.request.content
50 | inHeaders = keyword_value in str(flow.request.headers)
51 | return inPath or inContent or inHeaders
52 |
53 | def handle_request(self, flow):
54 | print flow.request.headers["Host"][0]
55 | if flow.request.scheme.endswith("http"):
56 | for (key_info, private_info_fuzzer) in self.keywords().iteritems():
57 | if (self.requestContains(flow,private_info_fuzzer)):
58 | requested_site = flow.request.headers["Host"][0]
59 | self.add_to_report("INSECURE_TRANSMISSION",
60 | "Application has leaked sensitive information via insecure transmission. Type: "+key_info+". Value leaked: " + private_info_fuzzer + " in request " + requested_site + flow.request.path)
61 | AnalyzerDecorator.handle_request(self,flow)
62 |
--------------------------------------------------------------------------------
/client/CommonComponent/ZIPPathTraversalAnalyzer.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from AnalyzerDecorator import AnalyzerDecorator
27 |
28 | class ZIPPathTraversalAnalyzer(AnalyzerDecorator):
29 |
30 | def handle_response(self, flow):
31 | #check for zip file
32 | if flow.request.scheme.endswith("http") and flow.response.headers.get("Content-Type")[0].endswith("application/zip"):
33 | self.add_to_report("ZIP_PATH_TRAVERSAL","A ZIP file was downloaded using HTTP, application could be vulnerable to ZIP path traversal which could cause remote code execution or at least allowing an attacker to write to any file")
34 | AnalyzerDecorator.handle_response(self,flow)
--------------------------------------------------------------------------------
/client/CommonComponent/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 |
--------------------------------------------------------------------------------
/client/Dispatcher.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import Utils
27 |
28 |
29 | class Dispatcher(object):
30 | # find the right trigger, analyzer and reporter according to filter_ID
31 | @staticmethod
32 | def get_component_for(filter_ID, claz):
33 | #ask for subclasses and find wich one can validate the element
34 | subclasses = Utils.get_subclasses(claz)
35 | #print subclasses
36 | for subclass in subclasses:
37 | if subclass.is_for(filter_ID):
38 | return subclass #create subclass
39 | return claz
40 |
--------------------------------------------------------------------------------
/client/DummyFilter/DummyAnalyzer.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from Analyzer import Analyzer
27 |
28 | #DummyAnalyzer for testing
29 | class DummyAnalyzer(Analyzer):
30 |
31 | @staticmethod
32 | def is_for(filter_id):
33 | #attend Dummy
34 | return "dummy" == filter_id
35 |
36 |
37 |
--------------------------------------------------------------------------------
/client/DummyFilter/DummyReporter.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from Reporter import Reporter
27 |
28 | #Dummy DummyReporter for testing
29 | class DummyReporter(Reporter):
30 |
31 | @staticmethod
32 | def is_for(filter_id):
33 | #attend Dummy
34 | return "dummy" == filter_id
35 |
36 | #overrides
37 | def create_vm_reports(self,trigger,analyzer):
38 | return {'status':'UNKNOWN','description':{'trigger':trigger,'analyzer':analyzer}}
39 |
40 |
--------------------------------------------------------------------------------
/client/DummyFilter/DummyTrigger.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import subprocess
27 | import random
28 | from CommonComponent.FuzzingTrigger import FuzzingTrigger
29 |
30 | THROTTLE = 1000
31 | EVENTS_PER_TEST = 100
32 |
33 | class DummyTrigger(FuzzingTrigger):
34 |
35 | @staticmethod
36 | def is_for(filter_id):
37 | #attend Dummy
38 | return filter_id == "dummy"
39 |
40 | #overrides
41 | def trigger(self):
42 | FuzzingTrigger.trigger(self)
43 |
44 |
45 |
--------------------------------------------------------------------------------
/client/DummyFilter/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 |
--------------------------------------------------------------------------------
/client/Emulator.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import abc
27 | import time
28 | import Utils
29 | import netifaces
30 | import logging
31 |
32 | class Emulator(object):
33 | acting_component = None
34 |
35 | def __init__(self, filter_id, package_name, description):
36 | self.remote_ip = description['emulator'] + ':5556'
37 | Utils.run_blocking_cmd("adb connect {0}:5556".format(self.remote_ip))
38 | Utils.run_blocking_cmd("adb root")
39 | logging.debug("waiting to connect to adb as root")
40 | time.sleep(5)
41 | Utils.run_blocking_cmd("adb connect {0}:5556".format(self.remote_ip))
42 | logging.debug("connected to adb as root")
43 |
44 | @staticmethod
45 | def get_emulator_for(filter_id, package_name, description):
46 | if not Emulator.acting_component:
47 | Emulator.acting_component = Emulator(filter_id, package_name, description)
48 | return Emulator.acting_component
49 |
50 | @staticmethod
51 | def get_emulator():
52 | return Emulator.acting_component
53 |
54 | def set_localhost_as_gateway(self):
55 | local_address = netifaces.ifaddresses('eth0')[netifaces.AF_INET][0]['addr']
56 | return self.run_adb_command('shell \"busybox route add -host {0} dev eth0; busybox route delete default; route add default gw {0} dev eth0\"'.format(local_address))
57 |
58 | def disconnect(self):
59 | return Utils.run_blocking_cmd("adb disconnect")
60 |
61 | def get_remote_ip(self):
62 | return self.remote_ip.split(":")[0]
63 |
64 | def run_adb_command(self, command):
65 | return Utils.run_blocking_cmd("adb -s {0} ".format(self.remote_ip) + command)
66 |
--------------------------------------------------------------------------------
/client/FileSchemeFilter/FileSchemeAnalyzer.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from Analyzer import Analyzer
27 | import base64
28 |
29 | # DummyAnalyzer for testing
30 | class FileSchemeAnalyzer(Analyzer):
31 | @staticmethod
32 | def is_for(filter_id):
33 | # attend Dummy
34 | return "WEBVIEW_FILE_SCHEME" == filter_id
35 |
36 | def handle_request(self, flow):
37 | if flow.request.path.find("?vulnerable_file_scheme") != -1:
38 | activity_index = flow.request.path.find("&activity=")
39 | self.add_to_report(self.get_filter_id(),
40 | "Dynamically verified that Javascript can be inyected running as file:// scheme via an Intent to " + base64.b64decode(
41 | flow.request.path[
42 | activity_index + len(
43 | "&activity="):]))
44 | Analyzer.handle_request(self,flow)
--------------------------------------------------------------------------------
/client/FileSchemeFilter/FileSchemeReporter.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from Reporter import Reporter
27 |
28 | # Dummy DummyReporter for testing
29 | class FileSchemeReporter(Reporter):
30 | @staticmethod
31 | def is_for(filter_id):
32 | #attend Dummy
33 | return "WEBVIEW_FILE_SCHEME" == filter_id
34 |
35 | #overrides
36 | def create_vm_reports(self, trigger, analyzer):
37 | if len(analyzer.keys()):
38 | return {'status': 'SUCCESS', 'description': analyzer}
39 | else:
40 | return {'status': 'UNKNOWN', 'description': analyzer}
41 |
--------------------------------------------------------------------------------
/client/FileSchemeFilter/FileSchemeTrigger.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import time
27 | import base64
28 | from Trigger import Trigger
29 |
30 | THROTTLE = 1000
31 | EVENTS_PER_TEST = 500
32 |
33 |
34 | class FileSchemeTrigger(Trigger):
35 | @staticmethod
36 | def is_for(filter_id):
37 | # attend Dummy
38 | return "WEBVIEW_FILE_SCHEME" == filter_id
39 |
40 |
41 | def get_exported_activity(self):
42 | return self.get_description()["activity"]
43 |
44 | # overrides
45 | def trigger(self):
46 | html = '''
47 |
48 |
49 |
50 | Webview File Scheme Test
51 |
52 |
53 |
54 |
62 | Webview File Scheme Test
63 |
64 |
65 | '''
66 | with open("test.html", "w") as local:
67 | local.write(html)
68 | self.get_emulator().run_adb_command('push test.html /mnt/sdcard/test.html')
69 | self.get_emulator().run_adb_command(
70 | "shell am start -n {0}/{1} file://mnt/sdcard/test.html".format(
71 | self.get_package_name(), self.get_exported_activity()))
72 | time.sleep(4)
73 | print "shell am start -n {0}/{1} file://mnt/sdcard/test.html".format(
74 | self.get_package_name(), self.get_exported_activity())
75 | self.get_emulator().run_adb_command(
76 | "shell am start -a android.intent.action.VIEW -a android.intent.category.BROWSEABLE -n {0}/{1} \"file://mnt/sdcard/test.html\"".format(
77 | self.get_package_name(), self.get_exported_activity()))
78 | # TODO: how to wait for app trying to load?
79 | time.sleep(4)
--------------------------------------------------------------------------------
/client/FileSchemeFilter/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 |
--------------------------------------------------------------------------------
/client/JavascriptInterfaceFilter/JavascriptInterfaceAnalyzer.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from Analyzer import Analyzer
27 | from libmproxy.protocol.http import decoded
28 | import lxml.html
29 | import base64
30 | import sys
31 |
32 |
33 | class JavascriptInterfaceAnalyzer(Analyzer):
34 |
35 | @staticmethod
36 | def is_for(filter_id):
37 | # attend Dummy
38 | return "JAVASCRIPTINTERFACE" == filter_id
39 |
40 | def handle_request(self, flow):
41 | if flow.request.path.find("?vulnerable_javascript_injection") != -1:
42 | visited_url_index = flow.request.path.find("&url=")
43 | interface_url_index = flow.request.path.find("&interface=")
44 | self.add_to_report(self.get_filter_id(),
45 | "Dynamically verified that malicious Javascript can be injected via HTTP via url %s and can run arbitrary code via the Javascript Interface %s" % (
46 | base64.b64decode(
47 | flow.request.path[visited_url_index + len("&url="):]),
48 | flow.request.path[interface_url_index + len("&interface="):visited_url_index]))
49 | Analyzer.handle_request(self,flow)
50 |
51 | def handle_response(self, flow):
52 | print "request path is %s " % flow.request.path
53 | # If it's injectable and it's not the injected request
54 | requested_site = flow.request.headers["Host"][0]
55 | if flow.request.scheme.endswith("http") and requested_site.find("www.fundacionsadosky.org.ar") == -1:
56 | visited_url = base64.b64encode(requested_site + flow.request.path)
57 | #taken from www.droidsec.org/tests/addjsif/
58 | script = '''vulnerable=[];for(i in top){el=top[i];if(el==null){continue};if(typeof(el)==='function'){continue}try{top[i].getClass().forName('java.lang.Runtime');vulnerable.push(i)}catch(e){}}if(vulnerable.length>0){var request=new XMLHttpRequest();request.open("GET","http://www.fundacionsadosky.org.ar/?vulnerable_javascript_injection=true&interface="+vulnerable.join()+"&url=''' + visited_url + '''",true);request.onreadystatechange=function(){};request.send()}'''
59 | content_type = flow.response.headers.get("Content-Type")
60 | if not content_type:
61 | content_type = flow.response.headers.get("Content-type")
62 | if content_type and "text/html" in content_type[0]:
63 | with decoded(flow.response): # automatically decode gzipped responses.
64 | if flow.response.content:
65 | try:
66 | response = flow.response.content
67 | print "Response is "+response
68 | root = lxml.html.fromstring(response)
69 | if root.find('.//*') is not None:
70 | print "TRIED MODIFYING /html " + requested_site+ flow.request.path
71 | # is HTML, use lxml to insert to head, body or script
72 | append_in = root.find('.//head')
73 | if append_in is None:
74 | append_in = root.find('.//body')
75 | elif append_in is None:
76 | append_in = root.find('.//script').getparent()
77 | else:
78 | append_in = root
79 | script = lxml.html.fromstring('')
80 | if append_in is not None:
81 | append_in.append(script)
82 | flow.response.content = lxml.html.tostring(root)
83 | except:
84 | print "There was a problem parsing the html response, skip it"
85 | # mimetype may be application/javascript or text/javascript
86 | elif content_type and "javascript" in content_type[0]:
87 | with decoded(flow.response): # automatically decode gzipped responses.
88 | print "TRIED MODIFYING /javascript " + requested_site + flow.request.path
89 | # is searching for library .JS (both cases sensitive) or JQUERY
90 | flow.response.content = script.encode("utf-8") + flow.response.content
91 | Analyzer.handle_response(self,flow)
92 |
--------------------------------------------------------------------------------
/client/JavascriptInterfaceFilter/JavascriptInterfaceReporter.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from Reporter import Reporter
27 |
28 | # Dummy DummyReporter for testing
29 | class JavascriptInterfaceAnalyzer(Reporter):
30 | @staticmethod
31 | def is_for(filter_id):
32 | # attend Dummy
33 | return "JAVASCRIPTINTERFACE" == filter_id
34 |
35 | # overrides
36 | def create_vm_reports(self, trigger, analyzer):
37 | if len(analyzer.keys()):
38 | return {'status': 'SUCCESS', 'description': analyzer}
39 | else:
40 | return {'status': 'UNKNOWN', 'description': analyzer}
41 |
--------------------------------------------------------------------------------
/client/JavascriptInterfaceFilter/JavascriptInterfaceTrigger.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import Utils
27 | import time
28 | from CommonComponent.FuzzingTrigger import FuzzingTrigger
29 | import logging
30 |
31 | THROTTLE = 1000
32 | EVENTS_PER_TEST = 500
33 |
34 |
35 | class JavascriptTrigger(FuzzingTrigger):
36 | def __init__(self, filter_id, package_name, description):
37 | FuzzingTrigger.__init__(self, filter_id, package_name, description)
38 |
39 | @staticmethod
40 | def is_for(filter_id):
41 | # attend Dummy
42 | return "JAVASCRIPTINTERFACE" == filter_id
43 |
44 | def trigger(self):
45 | # delay throttle since there's a lot of communication to be made probably
46 | self.set_throttle(4000)
47 | #halve the events so it doesn't take that much
48 | self.set_events_per_test(50)
49 | logging.debug("Lanzando FuzzingTrigger")
50 | FuzzingTrigger.trigger(self)
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/client/JavascriptInterfaceFilter/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 |
--------------------------------------------------------------------------------
/client/PhonegapFilter/PhonegapAnalyzerCVE3500.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from Analyzer import Analyzer
27 | from libmproxy.protocol.http import decoded
28 | import lxml.html
29 | import base64
30 |
31 | # DummyAnalyzer for testing
32 | class PhonegapAnalyzer(Analyzer):
33 | def __init__(self, filter_id, package_name, description):
34 | Analyzer.__init__(self,filter_id, package_name, description)
35 | # number of ocurrences of inyection, to add in report
36 | self.inyection_count = 0
37 |
38 | @staticmethod
39 | def is_for(filter_id):
40 | # attend Dummy
41 | return "PHONEGAP_CVE_3500_URL" == filter_id
42 |
43 | def handle_request(self, flow):
44 | if flow.request.path.find("?vulnerable_cve_3500") != -1:
45 | self.add_to_report(self.get_filter_id(), "Dynamically verified that application is vulnerable to CVE-3500")
46 | Analyzer.handle_request(self,flow)
47 |
--------------------------------------------------------------------------------
/client/PhonegapFilter/PhonegapAnalyzerJSInjection.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from Analyzer import Analyzer
27 | from libmproxy.protocol.http import decoded
28 | import lxml.html
29 | import base64
30 | from JavascriptInterfaceFilter.JavascriptInterfaceAnalyzer import JavascriptInterfaceAnalyzer
31 | # DummyAnalyzer for testing
32 | class PhonegapAnalyzer(JavascriptInterfaceAnalyzer):
33 |
34 | @staticmethod
35 | def is_for(filter_id):
36 | # attend Dummy
37 | return "PHONEGAP_JS_INJECTION" == filter_id
38 |
39 | def handle_request(self, flow):
40 | if flow.request.path.find("?vulnerable_javascript_injection") != -1:
41 | visited_url_index = flow.request.path.find("&url=")
42 | self.add_to_report(self.get_filter_id(),
43 | "Dynamically verified that malicious Javascript can be injected via HTTP via url %s" % base64.b64decode(
44 | flow.request.path[visited_url_index + 5:]))
45 | Analyzer.handle_request(self,flow)
46 |
47 |
--------------------------------------------------------------------------------
/client/PhonegapFilter/PhonegapReporter.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from Reporter import Reporter
27 |
28 | # Dummy DummyReporter for testing
29 | class PhonegapReporter(Reporter):
30 | @staticmethod
31 | def is_for(filter_id):
32 | # attend Dummy
33 | return "PHONEGAP_JS_INJECTION" == filter_id or \
34 | "PHONEGAP_CVE_3500_URL" == filter_id
35 |
36 | # overrides
37 | def create_vm_reports(self, trigger, analyzer):
38 | if len(analyzer.keys()):
39 | return {'status': 'SUCCESS', 'description': analyzer}
40 | else:
41 | return {'status': 'UNKNOWN', 'description': analyzer}
42 |
--------------------------------------------------------------------------------
/client/PhonegapFilter/PhonegapTriggerCVE3500.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import Utils
27 | import time
28 | import traceback
29 | from CommonComponent.FuzzingTrigger import FuzzingTrigger
30 |
31 | THROTTLE = 1000
32 | EVENTS_PER_TEST = 500
33 |
34 |
35 | class PhonegapTrigger(FuzzingTrigger):
36 | @staticmethod
37 | def is_for(filter_id):
38 | # attend Dummy
39 | return "PHONEGAP_CVE_3500_URL" == filter_id
40 |
41 | def get_main_activity(self):
42 | return self.get_description()["activity"]
43 |
44 | def test_cve_3500(self):
45 | html = '''
46 |
47 |
48 |
49 | Testing Phonegap CVE-2014-3500
50 |
51 |
52 |
53 |
65 | Testing Phonegap CVE-2014-3500
66 |
67 |
68 | '''
69 | with open("test.html", "w") as local:
70 | local.write(html)
71 | self.get_emulator().run_adb_command('push test.html /sdcard/test.html')
72 | self.get_emulator().run_adb_command(
73 | "shell am start -a android.intent.action.MAIN -n {0}/{1} --es url file:///sdcard/test.html".format(
74 | self.get_package_name(), self.get_main_activity()))
75 | time.sleep(3)
76 |
77 |
78 | def trigger(self):
79 | self.test_cve_3500()
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/client/PhonegapFilter/PhonegapTriggerJSInjection.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import Utils
27 | import time
28 | from CommonComponent.FuzzingTrigger import FuzzingTrigger
29 |
30 | THROTTLE = 1000
31 | EVENTS_PER_TEST = 500
32 |
33 |
34 | class PhonegapTrigger(FuzzingTrigger):
35 | @staticmethod
36 | def is_for(filter_id):
37 | # attend Dummy
38 | return "PHONEGAP_JS_INJECTION" == filter_id
39 |
40 | def test_javascript_inyection(self):
41 | # delay throttle since there's a lot of communication to be made probably
42 | self.set_throttle(4000)
43 | # halve the events so it doesn't take that much
44 | self.set_events_per_test(100)
45 | FuzzingTrigger.trigger(self)
46 |
47 | def trigger(self):
48 | self.test_javascript_inyection()
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/client/PhonegapFilter/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 |
--------------------------------------------------------------------------------
/client/Reporter.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import SimpleHTTPServer
27 | import SocketServer
28 | import os
29 | import abc
30 | import sys
31 | import logging
32 | import traceback
33 | import json
34 | import threading
35 | import multiprocessing
36 | from Dispatcher import *
37 | from Emulator import Emulator
38 |
39 |
40 | class ReporterHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
41 | report = {}
42 |
43 | def is_full_report(self):
44 | return len(ReporterHandler.report.keys()) == 2
45 |
46 | # only has POST
47 |
48 | def do_POST(self):
49 | # logging.warning("======= POST STARTED =======")
50 | try:
51 | if self.path == '/trigger' or self.path == '/analyzer':
52 | length = int(self.headers['Content-Length'])
53 | content = json.loads(self.rfile.read(length).decode('utf-8'))
54 | #save any of those two reports
55 | ReporterHandler.report[self.path[1:]] = content
56 | logging.warning(ReporterHandler.report)
57 | if self.is_full_report(): #have both reports already
58 | Reporter.get_reporter().send_report(ReporterHandler.report['trigger'],
59 | ReporterHandler.report['analyzer'])
60 | self.send_response(200)
61 | else:
62 | self.send_response(404)
63 | return
64 | except:
65 | logging.warning(traceback.format_exc())
66 | self.send_response(500)
67 |
68 |
69 | class Reporter(object):
70 | acting_component = None
71 |
72 | def __init__(self, filter_id, package_name, description):
73 | self.filter_id = filter_id
74 | self.package_name = package_name
75 | self.description = description
76 |
77 | @staticmethod
78 | def get_reporter():
79 | if not Reporter.acting_component:
80 | raise Exception("Reporter not initialized")
81 | return Reporter.acting_component
82 |
83 | @staticmethod
84 | def get_reporter_for(filter_id, package_name, description):
85 | if not Reporter.acting_component:
86 | reporter_class = Dispatcher.get_component_for(filter_id, Reporter)
87 | Reporter.acting_component = reporter_class(filter_id, package_name, description)
88 | return Reporter.acting_component
89 |
90 | @staticmethod
91 | # returns if its for FILTER_ID
92 | def is_for(filter_id):
93 | return False
94 |
95 | def get_package_name(self):
96 | return self.package_name
97 |
98 | def get_filter_id(self):
99 | return self.filter_id
100 |
101 | def get_description(self):
102 | return self.description
103 |
104 | def start_reporter(self, error_message_queue,signal_init,signal_close):
105 | try:
106 | Handler = ReporterHandler
107 | SocketServer.TCPServer.allow_reuse_address = True
108 | server = SocketServer.TCPServer(('localhost', 8081), Handler)
109 | server_thread = threading.Thread(target=server.serve_forever,args=())
110 | server_thread.start()
111 | signal_init.set()
112 | signal_close.wait()
113 | server.shutdown()
114 | except Exception:
115 | print traceback.format_exc()
116 | error_message_queue.put(traceback.format_exc())
117 |
118 | @abc.abstractmethod
119 | def create_vm_reports(self, trigger_rep, analyzer_rep):
120 | # create final report to send VM Manager
121 | ip = Emulator.get_emulator().get_remote_ip()
122 | return {'status': 'ERROR', 'emulator': ip, 'description': {'errors': 'Called abstract method from reporter'}}
123 |
124 | def send_report(self, trigger, analyzer):
125 | filter_report = self.create_vm_reports(trigger, analyzer)
126 | ip = Emulator.get_emulator().get_remote_ip()
127 | filter_report['emulator'] = ip
128 | if Utils.isTestingMode():
129 | print "FINAL REPORT "
130 | print filter_report
131 | else:
132 | Utils.notify(Utils.get_VM_Manager(), 'report', filter_report)
133 |
134 |
135 | from DummyFilter.DummyReporter import *
136 | from SSLFilter.SSLReporter import *
137 | from FileSchemeFilter.FileSchemeReporter import *
138 | from PhonegapFilter.PhonegapReporter import *
139 | from JavascriptInterfaceFilter.JavascriptInterfaceReporter import *
140 |
141 |
--------------------------------------------------------------------------------
/client/SSLFilter/SSLAnalyzer.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from Analyzer import Analyzer
27 |
28 | # DummyAnalyzer for testing
29 | class SSLAnalyzer(Analyzer):
30 | @staticmethod
31 | def is_for(filter_id):
32 | # attend Dummy
33 | return filter_id in [
34 | "SSL_CUSTOM_TRUSTMANAGER",
35 | "SSL_CUSTOM_HOSTNAMEVERIFIER",
36 | "SSL_ALLOWALL_HOSTNAMEVERIFIER",
37 | "SSL_INSECURE_SOCKET_FACTORY",
38 | "SSL_WEBVIEW_ERROR"
39 | ]
40 |
41 | def handle_request(self, flow):
42 | if flow.request.scheme.endswith("https"):
43 | self.add_to_report(self.get_filter_id(),
44 | 'SSL connection to host %s, app not validating certificates properly' % (
45 | flow.request.headers["Host"][0] + flow.request.path))
46 | Analyzer.handle_request(self,flow)
47 |
48 |
--------------------------------------------------------------------------------
/client/SSLFilter/SSLReporter.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from Reporter import Reporter
27 |
28 | # Dummy DummyReporter for testing
29 | class SSLReporter(Reporter):
30 | @staticmethod
31 | def is_for(filter_id):
32 | # attend Dummy
33 | return filter_id in [
34 | "SSL_CUSTOM_TRUSTMANAGER",
35 | "SSL_CUSTOM_HOSTNAMEVERIFIER",
36 | "SSL_ALLOWALL_HOSTNAMEVERIFIER",
37 | "SSL_INSECURE_SOCKET_FACTORY",
38 | "SSL_WEBVIEW_ERROR"
39 | ]
40 |
41 | #overrides
42 | def create_vm_reports(self, trigger, analyzer):
43 | if len(analyzer.keys()):
44 | return {'status': 'SUCCESS', 'description': analyzer}
45 | else:
46 | return {'status': 'UNKNOWN', 'description': analyzer}
47 |
--------------------------------------------------------------------------------
/client/SSLFilter/SSLTrigger.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import subprocess
27 | import random
28 | from Trigger import Trigger
29 | from CommonComponent.FuzzingTrigger import FuzzingTrigger
30 |
31 | THROTTLE = 1000
32 | EVENTS_PER_TEST = 500
33 |
34 |
35 | class SSLTrigger(FuzzingTrigger):
36 | def __init__(self, filter_id, package_name, description):
37 | FuzzingTrigger.__init__(self, filter_id, package_name, description)
38 | self.set_events_per_test(200)
39 |
40 | @staticmethod
41 | def is_for(filter_id):
42 | # attend Dummy
43 | return filter_id in [
44 | "SSL_CUSTOM_TRUSTMANAGER",
45 | "SSL_CUSTOM_HOSTNAMEVERIFIER",
46 | "SSL_ALLOWALL_HOSTNAMEVERIFIER",
47 | "SSL_INSECURE_SOCKET_FACTORY",
48 | "SSL_WEBVIEW_ERROR"
49 | ]
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/client/SSLFilter/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 |
--------------------------------------------------------------------------------
/client/StorageAnalyzer.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import subprocess
27 | import shlex
28 | import os
29 | import sqlite3
30 | import traceback
31 | from Emulator import Emulator
32 | import settings
33 |
34 |
35 | class StorageAnalyzer(object):
36 | def __init__(self, analyzer):
37 | self.analyzer = analyzer
38 |
39 | def sensitiveValues(self):
40 | return settings.FUZZER_VALUES
41 |
42 | def extracted_storage_dir(self):
43 | return self.analyzer.get_package_name() + "_files"
44 |
45 | def internal_storage_dir(self):
46 | return self.extracted_storage_dir() + "/internal_storage/"
47 |
48 | def modified_sdcard_dir(self):
49 | return self.extracted_storage_dir() + "/sdcard_modified_files/"
50 |
51 | def extract_storage(self):
52 | emulator = Emulator.get_emulator()
53 | directory = self.extracted_storage_dir()
54 | if not os.path.exists(directory):
55 | os.makedirs(directory)
56 | # dump internal memory and sdcard
57 | emulator.run_adb_command(
58 | "pull /data/data/" + self.analyzer.get_package_name() + " " + self.internal_storage_dir())
59 | emulator.run_adb_command("pull /sdcard/" + " " + self.modified_sdcard_dir())
60 |
61 | def is_database(self, fileName):
62 | cmd = shlex.split('file {0}'.format(fileName))
63 | result = subprocess.check_output(cmd)
64 | type = result.split(':')[1]
65 | return 'SQLite' in type
66 |
67 | def get_filter_id(self):
68 | return "INSECURE_STORAGE"
69 |
70 | def search_for_plaintext_in_db(self, connection, table, database):
71 | cursor = connection.cursor()
72 | cursor.execute("SELECT * FROM '{0}';".format(table))
73 | for row in cursor:
74 | for keyword, value in self.sensitiveValues().iteritems():
75 | if value in row:
76 | self.analyzer.add_to_report(self.get_filter_id(),
77 | "Found plaintext {0} (value {1}) in table {2} of database {3}".format(keyword, value, table,
78 | database))
79 |
80 | def search_for_plaintext(self, file):
81 | content = open(file).read()
82 | for keyword, value in self.sensitiveValues().iteritems():
83 | if value in content:
84 | self.analyzer.add_to_report(self.get_filter_id(),
85 | "Found plaintext {0} (value {1}) in file {2}".format(keyword, value, file))
86 |
87 | def analyze_shared_preferences(self, path):
88 | self.analyze_files(path)
89 |
90 | def analyze_files(self, path):
91 | for subdir, dirs, files in os.walk(path):
92 | for file in files:
93 | filePath = os.path.join(subdir, file)
94 | self.search_for_plaintext(filePath)
95 |
96 | def analyze_storage(self):
97 | self.extract_storage()
98 | self.analyze_database(self.internal_storage_dir() + 'databases/')
99 | self.analyze_shared_preferences(self.internal_storage_dir() + 'shared_prefs/')
100 | self.analyze_files(self.internal_storage_dir() + 'files/')
101 |
102 | def analyze_database(self, path):
103 | for subdir, dirs, files in os.walk(path):
104 | for file in files:
105 | filePath = os.path.join(subdir, file)
106 | try:
107 | if self.is_database(filePath):
108 | con = sqlite3.connect(filePath)
109 | cursor = con.cursor()
110 | cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
111 | for table in cursor:
112 | self.search_for_plaintext_in_db(con, table[0], filePath)
113 | except:
114 | print "Error " + filePath
115 | print traceback.format_exc()
116 |
--------------------------------------------------------------------------------
/client/Trigger.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import abc
27 | import traceback
28 | from Dispatcher import *
29 | from Emulator import Emulator
30 | # Import Filters after defining trigger
31 |
32 | class Trigger(object):
33 | # only need one component
34 | acting_component = None
35 |
36 | def __init__(self, filter_id, package_name, description):
37 | self.report = {}
38 | self.filter_id = filter_id
39 | self.package_name = package_name
40 | self.description = description
41 |
42 | def get_package_name(self):
43 | return self.package_name
44 |
45 | def get_filter_id(self):
46 | return self.filter_id
47 |
48 | def get_description(self):
49 | return self.description
50 |
51 | def get_emulator(self):
52 | return Emulator.get_emulator()
53 |
54 | @staticmethod
55 | def get_trigger():
56 | if not Trigger.acting_component:
57 | raise Exception("Trigger not initialized")
58 | return Trigger.acting_component
59 |
60 | @staticmethod
61 | def get_trigger_for(filter_id, package_name, description):
62 | if not Trigger.acting_component:
63 | trigger_class = Dispatcher.get_component_for(filter_id, Trigger)
64 | Trigger.acting_component = trigger_class(filter_id, package_name, description)
65 | return Trigger.acting_component
66 |
67 | @staticmethod
68 | # returns if its for FILTER_ID
69 | def is_for(FILTER_ID):
70 | return False
71 |
72 | @abc.abstractmethod
73 | def trigger(self):
74 | print "Trigger Base class"
75 |
76 | def add_to_report(self, key, value):
77 | if self.report[key]:
78 | self.report[key] = value
79 | else:
80 | self.report[key].append(value)
81 |
82 | def get_report(self):
83 | return self.report
84 |
85 | def send_report(self):
86 | Utils.notify(Utils.get_reporter(), 'trigger', self.get_report())
87 |
88 | def start_trigger(self, error_message_queue, signal_init, signal_close):
89 | try:
90 | # do not block VMclient
91 | signal_init.set()
92 | self.trigger()
93 | self.send_report()
94 | except Exception:
95 | print traceback.format_exc()
96 | error_message_queue.put(traceback.format_exc())
97 |
98 |
99 | from DummyFilter.DummyTrigger import *
100 | from SSLFilter.SSLTrigger import *
101 | from PhonegapFilter.PhonegapTriggerJSInjection import *
102 | from PhonegapFilter.PhonegapTriggerCVE3500 import *
103 | from FileSchemeFilter.FileSchemeTrigger import *
104 | from JavascriptInterfaceFilter.JavascriptInterfaceTrigger import *
105 |
106 |
107 |
--------------------------------------------------------------------------------
/client/Utils.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import urllib2
27 | import subprocess
28 | import shlex
29 | import traceback
30 | import json
31 | import settings
32 | import logging
33 |
34 | def isTestingMode():
35 | return settings.DEBUG_MODE
36 |
37 |
38 | def notify(address, path, params):
39 | logging.debug("Notifying "+address+'/'+path)
40 | data = json.dumps(params)
41 | url = '''http://''' + address + '/' + path
42 | try:
43 | logging.debug("Trigger: notify "+url +", data: "+data)
44 | request = urllib2.Request(url, data=data, headers={'Content-Type': 'application/json'})
45 | return urllib2.urlopen(request).read()
46 | except:
47 | print traceback.format_exc()
48 | logging.error(traceback.format_exc())
49 | pass
50 |
51 |
52 | def run_non_blocking_cmd(command):
53 | logging.debug("Running non-blocking command: "+command)
54 | return subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
55 |
56 |
57 | def log_process(p):
58 | if not p:
59 | return "process is null"
60 | s = None
61 | if p.poll() is not None:
62 | s = "process has finished already. Return code: %s\n" % p.returncode
63 | else:
64 | s = "process hasn't finished. Terminating it."
65 | p.kill()
66 | o, e = p.communicate()
67 | s += "STDOUT: %s, STDERR : %s " % (o, e)
68 | return s
69 |
70 |
71 | def run_blocking_cmd(command):
72 | logging.debug("Running blocking command: "+command)
73 | return subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
74 |
75 |
76 | def get_subclasses(c):
77 | subclasses = c.__subclasses__()
78 | #logging.debug("Subclassing " + repr(c)+". First list: " + repr(subclasses))
79 | for d in list(subclasses):
80 | subclasses.extend(get_subclasses(d))
81 | #logging.debug ("Subclassing "+repr(c)+" : Final list: " + repr(subclasses))
82 | return subclasses
83 |
84 |
85 | def get_VM_Manager():
86 | return settings.VM_MANAGER_IP
87 |
88 |
89 | def get_reporter():
90 | return settings.REPORTER_IP
91 |
--------------------------------------------------------------------------------
/client/VMClient.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | # -*- coding: utf-8 -*-
27 | import time
28 | import Utils
29 | import urllib
30 | import urllib2
31 | import traceback
32 | import sys
33 | import json
34 | import multiprocessing
35 | from Reporter import Reporter
36 | from Trigger import Trigger
37 | from Analyzer import Analyzer
38 | from Emulator import Emulator
39 | import Queue
40 | import threading
41 | import logging
42 |
43 |
44 | class VMClient(object):
45 | # since it's not thread safe, no modification of VMClient should occur during running of Trigger or Reporter
46 | vm_client = None
47 |
48 | @classmethod
49 | def get_VM_client(cls):
50 | if cls.vm_client is None:
51 | cls.vm_client = VMClient()
52 | return cls.vm_client
53 |
54 | def __init__(self):
55 | logging.basicConfig(filename="/tmp/VMClient.log", level=logging.DEBUG)
56 | self.get_apk_from_manager()
57 | self.trigger = Trigger.get_trigger_for(self.get_filter_tag(), self.get_package_name(), self.get_description())
58 | self.reporter = Reporter.get_reporter_for(self.get_filter_tag(), self.get_package_name(),
59 | self.get_description())
60 | self.analyzer = Analyzer.get_analyzer_for(self.get_filter_tag(), self.get_package_name(),
61 | self.get_description())
62 | self.emulator = Emulator.get_emulator_for(self.get_filter_tag(), self.get_package_name(),
63 | self.get_description())
64 | self.error_queue = multiprocessing.Queue()
65 | self.setup_device()
66 | logging.debug("Init successful")
67 | logging.debug("Trigger: " + repr(self.trigger))
68 | logging.debug("Reporter: " + repr(self.reporter))
69 | logging.debug("Analyzer: " + repr(self.analyzer))
70 | logging.debug("Emulator: " + repr(self.emulator))
71 |
72 | def get_emulator(self):
73 | return self.emulator
74 |
75 | def get_package_name(self):
76 | return self.package_name
77 |
78 | def get_filter_tag(self):
79 | return self.filter_id
80 |
81 | def get_description(self):
82 | return self.description
83 |
84 | def get_apk_from_manager(self):
85 | if Utils.isTestingMode():
86 | print "VMClient is being tested"
87 | self.filter_id = sys.argv[1]
88 | self.package_name = sys.argv[2]
89 | self.description = json.loads(sys.argv[3])
90 | logging.debug("VULNERABILITY: " + self.filter_id)
91 | logging.debug("PACKAGE: " + self.package_name)
92 | logging.debug("DESCRIPTION: " + json.dumps(self.description))
93 | else:
94 | url = '''http://''' + Utils.get_VM_Manager() + '/apk'
95 | # Open the url
96 | try:
97 | response = urllib.urlopen(url)
98 | self.filter_id = response.info().dict['filter']
99 | self.package_name = response.info().dict['apk'] # save only name
100 | download_url = response.info().dict['download_url'] # save only name
101 | content = response.read()
102 | self.description = json.loads(content)
103 | response = urllib.urlopen(download_url)
104 | # Open our local file for writing
105 | with open(self.package_name + ".apk", "w") as local_file:
106 | local_file.write(response.read())
107 | local_file.flush()
108 | local_file.close()
109 | # handle errors
110 | print "HANDLING:"
111 | print "VULNERABILITY: " + self.filter_id
112 | print "PACKAGE: " + self.package_name
113 | print "DESCRIPTION: " + json.dumps(self.description)
114 | except urllib2.HTTPError, e:
115 | print "HTTP Error:", e.code, url
116 | except urllib2.URLError, e:
117 | print "URL Error:", e.reason, url
118 |
119 | def send_FAIL_signal(self,description):
120 | headers = {'status': 'ERROR', 'emulator': self.get_emulator().get_remote_ip(),
121 | 'description': description}
122 | logging.error(description)
123 | Utils.notify(Utils.get_VM_Manager(), 'error', headers)
124 |
125 | def setup_device(self):
126 | emulator = self.get_emulator()
127 | # install application
128 | (output, err) = emulator.run_adb_command('install -r %s' % (self.package_name + ".apk"))
129 | self.add_error_message(output)
130 | self.add_error_message(err)
131 | logging.debug(err)
132 | #set client as gateway so analyzer intercepts traffic
133 | message = self.emulator.set_localhost_as_gateway()
134 | logging.debug("Setting localhost as gateway: "+ str(message))
135 |
136 |
137 | def start_trigger_process(self):
138 | return self.start_component_and_wait_for_initialization(self.trigger.start_trigger)
139 |
140 | def start_analyzer_process(self):
141 | return self.start_component_and_wait_for_initialization(self.analyzer.start_analyzer)
142 |
143 | def start_reporter_process(self):
144 | return self.start_component_and_wait_for_initialization(self.reporter.start_reporter)
145 |
146 | def start_component_and_wait_for_initialization(self, target):
147 | signal_init = multiprocessing.Event()
148 | signal_close = multiprocessing.Event()
149 | process = multiprocessing.Process(target=target, args=(self.error_queue, signal_init, signal_close))
150 | process.start()
151 | # wait for initialization
152 | signal_init.wait()
153 | return (process, signal_close)
154 |
155 | def wait_for_component(self, component):
156 | component[1].set()
157 | component[0].join()
158 |
159 | def time_out(self):
160 | print "A time out has occurred, the analysis failed"
161 | self.add_error_message("THE TEST TIMED OUT")
162 | logging.error("Test timed out")
163 | self.send_errors()
164 |
165 | def add_error_message(self, message):
166 | logging.error(message)
167 | self.error_queue.put(message)
168 |
169 | def send_errors(self):
170 | errors = []
171 | while True:
172 | try:
173 | errors.append(self.error_queue.get_nowait())
174 | except Queue.Empty:
175 | break
176 | self.send_FAIL_signal({"errors": errors})
177 |
178 | def start_timeout_error_handler(self):
179 | self.timer = threading.Timer(300, self.time_out)
180 | self.timer.start()
181 |
182 | def finish_timeout_error_handler(self):
183 | self.timer.cancel()
184 |
185 | def get_max_tries(self):
186 | return 1000
187 |
188 | def start_components(self):
189 | try:
190 | self.start_timeout_error_handler()
191 | if (Utils.isTestingMode() == False) and int(self.get_description()['count']) > self.get_max_tries():
192 | self.send_FAIL_signal({'tries': 'Couldn\'t verify the vulnerability dinamically'})
193 | else:
194 | analyzer = self.start_analyzer_process()
195 | reporter = self.start_reporter_process()
196 | # waits for reporter and analyzer to start before trigger.
197 | trigger = self.start_trigger_process()
198 | # wait trigger process to finish
199 | self.wait_for_component(trigger)
200 | logging.debug("already closed trigger")
201 | print "already closed trigger"
202 | # signal end of trigger
203 | self.wait_for_component(analyzer)
204 | print "already closed analyzer"
205 | logging.debug("already closed analyzer")
206 | self.wait_for_component(reporter)
207 | print "already closed reporter"
208 | logging.debug("already closed reporter")
209 | self.finish_timeout_error_handler()
210 | except:
211 | self.error_queue.put(traceback.format_exc())
212 | self.send_errors()
213 | finally:
214 | self.emulator.disconnect()
215 |
216 |
217 | if __name__ == '__main__':
218 | VMClient.get_VM_client().start_components()
219 |
--------------------------------------------------------------------------------
/client/client.sh:
--------------------------------------------------------------------------------
1 | adb start-server;
2 | while true; do
3 | sleep 10;
4 | python VMClient.py;
5 | done
6 |
7 |
--------------------------------------------------------------------------------
/client/client_setup.sh:
--------------------------------------------------------------------------------
1 | echo 1 > /proc/sys/net/ipv4/ip_forward
2 | iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
3 | iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8080
4 |
--------------------------------------------------------------------------------
/client/mitmproxy_setup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 |
3 | # Get mitmproxy files
4 | wget https://github.com/mitmproxy/mitmproxy/archive/v0.11.3.tar.gz
5 | wget https://github.com/mitmproxy/netlib/archive/v0.11.2.tar.gz
6 |
7 | # Install requirements
8 | sudo apt-get update
9 | sudo apt-get -y install python-pip
10 | sudo apt-get -y install python-cffi
11 | sudo apt-get -y install libffi-dev
12 | sudo apt-get -y install python-dev
13 | sudo apt-get -y install libssl-dev
14 | sudo apt-get -y install libxml2-dev
15 | sudo apt-get -y install libxslt-dev
16 | sudo apt-get -y install android-tools-adb
17 | sudo pip install --upgrade six
18 | sudo pip install netifaces
19 | sudo pip install --upgrade setuptools
20 |
21 | tar xvzf v0.11.2.tar.gz
22 | cd netlib-0.11.2
23 | sudo python setup.py install
24 | cd ..
25 |
26 | tar xvzf v0.11.3.tar.gz
27 | cd mitmproxy-0.11.3
28 | sudo python setup.py install
29 |
30 |
31 |
--------------------------------------------------------------------------------
/client/settings.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | VM_MANAGER_IP = 'IP_VM_MANAGER:8082'
27 | REPORTER_IP = 'localhost:8081'
28 | DEBUG_MODE = False
29 | FUZZER_VALUES={
30 | 'PASSWORD': 's3cr3tpass',
31 | 'MAIL' : 'fakeemailandroid@gmail.com',
32 | 'PHONE' : '1112341234',
33 | 'CONTACTNAME' : 'C0ntactFuzz',
34 | 'CONTACTPHONE' : '1107060504'
35 | }
36 | FUZZER_PRIVACY_VALUES={
37 | "android.telephony.TelephonyManager" : {
38 | "getSimOperatorName" : "QUAM-SIM",
39 | "getSimOperator" : "72201",
40 | "getNetworkOperatorName" : "QUAM-NETWORK",
41 | "getNetworkOperator" : "72207"
42 | },
43 | "com.android.internal.telephony.gsm.GSMPhone" : {
44 | "getDeviceId" : "352738061926670",
45 | "getImei" : "352738061926671",
46 | "getSubscriberId" : "722010000906017",
47 | "getLine1Number" : "1112341234"
48 | },
49 |
50 | "com.android.internal.telephony.gsm.CDMAPhone" : {
51 | "getDeviceId" : "352738061926672",
52 | "getMeid" : "352738061926673",
53 | "getSubscriberId" : "722010000906017",
54 | "getLine1Number" : "541101010101"
55 | },
56 | "com.android.internal.telephony.PhoneBase" :
57 | {
58 | "getIccSerialNumber" : "8954010111009060172f"
59 |
60 | },
61 | "android.net.wifi.WifiInfo" : {
62 | "getBSSID" : "de:ad:be:ef:aa:aa",
63 | "getIpAddress" : "192.168.0.2",
64 | "getMacAddress" : "de:ad:be:ef:bb:bb",
65 | "getSSID" : "ThizIsMyWifi"
66 | },
67 |
68 | "com.android.settings.Utils" : {
69 | "getWifiIpAddresses" : "192.168.0.2",
70 | "getDefaultIpAddresses" : "192.168.0.2"
71 | },
72 | "android.location.LocationManager" : {
73 | "requestLocationUpdates" : "-34.603773, -58.381700",
74 | "getLastKnownLocation" : "-34.603773, -58.381700"
75 | },
76 | "android.net.wifi.WifiManager" : {
77 | "getConfiguredNetworks" : "Not applicable yet",
78 | "getScanResults" : "Not applicable yet"
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/emulator/emulator_setup.sh:
--------------------------------------------------------------------------------
1 | #WORKING_FOLDER_PATH=/home/android/Android
2 | echo "Run with {SSL/NOSSL} {EMULATOR-IP} {GATEWAY-IP-FOR-EMULATOR} as args"
3 | WORKING_FOLDER_PATH=emulator_support_files
4 | EMULATOR_TYPE=$1
5 | emulator=$2:5556
6 | GW_FOR_EMULATOR=$3
7 | echo "Using emulator address $emulator"
8 | #Rooting, substrate, installing ssl bypass and fuzzer then linking
9 | #rooting the emulator
10 | connect_adb ()
11 | {
12 | adb disconnect
13 | adb connect "$1"
14 | sleep 8
15 | adb -s "$1" root
16 | #wait for adb to restart
17 | sleep 8
18 | adb connect "$1"
19 | }
20 |
21 | connect_adb "$emulator"
22 | #disabling lockscreen and suspension
23 | adb -s "$emulator" shell "sqlite3 /data/system/locksettings.db \"UPDATE locksettings SET value = '1' WHERE name = 'lockscreen.disabled'\""
24 | #adb -s "$emulator" shell "sqlite3 /data/data/com.android.providers.settings/databases/settings.db \"update system set value='-1' where name='screen_off_timeout'\""
25 | #rooting emulator
26 | adb -s "$emulator" push $WORKING_FOLDER_PATH/Android-x86-RootScript-4.3/ /data/local/
27 | adb -s "$emulator" shell "cd /data/local; sh install-device.sh"
28 | #add to init.sh remote adb, configure static ip to emulator and remove return 0
29 | adb -s "$emulator" remount
30 | adb -s "$emulator" shell "sed -i 's/return 0//g' /system/etc/init.sh"
31 | adb -s "$emulator" shell "echo 'adb tcpip 5556 &' >> /system/etc/init.sh"
32 | adb -s "$emulator" shell "echo 'ifconfig eth0 $2 netmask 255.255.255.0 &' >> /system/etc/init.sh"
33 | adb -s "$emulator" shell "echo 'busybox route add default gw $GW_FOR_EMULATOR dev eth0 &' >> /system/etc/init.sh"
34 | adb -s "$emulator" shell "echo 'return 0' >> /system/etc/init.sh"
35 | #reboot needed for SuperUser.apk to be instaled
36 | adb -s "$emulator" reboot &
37 | sleep 60
38 | connect_adb "$emulator"
39 | #start supersu to add shared_prefs configuration
40 | adb -s "$emulator" shell "am start -a android.intent.action.MAIN -n eu.chainfire.supersu/.MainActivity"
41 | sleep 8
42 | #change shared_pref to allow all apps
43 | adb -s "$emulator" push $WORKING_FOLDER_PATH/eu.chainfire.supersu_preferences.xml /data/data/eu.chainfire.supersu/shared_prefs/eu.chainfire.supersu_preferences.xml
44 | #reboot needed for grant access to be resolved
45 | adb -s "$emulator" reboot &
46 | sleep 60
47 | connect_adb "$emulator"
48 | #installing cydia
49 | adb -s "$emulator" install -r $WORKING_FOLDER_PATH/com.saurik.substrate.apk
50 | #installing extensions
51 | #if first emulator, install trust-killer
52 | if [[ "$EMULATOR_TYPE" == *"NOSSL"* ]]
53 | then
54 | adb -s "$emulator" install -r $WORKING_FOLDER_PATH/Android-SSL-TrustKiller.apk
55 | fi
56 | adb -s "$emulator" install -r $WORKING_FOLDER_PATH/Marvin-toqueton.apk
57 | #linking cydia
58 | adb -s "$emulator" shell /data/data/com.saurik.substrate/lib/libSubstrateRun.so do_link
59 | #rm all sdcard content
60 | adb -s "$emulator" shell "ls -d /sdcard/* | grep -v Android | xargs rm -r"
61 | #open substrate to update permitted.list (wait some seconds)pm
62 | adb -s "$emulator" shell am start -a android.intent.action.MAIN -n com.saurik.substrate/.SetupActivity
63 | sleep 8
64 | #copy the privacy.json file to sdcard
65 | adb -s "$emulator" shell am start -a android.intent.action.MAIN -n ar.fsadosky.marvintoqueton/.MainActivity
66 | #clear gapps and google play services because of crashes
67 | adb -s "$emulator" shell "pm uninstall com.google.android.gms"
68 | adb -s "$emulator" shell "pm clear com.google.android.gms"
69 | adb -s "$emulator" shell "pm clear com.google.android.gsf"
70 | sleep 8
71 | #rebooting phone
72 | adb -s "$emulator" shell /system/bin/setprop ctl.restart zygote
73 | #Busybox already installed in android-x86, no longer needs installing
74 | connect_adb "$emulator"
75 |
--------------------------------------------------------------------------------
/emulator/emulator_support_files/Android-SSL-TrustKiller.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/emulator/emulator_support_files/Android-SSL-TrustKiller.apk
--------------------------------------------------------------------------------
/emulator/emulator_support_files/Android-x86-RootScript-4.3/install-device.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | clear
3 | echo "-----------------------------"
4 | echo "Root script for Android 4.3"
5 | echo " By Quinny899 @ XDA"
6 | echo " Root by Chainfire @ XDA"
7 | echo "-----------------------------"
8 | echo "Script loaded"
9 | echo "Installing to device from device"
10 | echo "Mounting..."
11 | mount -o rw,remount /system
12 | echo "Removing old files..."
13 | rm -r -f /system/bin/.ext
14 | rm -f /system/bin/.ext/.su
15 | rm -f /system/xbin/daemonsu
16 | rm -f /system/xbin/su
17 | #rm -f /system/etc/init.sh
18 | rm -f /system/app/Superuser.apk
19 | echo "Copying files..."
20 | mkdir /system/bin/.ext
21 | cp system/bin/.ext/.su /system/bin/.ext/
22 | cp system/xbin/su /system/xbin/
23 | cp system/xbin/daemonsu /system/xbin/
24 | cp system/app/Superuser.apk /system/app/
25 | cat system/etc/init.sh >> /system/etc/init.sh
26 | echo "Setting permissions..."
27 | chmod 06755 /system/xbin/su
28 | chmod 06755 /system/xbin/daemonsu
29 | chmod 06755 /system/bin/.ext/.su
30 | chmod 777 /system/bin/.ext
31 | chmod 755 /system/etc/init.sh
32 | echo "Cleaning up..."
33 | echo "Finished. You need to reboot for root to be available"
34 |
--------------------------------------------------------------------------------
/emulator/emulator_support_files/Android-x86-RootScript-4.3/system/app/Superuser.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/emulator/emulator_support_files/Android-x86-RootScript-4.3/system/app/Superuser.apk
--------------------------------------------------------------------------------
/emulator/emulator_support_files/Android-x86-RootScript-4.3/system/bin/.ext/.su:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/emulator/emulator_support_files/Android-x86-RootScript-4.3/system/bin/.ext/.su
--------------------------------------------------------------------------------
/emulator/emulator_support_files/Android-x86-RootScript-4.3/system/bin/README:
--------------------------------------------------------------------------------
1 | This isn't blank, there's a hidden folder called .ext
--------------------------------------------------------------------------------
/emulator/emulator_support_files/Android-x86-RootScript-4.3/system/etc/init.sh:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2013 The Android-x86 Open Source Project
3 | #
4 | # License: GNU Public License v2 or later
5 | #
6 |
7 | function set_property()
8 | {
9 | # this must be run before post-fs stage
10 | echo $1=$2 >> /x86.prop
11 | }
12 |
13 | function init_misc()
14 | {
15 | # a hack for USB modem
16 | lsusb | grep 1a8d:1000 && eject
17 | }
18 |
19 | function init_hal_audio()
20 | {
21 | case "$PRODUCT" in
22 | VirtualBox*|Bochs*)
23 | [ -d /proc/asound/card0 ] || modprobe snd-sb16 isapnp=0 irq=5
24 | ;;
25 | *)
26 | ;;
27 | esac
28 | [ -d /proc/asound/card0 ] || modprobe snd-dummy
29 |
30 | for c in $(grep '\[.*\]' /proc/asound/cards | awk '{print $1}'); do
31 | alsa_ctl init $c
32 | alsa_amixer -c $c set Master on
33 | alsa_amixer -c $c set Master 100
34 | alsa_amixer -c $c set Headphone on
35 | alsa_amixer -c $c set Headphone 100
36 | alsa_amixer -c $c set Speaker 100
37 | alsa_amixer -c $c set Capture 100
38 | alsa_amixer -c $c set Capture cap
39 | alsa_amixer -c $c set PCM 100 unmute
40 | alsa_amixer -c $c set 'Mic Boost' 2
41 | done
42 | }
43 |
44 | function init_hal_bluetooth()
45 | {
46 | for r in /sys/class/rfkill/*; do
47 | type=$(cat $r/type)
48 | [ "$type" = "wlan" -o "$type" = "bluetooth" ] && echo 1 > $r/state
49 | done
50 |
51 | # these modules are incompatible with bluedroid
52 | rmmod ath3k
53 | rmmod btusb
54 | rmmod bluetooth
55 | }
56 |
57 | function init_hal_camera()
58 | {
59 | [ -c /dev/video0 ] || modprobe vivi
60 | }
61 |
62 | function init_hal_gps()
63 | {
64 | # TODO
65 | return
66 | }
67 |
68 | function set_drm_mode()
69 | {
70 | case "$PRODUCT" in
71 | ET1602*)
72 | drm_mode=1366x768
73 | ;;
74 | *)
75 | ;;
76 | esac
77 |
78 | [ -n "$drm_mode" ] && set_property debug.drm.mode.force $drm_mode
79 | }
80 |
81 | function init_uvesafb()
82 | {
83 | case "$PRODUCT" in
84 | *Q550)
85 | UVESA_MODE=${UVESA_MODE:-1280x800}
86 | ;;
87 | ET2002*)
88 | UVESA_MODE=${UVESA_MODE:-1600x900}
89 | ;;
90 | T91*)
91 | UVESA_MODE=${UVESA_MODE:-1024x600}
92 | ;;
93 | VirtualBox*|Bochs*)
94 | UVESA_MODE=${UVESA_MODE:-1024x768}
95 | ;;
96 | *)
97 | ;;
98 | esac
99 |
100 | modprobe uvesafb mode_option=${UVESA_MODE:-800x600}-16 ${UVESA_OPTION:-mtrr=3 scroll=redraw}
101 | }
102 |
103 | function init_hal_gralloc()
104 | {
105 | case "$(cat /proc/fb | head -1)" in
106 | 0*inteldrmfb|0*radeondrmfb)
107 | set_property hal.gralloc drm
108 | set_drm_mode
109 | ;;
110 | 0*svgadrmfb)
111 | ;;
112 | "")
113 | init_uvesafb
114 | ;&
115 | 0*)
116 | [ "$HWACCEL" = "1" ] || set_property debug.egl.hw 0
117 | ;;
118 | esac
119 | }
120 |
121 | function init_hal_hwcomposer()
122 | {
123 | # TODO
124 | return
125 | }
126 |
127 | function init_hal_lights()
128 | {
129 | chown 1000.1000 /sys/class/backlight/*/brightness
130 | }
131 |
132 | function init_hal_power()
133 | {
134 | # TODO
135 | case "$PRODUCT" in
136 | *)
137 | ;;
138 | esac
139 | }
140 |
141 | function init_hal_sensors()
142 | {
143 | case "$(cat $DMIPATH/uevent)" in
144 | *ICONIA*W*)
145 | set_property hal.sensors w500
146 | ;;
147 | *S10-3t*)
148 | set_property hal.sensors s103t
149 | ;;
150 | *Inagua*)
151 | #setkeycodes 0x62 29
152 | #setkeycodes 0x74 56
153 | set_property hal.sensors kbd
154 | set_property hal.sensors.kbd.type 2
155 | ;;
156 | *TEGA*|*2010:svnIntel:*)
157 | set_property hal.sensors kbd
158 | set_property hal.sensors.kbd.type 1
159 | io_switch 0x0 0x1
160 | setkeycodes 0x6d 125
161 | ;;
162 | *MS-N0E1*)
163 | ;;
164 | *)
165 | set_property hal.sensors kbd
166 | ;;
167 | esac
168 | }
169 |
170 | function init_ril()
171 | {
172 | case "$PRODUCT" in
173 | TEGA*|Intel*)
174 | set_property rild.libpath /system/lib/libreference-ril.so
175 | set_property rild.libargs "-d /dev/ttyUSB2"
176 | ;;
177 | *)
178 | ;;
179 | esac
180 | }
181 |
182 | function do_init()
183 | {
184 | init_misc
185 | init_hal_audio
186 | init_hal_bluetooth
187 | init_hal_camera
188 | init_hal_gps
189 | init_hal_gralloc
190 | init_hal_hwcomposer
191 | init_hal_lights
192 | init_hal_power
193 | init_hal_sensors
194 | init_ril
195 | chmod 640 /x86.prop
196 | post_init
197 | }
198 |
199 | function do_netconsole()
200 | {
201 | modprobe netconsole netconsole="@/,@$(getprop dhcp.eth0.gateway)/"
202 | }
203 |
204 | function do_bootcomplete()
205 | {
206 | for bt in $(lsusb -v | awk ' /Class:.E0/ { print $9 } '); do
207 | chown 1002.1002 $bt && chmod 660 $bt
208 | done
209 | }
210 |
211 | PATH=/system/bin:/system/xbin
212 |
213 | DMIPATH=/sys/class/dmi/id
214 | BOARD=$(cat $DMIPATH/board_name)
215 | PRODUCT=$(cat $DMIPATH/product_name)
216 |
217 | # import cmdline variables
218 | for c in `cat /proc/cmdline`; do
219 | case $c in
220 | androidboot.hardware=*)
221 | ;;
222 | *=*)
223 | eval $c
224 | ;;
225 | esac
226 | done
227 |
228 | [ -n "$DEBUG" ] && set -x || exec &> /dev/null
229 |
230 | # import the vendor specific script
231 | hw_sh=/vendor/etc/init.sh
232 | [ -e $hw_sh ] && source $hw_sh
233 |
234 | case "$1" in
235 | netconsole)
236 | [ -n "$DEBUG" ] && do_netconsole
237 | ;;
238 | bootcomplete)
239 | do_bootcomplete
240 | ;;
241 | init|"")
242 | do_init
243 | ;;
244 | esac
245 | daemonsu --daemon &
246 | return 0
247 |
--------------------------------------------------------------------------------
/emulator/emulator_support_files/Android-x86-RootScript-4.3/system/xbin/daemonsu:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/emulator/emulator_support_files/Android-x86-RootScript-4.3/system/xbin/daemonsu
--------------------------------------------------------------------------------
/emulator/emulator_support_files/Android-x86-RootScript-4.3/system/xbin/su:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/emulator/emulator_support_files/Android-x86-RootScript-4.3/system/xbin/su
--------------------------------------------------------------------------------
/emulator/emulator_support_files/Marvin-toqueton.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/emulator/emulator_support_files/Marvin-toqueton.apk
--------------------------------------------------------------------------------
/emulator/emulator_support_files/busybox:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/emulator/emulator_support_files/busybox
--------------------------------------------------------------------------------
/emulator/emulator_support_files/com.saurik.substrate.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/emulator/emulator_support_files/com.saurik.substrate.apk
--------------------------------------------------------------------------------
/emulator/emulator_support_files/eu.chainfire.supersu_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
21 |
--------------------------------------------------------------------------------
/images/architecture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/images/architecture.jpg
--------------------------------------------------------------------------------
/server/DBCache_django.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | class DBCache_django(object):
27 | def __init__(self):
28 | self.cache = {}
29 |
30 | def cache_dynamic_test_for_vm(self, vm_id, dynamic_test_object):
31 | self.cache[vm_id] = dynamic_test_object
32 |
33 | def get_dynamic_test_for_vm(self, vm_id):
34 | if not vm_id in self.cache.keys():
35 | raise Exception("Cache corrupted")
36 | return self.cache[vm_id]
37 |
38 |
--------------------------------------------------------------------------------
/server/DBManager_django.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import Utils
27 | import json
28 | import os
29 | import sys
30 | sys.path.append(os.path.join(os.path.dirname(__file__), 'django_support'))
31 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_support.settings")
32 | from django.conf import settings
33 | from django.db import connections
34 | from django_support.models import VulnerabilityResult
35 | from django_support.models import App
36 | from django_support.models import DynamicTestResults
37 | from DBCache_django import DBCache_django
38 | import settings
39 | import random
40 |
41 | class DBManager_django(object):
42 |
43 | def __init__(self):
44 | self.cache = DBCache_django()
45 |
46 | def default_filter_state(self, filter_id, apk_name):
47 | return {"status":"UNKNOWN", "count":0, "description":{}}
48 |
49 | def pick_dynamic_test_with_status_unknown(self,vm_client_id):
50 | dynamic_test = DynamicTestResults.objects.filter(status__exact='UNKNOWN').order_by('?').first()
51 | package_name = dynamic_test.vuln.app.package_name
52 | vulnerability_type = dynamic_test.vuln.name
53 | if(dynamic_test.vuln.dynamic_test_params is not None):
54 | dynamic_test_params = json.loads(dynamic_test.vuln.dynamic_test_params)
55 | else:
56 | dynamic_test_params = {}
57 | dynamic_test_params['count'] = dynamic_test.count
58 | download_url = settings.DOWNLOAD_APK_SITE + '%d'%dynamic_test.vuln.app.id + '/apk/?'
59 | self.cache.cache_dynamic_test_for_vm(vm_client_id,dynamic_test)
60 | print (vulnerability_type, package_name, download_url, dynamic_test_params)
61 | return (vulnerability_type, package_name, download_url, dynamic_test_params)
62 |
63 | def update_success(self,vm_client_id,description):
64 | dynamic_test = self.cache.get_dynamic_test_for_vm(vm_client_id)
65 | for vuln_type in description.keys():
66 | if vuln_type == dynamic_test.vuln.name:
67 | dynamic_test.status = "SUCCESS"
68 | dynamic_test.count +=1
69 | dynamic_test.description = {vuln_type : description[vuln_type]}
70 | dynamic_test.save()
71 | else:
72 | for vulnerability in description[vuln_type]:
73 | #its one of the dynamic only tested vulnerabilities, create a new vulnerability with its
74 | #description
75 | vulnerability = VulnerabilityResult(name = vuln_type,
76 | description = vulnerability,
77 | confidence = 1,
78 | dynamicTest = False,
79 | dynamic_test_params = None,
80 | app = dynamic_test.vuln.app)
81 | vulnerability.save()
82 |
83 |
84 | def log_failure(self,vm_client_id,status,extras):
85 | dynamic_test = self.cache.get_dynamic_test_for_vm(vm_client_id)
86 | dynamic_test.status = status
87 | dynamic_test.count +=1
88 | dynamic_test.description = extras
89 | dynamic_test.save()
90 |
91 |
--------------------------------------------------------------------------------
/server/ONE-API/NetworkInfo.java:
--------------------------------------------------------------------------------
1 | import org.opennebula.client.Client;
2 | import org.opennebula.client.vnet.VirtualNetwork;
3 | import org.opennebula.client.OneResponse;
4 | import org.opennebula.client.host.HostPool;
5 |
6 | /**
7 | *
8 | * author oneadmin
9 | */
10 | public class NetworkInfo {
11 |
12 | public static void main(String[] args) throws Exception {
13 | //password and URL standard
14 | Client client = new Client( args[0],args[1] );
15 | //network ID
16 | int net_id = Integer.parseInt(args[2]);
17 | OneResponse or = VirtualNetwork.info(client,net_id);
18 | if (or.isError()) {
19 | System.out.println(or.getErrorMessage());
20 | }
21 | else{
22 | System.out.println(or.getMessage());
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/server/ONE-API/SnapshotRestore.java:
--------------------------------------------------------------------------------
1 | import org.opennebula.client.Client;
2 | import org.opennebula.client.vm.VirtualMachine;
3 | import org.opennebula.client.OneResponse;
4 | import org.opennebula.client.host.HostPool;
5 |
6 | /**
7 | *
8 | * author oneadmin
9 | */
10 | public class SnapshotRestore {
11 |
12 | public static void main(String[] args) throws Exception {
13 | Client client = new Client( args[0],args[1] );
14 | int vm_id = Integer.parseInt(args[2]);
15 | int snapshot_id = Integer.parseInt(args[3]);
16 | OneResponse or = VirtualMachine.snapshotRevert(client,vm_id,snapshot_id);
17 | if (or.isError()) {
18 | System.out.println(or.getErrorMessage());
19 | }
20 | else{
21 | System.out.println(or.getMessage());
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/server/ONE-API/lib/org.opennebula.client.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/server/ONE-API/lib/org.opennebula.client.jar
--------------------------------------------------------------------------------
/server/ONE-API/lib/ws-commons-util-1.0.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/server/ONE-API/lib/ws-commons-util-1.0.2.jar
--------------------------------------------------------------------------------
/server/ONE-API/lib/xmlrpc-client-3.1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/server/ONE-API/lib/xmlrpc-client-3.1.2.jar
--------------------------------------------------------------------------------
/server/ONE-API/lib/xmlrpc-common-3.1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/server/ONE-API/lib/xmlrpc-common-3.1.2.jar
--------------------------------------------------------------------------------
/server/ONE-API/network_info.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/server/ONE-API/network_info.jar
--------------------------------------------------------------------------------
/server/ONE-API/restore.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/programa-stic/Marvin-dynamic-Analyzer/add9f6612206275c8e19157123731762a9504234/server/ONE-API/restore.jar
--------------------------------------------------------------------------------
/server/Utils.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | import subprocess
27 | import shlex
28 |
29 | def run_get_output(command):
30 | try:
31 | return subprocess.check_output(shlex.split(command),stderr=subprocess.STDOUT)
32 | except subprocess.CalledProcessError as grepexc:
33 | return grepexc.output
34 |
35 | def run_non_blocking_cmd(command):
36 | return subprocess.Popen(shlex.split(command),stdout=subprocess.PIPE,stderr=subprocess.PIPE)
37 |
38 |
--------------------------------------------------------------------------------
/server/VMManager.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | #!/usr/bin/env python
27 | import SimpleHTTPServer
28 | import SocketServer
29 | import logging
30 | from DBManager_django import DBManager_django
31 | import Utils
32 | import thread
33 | import traceback
34 | import xml.etree.ElementTree as ET
35 | import json
36 | import settings
37 | import random
38 |
39 |
40 | class VMManager(object):
41 | __vmm = None
42 |
43 | def __init__(self):
44 | self.db = DBManager_django()
45 | self.running_emulators = set()
46 |
47 | @staticmethod
48 | def get_vmm():
49 | if not VMManager.__vmm:
50 | VMManager.__vmm = VMManager()
51 | return VMManager.__vmm
52 |
53 | def restore_vm(self, ip):
54 | thread.start_new_thread(self.one_restore_vm, (ip,))
55 |
56 | def one_restore_vm(self, ip):
57 | self.restore_host_to_snapshot(self.get_vm_id_from_ip(ip))
58 |
59 | def get_vm_id_from_ip(self, ip):
60 | xml_response = Utils.run_get_output(
61 | 'java -jar ONE-API/network_info.jar %s %s %s' % (settings.ONE_CREDS, settings.ONE_IP, settings.NET_ID))
62 | et = ET.fromstring(xml_response)
63 | for lease in et.iter("LEASE"):
64 | if lease.find("IP") is not None and lease.find("IP").text == ip:
65 | return int(lease.find("VM").text)
66 | raise Exception("NO VM ID found for %s" % ip)
67 |
68 | def restore_host_to_snapshot(self, vm_emulator_id):
69 | # hardcoding snapshot ID to 1
70 | return Utils.run_get_output(
71 | 'java -jar ONE-API/restore.jar %s %s %d %d' % (settings.ONE_CREDS, settings.ONE_IP, vm_emulator_id, 0))
72 |
73 | def save_report(self, vm_client_id, content):
74 | print content
75 | status = content['status']
76 | extras = content['description']
77 | if status == 'SUCCESS':
78 | self.db.update_success(vm_client_id, extras)
79 | else:
80 | # there was an error in the report
81 | self.db.log_failure(vm_client_id, status, extras)
82 |
83 | def find_target_for_VM_client(self,vm_client_id):
84 | return self.db.pick_dynamic_test_with_status_unknown(vm_client_id)
85 |
86 | def add_running_emulator(self, emulator):
87 | self.running_emulators.add(emulator)
88 |
89 | def remove_running_emulator(self, emulator):
90 | self.running_emulators.remove(emulator)
91 |
92 | def find_emulator_for(self, vulnerability_type):
93 | possibleEmulators = settings.ANDROID_VM_POOL
94 | if "SSL" in vulnerability_type:
95 | key = "SSL"
96 | elif vulnerability_type in ["PHONEGAP_JS_INJECTION", "JAVASCRIPTINTERFACE"]:
97 | key = "JAVASCRIPTINTERFACE"
98 | else:
99 | key = "NONSSL"
100 | print set(possibleEmulators[key]) - self.running_emulators
101 | return random.sample(set(possibleEmulators[key]) - self.running_emulators, 1)[0]
102 |
103 | def get_VMManager_request_handler(self):
104 | return VMManagerRequestHandler
105 |
106 |
107 | class VMManagerRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
108 | def end_headers(self, filter, apk, download_url):
109 | # set extra headers for apk
110 | self.send_header('Content-Type', 'application/json')
111 | # set to "dummy" for testing
112 | self.send_header("filter", filter)
113 | self.send_header("apk", apk)
114 | self.send_header("download_url", download_url)
115 | SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self)
116 |
117 | def do_GET(self):
118 | logging.warning("======= GET STARTED =======")
119 | if self.path.startswith('/apk'):
120 | vmm = VMManager.get_vmm()
121 | vm_client_id = self.client_address[0]
122 | filter, apk, download_url, description = vmm.find_target_for_VM_client(vm_client_id)
123 | description['emulator'] = vmm.find_emulator_for(filter)
124 | vmm.add_running_emulator(description['emulator'])
125 | description = json.dumps(description)
126 | self.send_response(200)
127 | self.end_headers(filter, apk, download_url)
128 | self.wfile.write(description)
129 | else:
130 | self.send_response(404)
131 |
132 | def do_POST(self):
133 | logging.warning("======= POST STARTED =======")
134 | try:
135 | length = int(self.headers['Content-Length'])
136 | if self.path == '/report' or self.path == '/error':
137 | content = json.loads(self.rfile.read(length).decode('utf-8'))
138 | # TODO: should be an asynchrous request so the do_POST doesn't get hang waiting
139 | # VM ID matchs the vm ip for now
140 | vm_emulator_id = content['emulator']
141 | vm_client_id = self.client_address[0]
142 | vmm = VMManager.get_vmm()
143 | vmm.remove_running_emulator(vm_emulator_id)
144 | vmm.save_report(vm_client_id, content)
145 | vmm.restore_vm(vm_emulator_id)
146 | self.send_response(200)
147 | except:
148 | print traceback.format_exc()
149 | # if server failed, still restore VM ?
150 | VMManager.get_vmm().restore_vm(vm_emulator_id)
151 | self.send_response(500)
152 |
153 |
154 | def start_VMManager():
155 | SocketServer.TCPServer.allow_reuse_address = True
156 | server = SocketServer.TCPServer(('0.0.0.0', 8082), VMManager.get_vmm().get_VMManager_request_handler())
157 | try:
158 | server.serve_forever()
159 | except KeyboardInterrupt:
160 | server.shutdown()
161 | server.socket.close()
162 |
163 |
164 | if __name__ == '__main__':
165 | start_VMManager()
166 |
--------------------------------------------------------------------------------
/server/django_support/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 |
--------------------------------------------------------------------------------
/server/django_support/models.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from django.db import models
27 | from bungiesearch.managers import BungiesearchManager
28 | # Create your models here.
29 |
30 | class App(models.Model):
31 | QUEUED_STATUS = 'QUEUED'
32 | DOWNLOADING = 'DOWNL'
33 | DOWNLOADED = 'DLED'
34 | START_STAT = 'STATBEG'
35 | START_STAT = 'STATEND'
36 | START_VF = 'STARTVF'
37 | END_VF = 'ENDVF'
38 |
39 |
40 | # app_id = models.AutoField(db_index=True, blank=True)
41 | status = models.CharField(default = "QUEUED", max_length=20)
42 | package_name = models.CharField(db_index=True, max_length=100)
43 | app_name = models.CharField(blank = True, db_index=True, max_length=100)
44 | version = models.CharField(blank = True, max_length=30)
45 | md5 = models.CharField(db_index=True, max_length=100)
46 | sha1 = models.CharField(db_index=True, max_length=100)
47 | uploaded = models.DateField(auto_now_add = True, blank=True)
48 | targetSDK = models.CharField(blank = True, max_length=10)
49 | minSDK = models.CharField(blank = True, max_length=10)
50 | bayesResult = models.NullBooleanField(blank=True)
51 | bayesConfidence = models.DecimalField(blank=True, null=True, max_digits=4, decimal_places=3)
52 |
53 | objects = BungiesearchManager()
54 |
55 | def __unicode__(self):
56 | return self.package_name + ' ' + self.version
57 |
58 | class Meta:
59 | app_label = 'frontpage'
60 |
61 | class Sourcefile(models.Model):
62 | file_name = models.CharField(max_length=200)
63 | file_contents = models.TextField()
64 | app = models.ForeignKey(App)
65 |
66 | objects = BungiesearchManager()
67 |
68 | def __unicode__(self):
69 | return self.file_name
70 |
71 | class Meta:
72 | app_label = 'frontpage'
73 |
74 |
75 | class Permission(models.Model):
76 | name = models.CharField(max_length=100)
77 | perm_description = models.TextField()
78 | perm_danger = models.TextField()
79 | app = models.ManyToManyField(App)
80 |
81 | objects = BungiesearchManager()
82 |
83 | def __unicode__(self):
84 | return self.name
85 |
86 | class Meta:
87 | app_label = 'frontpage'
88 |
89 |
90 | class Activity(models.Model):
91 | name = models.CharField(max_length=150)
92 | app = models.ForeignKey(App)
93 | objects = BungiesearchManager()
94 |
95 | def __unicode__(self):
96 | return self.name
97 |
98 | class Meta:
99 | app_label = 'frontpage'
100 |
101 | class Receiver(models.Model):
102 | name = models.CharField(max_length=150)
103 | app = models.ForeignKey(App)
104 | objects = BungiesearchManager()
105 |
106 | def __unicode__(self):
107 | return self.name
108 |
109 | class Meta:
110 | app_label = 'frontpage'
111 |
112 | class Provider(models.Model):
113 | name = models.CharField(max_length=150)
114 | app = models.ForeignKey(App)
115 | objects = BungiesearchManager()
116 |
117 | def __unicode__(self):
118 | return self.name
119 |
120 | class Meta:
121 | app_label = 'frontpage'
122 |
123 | class Service(models.Model):
124 | name = models.CharField(max_length=150)
125 | app = models.ForeignKey(App)
126 |
127 | objects = BungiesearchManager()
128 |
129 | def __unicode__(self):
130 | return self.name
131 |
132 | class Meta:
133 | app_label = 'frontpage'
134 |
135 | class VulnerabilityResult(models.Model):
136 | name = models.CharField(max_length=150)
137 | description = models.TextField()
138 | confidence = models.CharField(max_length=10, null=True)
139 | dynamicTest = models.BooleanField(default=False)
140 | dynamic_test_params = models.TextField(null=True)
141 | app = models.ForeignKey(App)
142 |
143 | objects = BungiesearchManager()
144 |
145 | def __unicode__(self):
146 | return self.name
147 |
148 | class Meta:
149 | app_label = 'frontpage'
150 |
151 | class DynamicTestResults(models.Model):
152 | name = models.CharField(max_length=150)
153 | status = models.CharField(max_length=150)
154 | count = models.IntegerField()
155 | description = models.TextField()
156 | vuln = models.ForeignKey(VulnerabilityResult)
157 | objects = BungiesearchManager()
158 | #app = models.ForeignKey(App)
159 |
160 | def __unicode__(self):
161 | return self.name
162 |
163 | class Meta:
164 | app_label = 'frontpage'
165 |
166 |
167 |
168 | class NoUpdatedField(models.Model):
169 | package_name = models.CharField(max_length=150, db_index=True)
170 |
171 | objects = BungiesearchManager()
172 |
173 | class Meta:
174 | app_label = 'frontpage'
175 |
176 |
177 | class ManagedButEmpty(models.Model):
178 | package_name = models.CharField(max_length=150, db_index=True)
179 |
180 | objects = BungiesearchManager()
181 |
182 | class Meta:
183 | app_label = 'frontpage'
184 |
185 | class Unmanaged(models.Model):
186 | package_name = models.CharField(max_length=150, db_index=True)
187 |
188 | objects = BungiesearchManager()
189 |
190 | class Meta:
191 | app_label = 'frontpage'
192 |
193 |
--------------------------------------------------------------------------------
/server/django_support/myindices.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | from models import App
27 | from models import Sourcefile
28 | from models import Permission
29 | from models import Service
30 | from models import Activity
31 | from models import Provider
32 | from bungiesearch.fields import StringField
33 | from bungiesearch.indices import ModelIndex
34 |
35 |
36 | class AppIndex(ModelIndex):
37 | #effectived_date = DateField(eval_as='obj.created if obj.created and obj.published > obj.created else obj.published')
38 | meta_data = StringField(eval_as='" ".join([fld for fld in [obj.package_name, obj.app_name, obj.md5, obj.sha1] if fld])')
39 |
40 | class Meta:
41 | model = App
42 | #exclude = []
43 | #hotfixes = {}
44 | default = True
45 |
46 | class SourcefileIndex(ModelIndex):
47 | #effectived_date = DateField(eval_as='obj.created if obj.created and obj.published > obj.created else obj.published')
48 | meta_data = StringField(eval_as='" ".join([fld for fld in [obj.file_name, obj.file_contents] if fld])')
49 |
50 | class Meta:
51 | model = Sourcefile
52 | exclude = ('file_contents')
53 | #hotfixes = {}
54 | default = True
55 |
56 | class PermissionIndex(ModelIndex):
57 | #effectived_date = DateField(eval_as='obj.created if obj.created and obj.published > obj.created else obj.published')
58 | #meta_data = StringField(eval_as='" ".join([fld for fld in [obj.link, str(obj.tweet_count), obj.raw] if fld])')
59 |
60 | class Meta:
61 | model = Permission
62 | #exclude = ('raw', 'missing_data', 'negative_feedback', 'positive_feedback', 'popularity_index', 'source_hash')
63 | #hotfixes = {}
64 | default = True
65 |
66 | class ActivityIndex(ModelIndex):
67 | #effectived_date = DateField(eval_as='obj.created if obj.created and obj.published > obj.created else obj.published')
68 | #meta_data = StringField(eval_as='" ".join([fld for fld in [package_name, app_name, md5, sha1] if fld])')
69 |
70 | class Meta:
71 | model = Activity
72 | #exclude = ('raw', 'missing_data', 'negative_feedback', 'positive_feedback', 'popularity_index', 'source_hash')
73 | #hotfixes = {}
74 | default = True
75 |
76 | class ServiceIndex(ModelIndex):
77 | #effectived_date = DateField(eval_as='obj.created if obj.created and obj.published > obj.created else obj.published')
78 | #meta_data = StringField(eval_as='" ".join([fld for fld in [obj.link, str(obj.tweet_count), obj.raw] if fld])')
79 |
80 | class Meta:
81 | model = Service
82 | #exclude = ('raw', 'missing_data', 'negative_feedback', 'positive_feedback', 'popularity_index', 'source_hash')
83 | #hotfixes = {}
84 | default = True
85 |
86 | class ProviderIndex(ModelIndex):
87 | #effectived_date = DateField(eval_as='obj.created if obj.created and obj.published > obj.created else obj.published')
88 | #meta_data = StringField(eval_as='" ".join([fld for fld in [obj.link, str(obj.tweet_count), obj.raw] if fld])')
89 |
90 | class Meta:
91 | model = Provider
92 | #exclude = ('raw', 'missing_data', 'negative_feedback', 'positive_feedback', 'popularity_index', 'source_hash')
93 | #hotfixes = {}
94 | default = True
95 |
96 |
97 |
--------------------------------------------------------------------------------
/server/django_support/settings.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | """
27 | Django settings for marvin project.
28 |
29 | For more information on this file, see
30 | https://docs.djangoproject.com/en/1.6/topics/settings/
31 |
32 | For the full list of settings and their values, see
33 | https://docs.djangoproject.com/en/1.6/ref/settings/
34 | """
35 |
36 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
37 | import os
38 | BASE_DIR = os.path.dirname(os.path.dirname(__file__))
39 | SITE_ID = 1
40 |
41 | # Quick-start development settings - unsuitable for production
42 | # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
43 |
44 | # SECURITY WARNING: keep the secret key used in production secret!
45 | SECRET_KEY = '*'
46 |
47 | # SECURITY WARNING: don't run with debug turned on in production!
48 | DEBUG = True
49 |
50 | TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]
51 | TEMPLATE_DEBUG = True
52 | TEMPLATE_CONTEXT_PROCESSORS = ("django.contrib.auth.context_processors.auth",
53 | "django.core.context_processors.debug",
54 | "django.core.context_processors.i18n",
55 | "django.core.context_processors.media",
56 | "django.core.context_processors.static",
57 | "django.core.context_processors.tz",
58 | "django.contrib.messages.context_processors.messages")
59 |
60 | ALLOWED_HOSTS = ['*']
61 |
62 |
63 | # Application definition
64 |
65 | INSTALLED_APPS = (
66 | 'django.contrib.admin',
67 | 'django.contrib.auth',
68 | 'django.contrib.contenttypes',
69 | 'django.contrib.sessions',
70 | 'django.contrib.messages',
71 | 'django.contrib.staticfiles',
72 | 'bungiesearch',
73 | 'djgpa',
74 | 'preferences',
75 | 'django.contrib.sites',
76 | 'frontpage',
77 | )
78 |
79 | MIDDLEWARE_CLASSES = (
80 | 'django.contrib.sessions.middleware.SessionMiddleware',
81 | 'django.middleware.common.CommonMiddleware',
82 | 'django.middleware.csrf.CsrfViewMiddleware',
83 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
84 | 'django.contrib.messages.middleware.MessageMiddleware',
85 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
86 | )
87 |
88 | BUNGIESEARCH = {
89 | 'URLS': ['IP_ELASTICSEARCH_SERVER'], # No leading http:// or the elasticsearch client will complain.
90 | 'INDICES': {'apps2': 'django_support.myindices'}, # Must be a module path.
91 | #'ALIASES': {'bsearch': 'marvin.search_aliases'},
92 | 'SIGNALS': {'BUFFER_SIZE': 1},
93 | 'TIMEOUT': 5
94 | }
95 |
96 | # Database
97 | # https://docs.djangoproject.com/en/1.6/ref/settings/#databases
98 |
99 | DATABASES = {
100 | 'default': {
101 | 'ENGINE': 'django.db.backends.mysql',
102 | 'NAME': 'marvin',
103 | 'USER': 'marvin',
104 | 'PASSWORD': '',
105 | 'HOST': 'IP_DJANGO_SERVER',
106 | 'PORT': '3306'
107 | }
108 | }
109 |
110 | DEFAULT_INDEX_TABLESPACE=''
111 |
112 | # Internationalization
113 | # https://docs.djangoproject.com/en/1.6/topics/i18n/
114 |
115 | LANGUAGE_CODE = 'en-us'
116 |
117 | TIME_ZONE = 'UTC'
118 |
119 | USE_I18N = True
120 |
121 | USE_L10N = True
122 |
123 | USE_TZ = True
124 |
125 |
--------------------------------------------------------------------------------
/server/settings.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Fundacion Dr. Manuel Sadosky
2 | # All rights reserved.
3 |
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions are met:
6 |
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 |
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 |
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
26 | NET_ID = 1 #ID used for the framework virtual network
27 | #credentials for RPC
28 | ONE_IP = "http://OPEN_NEBULA_HOST:2633/RPC2"
29 | ONE_CREDS = "oneadmin:ONEADMINCREDENTIALS" #OpenNebula xml RPC credentials
30 | ELASTIC_SEARCH_SERVER = "IP_ELASTICSEARCH_SERVER"
31 | DOWNLOAD_APK_SITE = "http://FRONTEND_IP_ADDRESS:8080/frontpage/"
32 | ANDROID_VM_POOL = {"NONSSL":{"NON_SSL_EMULATOR_IP"},"SSL":{"EMULATOR_IP"},"JAVASCRIPTINTERFACE":{"ICS_EMULATOR_IP"}}
33 |
--------------------------------------------------------------------------------