automating ios blackbox security scanning - zeronights · automating ios blackbox security scanning...

Post on 05-Jun-2020

14 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Automating iOS blackbox security scanningMikhail Sosonkin mikhail@synack.com

SYNACK Inc.

ME!

“leverages the best combination of humans and technology to discover security vulnerabilities in our customers’ web apps, mobile apps, IoT devices and infrastructure endpoints”

Employer!

- SYNACK.com

Why do we care?

Our privacy. Our money.Our freedoms.

Wouldn’t want to lose any of those things!

Step 2: Apply IDAPro

For those that don’t know Aarch64IdaRef documentation plugin: https://github.com/nologic/idaref

DYLD_INSERT_LIBRARIES=dumpdecrypted.dylibThanks Stephan Esser!

In-process• Frida• Cycrypt• LLDB

• Tracing Objective-C calls and mach port messages• https://github.com/nologic/objc_trace

External

• FileMon• MiTM proxy

SSL Kill Switch

Step 3: Dynamic Analysis

• Objective-C messages• On iOS, more meaningful than strace• Might want to hit/fuzz a particular method• In case of Swift, we see runtime library interactions

• Swift Reversing by Ryan Stortz

• Mach Port Messages• Any sort of IPC• CFMessagePort, etc

Collecting Coverage Information

1. Allocate a page - a jump page

2. Set objc_msgSend readable and writable

3. Copy preamble bytes from objc_msgSend

4. Check for branch instructions in preamble

5. Modify objc_msgSend preamble

6. Set jump page to readable and executable

7. Set objc_msgSend readable and executable

Objc_Trace

Call Sequence

Hook Steps

void* hook_callback64_pre(id self, SEL op, void* a1, ...) {

Class cls = object_getClass(self);

if(cls != NULL && op != NULL)

cacheImp = c_cache_getImp(cls, op);

if(!cacheImp) {

// not in cache, never been called, record the call.

const struct mach_header* libobjc_base = libobjc_dylib_base();

c_cache_getImp = (p_cache_getImp)((uint8_t*)libobjc_base) + 97792 + 0x4000;

Important Optimization

Only record unseen method calls

Find the cache check function cache_getImp

What do we get out of this?

{ '_payload': { '_payload': { '_msg': '\x00\x00\x08\x00\x00\x00subsystem\x00\x00\x00\x00@\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00ha', 'type': 2048},

'magic': '!CPX',

'version': 5},

'msgh_bits': 1250579,

'msgh_id': 268435456,

'msgh_local_port': '0x30b',

'msgh_remote_port': '0x10b',

'msgh_reserved': 2819,

'msgh_size': 256}

MACH Shark

Machshark

• Attach using LLDB• Breakpoint on

• bootstrap_look_up2• Rocketbootstrap_look_up or bootstrap_look_up3• mach_msg

• Least intrusive but slow• Harder to get the responses

• Often less important• Compensate by breakpointing the server

• Detailed on debugtrap.com

Another mach_shark method

Most apps are largely user reactive in nature

The difficulty of Apps

“A little engine for driving the UI while doing

blackbox testing of an iOS App”

- CHAOTICMARCH

• Time saving• Repeatable• WebAPI Discovery• Code Coverage

• Discover Preinstalled Malware• Cameras arrived with malware from Amazon

Why automate?

Apply intelligence!

● Simulate the user ● Read and understand the UI

How does the UI look like in memory?

cy# UIApp.keyWindow

<UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray>;>

| <TiRootViewNeue; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer>>

...

<TiUITableViewCell; baseClass = UITableViewCell; text = 'Log On';

| <TiGradientLayer;> (layer)

| <UITableViewCellContentView; frame = (0 0; 256 43.5); layer = <CALayer>>

| | <UITableViewLabel; frame = (74 0; 167 43.5); text = 'Log On'>

| | <UIImageView; frame = (15 0; 44 43.5); layer = <CALayer>>

| <_UITableViewCellSeparatorView; frame = (74 43.5; 182 0.5); layer = <CALayer>>

● Lua Scriptable Logic● Standard functions for touching the device● Options for record/replay● Finding UI Components● Regulating speed of execution● Support for multiple targets● Mechanisms for generic logic● Lightweight injected module

CHAOTICMARCH

Source

Powered by:

• LibSimulateTouch• LUA• #import <UIKit/UIKit.h>

CHAOTICMARCH

while true dolocal button = getButton(clickedButtons)

-- put some info in.fill_all_fields()click_button(button)

if(button["text"] ~= nil) thenclickedButtons[button["text"]] = 1

endusleep(2 * 1000000)

end

A basic script

• Discovery• WebAPI - gives you working samples.• Local behaviour

• File accesses, IPC interactions, and code coverage

• Fuzzing• Testing kiosk type apps.• Automate the UI to trigger events.

Applications

Deadly in the right combination

MITM Proxy

Request

Fuzz

Parse

Mutator

Attack scenario

1 - Make a post

2 - Get exploited binary/XSS with phish

3 - Steal creds or tokens

4 - Put up a draft

5 - Request messages

6 - respond with attack content

AttackerUser

We focus on this

while true do

local inputs = findOfTypes("UITextField", "")

for index, inputField in pairs(inputs) do

click_button(inputField)

inputText("SomeInput!!")

end

-- touch login

touchDown(3, 138, 619);

usleep(83148.83);

touchUp(3, 141, 615);

check_alert()

end

Source

Defending apps from undesirable automation!

• Detecting hidden components is not straightforward!• Misuse

• Labels as buttons• Input forms as labels

• Trees of invisible to the user elements• Kind of like anti-debugging or anti-RE.

Anti Automation techniques

• Apps are important!• Automation of the UI• Collection of coverage information• Fuzzing of responses messages

Wrap up!

Questions?

Email: mikhail@synack.com, blog: debugtrap.comTwitter: @hexlogic

Source:CHAOTICMARCH: https://github.com/synack/chaoticmarch

Machshark: https://github.com/nologic/machshark

Objc_trace: https://github.com/nologic/objc_trace

Thank you!

Images: http://iconmonstr.com/

top related