Introduction

Firstly I want to note I’m not a security researcher, ethical hacker or at all competent at reverse engineering. I’m currently working as a Java developer but I’ve always had an hobby interest in computer security.

Recently I’ve been ever more interested in the security side of things and have been studying various topics, from binary exploitation, reverse engineering to WPA cracking. I decided I would start writing blogs on my learning; and the application of that learning. Even if nobody reads it at least I will have notes on previous projects, and I find that writing things down always commits my thoughts more thoroughly.

Finding a Target

Today I had quite a bit of free time so I decided I would try my hand at reverse engineering. My experience with Java is sound having programmed commercially with it for a number of years, and Java decompilers can normally provide the exact source code (providing no obfuscation was undertaken), so reverse engineering something written in Java seemed like the best choice.

I was having a think about what kind of project to reverse engineer when I remembered something I had seen in the comments of an eclipse plugin which had put me off using that plugin.

From the Eclipse Class Decompiler plugin page: (https://marketplace.eclipse.org/content/eclipse-class-decompiler)

This seemed rather suspect and I wouldn’t have expected an eclipse plugin to have this functionality.

Note that this plugin is in the top 20 most downloaded eclipse plugins of all time, with almost 400k downloads.

Investigation

So first things first I need to get a copy of the plugin and then decompile it, or at least find the source of the project.

The first place I checked out was the projects website (http://www.cpupk.com/decompiler/) which led me to its github page (https://github.com/cnfree/Eclipse-Class-Decompiler/). I had a look around the code on github but couldn’t seem to find the “phone home” functionality. Perhaps I was missing something but I had other suspicions. So I decided I would install the extension and decompile the binaries.

Now since I suspected this plugin could have something sinister within I wasn’t going to install it on my actual machine. Instead I span up a new windows VM and installed java and eclipse.

I then installed the plugin and had a look around the filesystem for the plugin binaries. Finally finding them in the <user_home>/.p2/pool/plugins directory.

I pulled the jars off of the VM into my main eclipse, where I use (what I believe is) a reputable decompiler, jd (http://jd.benow.ca/), to analyse the classes. On opening the main plugin class I found some shall we say interesting code, which appeared to store a variable called “adclick.count”.

Note that this code didn’t appear in the github version of the project.

I quickly found the binaries contained quite a lot of classes so rather than manually inspect them all (which might take quite a few hours) I decided to grep the decompiled source for the ‘java.net.*’ package, since the comments on the eclipse marketplace page appeared to suggest some connections were happening.

So now I had a smaller code set to have a more thorough look at.

After inspecting these classes I found some suspect code in IOUtils, which appeared to provide a helper method for closing HTTP connections (why would a code decompiler need to close HTTP connections?).

Next, in the UIUtil class I found a method which appeared to open URLs in an external browser, and increment the adclick.count variable.

In the UserUtil class I found quite a bit to be concerned about. Firstly there appeared to be multiple calls to various (seemingly unrelated) websites in the collectUserIp() method.

I traced this method to see what the code was doing with this information

… and found that it was being used in a class called BackgroundHandler.

Inspection of this class found that the code was collecting a plethora of information about the users system, converting it to a JSON object then sending it to the URL “http://decompiler.cpupk.com/statistics.php”.

At this point I wanted to see what information the plugin was receiving and then sending to its server. I setup burp (https://portswigger.net/burp/) on my host machine and bound the HTTP proxy to its local network address. This would allow the guest OS to proxy to this.

And then set the proxy settings in the windows guest OS.

I started up eclipse again and watched the requests/responses sent through the proxy. Firstly there were some calls to eclipse (as you might expect), however I soon received the calls from thecollectUserIp() method. The pv.sohu.com/cityjson appears to return a javascript variable with the callers IP address and a continent id and name.

Next I observed the call to ip.taobao.com/service/ipinfo.php, which appears to return more specific geographical information about the ip address given.

Lastly I observed the “call home” functionality the comment from the marketplace seemed to talk about. Which compiled the information gathered and sent it to decompiler.cpupk.com/statistics.php.

I turned my attention back to the analyzeUserInfo() class as the call to upload the user information must actually have an important response, the response was handled by a number of further methods.

The method which stood out was checkAdConfig. The checkAdConfig method parses a JSON object for a number of variables; adConfig, adCondition, adStyles…

Burp revealed the response object from the server. Not all of the available variables were being provided currently.

I decided to search the code again this time for the adclick.count variable discovered earlier in the investigation. This time I found a yet unexplored class, HtmlLinkTrimItem.

This class had a number of interesting features. Firstly it appears to provide a browser implementation. Secondly it calls a method updateTrimUrl() on initialisation which appears to call a URL as defined by the trayLinkUrl property in a seperate thread using a non-visible browser.

I had a search around the code to see where the HtmlLinkTrimItem class was referenced. And found it referenced in a number of other classes.

The TrayLinkV1 and TrayLinkV2 classes are used by a class LinkTrimChecker, which appears to use them to instantiate the HtmlLinkTrimItem (which would in turn trigger the background browser).

The LinkTrimChecker.displayTrayLink method is called by the TrayLinkUtil.displayTrayLink method which in turn is used by the BackgroundHandler.checkTrayLink method.

If you were watching closely earlier then you may have noticed that the checkTrayLink method is one of the methods which processes the JSON object returned by the home server.

The TrayLinkUtil.displayTrayLink appears to be called when there is a trayLink JSON object within the response.

Burp had previously shown this object existed but was blank in the response I recorded earlier.

So what happens if the object isn’t blank?

Well the displayTrayLink method would be called, which would delegate to LinkTrimChecker, as previouly discussed.

But you may notice the second parameter to the delegated method, TrayLinkUtil.enableShowTrayLink(), it appears that this must also resolve to true for the background browser to be enabled. This method checks that the preference store contains a property ‘trayLinkStrategy’ and that a matchAdCondition method from the UserUtil class returns true.

During my earlier investigation I noticed that the trayLinkStrategy property is set when the trayLink JSON object is parsed from the server response.

Next I had a look at the matchAdCondition method. This method checks if the preference store contains an adCondition integer (or defaults to 100). And compares the total number of user decompiled classes against this value. Returning true if the user has decompiled more than this number.

So it appears the background browser will start making requests after a user has decompiled more than 100 classes, or if the adCondition field of the server response was changed to a value less than the users decompiled class count.

Next I wanted to investigate how the trayLinkUrl was being set as this is the URL the background browser is opening. I found this functionality in the TrayLinkUtil class. The trayLinkStrategy property (set by the server response), needs to be populated and then a second method checks the property, if it contains a JSON object with a url field it returns this url. Otherwise it may contain an array of these objects with a priority weighting which is used to randomly (with weighting) select the url.

I had also noticed that the background browser was opened on a timer, this timer was defined by the getTrayUrlDisplayTime method in the TrayLinkUtil class again. This method appears to suggest that the trayLinkStrategy JSON object could also contain a property ‘showTime’ along with the url previously discovered.

I decided to combine everything I had learned so far and try and modify the server response (using burp) to trigger the adware functionality. I modified the response to include a trayLink object containing a URL to google.com along with a showTime of 1 minute. I also included an adCondition of 2, as I would have undoubtedly crossed this limit already.

At this point I hooked jvisualvm (https://visualvm.github.io/) to eclipse and took a heap dump. I wanted to confirm the modifications I had made were indeed within the properties. I ran the following object query (OQL) on the heap dump.

select s from java.lang.String s where s.toString().equals(“trayLinkStrategy”)

This provided me with 2 hits, the top hit was referenced in the eclipse InstanceProperties and I was able to observe my changes.

Notice that the value and key table items 3 and 8 contain the trayLinkStrategy and adCondition. Now set to the JSON object I added along with the value 2 for adCondition.

After around a minute I noticed burp had focused, and I could see that the VM had made a request to google:80. Success!

In order to ensure this wasn’t a fluke (as I imagine quite a few different applications/code may have reason to contact google), I repeated the test with imgur.com.

And the results were the same, the VM was making requests to imgur.com:80.

At this point I noticed that the windows VM was getting errors which look like IE certificate issues. I assume this is due to imgur requesting resources over TLS and the burp certificate not matching the DN of these resources.

You can see here the stream of calls to imgur when I left eclipse running.

Conclusions

So I’m pretty happy with the results of my efforts, I was able to uncover what very much looks like adware in one of the most installed plugins for eclipse, along with the commented “call home” method. I think the fact that this code doesn’t appear in the published github source code is evidence that it probably shouldn’t be there.

I need to mention that only the functionality exists and at no point have I witnessed the response from the server actually providing the required JSON object to trigger the adware.

I’m going to contact eclipse about this plugin as I imagine they don’t condone having this sort of functionality.

If anyone has any questions please feel free to leave a comment.

Edit: After some further thoughts it occurred to me that this code could potentially be used to download files onto the users system (still to test). This is especially egregious as the communication is completely unencrypted.

Another edit: I tested the theory of the above edit.

I created a fake java payload jar file which just contained a JFrame with a message in it and hosted it on port 80 of the host computer using python

sudo python3 -m http.server 80

When I set my host PC to be the “trayLink” I got the following displaying in the VM.

Obviously I wouldn’t expect anyone to open or save this particular file, but perhaps with another vulnerability they wouldn’t have to click anything, or with some social engineering; for example what if the popup said EclipseUpdate.exe?

As the “call home” call is in HTTP this could also be used to attack victims by modifying the response calls through MITM.

Edit 3: Eclipse have removed the plugin from the marketplace and released a press release advising that users uninstall the plugin (https://eclipse.org/org/press-release/20170814_security_bulletin.php).