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.

This article is going to explain how to quickly get up to speed with Needle and its usage. To get a copy of Needle, and for a detailed walktrough on how to install it (since both Kali and OSX are supported), follow the “Installation Guide” on the project’s Github Wiki.

First Use

Once ready, to launch Needle just open a console and type:

$ python needle.py
      __  _ _______ _______ ______         ______
      | \ | |______ |______ | \     |      |______
      | \_| |______ |______ |_____/ |_____ |______
                  Needle v0.0.3 [mwr.to/needle]
    [MWR InfoSecurity (@MWRLabs) - Marco Lancini (@LanciniMarco)]

[needle] > help
Commands (type [help|?] <topic>):
---------------------------------
back exit info kill pull reload search shell show use
exec_command help jobs load push resource set shell_local unset

[needle] > show options
Name          Current Value   Required   Description
------------  -------------   --------   -----------
APP                            no        Bundle ID of the target application (e.g., com.example.app). Leave empty to launch wizard
DEBUG         False            yes       Enable debugging output
IP            127.0.0.1        yes       IP address of the testing device (set to localhost to use USB)
PASSWORD      alpine           yes       SSH Password of the testing device
PORT          2222             yes       Port of the SSH agent on the testing device (needs to be != 22 to use USB)
PROXY                          no        Proxy server (address:port)
SETUP_DEVICE  True             yes       Set to true to enable auto-configuration of the device (installation of all the tools needed)
USERNAME      root             yes       SSH Username of the testing device
VERBOSE       True             yes       Enable verbose output

[needle] >

One of the main goals we wanted to achieve with Needle was for it to be easy to use, even for those who are just starting to approach iOS security. With this in mind, as seen above, the command line interface resembles the one adopted by Metasploit.

The tool has some global options (listed with the “show options” command, and set with the “set <option> <value>” command):

  • USERNAME, PASSWORD: SSH credentials of the testing device (set by default to “root” and “alpine”, respectively)
  • IP, PORT: the session manager embedded in the core of Needle is able to handle SSH connections over Wi-Fi or USB. If SSH-over-USB is the chosen method, the IP option must be set to localhost (“set IP 127.0.0.1”), and PORT set to anything different from 22 (“set PORT 2222”)
  • VERBOSE, DEBUG: if set to True, they will enable verbose and debug logging, respectively
  • SETUP_DEVICE: if set to True, Needle checks if all the dependencies needed are already present on the device, otherwise it will install them
  • APP: this is the bundle identifier of the app to analyze (e.g., “com.example.app”). If it is not known beforehand, this field can be left empty. In this case, Needle will launch a wizard which prompts the user to select an app among those already installed on the device

Basic Features

Although the power of Needle is comprised in its modules, the core itself offers some basic features that allow it to interact with the device.

Execute local command (<cmd>)

Needle’s CLI is basically a shell itself, so it is possible to run commands on the local workstation just by typing them.

[needle] > cat /etc/hostname
[*] Executing Local Command: cat /etc/hostname
launchpad

[needle] > ifconfig lo
[*] Executing Local Command: ifconfig lo
lo Link encap:Local Loopback
 inet addr:127.0.0.1 Mask:255.0.0.0
 inet6 addr: ::1/128 Scope:Host
 UP LOOPBACK RUNNING MTU:65536 Metric:1
 RX packets:48454 errors:0 dropped:0 overruns:0 frame:0
 TX packets:48454 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:0
 RX bytes:33149117 (31.6 MiB) TX bytes:33149117 (31.6 MiB)

Shell (shell)

Type “shell” to drop a shell on the remote device.

[needle] > shell
[*] Spawning a shell...
[*] Checking connection with device...
[V] Connection not present, creating a new instance
[V] Setting up USB port forwarding on port 2222
[V] Setting up SSH connection...
[+] Connected to: 127.0.0.1
Warning: Permanently added '[127.0.0.1]:2222' (RSA) to the list of known hosts.
MWR-iPhone:~ root# id
uid=0(root) gid=0(wheel) groups=0(wheel),...

Execute command on device (exec_command <cmd>)

To execute a single command on the remote device.

[needle] > exec_command id
[*] Checking connection with device...
[+] Already connected to: 127.0.0.1
[*] Executing: id
 uid=0(root) gid=0(wheel) groups=0(wheel)...

Push/pull files (<push/pull> <src> <dst>)

It is also possible to retrieve or upload files from/on the device. Note that both the source and destination paths must be enclosed in quotes.

[needle] > pull "/etc/hosts" "/tmp/iphone_hosts"
[*] Checking connection with device...
[+] Already connected to: 127.0.0.1
[*] Pulling: /etc/hosts -> /tmp/iphone_hosts
[needle] > cat /tmp/iphone_hosts
[*] Executing Local Command: cat /tmp/iphone_hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost

Autoconfiguration

Configuration of the global options can also be automated, using a resource file. First, create a resource file with the commands you want to have automatically executed. For example:

$ cat config.txt
# This is a comment, it won't be executed
set DEBUG False
set VERBOSE False

# If SETUP_DEVICE is set to True,
# Needle will automatically install all the required tools on the device
set SETUP_DEVICE False

set IP 192.168.0.10
set PORT 5555
set APP com.example.app
use binary/metadata

Then, launch Needle and instruct it to load the resource file:

python needle.py -r config.txt

Modular approach

Another goal that shaped Needle’s design was for it to be easily extensible. That’s the reason why every feature has been wrapped in its own module.

Since every module focuses on a particular task, with the core handling common problems (like communication with the device, actual execution of commands, etc.), creation of new modules is a matter of a few lines of python code.

The “show modules” command can be used to list all the modules currently available in the framework.

[needle][install] > show modules

Binary
------
 binary/class_dump
 binary/compilation_checks
 binary/install
 binary/metadata
 binary/pull_ipa
 binary/shared_libraries
 binary/strings

Comms
-----
 comms/certs/delete_ca
 comms/certs/export_ca
...

Otherwise, the “search " command can be used to search available modules that match the query.

[needle] > search binary
[*] Searching for "binary"...

Binary
------
 binary/class_dump
 binary/compilation_checks
 binary/install
 binary/metadata
 binary/pull_ipa
 binary/shared_libraries
 binary/strings

Storage
-------
 storage/data/files_binarycookies

Once selected, the “info” command can be used to show details of a particular module.

[needle] > use binary/strings
[needle][strings] > info

Name: Strings
Path: modules/binary/strings.py
Author: @LanciniMarco (@MWRLabs)

Description:
Find strings in the (decrypted) application binary, then try to extract URIs and ViewControllers

Options:
 Name     Current Value                    Required   Description
 -------  -------------                    --------   -----------
 ANALYZE  True                             no         Analyze recovered strings and try to recover URI
 FILTER                                    no         Filter the output (grep)
 LENGTH   10                               yes        Minimum length for a string to be considered
 OUTPUT   /root/.needle/tmp/strings.txt    no         Full path of the output file

Or, to get only the available options:

[needle][strings] > show options
 Name     Current Value                    Required   Description
 -------  -------------                    --------   -----------
 ANALYZE  True                             no         Analyze recovered strings and try to recover URI
 FILTER                                    no         Filter the output (grep)
 LENGTH   10                               yes        Minimum length for a string to be considered
 OUTPUT   /root/.needle/tmp/strings.txt    no         Full path of the output file

Like the global options, even module-specific ones can be edited with the “set” and “unset” commands.

[needle][strings] > set FILTER password
FILTER => password
[needle][strings] > show options
 Name     Current Value                    Required   Description
 -------  -------------                    --------   -----------
 ANALYZE  True                             no         Analyze recovered strings and try to recover URI
 FILTER   password                         no         Filter the output (grep)
 LENGTH   10                               yes        Minimum length for a string to be considered
 OUTPUT   /root/.needle/tmp/strings.txt    no         Full path of the output file

When all the options are set as preferred, the “run” command can be used to start the module’s execution. If a target app has not been selected yet (with the global option “TARGET_APP” still unset), Needle will first launch a wizard that will help the user in selecting a target.

[needle][strings] > run
[*] Checking connection with device...
[+] Already connected to: 127.0.0.1
[V] Creating temp folder: /var/root/needle/
[*] Target app not selected. Launching wizard...
[V] Refreshing list of installed apps...
[+] Apps found:
    0 - com.highaltitudehacks.dvia
    1 - uk.co.bbc.newsuk
Please select a number: 0
[+] Target app: com.highaltitudehacks.dvia
[*] Decrypting the binary...
[?] The app might be already decrypted. Trying to retrieve the IPA...
[V] Decrypted IPA stored at: /var/root/needle/decrypted.ipa
[*] Unpacking the decrypted IPA...
[V] Analyzing binary...
[+] The following strings has been found:
     %@: Unable to get password of credential %@
     %s -- Cannot be used in OpenSSL mode. An IV or password is required
     Both password and the key (%d) or HMACKey (%d) are set.
     CFHTTPMessageAddAuthentication(httpMsg, _responseMsg, (__bridge CFStringRef)_credential.user, (__bridge CFStringRef)password, kCFHTTPAuthenticationSchemeBasic, _httpStatus == 407)
     Cannot sign up without a password.
     Congrats! You've found the right username and password!
     Huh, couldn't get password of %@; trying again
     Please enter a password
     T@"NSString",&,N,V_password
     T@"NSString",C,N,V_password
     T@"UITextField",&,N,V_passwordTextField
     ...
[*] Saving output to file: /root/.needle/tmp/strings.txt

Finally, the “show source” command can be used to inspect the actual source code of the selected module.

[needle][strings] > show source
 1|from core.framework.module import BaseModule
 2|
 3|
 4|class Module(BaseModule):
 5|    meta = {
 6|           'name': 'Strings',
 7|           'author': '@LanciniMarco (@MWRLabs)',
 8|           'description': 'Find strings in the (decrypted) application binary, then try to extract URIs and ViewControllers',
 9|           'options': (
10|                      ('length', 10, True, 'Minimum length for a string to be considered'),
11|                      ('filter', '', False, 'Filter the output (grep)'),
12|                      ('output', True, False, 'Full path of the output file'),
13|                      ('analyze', True, False, 'Analyze recovered strings and try to recover URI'),
14|          ),
15|    }
16|
17|    # ====================================================================
18|    # UTILS
19|    # ====================================================================
20|    def __init__(self, params):
21|        BaseModule.__init__(self, params)
...

Background jobs

Needle also has support for background jobs that can be left running during the execution of other modules. Some modules, especially those containing the “monitor” keyword in their name, rely on such background jobs.

[needle] > use dynamic/monitor/files
[needle][files] > info

Name: Monitor File changes
Path: modules/dynamic/monitor/files.py
Author: @LanciniMarco (@MWRLabs)

Description:
    Monitor the app data folder and keep track of modified files

Options:
 Name    Current Value                       Required   Description
 ------  -------------                       --------   -----------
 FOLDER                                      no         The folder to monitor (leave empty to use the app Data directory
 OUTPUT  /root/.needle/tmp/modifiedfiles.txt no         Full path of the output file


[needle][files] > run
[*] Checking connection with device...
[+] Already connected to: 127.0.0.1
[+] Target app: com.highaltitudehacks.dvia
[+] Monitoring: /private/var/mobile/Containers/Data/Application/031CAB32-6115-4613-B56F-CFF61BCED692
[*] Monitoring in background...Kill this process when you want to see the dumped content

[needle] >

The “jobs” command can be used to list all the currently running background processes.

[needle] > jobs
[+] Running jobs:
 0 - dynamic_monitor_files
[needle] >

The “kill” command can then be used to stop a background job, and therefore retrieve its output.

[needle][files] > kill 0
[D] [REMOTE CMD] Stopping Remote Background Command [pid: 510]
[D] [REMOTE CMD] Remote Command: kill 510
[*] Retrieving output file...
[*] Pulling: /var/root/needle/fsmon -> /root/.needle/tmp/modifiedfiles.txt
[+] Content of file '/root/.needle/tmp/modifiedfiles.txt':
FSE_CREATE_FILE 512 "DamnVulnerableIO" /private/var/mobile/Containers/Data/Application/05F34A75-55C6-41E4-BB51-0F3777DF6D97/tmp/cy-TS2mr3.dylib
FSE_DELETE 512 "DamnVulnerableIO" /private/var/mobile/Containers/Data/Application/05F34A75-55C6-41E4-BB51-0F3777DF6D97/tmp/cy-TS2mr3.dylib
FSE_CONTENT_MODIFIED 512 "DamnVulnerableIO" /private/var/mobile/Containers/Data/Application/05F34A75-55C6-41E4-BB51-0F3777DF6D97/tmp/cy-TS2mr3.dylib
FSE_XATTR_MODIFIED 512 "DamnVulnerableIO" /private/var/mobile/Containers/Data/Application/05F34A75-55C6-41E4-BB51-0F3777DF6D97/Library/Private Documents/Parse
FSE_XATTR_MODIFIED 512 "DamnVulnerableIO" /private/var/mobile/Containers/Data/Application/05F34A75-55C6-41E4-BB51-0F3777DF6D97/Library/Application Support/FlurryFiles
...
[*] A copy of the output has been saved at the following location: /root/.needle/tmp/modifiedfiles.txt
[needle] >

Features

Here we are going to list some of the modules included in v0.0.3 of Needle. For a complete (and up to date) list of supported features, please refer to the “Feature List” on the project’s Github Wiki.

Binary Analysis

  • binary/class_dump: Dump the class interfaces
  • binary/compilation_checks: Check for basic binary protections (PIE, ARC, stack canaries, binary encryption)
  • binary/install: Automatically upload and install an IPA on the device
  • binary/metadata: Retrieve and display the app’s metadata (UUID, app name/version, bundle name/id, bundle/data/* binary directory, binary path/name, entitlements, url handlers, architectures, platform/sdk/os version)
  • binary/pull_ipa: Decrypt and pull the application’s IPA from the device
  • binary/shared_libraries: List the shared libraries used by the application
  • binary/strings: Find strings in the (decrypted) application binary, then tries to extract URIs and ViewControllers

Storage

  • storage/caching/screenshot: Test if a screenshot of the application’s main window is cached when the application’s process is moved to the background
  • storage/data/files_binarycookies: List the Binary Cookies files contained in the app folders, along with their Data Protection Class. Plus, offers the chance to pull and inspect them
  • storage/data/files_cachedb: List the Cache.db files contained in the app folders, along with their Data Protection Class. Plus, offers the chance to pull and inspect them
  • storage/data/files_plist: List the plist files contained in the app folders, along with their Data Protection Class. Plus, offers the chance to inspect them
  • storage/data/files_sql: List the SQL files contained in the app folders, along with their Data Protection Class. Plus, offers the chance to pull and inspect them
  • storage/data/keychain_dump: Dump the keychain

Dynamic Analysis

  • dynamic/detection/jailbreak_detection: Verify that the app cannot be run on a jailbroken device
  • dynamic/ipc/open_uri: Test IPC attacks by launching URI Handlers
  • dynamic/memory/heap_dump: Dump memory regions of the app and look for strings
  • dynamic/monitor/files: Monitor the app data folder and keep track of modified files
  • dynamic/monitor/pasteboard: Monitor the OS Pasteboard and dump its content
  • dynamic/monitor/syslog: Monitor the syslog in background and dump its content
  • dynamic/watch/syslog: Watch the syslog in realtime

Hooking

  • hooking/cycript/cycript_shell: Spawn a Cycript shell attached to the target app
  • hooking/frida/frida_launcher: Run Frida scripts (JS payloads)
  • hooking/frida/frida_shell: Spawn a Frida shell attached to the target app
  • hooking/frida/frida_trace: Trace the specified functions using frida-trace
  • hooking/frida/script_enum-all-methods: Enumerate all methods from all classes in the application
  • hooking/frida/script_enum-classes: Enumerate available classes
  • hooking/frida/script_find-class-enum-methods: Find the target class specified and enumerate its methods

Communications

  • comms/certs/delete_ca: Delete one (or more) certificates installed on device
  • comms/certs/export_ca: Export one (or more) certificates installed on device
  • comms/certs/import_ca: Import a certificate from a file in PEM format
  • comms/certs/install_ca_mitm: Install the CA Certificate of MitmProxy on the device
  • comms/certs/list_ca: List the certificates installed on device
  • comms/proxy/proxy_regular: Intercept the traffic generated by the device

Static Analysis

  • static/code_checks: Static analysis of the apps’s source code. Aims to find usage of potentially insecure functions. If 2 folders are specified (for example if we have 2 versions of the same codebase), Needle will detect the files that has been modified, and will apply the checks only on those ones