WithSecureLabs / needle

The iOS Security Testing Framework
https://mobiletools.mwrinfosecurity.com/
Other
1.33k stars 284 forks source link

Fix logic issue in "script_anti-hooking-check.py" if an app has not been set #216

Closed Yogehi closed 6 years ago

Yogehi commented 6 years ago

the "def module_pre(self)" function calls the function 'module_pre' in the class 'FridaScript' in the file '/needle/needle/core/framework/module.py'.

in this function, line 299 tries to spawn the app using 'self.app_metadata'. however, this assumes that the user had already set an app to begin with. usually, when you start a needle module and you haven't specified an app yet, needle will make the user go through the wizard of selecting an app.

so if the user had not specified an app yet before running this module, then needle will error out while trying to execute this module.

i opted to comment out the offending code in this module instead of deleting because i wasn't sure why the function 'module_pre' was in this module to begin with.

marco-lancini commented 6 years ago

@Yogehi, if an app hasn't been selected yet, then (rather than commenting out the entire module_pre function, you can do the following:

def module_pre(self):
        return BaseModule.module_pre(self, bypass_app=True)

@HenryHoggard I suggest to close this PR without merging it

Yogehi commented 6 years ago

@marco-lancini I tried the fix that was outlined. I got the following error:

 ------------------------------------------------------------
Traceback (most recent call last):
  File "/root/Programs/needle/needle/core/framework/module.py", line 111, in do_run
    pre = self.module_pre()
  File "/root/Programs/needle/needle/modules/hooking/frida/script_anti-hooking-check.py", line 45, in module_pre
    return BaseModule.module_pre(self, bypass_app=True)
NameError: global name 'BaseModule' is not defined
------------------------------------------------------------
[!] NameError: global name 'BaseModule' is not defined

Full 'script_anti-hooking-check.py' script below:

from core.framework.module import FridaScript

class Module(FridaScript):
    meta = {
        'name': 'Frida Script: Anti Hooking Checks',
        'author': 'Henry Hoggard (@MWRLabs)',
        'description': 'Display an Alert in the target application. Can be used as simple proof that there are no anti-hooking checks in place.',
        'options': (
            ('title', "Needle", True, 'Title of alert box.'),
            ('content', "If this message is visible, this application has insufficient anti-hooking protections.", True, 'Content of alert box.')
        ),
    }

    JS = '''\
if(ObjC.available) {
    var handler = new ObjC.Block({
      retType: 'void',
      argTypes: ['object'],
      implementation: function () {
      }
    });
    var UIAlertController = ObjC.classes.UIAlertController;
    var UIAlertAction = ObjC.classes.UIAlertAction;
    var UIApplication = ObjC.classes.UIApplication;
    ObjC.schedule(ObjC.mainQueue, function () {
      var title = "%s";
      var content = "%s";
      var alert = UIAlertController.alertControllerWithTitle_message_preferredStyle_(title, content, 1);
      var defaultAction = UIAlertAction.actionWithTitle_style_handler_('OK', 0, handler);
      alert.addAction_(defaultAction);
      UIApplication.sharedApplication().keyWindow().rootViewController().presentViewController_animated_completion_(alert, true, NULL);
    })
} else {
    console.log("Objective-C Runtime is not available!");
}
    '''

    msg = None

    # ==================================================================================================================
    # RUN
    # ==================================================================================================================
    def module_pre(self):
        return BaseModule.module_pre(self, bypass_app=True)

    def module_run(self):
        # If error has been detected, log issue and exit
        if self.msg:
            self.add_issue('Anti-Hooking Check', 'It was not possible to attach frida: {}'.format(self.msg), 'INVESTIGATE', None)
            return
        # Run the payload
        try:
            self.printer.info("Parsing payload")
            title = self.options['title']
            content = self.options['content']
            hook = self.JS % (title, content)
            script = self.session.create_script(hook)
            script.on('message', self.on_message)
            script.load()
        except Exception as e:
            self.printer.warning("Script terminated abruptly")
            self.printer.warning(e)
marco-lancini commented 6 years ago

@Yogehi the one above is a generic example on how to bypass the app validation. In this case, the script_anti-hooking-check.py is an instance of FridaScript, therefore you'll have to:

def module_pre(self):
        return FridaScript.module_pre(self, bypass_app=True)
Yogehi commented 6 years ago

Got a different error.

[needle] > set debug true
DEBUG => true
[needle] > use hooking/frida/script_anti-hooking-check
[needle][script_anti-hooking-check] > run
------------------------------------------------------------
Traceback (most recent call last):
  File "/root/Programs/needle/needle/core/framework/module.py", line 111, in do_run
    pre = self.module_pre()
  File "/root/Programs/needle/needle/modules/hooking/frida/script_anti-hooking-check.py", line 45, in module_pre
    return FridaScript.module_pre(self, bypass_app=True)
TypeError: module_pre() got an unexpected keyword argument 'bypass_app'
------------------------------------------------------------
[!] TypeError: module_pre() got an unexpected keyword argument 'bypass_app'

Full script below:

from core.framework.module import FridaScript

class Module(FridaScript):
    meta = {
        'name': 'Frida Script: Anti Hooking Checks',
        'author': 'Henry Hoggard (@MWRLabs)',
        'description': 'Display an Alert in the target application. Can be used as simple proof that there are no anti-hooking checks in place.',
        'options': (
            ('title', "Needle", True, 'Title of alert box.'),
            ('content', "If this message is visible, this application has insufficient anti-hooking protections.", True, 'Content of alert box.')
        ),
    }

    JS = '''\
if(ObjC.available) {
    var handler = new ObjC.Block({
      retType: 'void',
      argTypes: ['object'],
      implementation: function () {
      }
    });
    var UIAlertController = ObjC.classes.UIAlertController;
    var UIAlertAction = ObjC.classes.UIAlertAction;
    var UIApplication = ObjC.classes.UIApplication;
    ObjC.schedule(ObjC.mainQueue, function () {
      var title = "%s";
      var content = "%s";
      var alert = UIAlertController.alertControllerWithTitle_message_preferredStyle_(title, content, 1);
      var defaultAction = UIAlertAction.actionWithTitle_style_handler_('OK', 0, handler);
      alert.addAction_(defaultAction);
      UIApplication.sharedApplication().keyWindow().rootViewController().presentViewController_animated_completion_(alert, true, NULL);
    })
} else {
    console.log("Objective-C Runtime is not available!");
}
    '''

    msg = None

    # ==================================================================================================================
    # RUN
    # ==================================================================================================================
    def module_pre(self):
        return FridaScript.module_pre(self, bypass_app=True)

    def module_run(self):
        # If error has been detected, log issue and exit
        if self.msg:
            self.add_issue('Anti-Hooking Check', 'It was not possible to attach frida: {}'.format(self.msg), 'INVESTIGATE', None)
            return
        # Run the payload
        try:
            self.printer.info("Parsing payload")
            title = self.options['title']
            content = self.options['content']
            hook = self.JS % (title, content)
            script = self.session.create_script(hook)
            script.on('message', self.on_message)
            script.load()
        except Exception as e:
            self.printer.warning("Script terminated abruptly")
            self.printer.warning(e)
HenryHoggard commented 6 years ago

On brief look this needs a patch in framework/module.py . The Frida module_pre should be calling app_check(). @marco-lancini thoughts?

marco-lancini commented 6 years ago

Not necessarily, Frida scripts could be quite independent from specific apps

Yogehi commented 6 years ago

closing PR to clear up commit clutter

new PR: https://github.com/mwrlabs/needle/pull/232