Reverse Engineering an Eclipse Plugin

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)

0 the target - eclipse class decompiler.png

comments.png

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.

400kinstalls.png

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.

1 make new vm

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.

Found jars in filesystem plugins dir.png

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”.

adclick in source.png

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

adclick not in github.png

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.

search results.png

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?).

IOUtils contains methods for closing sockets.png

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

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.

UserUtil hmmm.png

I traced this method to see what the code was doing with this informationCall hierarchy of collectUserip().png

… 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&#8221;.

analyzeUserInfo.png

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.

2 burp address bind.png

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

4 set proxy settings.png

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.

pv.sohu.response.png

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.

ip.taobao.response.png

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.

call home.png

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.

response is used.png

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

check ad config.png

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

statistics response.png

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.

JD decompiler search.png

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.

update trim url.png

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.

grep HtmlLinkTrimItem.png

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).

LinkTrimChecker.png

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.

checkTrayLink.png

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.

display tray link.png

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.

enable show tray link.png

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.

matchAdCondition.png

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.

tray link url.png

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.

traylink url display time.png

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.second injecting more stuff.png

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.

OQL.png

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.

injeted more.png

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

hit.png

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.

test 2 imgur injected.png

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

hit2.png

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.

error cert.png

imgur lookup for resources.png

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

imgur multiple.png

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.

fake payload download.png

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).

24 thoughts on “Reverse Engineering an Eclipse Plugin

  1. I don’t know of a comparable plugin.

    But since the author has provided the source of the current version [1], it was quite easy to strip out all privacy-concerning parts and create a pull request [2]. Unit this is merged, you can use the patched plugin jars from [3] to use the plugin without the problems discussed in the article.

    [1] https://github.com/cpupk/ecd
    [2] https://github.com/cpupk/ecd/pull/1
    [3] https://github.com/pbi-qfs/ecd/releases/tag/v2.10.0-adFree

    Liked by 1 person

  2. I noticed that an issue was filed in the plugin, and the developer appears to have made a new release (which I noticed in Eclipse) that allegedly addresses the original issues. I think the implication is that the questionable symptoms were somewhat inadvertent and not intended to support “adware”. I don’t represent the author or the plugin, just interpreting what I’m seeing. It would be useful if you reexamined this to see if it’s not behaving properly.

    Liked by 1 person

  3. I’m excited to uncover this site. I need to to thank you for
    ones time due to this fantastic read!! I definitely really liked every little bit of it and i also have you
    bookmarked to check out new stuff on your web site.

    Liked by 1 person

  4. this chinese idiots cheat in every area. you can see that plugin published by chinese. if you try to download anything from the internet, you have to check its origin, if it s from china, dont download.

    Liked by 1 person

    1. @sakir that sounds like a stereotype-based bias. Please take a look at the, ah, ‘stack trace’ of your rationale. Does it look as suspect as the code described by this blog does? If so, reevaluate 🙂
      @0x10f8 Thank you so much for this blog post! Had you not uncovered this and informed Eclipse Foundation, it’s quite likely I would’ve ended up installing the adware version when searching for the plug-in by name just about an hour ago instead of the “clean” version. From one honest Java enthusiast to another, I salute you 🙂

      Like

Leave a comment