Two ways to attack Internet based applications written in Java

Introduction

Recently I have come across with a rather nice chat called DoBeDo. It a nicely written in Java chat, where quite a few great people are hanging out. The chat is nice however, it has a number of poorly programmed features and was a rather slow applet (mostly due to poor programming design, not Java itself).

Because I was rather pissed at these stupid things and for a few months I didn't notice any differences I decided to fix it myself. In order to do that I had to understand how this chat communicates via proprietary protocol. I also thought it could be a good exercise for my skills and chance to improve them that little bit.
 

Legal stuff

Everything that was done is completely legal. As a person who solely believe in obeying all laws no matter how stupid they might be, I opted to use only legal methods in this research. Given that there is no license whatsoever on how we can use the chat applet written in Java I had the following two approaches: decompiling the applet and thus reverse engineering what it does, and analyzing TCP/IP traffic on my local machine.

Both approaches involve running tools on my own computer on publicly available files (Java .class files) that are being downloaded by browser, thus no attempts were made to gain any unauthorized access to the main server. It simply not required, and this is a bit scary how easy people can do things they were not supposed to due to lousy programming practices.
 

1st approach: Decompiling Java applet.

Probably not everyone knows how decompiling works. It generally fails to produce any meaningful text for C/C++ based programs mainly because debugging symbols are stripped off in the release versions. However, Java inherently has full symbol information embedded into "binary" files, and hence is an easy prey for decompilers. There are quite a few around, some of the commercial but some are not. The one I used for this task is  Jad v1.5.7 by Pavel Kouznetsov (a fellow Russian).

First task is to get hold of actual Java .class files. Unfortunately authors of the chat didn't use packed JAR format (ZIP file) and as the result it's not only loads longer, but also takes one to get all files manually, which was a bit irritating. I guess this was their "security" measure. Anyway, here is the list of files:

    AreaServer.class Avatar.class AvatarUserPanel.class Bubble.class ChatClient.class ChatLog.class ChatRoom.class COMI.class Communicator.class DoBeDoBanner.class DoBeDoChat.class DoBeDoList.class DropMenu.class Emoticon.class IAreaServerClient.class IChatClient.class IChatLog.class IChatObject.class IChatRoom.class IClickAreaClient.class IClickAreaServer.class ICOM.class IHotAreaClient.class IHotAreaServer.class IIntro.class IListener.class ILoader.class IMapObject.class IMovableChatObject.class Intro.class IPaint.class IPaintServer.class ISelectableChatObject.class Loader.class Login.class Map.class MapCircle.class MapObject.class MapPolygon.class MapText.class NewCircle.class NewPolygon.class NewRectangle.class NewShape.class PaintServer.class RecordSet.class Sender.class Tab.class TabView.class

    The OO design is rather good, one point to the authors, but it's hell lot of files.


Jad worked out just fine and produced about 357k of source code. You will be surprised how readable is it! Here is a little code snippet from decompiled Communicator.class:


    public void onLeave(String s, String s1)
    {
        IChatRoom ichatroom = (IChatRoom)chatClient.getChatObject(s);
        IChatObject ichatobject = chatClient.getChatObject(s1);
        if(ichatroom == null || ichatobject == null)
        {
            System.out.println("\nOne of the objects could not be found in onLeave call!");
            return;
        }
        else
        {
            moveObjectFromRoom(ichatobject, ichatroom);
            chatClient.objectViewChanged(ichatroom);
            isWaitingFor.remove("onLeave");
            return;
        }
    }

The lack of comments will stop only inexperienced programmers.

A quick look reveals that they use a chat server located at  195.7.67.136, port 443. The chat loader loads a list of specified
classes in booting HTML file.  Funny thing is that this chat specifically doesn't want to run locally due to "security" problems. It is also interesting that guys who programmed it meant to make a proper login procedure, but it never appears on the screen.
Actually now it is time to name these guys: Andreas Arrg and Henrik Wall. They appear in internal list of credits. Nice work guys, but you should have paid a LOT more attention to security issues instead of hard coding bi-lingual features (Swedish/English).

The communication is done using two main channels. First is the main server at 443 port where a chat client sends commands and receives updated. Every sent/received command is a one line ending with "\r\n" (0x0D 0x0A). The second is when a client requests an image (GIF/JPG) via HTTP protocol.
 

    Examples of commands send from client to server:

  1. sendToAll'emote,6,gagging for it.'157'868687'
  2. updateProperty'20581'20581'position'150,110'N'
Due to possible abuse of the commands I would prefer to avoid explaining what these numbers mean. I was shocked how easy it was to figure out what they all mean though. I was shocked seeing a complete lack of programming logic designed to, say prevent an avatar giving something it doesn't own or not even on-line.
The client also sends a lot of HTTP GET commands to fetch images from the server on port 80.

    Examples of commands received by client from server:

  1. onReceive'whisper,miaow?'76557' '93842'
  2. onEnter'171'13'icon'avatar/gal1.gif'my_room'109481'owns'5650,1,5696,1'OBJECTCLASS'
    CHATOBJECT'position'287,151'OBJECTID'109480'current_room'176'avatar_mood'01'avatar_style'01'
    avatar_sex'02'clan_id'20'OBJECTTYPE'AVATAR'label'Alicia5'
  3. onUpdateProperty'13709'position'535,251'
We receive lots of event like commands with ON prefix which makes the chat client change position of avatars, display balloons etc. Obviously all numbers in actual commands are not of the real people/places.
 

It seems to me that guys were a bit influenced by IRC, but didn't take into account many security features found in the protocol. Ever read RFC?
 

Unfortunately DoBeDo chat is a nice chat where I like to hang out myself, and I can't reveal too many details on how to exploit the system as no doubt it will be abused.

One might be tempted to make a change and recompile it, however I didn't bother. It is easier to write a Perl script doing all I wanted.

2nd approach: Traffic analysis.

Traffic analysis is performed by analyzing what actual program sends and receives from the server, and thus reverse engineering the programmed logic. All a good programmer needs is raw logs, and he can figure out how to write a trivial program to make analysis an easy and enjoying experience. Well, not really enjoying, but definitely rewarding. For this task I used tool called BUTTSniffer by CDC. While these guys sound a bit obscure, they are one of the best experts in security field.

The output of this program will looks like this (my IP was changed to xxx.yyy.zz.z): It may look weird and cryptic to a non-professional, but for those who see it says everything.

Source IP: xxx.yyy.zz.z  Target IP: 195.7.67.136 TCP  Length: 0  Source Port: 1221 
Target Port: 443  Seq: 00542AF9  Ack: 032190BF Flags: A  Window: 8225  TCP ChkSum: 11415 UrgPtr: 0

Source IP: 195.7.67.136  Target IP: xxx.yyy.zz.z TCP  Length: 43  Source Port: 443 
Target Port: 1221  Seq: 032190BF  Ack: 00542AF9 Flags: PA  Window: 8107  TCP ChkSum: 32272 UrgPtr: 0
 00000000: 6F 6E 55 70 64 61 74 65 50 72 6F 70 65 72 74 79   onUpdateProperty
 00000010: 27 31 36 38 37 37 32 27 70 6F 73 69 74 69 6F 6E   '168772'position
 00000020: 27 32 34 39 2C 32 30 32 27 0D 0A                  '249,202'..

Source IP: xxx.yyy.zz.z  Target IP: 195.7.67.136 TCP  Length: 0  Source Port: 1221 
Target Port: 443  Seq: 00542AF9  Ack: 032190EA Flags: A  Window: 8182  TCP ChkSum: 11415 UrgPtr: 0

Source IP: 195.7.67.136  Target IP: xxx.yyy.zz.z TCP  Length: 1  Source Port: 443 
Target Port: 1221  Seq: 032190EA  Ack: 00542AF9 Flags: PA  Window: 8107  TCP ChkSum: 48600 UrgPtr: 0
 00000000: 6F                                                 o

Source IP: xxx.yyy.zz.z  Target IP: 195.7.67.136 TCP  Length: 0  Source Port: 1221 
Target Port: 443  Seq: 00542AF9  Ack: 032190EB Flags: A  Window: 8181  TCP ChkSum: 11415  UrgPtr: 0

Source IP: 195.7.67.136  Target IP: xxx.yyy.zz.z TCP  Length: 20  Source Port: 443 
Target Port: 1221  Seq: 032190EB  Ack: 00542AF9 Flags: PA  Window: 8107  TCP ChkSum: 44153 UrgPtr: 0
 00000000: 6E 4C 65 61 76 65 27 31 36 38 27 31 35 39 37 33   nLeave'168'15973
 00000010: 38 27 0D 0A                                       8'..

After an hour of traffic capturing all became clear. Another approach but the same result. This couldn't be attributed to any flaws of Java. While for some this dump will not mean a thing, those who can will see it all.

I found that this approach gives faster results than with decompilation. The latter however is useful to see what features are in that are not available for you, and hence get them (ie zapping people), something that traffic analysis won't reveal because unless you use this feature, you can't see the command strings in TCP dump.

Conclusions

Don't take security for granted on the Net. Even binary code is not safe and there are quite a few people capable of disassembling your code. Probably 99.99% of people would not even think of reverse engineering your code (as less and less qualified people are left), but this 0.01% can bite your ass harder than all the rest combined. Programming for the Internet is a big difference in security sense of view than programming standalone program. Consider hiring a security consultant and then commit regular security audits. On the Net loss of security is essentially equals to the loss of business.

I tried to limit details to minimum to avoid potentially devastating effect on the fellow chatters. However, being silent and turning a blind eye on obvious security holes is like being a straus who hides his head in sand.

Solutions

  1. Obfuscate your Java code to prevent easy decompiling.
  2. Encrypt all traffic at the application level (not XOR though, please).
This will make reverse engineering a lot harder. To make it hell of a job use the following tricks:
  1. Use fake logic structures and yummy looking strings that will just mislead the attacker.
  2. Scramble all important commands in the code, avoid using plain text at all.
  3. Self verify your own code, it might be byte patched.
And finally the biggest mistake in DoBeDo is on the server side. The server blindly trusts the client, and this is nuts! Never ever trust a client program (it might be forged), never ever trust IP address (it might spoofed or proxied). Add all necessary checks on the server side such as to prevent people doing things they are not supposed. This is by far is the biggest fundamental flaw in the DoBeDo case study.
 

Last words

Some would argue, who cares about this stupid chat server? No one, but amazingly programmer with poor habits and lack of proper understanding of security and what can be done, will go on doing the same stuff in banks, shops, airlines etc. Java programmers are a hot commodity these days, everyone wants to hire them. Let's pray people programming anything serious are damn serious at doing their job. And this is by far the most scarier part of this story.

Some would cry out loud accusing me of being evil, but they are wrong. Evil doesn't come forward with a good advice, as evil exploits weaknesses for it's own evil purposes without telling them. Blame not the messenger, but blame the cause, the root of the evil, which in this case is a poor design of the Java application.
 

To the authors: for Christ sake guys, could not you cache all these images in memory to make moving from one room to another faster? This is so obvious.



Version:    1.1
Date:    19 Dec, 1999.