From 7b5f3bf6f26ee7f8f9447be397442d7d5367c0b0 Mon Sep 17 00:00:00 2001 From: ccsplit Date: Mon, 8 May 2017 16:02:44 -0500 Subject: [PATCH 01/20] Use unquote to convert spaces. Fixes #151. Since the information is passed back and forth through JSON with the agent it is URL-Encoded and therefore it needs to be removed when passing the string to an local_operation/remote_operation path command. --- needle/core/device/app.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/needle/core/device/app.py b/needle/core/device/app.py index d9beec2..c8d7db2 100644 --- a/needle/core/device/app.py +++ b/needle/core/device/app.py @@ -58,9 +58,9 @@ def __parse_from_agent(self): # Parse the JSON name = self.__extract_field(agent_info, 'DisplayName').encode('ascii','replace') bundle_id = self.__extract_field(agent_info, 'BundleIdentifier') - data_directory = self.__extract_field(agent_info, 'DataContainer', path=True) - bundle_directory = self.__extract_field(agent_info, 'BundleContainer', path=True) - binary_directory = self.__extract_field(agent_info, 'BundleURL', path=True) + data_directory = self.__extract_field(agent_info, 'DataContainer', path=True, urldecode=True) + bundle_directory = self.__extract_field(agent_info, 'BundleContainer', path=True, urldecode=True) + binary_directory = self.__extract_field(agent_info, 'BundleURL', path=True, urldecode=True) app_version = self.__extract_field(agent_info, 'BundleVersion') sdk_version = self.__extract_field(agent_info, 'SDKVersion') entitlements = self.__extract_field(agent_info, 'Entitlements') @@ -114,10 +114,17 @@ def __detect_architectures(self, binary): res = msg.rsplit(': ')[-1].split(' ') return res - def __extract_field(self, data, field, path=False): + def __extract_field(self, data, field, path=False, urldecode=False): """Extract the specified entry from the plist file. Returns empty string if not present.""" try: temp = data[field] + if urldecode: + try: + from urllib.parse import unquote + except ImportError: + # Python 2.x + from urllib import unquote + temp = unquote(temp) if path: prefix = 'file://' if temp.startswith(prefix): From f928ef3270880b6289f45b6209f61367434249a5 Mon Sep 17 00:00:00 2001 From: ccsplit Date: Mon, 15 May 2017 12:46:28 -0500 Subject: [PATCH 02/20] Add the start of a way to handle special characters. Added a preliminary way to handle issues with special characters within the iOS Application name. --- needle/core/device/app.py | 2 +- needle/core/utils/utils.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/needle/core/device/app.py b/needle/core/device/app.py index 18c7e51..88f8c61 100644 --- a/needle/core/device/app.py +++ b/needle/core/device/app.py @@ -24,7 +24,7 @@ def _retrieve_metadata(self): metadata_agent = self.__parse_from_agent() # Content of the app's local Info.plist - plist_info_path = Utils.escape_path('%s/Info.plist' % metadata_agent['binary_directory']) + plist_info_path = Utils.escape_path('%s/Info.plist' % metadata_agent['binary_directory'], escape_accent=True) print(plist_info_path) diff --git a/needle/core/utils/utils.py b/needle/core/utils/utils.py index 573781a..df0f8d9 100644 --- a/needle/core/utils/utils.py +++ b/needle/core/utils/utils.py @@ -17,11 +17,16 @@ class Utils(object): # PATH UTILS # ================================================================================================================== @staticmethod - def escape_path(path): + def escape_path(path, escape_accent=False): """Escape the given path.""" import pipes path = path.strip() # strip path = path.strip(''''"''') # strip occasional single/double quotes from both sides + if escape_accent: + # Find the accents/backquotes that do not have a backslash + # in front of them and escape them. + path = re.sub('(? -1: + # Attempt to escape the command args[0] in order to escape the accent. + device.printer.debug("Attempting retry with the accents/backquotes escaped.") + if len(args) > 0: + print "Args: {}".format(args) + args = [Utils.escape_path(i) if idx == 0 else i + for idx, i in enumerate(args)] device.disconnect() device.printer.warning("Resetting connection to device...") device.connect() From a7b79116688bfd3811d638689609195f2d9153e2 Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Mon, 22 May 2017 14:03:31 +0100 Subject: [PATCH 03/20] Remove print statement --- needle/core/utils/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/needle/core/utils/utils.py b/needle/core/utils/utils.py index df0f8d9..22bf5ca 100644 --- a/needle/core/utils/utils.py +++ b/needle/core/utils/utils.py @@ -26,7 +26,6 @@ def escape_path(path, escape_accent=False): # Find the accents/backquotes that do not have a backslash # in front of them and escape them. path = re.sub('(? Date: Wed, 12 Jul 2017 14:34:18 +0100 Subject: [PATCH 04/20] [FIX] Reintroduce comment --- needle/core/device/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/needle/core/device/app.py b/needle/core/device/app.py index 137c6ca..7173e48 100644 --- a/needle/core/device/app.py +++ b/needle/core/device/app.py @@ -21,6 +21,7 @@ def _retrieve_metadata(self): # Parse output from the agent metadata_agent = self.__parse_from_agent() + # Content of the app's local Info.plist plist_info_path = Utils.escape_path('%s/Info.plist' % metadata_agent['binary_directory'], escape_accent=True) plist_info = self._device.remote_op.parse_plist(plist_info_path) metadata_info = self.__parse_plist_info(plist_info) From c2a89ca0c7e9de3c0e4da54289957900249b4f4c Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Wed, 12 Jul 2017 14:36:08 +0100 Subject: [PATCH 05/20] Improved output --- needle/modules/storage/data/keychain_dump_frida.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/needle/modules/storage/data/keychain_dump_frida.py b/needle/modules/storage/data/keychain_dump_frida.py index f94d846..4c0fd64 100644 --- a/needle/modules/storage/data/keychain_dump_frida.py +++ b/needle/modules/storage/data/keychain_dump_frida.py @@ -167,7 +167,9 @@ def module_run(self): self.printer.warning(e) def module_post(self): - self.printer.info("Keychain Items:") - self.print_cmd_output() - self.add_issue('Keychain items detected ({})'.format(len(self.results)), None, 'INVESTIGATE', self.options['output']) - + if self.results: + self.printer.info("Keychain Items:") + self.print_cmd_output() + self.add_issue('Keychain items detected ({})'.format(len(self.results)), None, 'INVESTIGATE', self.options['output']) + else: + self.printer.warning("No items found.") From a3c23c18a1cbac3de50e91707f5a3854259bdb77 Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Wed, 12 Jul 2017 14:50:14 +0100 Subject: [PATCH 06/20] [FIX] Search PID for System Apps --- CHANGELOG.md | 1 + needle/core/device/app.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 614029d..83bf628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Added #### Fixed +- **[CORE]** Search PID for System Apps - **[MODULE]** Keychain extraction of data not encodable in UTF8 _[from @federicodotta]_ - **[MODULE]** Improved jailbreak detection bypass (`dynamic/detection/script_jailbreak-detection-bypass.py`) diff --git a/needle/core/device/app.py b/needle/core/device/app.py index 7173e48..7d83958 100644 --- a/needle/core/device/app.py +++ b/needle/core/device/app.py @@ -186,7 +186,7 @@ def search_pid(self, binary_name): cmd = "ps ax | grep -i '{binary_name}'".format(binary_name=binary_name) out = self._device.remote_op.command_blocking(cmd) try: - process_list = filter(lambda x: '/var/mobile' in x, out) + process_list = filter(lambda x: 'grep' not in x, out) if not process_list: process_list = filter(lambda x: '/var/containers' in x, out) process = process_list[0].strip() From 1610218ce8f20151855b9db8ec69e75a3694935f Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Wed, 12 Jul 2017 14:58:59 +0100 Subject: [PATCH 07/20] Automatically spawn Agent when sending a command --- CHANGELOG.md | 1 + needle/core/device/agent.py | 3 +++ needle/core/utils/constants.py | 1 + 3 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83bf628..a9a6937 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Fixed - **[CORE]** Search PID for System Apps +- **[CORE]** Automatically spawn Agent when sending a command - **[MODULE]** Keychain extraction of data not encodable in UTF8 _[from @federicodotta]_ - **[MODULE]** Improved jailbreak detection bypass (`dynamic/detection/script_jailbreak-detection-bypass.py`) diff --git a/needle/core/device/agent.py b/needle/core/device/agent.py index 44e26b0..4087fca 100644 --- a/needle/core/device/agent.py +++ b/needle/core/device/agent.py @@ -60,5 +60,8 @@ def disconnect(self): @Retry() def exec_command_agent(self, cmd): + # Currently the agent needs to be in the foreground in order to being able to receive commands + if self._device.ssh: + self._device.app.open(Constants.AGENT_BUNDLE_ID) self._device.printer.debug("{} Executing command: {}".format(Constants.AGENT_TAG, cmd)) return self.client.send_to_device(cmd) diff --git a/needle/core/utils/constants.py b/needle/core/utils/constants.py index 005ca6a..d79376c 100644 --- a/needle/core/utils/constants.py +++ b/needle/core/utils/constants.py @@ -50,6 +50,7 @@ class Constants(object): # AGENT CONSTANTS AGENT_TAG = "[AGENT]" AGENT_WELCOME = "Welcome to Needle Agent" + AGENT_BUNDLE_ID = "mwr.needle.agent" AGENT_VERSION_MARK = "VERSION: " AGENT_OUTPUT_END = " :OUTPUT_END:" AGENT_TIMEOUT_READ = 5 From 6e79b23d428ecda92928b45eefff6b0c3746a57c Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Wed, 12 Jul 2017 15:11:15 +0100 Subject: [PATCH 08/20] Frida: Switching to default OPEN --- needle/core/framework/module.py | 2 +- needle/modules/storage/data/keychain_dump_frida.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/needle/core/framework/module.py b/needle/core/framework/module.py index cb79888..0d7613d 100644 --- a/needle/core/framework/module.py +++ b/needle/core/framework/module.py @@ -286,7 +286,7 @@ class FridaScript(FridaModule): def __init__(self, params): FridaModule.__init__(self, params) # Add option for launch mode - opt = ('spawn', True, True, 'If set to True, Frida will be used to spawn the app. ' + opt = ('spawn', False, True, 'If set to True, Frida will be used to spawn the app. ' 'If set to False, the app will be launched and Frida will be attached to the running instance') self.register_option(*opt) opt = ('resume', True, True, 'If set to True, Frida will resume the application process after spawning it (recommended)') diff --git a/needle/modules/storage/data/keychain_dump_frida.py b/needle/modules/storage/data/keychain_dump_frida.py index 4c0fd64..f54708f 100644 --- a/needle/modules/storage/data/keychain_dump_frida.py +++ b/needle/modules/storage/data/keychain_dump_frida.py @@ -124,7 +124,7 @@ class Module(FridaScript): for (var i = 0; i < result.count(); i++){ var entry = result.objectAtIndex_(i); send(JSON.stringify({ - Data: bytesToHex(Memory.readByteArray(entry.objectForKey_("v_Data").bytes(),entry.objectForKey_("v_Data").length())) + + Data: bytesToHex(Memory.readByteArray(entry.objectForKey_("v_Data").bytes(),entry.objectForKey_("v_Data").length())) + ( ObjC.classes.NSString.stringWithUTF8String_(entry.objectForKey_("v_Data").bytes()) ? " (UTF8 String: '" + ObjC.classes.NSString.stringWithUTF8String_(entry.objectForKey_("v_Data").bytes()).valueOf() + "')": "" ), EntitlementGroup: entry.objectForKey_("agrp").valueOf(), Protection: constants[entry.objectForKey_("pdmn")].valueOf(), @@ -172,4 +172,4 @@ def module_post(self): self.print_cmd_output() self.add_issue('Keychain items detected ({})'.format(len(self.results)), None, 'INVESTIGATE', self.options['output']) else: - self.printer.warning("No items found.") + self.printer.warning("No items found.") \ No newline at end of file From 97824f44f811dcf59b80c9b2c251c44571e1e5d5 Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Wed, 12 Jul 2017 16:33:55 +0100 Subject: [PATCH 09/20] Minor on metadata parsing --- needle/core/device/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/needle/core/device/app.py b/needle/core/device/app.py index 7d83958..30adcc7 100644 --- a/needle/core/device/app.py +++ b/needle/core/device/app.py @@ -134,7 +134,7 @@ def __extract_field(self, data, field, path=False, urldecode=False): if path: prefix = 'file://' if temp.startswith(prefix): - temp = temp[len(prefix):] + temp = Utils.escape_path(temp[len(prefix):]) return temp except: return "" From 760b299d47b22ac1389a9c8b87d348e52e509102 Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Thu, 13 Jul 2017 09:49:57 +0100 Subject: [PATCH 10/20] [FIX] Minor fixes --- CHANGELOG.md | 6 +----- needle/core/device/agent.py | 3 --- needle/core/utils/constants.py | 2 ++ needle/core/utils/utils.py | 7 ------- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9a6937..6bf79f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,15 +12,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased -#### Added - #### Fixed - **[CORE]** Search PID for System Apps -- **[CORE]** Automatically spawn Agent when sending a command - **[MODULE]** Keychain extraction of data not encodable in UTF8 _[from @federicodotta]_ - **[MODULE]** Improved jailbreak detection bypass (`dynamic/detection/script_jailbreak-detection-bypass.py`) - -#### Removed +- **[MODULE]** Improved certificate pinning bypass (`comms/proxy/pinning_bypass_frida`) diff --git a/needle/core/device/agent.py b/needle/core/device/agent.py index 4087fca..44e26b0 100644 --- a/needle/core/device/agent.py +++ b/needle/core/device/agent.py @@ -60,8 +60,5 @@ def disconnect(self): @Retry() def exec_command_agent(self, cmd): - # Currently the agent needs to be in the foreground in order to being able to receive commands - if self._device.ssh: - self._device.app.open(Constants.AGENT_BUNDLE_ID) self._device.printer.debug("{} Executing command: {}".format(Constants.AGENT_TAG, cmd)) return self.client.send_to_device(cmd) diff --git a/needle/core/utils/constants.py b/needle/core/utils/constants.py index d79376c..6484688 100644 --- a/needle/core/utils/constants.py +++ b/needle/core/utils/constants.py @@ -63,6 +63,8 @@ class Constants(object): '10': [ 'binary/installation/install', 'binary/installation/pull_ipa', + 'binary/reversing/class_dump', + 'binary/reversing/strings' ] } diff --git a/needle/core/utils/utils.py b/needle/core/utils/utils.py index 207623e..7915539 100644 --- a/needle/core/utils/utils.py +++ b/needle/core/utils/utils.py @@ -202,13 +202,6 @@ def wrapper(obj, *args, **kwargs): self.actual_tries += 1 exception = e device.printer.error(exception) - if str(e).find('`') > -1: - # Attempt to escape the command args[0] in order to escape the accent. - device.printer.debug("Attempting retry with the accents/backquotes escaped.") - if len(args) > 0: - print "Args: {}".format(args) - args = [Utils.escape_path(i) if idx == 0 else i - for idx, i in enumerate(args)] device.disconnect() device.printer.warning("Resetting connection to device...") device.connect() From b5f7f68530adbf1a85040854c934644f86b7f831 Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Thu, 13 Jul 2017 09:50:37 +0100 Subject: [PATCH 11/20] [MODULE] Improved certificate pinning bypass --- needle/modules/comms/proxy/pinning_bypass_frida.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/needle/modules/comms/proxy/pinning_bypass_frida.py b/needle/modules/comms/proxy/pinning_bypass_frida.py index 70e69d0..4d23b7e 100644 --- a/needle/modules/comms/proxy/pinning_bypass_frida.py +++ b/needle/modules/comms/proxy/pinning_bypass_frida.py @@ -62,6 +62,18 @@ class Module(FridaScript): return SSLSetSessionOption(context, option, value); }, 'int', ['pointer', 'int', 'bool'])); + // iOS 10 + var tls_helper_create_peer_trust = new NativeFunction( + Module.findExportByName(null, "tls_helper_create_peer_trust"), + 'int', + ['pointer', 'bool', 'pointer'] + ); + + Interceptor.replace(tls_helper_create_peer_trust, new NativeCallback(function(hdsk, server, trustRef) { + return noErr; + }, 'int', ['pointer', 'bool', 'pointer'])); + + // // OLD WAY // From 3e71e42b53af9123a36d6b6b2e5e170d0c4627ac Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Thu, 13 Jul 2017 09:59:20 +0100 Subject: [PATCH 12/20] [V1.3.2] Update version and changelog --- CHANGELOG.md | 2 +- needle/core/utils/constants.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bf79f7..2909fdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). -## Unreleased +## [1.3.2] - 2017-07-13 #### Fixed - **[CORE]** Search PID for System Apps - **[MODULE]** Keychain extraction of data not encodable in UTF8 _[from @federicodotta]_ diff --git a/needle/core/utils/constants.py b/needle/core/utils/constants.py index 6484688..ec7604d 100644 --- a/needle/core/utils/constants.py +++ b/needle/core/utils/constants.py @@ -12,7 +12,7 @@ class Constants(object): AUTHOR = 'MWR InfoSecurity (@MWRLabs) - Marco Lancini (@LanciniMarco)' EMAIL = 'marco.lancini@mwrinfosecurity.com' WEBSITE = 'mwr.to/needle' - VERSION = '1.3.1' + VERSION = '1.3.2' VERSION_CHECK = 'https://raw.githubusercontent.com/mwrlabs/needle/master/needle/core/utils/constants.py' # Name variables From 104a7f1bba8ea4a60af0ed3a0652c017f8bed72c Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Thu, 13 Jul 2017 18:51:24 +0100 Subject: [PATCH 13/20] Minor - revert --- .../script_jailbreak-detection-bypass.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/needle/modules/dynamic/detection/script_jailbreak-detection-bypass.py b/needle/modules/dynamic/detection/script_jailbreak-detection-bypass.py index 4cab240..e3dd3d9 100644 --- a/needle/modules/dynamic/detection/script_jailbreak-detection-bypass.py +++ b/needle/modules/dynamic/detection/script_jailbreak-detection-bypass.py @@ -62,22 +62,6 @@ class Module(FridaScript): "CYObjectiveC", "frida_agent_main"]; -Interceptor.attach(ObjC.classes.NSFileManager["- fileExistsAtPath:"].implementation, { - onEnter: function (args) { - this.path_to_hide = false; - this.path = ObjC.Object(args[2]).toString(); - if (paths.indexOf(this.path) >= 0) { - this.path_to_hide = true; - send("Hooking fileExistsAtPath to return false"); - } - }, - onLeave: function (retval) { - if (this.path_to_hide) { - retval.replace(0x0); - } - } -}); - var resolver = new ApiResolver('objc'); resolver.enumerateMatches('*[* is*ailbroken]', { onMatch: function (match) { From fca6775e11f4abaed89d79f7aa164ed77e13d5b2 Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Thu, 13 Jul 2017 18:52:55 +0100 Subject: [PATCH 14/20] Update pinning_bypass_frida.py --- needle/modules/comms/proxy/pinning_bypass_frida.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/needle/modules/comms/proxy/pinning_bypass_frida.py b/needle/modules/comms/proxy/pinning_bypass_frida.py index 4d23b7e..39de902 100644 --- a/needle/modules/comms/proxy/pinning_bypass_frida.py +++ b/needle/modules/comms/proxy/pinning_bypass_frida.py @@ -62,17 +62,6 @@ class Module(FridaScript): return SSLSetSessionOption(context, option, value); }, 'int', ['pointer', 'int', 'bool'])); - // iOS 10 - var tls_helper_create_peer_trust = new NativeFunction( - Module.findExportByName(null, "tls_helper_create_peer_trust"), - 'int', - ['pointer', 'bool', 'pointer'] - ); - - Interceptor.replace(tls_helper_create_peer_trust, new NativeCallback(function(hdsk, server, trustRef) { - return noErr; - }, 'int', ['pointer', 'bool', 'pointer'])); - // // OLD WAY From e39499e94b9bb5d0fd4b54b533b0aa6aff48dc0f Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Mon, 7 Aug 2017 12:51:25 +0100 Subject: [PATCH 15/20] Update README.md Add Black Hat Arsenal 2017 badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 93245ed..56f2b7d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ![Needle](https://labs.mwrinfosecurity.com/assets/needle-logo-blue.jpg) [![Black Hat Arsenal](https://www.toolswatch.org/badges/arsenal/2016.svg)](https://www.blackhat.com/us-16/arsenal.html#needle) +[![Black Hat Arsenal](https://rawgit.com/toolswatch/badges/master/arsenal/2017.svg)](https://www.blackhat.com/us-17/arsenal.html#needle) _Needle_ is an open source, modular framework to streamline the process of conducting security assessments of iOS apps. From d26cf5191ebd6b580a2054459262b0e6ad373c0b Mon Sep 17 00:00:00 2001 From: root Date: Sat, 4 Nov 2017 01:32:20 -0400 Subject: [PATCH 16/20] External sshpass command now supports complex passwords --- needle/core/device/device.py | 4 ++-- needle/core/device/remote_operations.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/needle/core/device/device.py b/needle/core/device/device.py index 7b6e851..41e29a5 100644 --- a/needle/core/device/device.py +++ b/needle/core/device/device.py @@ -244,7 +244,7 @@ def cleanup(self): def shell(self): """Spawn a system shell on the device.""" - cmd = 'sshpass -p "{password}" ssh {hostverification} -p {port} {username}@{ip}'.format(password=self._password, + cmd = 'sshpass -p \'{password}\' ssh {hostverification} -p {port} {username}@{ip}'.format(password=self._password, hostverification=Constants.DISABLE_HOST_VERIFICATION, port=self._port, username=self._username, @@ -259,4 +259,4 @@ def pull(self, src, dst): def push(self, src, dst): """Push a file on the device.""" self.printer.info("Pushing: %s -> %s" % (src, dst)) - self.remote_op.upload(src, dst) \ No newline at end of file + self.remote_op.upload(src, dst) diff --git a/needle/core/device/remote_operations.py b/needle/core/device/remote_operations.py index 0086185..233eb27 100644 --- a/needle/core/device/remote_operations.py +++ b/needle/core/device/remote_operations.py @@ -98,7 +98,7 @@ def command_blocking(self, cmd, internal=True): def command_interactive(self, cmd): """Run a command which requires an interactive shell.""" self._device.printer.debug("[REMOTE CMD] Remote Interactive Command: %s" % cmd) - cmd = 'sshpass -p "{password}" ssh {hostverification} -p {port} -t {username}@{ip} "{cmd}"'.format(password=self._device._password, + cmd = 'sshpass -p \'{password}\' ssh {hostverification} -p {port} -t {username}@{ip} "{cmd}"'.format(password=self._device._password, hostverification=Constants.DISABLE_HOST_VERIFICATION, port=self._device._port, username=self._device._username, @@ -111,7 +111,7 @@ def command_interactive(self, cmd): def command_interactive_tty(self, cmd): """Run a command in a full TTY shell.""" self._device.printer.debug("[REMOTE CMD] Remote Interactive TTY Command: %s" % cmd) - cmd = 'sshpass -p "{password}" ssh {hostverification} -p {port} -t {username}@{ip} "{cmd}"'.format(password=self._device._password, + cmd = 'sshpass -p \'{password}\' ssh {hostverification} -p {port} -t {username}@{ip} "{cmd}"'.format(password=self._device._password, hostverification=Constants.DISABLE_HOST_VERIFICATION, port=self._device._port, username=self._device._username, @@ -164,7 +164,7 @@ def download(self, src, dst, recursive=False): src, dst = Utils.escape_path_scp(src), Utils.escape_path(dst) self._device.printer.debug("Downloading: %s -> %s" % (src, dst)) - cmd = 'sshpass -p "{password}" scp {hostverification} -P {port}'.format(password=self._device._password, + cmd = 'sshpass -p \'{password}\' scp {hostverification} -P {port}'.format(password=self._device._password, hostverification=Constants.DISABLE_HOST_VERIFICATION, port=self._device._port) if recursive: cmd += ' -r' @@ -179,7 +179,7 @@ def upload(self, src, dst, recursive=True): src, dst = Utils.escape_path_scp(src), Utils.escape_path_scp(dst) self._device.printer.debug("Uploading: %s -> %s" % (src, dst)) - cmd = 'sshpass -p "{password}" scp {hostverification} -P {port}'.format(password=self._device._password, + cmd = 'sshpass -p \'{password}\' scp {hostverification} -P {port}'.format(password=self._device._password, hostverification=Constants.DISABLE_HOST_VERIFICATION, port=self._device._port) if recursive: cmd += ' -r' From a937d4e1d623a933f5163110ee42842a53b8627f Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Tue, 5 Dec 2017 15:31:40 +0000 Subject: [PATCH 17/20] Update README.md New description --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 56f2b7d..c51c036 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,11 @@ _Needle_ is an open source, modular framework to streamline the process of condu Assessing the security of an iOS application typically requires a plethora of tools, each developed for a specific need and all with different modes of operation and syntax. The Android ecosystem has tools like "[drozer](https://mwr.to/drozer)" that have solved this problem and aim to be a ‘one stop shop’ for the majority of use cases, however iOS does not have an equivalent. -Needle is an open source modular framework which aims to streamline the entire process of conducting security assessments of iOS applications, and acts as a central point from which to do so. Given its modular approach, Needle is easily extensible and new modules can be added in the form of python scripts. Needle is intended to be useful not only for security professionals, but also for developers looking to secure their code. A few examples of testing areas covered by Needle include: data storage, inter-process communication, network communications, static code analysis, hooking and binary protections.​ The only requirement in order to run Needle effectively is a jailbroken device. +[Needle](github.com/mwrlabs/needle) is the MWR's iOS Security Testing Framework, released at Black Hat USA in August 2016. It is an open source modular framework which aims to streamline the entire process of conducting security assessments of iOS applications, and acts as a central point from which to do so. Needle is intended to be useful not only for security professionals, but also for developers looking to secure their code. A few examples of testing areas covered by Needle include: data storage, inter-process communication, network communications, static code analysis, hooking and binary protections. The only requirement in order to run Needle effectively is a jailbroken device. + +The release of version 1.0.0 provided a major overhaul of its core and the introduction of a new native agent, written entirely in Objective-C. The new [NeedleAgent](https://github.com/mwrlabs/needle-agent) is an open source iOS app complementary to Needle, that allows to programmatically perform tasks natively on the device, eliminating the need for third party tools.  + +Needle has been presented at and used by workshops in various international conferences like Black Hat USA/EU, OWASP AppSec and DEEPSEC. It was also included by ToolsWatch in the shortlist for the [Top Security Tools of 2016](http://www.toolswatch.org/2017/02/2016-top-security-tools-as-voted-by-toolswatch-org-readers/), and it is featured in the [OWASP Mobile Testing Guide](https://github.com/OWASP/owasp-mstg). Needle is open source software, maintained by [MWR InfoSecurity](https://www.mwrinfosecurity.com/). From e48f1fcf61287149b4c640ead62376dd4c01ceaf Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Tue, 26 Dec 2017 22:13:15 +0100 Subject: [PATCH 18/20] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c51c036..b3a9268 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ _Needle_ is an open source, modular framework to streamline the process of condu Assessing the security of an iOS application typically requires a plethora of tools, each developed for a specific need and all with different modes of operation and syntax. The Android ecosystem has tools like "[drozer](https://mwr.to/drozer)" that have solved this problem and aim to be a ‘one stop shop’ for the majority of use cases, however iOS does not have an equivalent. -[Needle](github.com/mwrlabs/needle) is the MWR's iOS Security Testing Framework, released at Black Hat USA in August 2016. It is an open source modular framework which aims to streamline the entire process of conducting security assessments of iOS applications, and acts as a central point from which to do so. Needle is intended to be useful not only for security professionals, but also for developers looking to secure their code. A few examples of testing areas covered by Needle include: data storage, inter-process communication, network communications, static code analysis, hooking and binary protections. The only requirement in order to run Needle effectively is a jailbroken device. +[Needle](https://github.com/mwrlabs/needle) is the MWR's iOS Security Testing Framework, released at Black Hat USA in August 2016. It is an open source modular framework which aims to streamline the entire process of conducting security assessments of iOS applications, and acts as a central point from which to do so. Needle is intended to be useful not only for security professionals, but also for developers looking to secure their code. A few examples of testing areas covered by Needle include: data storage, inter-process communication, network communications, static code analysis, hooking and binary protections. The only requirement in order to run Needle effectively is a jailbroken device. The release of version 1.0.0 provided a major overhaul of its core and the introduction of a new native agent, written entirely in Objective-C. The new [NeedleAgent](https://github.com/mwrlabs/needle-agent) is an open source iOS app complementary to Needle, that allows to programmatically perform tasks natively on the device, eliminating the need for third party tools.  From 77210e9657d85a450d1084f6a5d1b0a0942a60c6 Mon Sep 17 00:00:00 2001 From: Marco Lancini Date: Thu, 26 Jul 2018 17:50:40 +0100 Subject: [PATCH 19/20] Revert "External sshpass command now supports complex passwords" --- needle/core/device/device.py | 4 ++-- needle/core/device/remote_operations.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/needle/core/device/device.py b/needle/core/device/device.py index 41e29a5..7b6e851 100644 --- a/needle/core/device/device.py +++ b/needle/core/device/device.py @@ -244,7 +244,7 @@ def cleanup(self): def shell(self): """Spawn a system shell on the device.""" - cmd = 'sshpass -p \'{password}\' ssh {hostverification} -p {port} {username}@{ip}'.format(password=self._password, + cmd = 'sshpass -p "{password}" ssh {hostverification} -p {port} {username}@{ip}'.format(password=self._password, hostverification=Constants.DISABLE_HOST_VERIFICATION, port=self._port, username=self._username, @@ -259,4 +259,4 @@ def pull(self, src, dst): def push(self, src, dst): """Push a file on the device.""" self.printer.info("Pushing: %s -> %s" % (src, dst)) - self.remote_op.upload(src, dst) + self.remote_op.upload(src, dst) \ No newline at end of file diff --git a/needle/core/device/remote_operations.py b/needle/core/device/remote_operations.py index 233eb27..0086185 100644 --- a/needle/core/device/remote_operations.py +++ b/needle/core/device/remote_operations.py @@ -98,7 +98,7 @@ def command_blocking(self, cmd, internal=True): def command_interactive(self, cmd): """Run a command which requires an interactive shell.""" self._device.printer.debug("[REMOTE CMD] Remote Interactive Command: %s" % cmd) - cmd = 'sshpass -p \'{password}\' ssh {hostverification} -p {port} -t {username}@{ip} "{cmd}"'.format(password=self._device._password, + cmd = 'sshpass -p "{password}" ssh {hostverification} -p {port} -t {username}@{ip} "{cmd}"'.format(password=self._device._password, hostverification=Constants.DISABLE_HOST_VERIFICATION, port=self._device._port, username=self._device._username, @@ -111,7 +111,7 @@ def command_interactive(self, cmd): def command_interactive_tty(self, cmd): """Run a command in a full TTY shell.""" self._device.printer.debug("[REMOTE CMD] Remote Interactive TTY Command: %s" % cmd) - cmd = 'sshpass -p \'{password}\' ssh {hostverification} -p {port} -t {username}@{ip} "{cmd}"'.format(password=self._device._password, + cmd = 'sshpass -p "{password}" ssh {hostverification} -p {port} -t {username}@{ip} "{cmd}"'.format(password=self._device._password, hostverification=Constants.DISABLE_HOST_VERIFICATION, port=self._device._port, username=self._device._username, @@ -164,7 +164,7 @@ def download(self, src, dst, recursive=False): src, dst = Utils.escape_path_scp(src), Utils.escape_path(dst) self._device.printer.debug("Downloading: %s -> %s" % (src, dst)) - cmd = 'sshpass -p \'{password}\' scp {hostverification} -P {port}'.format(password=self._device._password, + cmd = 'sshpass -p "{password}" scp {hostverification} -P {port}'.format(password=self._device._password, hostverification=Constants.DISABLE_HOST_VERIFICATION, port=self._device._port) if recursive: cmd += ' -r' @@ -179,7 +179,7 @@ def upload(self, src, dst, recursive=True): src, dst = Utils.escape_path_scp(src), Utils.escape_path_scp(dst) self._device.printer.debug("Uploading: %s -> %s" % (src, dst)) - cmd = 'sshpass -p \'{password}\' scp {hostverification} -P {port}'.format(password=self._device._password, + cmd = 'sshpass -p "{password}" scp {hostverification} -P {port}'.format(password=self._device._password, hostverification=Constants.DISABLE_HOST_VERIFICATION, port=self._device._port) if recursive: cmd += ' -r' From 52e14f67d5f818f325a5c6ff4504ac114be62cbc Mon Sep 17 00:00:00 2001 From: Jan Rude Date: Tue, 15 Jan 2019 17:24:59 +0100 Subject: [PATCH 20/20] Update dependency_installer.py Don't use deprecated `apt-get --force-yes` --- needle/modules/device/dependency_installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/needle/modules/device/dependency_installer.py b/needle/modules/device/dependency_installer.py index f0cdfbd..5a41ec3 100644 --- a/needle/modules/device/dependency_installer.py +++ b/needle/modules/device/dependency_installer.py @@ -61,7 +61,7 @@ def __apt_add_repo(self, repo): def __apt_install(self, package): """Install the given package using apt-get.""" - cmd = '{apt} install -y --force-yes {package}'.format(apt=Constants.DEVICE_TOOLS['APT-GET'], package=package) + cmd = '{apt} install -y --allow-downgrades --allow-remove-essential --allow-change-held-packages {package}'.format(apt=Constants.DEVICE_TOOLS['APT-GET'], package=package) self.device.remote_op.command_blocking(cmd, internal=True) def __install_package(self, toolname, tool):