In the ocean of web application development frameworks there are a quite a few which tries to create rich web application in the same way as traditional desktop-based applications. One of them is the open-source Echo Web Framework from NextApp. It is a Java based system which is kind of practical because everybody has at least one Java developer friend. The Echo applications can be deployed in most of the Java web containers. But the most important difference is that instead of creating for instance a .jsp file to create a view the developer write only things like window.add(button);. That means that for the developer should not care about the fact that his application will be accessed with a web browser. In some way it is really cool that you can just say the words and everything happens automagically but for me it is always a bit weird when I don’t have control over something, but that’s just my taste. And the magic in this case is done by JavaScript. Before going into details I must say that I don’t have full understanding of the Echo Framework and how one should use it properly, I understood it only to be able to do a pentest and to attack it properly. In this post I write about the Echo2 framework and my experiences from the penetration tester’s point of view.

Server side

Just a little summary about the server-side of the application in bullet-points because that is the part I studied the less:

  • Code is written in Java using the classes of the Framework.
  • App is deployed in container such as Tomcat.
  • Everything is the same as in case of other Java web applications, like the WEB-INF directory or the config files.

Client side

As I have already mentioned the magic happens here. When the first page is opened a bunch of JavaScript code gets downloaded and when everything is there it starts to work and builds up the html code on client-side. From the first initialization the JavaScript code will constantly run and change the HTML here and there.

Communication

The original concept of the framework which lay the communication basics down is that there is always a holy state that is maintained parallel both client- and server-side. Most of the communication is synchronization. When a change is done on client-side then a synchronization request is sent to the server to tell it the changes in the state. Also the responses from server usually contain the things that should be updated in the client-side state. Here I must note that always the server has right. That means that whenever something goes wrong and something goes out of sync – for instance because somebody manipulates the requests – then the server will tell the client to do a full synchronization. In that case the client will throw away the whole state and downloads everything from the server from the JavaScript source code to the state itself.The whole communication is based on XmlHttpRequest. And they really mean the XML part because everything is sent in XML.

There are four important message types:

  • Synchronization
  • Framework module download
  • File upload
  • File download

Synchronization

As you could have guessed already the synchronization messages are the most important. It is not really straightforward when will a message be sent, for instance one would think that posting a form by clicking the submit button will do the syncing, but actually syncing is independent from buttons. The client will even sync when you fill an input field and leave it. So you always have to keep one eye on your proxy or firebug or whatever you use. To give an example here is a simple synchronization message together with the response:

POST /NumberGuess/app?serviceId=Echo.Synchronize HTTP/1.1
Host: 192.168.109.104:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Proxy-Connection: keep-alive
Content-Type: text/xml; charset=UTF-8
Referer: http://192.168.109.104:8080/NumberGuess/app
Content-Length: 462
Cookie: JSESSIONID=FDF8EA7C30FCC052A52A90489D5A646E
Pragma: no-cache
Cache-Control: no-cache

<client-message xmlns="http://www.nextapp.com/products/echo2/climsg" trans-id="1" focus="c_7">
  <message-part xmlns="" processor="EchoPropertyUpdate">
    <property component-id="c_7" name="text">22</property>
    <property component-id="c_7" name="horizontalScroll" value="0"/>
    <property component-id="c_7" name="verticalScroll" value="0"/>
  </message-part>
  <message-part xmlns="" processor="EchoAction">
    <action component-id="c_8" name="click"/>
  </message-part>
</client-message>


HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Pragma: no-cache
Cache-Control: no-store
Expires: 0
Content-Type: text/xml;charset=UTF-8
Date: Fri, 01 Jun 2012 15:42:28 GMT
Content-Length: 1858

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<server-message xmlns="http://www.nextapp.com/products/echo2/svrmsg/servermessage" async-interval="disable" modal-id="" trans-id="2">
  <libraries/>
  <message-part-group id="init">
    <message-part processor="EchoServerDelayMessage.MessageProcessor">
      <set-message>
        <content>
          <div xmlns="http://www.w3.org/1999/xhtml" id="serverDelayMessage" style="position:absolute;top:0px;left:0px;width:100%;height:100%;cursor:wait;margin:0px;padding:0px;visibility:hidden;z-index:10000;">
            <table style="width:100%;height:100%;border:0px;padding:0px;">
              <tbody>
                <tr>
                  <td>
                    <div id="serverDelayMessageLong" style="margin-top:40px;margin-left:auto;margin-right:auto;background-color:#afafbf;color:#000000;padding:40px;width:200px;border:groove 2px #bfbfcf;font-family:verdana,arial,helvetica,sans-serif;font-size:10pt;text-align:center;">Please wait...</div>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </content>
      </set-message>
    </message-part>
  </message-part-group>
  <message-part-group id="preremove"/>
  <message-part-group id="remove">
    <message-part processor="EchoDomUpdate.MessageProcessor">
      <dom-remove target-id="c_4"/>
      <dom-remove target-id="c_5"/>
      <dom-remove target-id="c_6"/>
    </message-part>
  </message-part-group>
  <message-part-group id="update">
    <message-part processor="EchoDomUpdate.MessageProcessor">
      <dom-add>
        <content parent-id="c_2_cell_c_4">
          <span xmlns="http://www.w3.org/1999/xhtml" id="c_4">Your guess, 22 was too low.  Try again:</span>
        </content>
      </dom-add>
      <dom-add>
        <content parent-id="c_2_cell_c_5">
          <span xmlns="http://www.w3.org/1999/xhtml" id="c_5">You have made 1 guess.</span>
        </content>
      </dom-add>
      <dom-add>
        <content parent-id="c_2_cell_c_6">
          <span xmlns="http://www.w3.org/1999/xhtml" id="c_6">Guess a number between 23 and 100:</span>
        </content>
      </dom-add>
    </message-part>
  </message-part-group>
  <message-part-group id="postupdate"/>
</server-message>

Mind that the XMLs are normally not pretty formatted I just wanted to make it readable. As you can see it is not so difficult to understand what happens. The client sends the values and in the ‘processor’ attribute tells who should deal with the data. In the response the server simply tells the client what to change in his state in DOM. And here you could see the first thing that makes the pentester’s life miserable: the field IDs. I will talk about them later. And more or less that was the synchronization.

Framework modul download

This one is not really complicated either. The framework doesn’t download the whole JavaScript library at once, but it does it just-in-time. For instance when it tries to create a window but there is no JavaScript then first requests the appropriate JavaScript module and then synchronizes the data. This is done by simple GET requests like this:


GET /NumberGuess/app?serviceId=Echo.ClientEngine HTTP/1.1

You will see the Echo.ClientEngine a lot because that is the core of the client-side code. In the responses the JavaScript is returned in text/plain.

File upload

When you have a file upload form then the system gets everything ready in the background for the file upload such as creating an ‘uploaduid’. Without ‘uploaduid’ there is no fun, and it will be created when the upload form is opened. Here is an example request:

POST /testapp/app?serviceId=Echo.Upload&uploaduid=3503 HTTP/1.1
Host: 192.168.109.104:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: https://192.168.109.104:8080/testapp/app?serviceId=uploadformUid&uploadformUid=3503
Cookie: JSESSIONID=CAF49DC8F468C21858EE7E45C77704EF
Content-Type: multipart/form-data; boundary=---------------------------169443243924626
Content-Length: 211

-----------------------------169443243924626
Content-Disposition: form-data; name="Echo.UploadForm.File"; filename="test2.txt"
Content-Type: text/plain

test
-----------------------------169443243924626--

The response will be a 302 Moved Temporarily which will redirect you back to your upload form.

File download

That is somewhat the same as the upload. A server-side ‘downloaduid’ is created just before the download so it could be sent to the client. As the user clicks on the download a GET request is sent like the following:


GET /testapp/app?serviceId=Echo.Download&downloaduid=568bf3ec_1371258a8cd_1b53 HTTP/1.1

The response will be something like that:

HTTP/1.1 200 OK
Date: Tue, 08 May 2012 15:21:24 GMT
Server: Apache/2.2.22 (EL)
Pragma: cache
Cache-Control: no-store
Expires: 0
Content-Disposition: attachment; filename="test2.txt"
Connection: close
Content-Type: text/plain; charset=UTF-8
Content-Length: 4

test

Pentesting Echo2

To summarize it in one sentence: pentesting an Echo2 application is a pain in the ass. The developers could take it as a compliment but that will not make it better for you if you are a pentester. So let see why.

Component IDs

As you could see in the synchronization examples the system uses generated IDs for the fields on the UI. I can tell you right now that it changes all the time, so when you open a window then close it and open it again the IDs will be different. The only thing that seems to be fixed is the difference between two IDs because the number in it is just an incremented value and probably the IDs are assigned always in the same order.

Transaction ID

If the component ID was not enough to make you cry then here is another one. The transaction ID is used to keep track the requests. There is always a trans-id in the request and in the response of it will be incremented by 1. The next request should use the ID of the last response. Whenever a request is received from the server which has an unexpected transaction ID then the server will force the client to do a full synchronization to fix it.

Automation … nope

I’m sure you have already figured out that automation will not work easily. Due to the use of the component IDs and the transaction IDs replaying requests and automating it is really difficult I would say almost impossible. Guessing the right component ID is possible but difficult. I tried to check the last transaction ID and setup Burp Intruder by using it but it takes a lot of time and if anything goes wrong the server will go to an error state when it waits for the client to re-synchronize until that no request will do anything. Also many times the data is not sent at the same time when the action is performed. For instance in case of a form when you click the ‘submit’ button then only this fact will be sent to the server (like <action component-id=”c_2297″ name=”click”/>) because the input data have already been synchronized to the server.

CSRF … not really

Although there is no dedicated protection against CSRF such as special token or hidden field, still it is more or less infeasible. To execute a successful CSRF the attacker will have to know the correct component IDs the current transaction IDs and the whole state of the application when the attack is executed.

XSS … you try it

So it seems that people writing a framework based on JavaScript in client-side have some understanding how to protect against XSS. There was client-side escaping before sending a request, and before rendering a response, and also server-side escaping. I guess the input validation is up to the actual application. Also one needs some real encoding magic to insert HTML tags into the XML request without the server-side XML parser parsing it as unknown XML element. So no I didn’t find any XSS in the framework but you should check as well because there must be one…there is always one.

XML injection … still no

XML injection seems like a good idea because the whole communication is done using XML so at least there are XMLs to inject into. However after thinking it through one just won’t find the target. On server-side there is no XML to inject into one could only attack the parser. Data could be stored in XML on server-side but again it’s up to the application. So if your app does that then there is an attack surface but otherwise there isn’t. However injecting in the server response XML could be interesting but in my case it was well protected by the server-side validation and escaping.

Suggestions

Ok so far I wrote down everything that makes a pentester cry. So let me make up for that and add something constructive to this post.

  • When planning the test take into account that without automation it will take much longer time to test a few things. Probably you will need to plan more time for simple tasks.
  • Focus on the application itself instead of the Echo framework. So instead of testing every input field for XSS, try to test the application behind the framework. Business logic or anything that is not implemented in the framework will potentially have more vulnerabilities then Echo.
  • Test features and interfaces that are not offered by the framework. If there is another interface to the system then you will have a greater chance to find something there because the developers usually get used to the fact that the framework does everything for them and they tend to forget when they step outside of the protection of it.
  • Since the normal testing routine and automation with Burp doesn’t work I did most of the things manually. For me the fastest (but still awkwardly slow) way to test requests was to rewrite them in Burp proxy instead of storing it in Repeater and testing from there.

So that is all about the Echo2 framework. I can assure you that there are bugs and vulnerabilities in Echo applications as well just the framework makes it a bit difficult to find them. However testing the framework itself could be an interesting project…maybe if I have some time.