From 14fac02bf8030c942ea72f2b66a18c8e72de2b2a Mon Sep 17 00:00:00 2001 From: Dhrumil Mistry <56185972+dmdhrumilmistry@users.noreply.github.com> Date: Sat, 16 Jul 2022 18:17:36 +0530 Subject: [PATCH 1/3] create partial ssl pinner script start frida server on device --- pyhtools/attackers/Android/__init__.py | 0 pyhtools/attackers/Android/mitm/__init__.py | 0 pyhtools/attackers/Android/mitm/cert_pin.py | 141 ++++++++++++++++++++ requirements.txt | 2 + 4 files changed, 143 insertions(+) create mode 100644 pyhtools/attackers/Android/__init__.py create mode 100644 pyhtools/attackers/Android/mitm/__init__.py create mode 100644 pyhtools/attackers/Android/mitm/cert_pin.py diff --git a/pyhtools/attackers/Android/__init__.py b/pyhtools/attackers/Android/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pyhtools/attackers/Android/mitm/__init__.py b/pyhtools/attackers/Android/mitm/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pyhtools/attackers/Android/mitm/cert_pin.py b/pyhtools/attackers/Android/mitm/cert_pin.py new file mode 100644 index 0000000..dc49c87 --- /dev/null +++ b/pyhtools/attackers/Android/mitm/cert_pin.py @@ -0,0 +1,141 @@ +from ppadb.client import Client +from ppadb.device import Device +from os.path import isfile, basename +from textwrap import dedent + +import frida +import logging +logging.basicConfig(level=logging.DEBUG, + format='[%(asctime)s] [%(levelname)s] - %(message)s') + + +class PinCertificateExceptions: + ''' + Pin Certificate Exception Class + ''' + class ServerNotRunning(Exception): + pass + + class NoDevicesFound(Exception): + pass + + +class PinCertificate: + def __init__(self, apk_path: str, package_name: str, cert_path: str, frida_binary_path: str, frida_script_path: str, device_name: str, host: str = '127.0.0.1', port: int = 5037, apk_installed: bool = False,): + # check data types + assert type(apk_path) == str + assert type(package_name) == str + assert type(cert_path) == str + assert type(device_name) == str + assert type(frida_binary_path) == str + assert type(host) == str + assert type(port) == int + assert type(apk_installed) == bool + + # check if files are available at their paths + if not isfile(apk_path): + raise FileNotFoundError(f'{apk_path} APK file not found') + + if not isfile(cert_path): + raise FileNotFoundError(f'{cert_path} Certificate file not found') + + if not isfile(frida_binary_path): + raise FileNotFoundError( + f'{frida_binary_path} Frida binary file not found') + + if not isfile(frida_script_path): + raise FileNotFoundError( + f'{frida_binary_path} Frida binary file not found') + + # assign values + self.__device_name = device_name + self.__apk_path = apk_path + self.__apk_installed = apk_installed + self.__package_name = package_name + self.__cert_path = cert_path + self.__frida_path = frida_binary_path + + # set initial values + self.device = None + + # connect to adb server + self._adb = Client( + host=host, + port=port + ) + + def get_device(self): + self.devices() + device: Device = self._adb.device(self.__device_name) + return device + + def devices(self): + try: + devices: list[Device] = self._adb.devices() + if len(devices) == 0: + raise PinCertificateExceptions.NoDevicesFound( + "No ADB Devices Attached") + + return devices + except RuntimeError: + raise PinCertificateExceptions.ServerNotRunning( + "ADB Server is not running, start using `adb start-server`") + + def get_frida_devices(self): + devices = frida.enumerate_devices() + if len(devices) == 0: + raise PinCertificateExceptions.NoDevicesFound( + "No Frida Devices Found") + + return devices + + def pin_certificate(self): + logging.info("Starting Certificate Pinning Procedure..") + + # get device + self.device: Device = self.get_device() + logging.info(f'Connected to {self.__device_name} device') + + # install certificate + if not self.__apk_installed: + self.device.install(path=self.__apk_path, reinstall=True) + logging.info( + f'{basename(self.__apk_path)} APK installation completed') + + # push certificate to the device + self.device.push( + src=self.__cert_path, + dest=r'/data/local/tmp/cert-der.crt', + mode=644 + ) + logging.info( + f'{self.__cert_path} certificate pushed to /data/local/tmp/cert-der.crt') + + # push frida binary to the device + self.device.push( + src=self.__frida_path, + dest=r'/data/local/tmp/frida-server', + mode=555 + ) + logging.info( + f'{self.__frida_path} frida binary pushed to /data/local/tmp/frida-server') + + # start frida server + logging.info("Starting Frida server") + self.device.shell('/data/local/tmp/frida-server &') + + + +if __name__ == '__main__': + pinner = PinCertificate( + apk_path=r'apk-path', + package_name=r'com.app.package', + cert_path=r'burp_pro_cert.der', + frida_binary_path=r'frida-server-15.1.28-android-x86', + frida_script_path=r'bypass-ssl-pinning.js', + device_name='emulator-5554', + host='127.0.0.1', + port=5037, + ) + + pinner.pin_certificate() diff --git a/requirements.txt b/requirements.txt index 121ec2c..4249d65 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,10 @@ beautifulsoup4>=4.9.3 colorama>=0.4.4 +frida-tools>=10.8.0 #netfilterqueue (for linux devices only): sudo pip3 install --upgrade -U git+https://github.com/kti/python-netfilterqueue kamene>=0.32 nuitka +pure-python-adb pyfiglet>=0.8.post1 pynput>=1.7.3 pytelegrambotapi>=4.0.1 From d1d0b6494888dff6ad2f615891abf6ca661d2716 Mon Sep 17 00:00:00 2001 From: Dhrumil Mistry <56185972+dmdhrumilmistry@users.noreply.github.com> Date: Sun, 17 Jul 2022 17:35:57 +0530 Subject: [PATCH 2/3] update SSL pinner create utils helper --- pyhtools/attackers/Android/mitm/cert_pin.py | 69 ++++++++++++--------- pyhtools/attackers/Android/mitm/utils.py | 16 +++++ 2 files changed, 55 insertions(+), 30 deletions(-) create mode 100644 pyhtools/attackers/Android/mitm/utils.py diff --git a/pyhtools/attackers/Android/mitm/cert_pin.py b/pyhtools/attackers/Android/mitm/cert_pin.py index dc49c87..a29cded 100644 --- a/pyhtools/attackers/Android/mitm/cert_pin.py +++ b/pyhtools/attackers/Android/mitm/cert_pin.py @@ -1,10 +1,13 @@ from ppadb.client import Client from ppadb.device import Device from os.path import isfile, basename -from textwrap import dedent +from os import system +from . import utils +import asyncio import frida import logging +import threading logging.basicConfig(level=logging.DEBUG, format='[%(asctime)s] [%(levelname)s] - %(message)s') @@ -21,16 +24,16 @@ class NoDevicesFound(Exception): class PinCertificate: - def __init__(self, apk_path: str, package_name: str, cert_path: str, frida_binary_path: str, frida_script_path: str, device_name: str, host: str = '127.0.0.1', port: int = 5037, apk_installed: bool = False,): + def __init__(self, apk_path: str, package_name: str, cert_path: str, frida_binary_path: str, frida_script_path: str, device_name: str, host: str = '127.0.0.1', port: int = 5037,): # check data types assert type(apk_path) == str assert type(package_name) == str assert type(cert_path) == str assert type(device_name) == str assert type(frida_binary_path) == str + assert type(frida_script_path) == str assert type(host) == str assert type(port) == int - assert type(apk_installed) == bool # check if files are available at their paths if not isfile(apk_path): @@ -50,13 +53,10 @@ def __init__(self, apk_path: str, package_name: str, cert_path: str, frida_bina # assign values self.__device_name = device_name self.__apk_path = apk_path - self.__apk_installed = apk_installed self.__package_name = package_name self.__cert_path = cert_path self.__frida_path = frida_binary_path - - # set initial values - self.device = None + self.__frida_script_path = frida_script_path # connect to adb server self._adb = Client( @@ -64,12 +64,15 @@ def __init__(self, apk_path: str, package_name: str, cert_path: str, frida_bina port=port ) + # set initial values + self.device = self.get_device() + def get_device(self): - self.devices() + _ = self.get_adb_devices() device: Device = self._adb.device(self.__device_name) return device - def devices(self): + def get_adb_devices(self): try: devices: list[Device] = self._adb.devices() if len(devices) == 0: @@ -89,6 +92,19 @@ def get_frida_devices(self): return devices + def install_apk(self, force_install: bool = True): + if self.device.is_installed(self.__package_name) and force_install: + self.device.uninstall(self.__package_name) + + self.device.install(self.__apk_path) + + if self.device.is_installed(self.__package_name): + return True + return False + + def start_frida(self): + asyncio.run(utils.run(f'adb shell /data/local/tmp/frida-server &')) + def pin_certificate(self): logging.info("Starting Certificate Pinning Procedure..") @@ -96,11 +112,14 @@ def pin_certificate(self): self.device: Device = self.get_device() logging.info(f'Connected to {self.__device_name} device') - # install certificate - if not self.__apk_installed: - self.device.install(path=self.__apk_path, reinstall=True) + # install apk + logging.info(f'Installing package') + if self.install_apk(): logging.info( - f'{basename(self.__apk_path)} APK installation completed') + f'{basename(self.__apk_path)} APK installation completed successfully') + else: + logging.error( + f'{basename(self.__apk_path)} APK installation failed!') # push certificate to the device self.device.push( @@ -120,22 +139,12 @@ def pin_certificate(self): logging.info( f'{self.__frida_path} frida binary pushed to /data/local/tmp/frida-server') - # start frida server + # start frida server in different thread logging.info("Starting Frida server") - self.device.shell('/data/local/tmp/frida-server &') - - - -if __name__ == '__main__': - pinner = PinCertificate( - apk_path=r'apk-path', - package_name=r'com.app.package', - cert_path=r'burp_pro_cert.der', - frida_binary_path=r'frida-server-15.1.28-android-x86', - frida_script_path=r'bypass-ssl-pinning.js', - device_name='emulator-5554', - host='127.0.0.1', - port=5037, - ) + frida_thread = threading.Thread(target=self.start_frida) + frida_thread.start() + # self.device.shell('su /data/local/tmp/frida-server &') - pinner.pin_certificate() + # Start SSL pinning + system( + f'frida -U -l {self.__frida_script_path} --no-paus -f {self.__package_name}') diff --git a/pyhtools/attackers/Android/mitm/utils.py b/pyhtools/attackers/Android/mitm/utils.py new file mode 100644 index 0000000..e26e17e --- /dev/null +++ b/pyhtools/attackers/Android/mitm/utils.py @@ -0,0 +1,16 @@ +import asyncio + + +async def run(cmd): + proc = await asyncio.create_subprocess_shell( + cmd, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE) + + stdout, stderr = await proc.communicate() + + # print(f'[{cmd!r} exited with {proc.returncode}]') + if stdout: + print(f'[stdout]\n{stdout.decode()}') + if stderr: + print(f'[stderr]\n{stderr.decode()}') From 1c91336d5386c3c9c05f557a0a783b9a5e4ff3e4 Mon Sep 17 00:00:00 2001 From: Dhrumil Mistry <56185972+dmdhrumilmistry@users.noreply.github.com> Date: Sun, 17 Jul 2022 18:02:45 +0530 Subject: [PATCH 3/3] update requirements in setup.py create Android SSL pinning example script --- .gitignore | 3 ++- examples/Android/intercept-using-burp.py | 16 +++++++++++++++ setup.py | 26 +++++++++++++----------- 3 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 examples/Android/intercept-using-burp.py diff --git a/.gitignore b/.gitignore index 03153a0..2ebe9ef 100644 --- a/.gitignore +++ b/.gitignore @@ -149,4 +149,5 @@ cython_debug/ *.exe *.build *.dist -*exectuables* \ No newline at end of file +*exectuables* +*temp* \ No newline at end of file diff --git a/examples/Android/intercept-using-burp.py b/examples/Android/intercept-using-burp.py new file mode 100644 index 0000000..8015d2d --- /dev/null +++ b/examples/Android/intercept-using-burp.py @@ -0,0 +1,16 @@ +from pyhtools.attackers.Android.mitm.cert_pin import PinCertificate + +pinner = PinCertificate( + apk_path=r'/home/hacker/apks/com.application.name.apk', # application package path + package_name=r'com.application.name', # package name of target application + cert_path=r'burp_cert.der', # burpsuite/custom CA certificate + frida_binary_path=r'frida-server-15.1.28-android-x86', # download and update path, (https://github.com/frida/frida/releases) + frida_script_path=r'script.js', # download from frida examples (https://codeshare.frida.re/@pcipolloni/universal-android-ssl-pinning-bypass-with-frida/) + device_name='emulator-5554', # device name from adb + host='127.0.0.1', # adb host + port=5037, # adb port +) + +pinner.pin_certificate() + +# once certificate is pinned you can exit python script using ctrl+c then return key \ No newline at end of file diff --git a/setup.py b/setup.py index 88be931..beacd2d 100644 --- a/setup.py +++ b/setup.py @@ -19,23 +19,25 @@ packages=find_packages(), include_package_data=True, install_requires=[ - 'beautifulsoup4', - 'colorama', - # 'netfilterqueue', # (for linux devices only): sudo pip3 install -U git+https://github.com/kti/python-netfilterqueue + 'beautifulsoup4>=4.9.3', + 'colorama>=0.4.4', + 'frida-tools>=10.8.0', + # 'netfilterqueue', #(for linux devices only): sudo pip3 install --upgrade -U git+https://github.com/kti/python-netfilterqueue, + 'kamene>=0.32', 'nuitka', - 'kamene', - 'scapy', - 'psutil', - 'prettytable', - 'pynput', - 'pyfiglet', - 'pytelegrambotapi', + 'pure-python-adb', + 'pyfiglet>=0.8.post1', + 'pynput>=1.7.3', + 'pytelegrambotapi>=4.0.1', + 'prettytable>=2.1.0', + 'psutil>=5.8.0', 'pyinstaller', - 'requests', + 'requests>=2.25.1', + 'scapy>=2.4.5', + # 'wmi', # for windows process management 'zstandard', ], classifiers=[ - 'Development Status :: 4 - Beta', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.6',