I was lucky enough to do a penetration test on applications using Direct Web Remoting (DWR), and I would like to share my experiences. It is another interesting technology in the wild jungle of the web frameworks and libraries. It defines itself as follows:
“DWR is a Java library that enables Java on the server and JavaScript in a browser to interact and call each other as simply as possible.”

So DWR is a library that can be used in your Java code. It will generate the JavaScript that will be used in the client-side to communicate with the server-side. This JavaScript code will call the exposed Java methods to process client data. It also implements a two way communication so not only the client-side can request data from the server but also the server can push data or trigger events in the client-side.
To get to know the system I recommend the DEMO application (dwr.war) that can be downloaded from here.

Communication

Since this is not a whole web framework just a library, it won’t control the whole communication. That means if you submit a form it will send a plain old POST request unless you intentionally want to do it using DWR. However it is really practical to fill drop-down menus or any dynamic content on the page on-the-fly. That means that a DWR request can be sent any time, so you need to check your proxy regularly. An example request looks like the following:

POST /dwr/dwr/call/plaincall/Demo.sayHello.dwr HTTP/1.1
Host: 192.168.109.111: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/plain; charset=UTF-8
Referer: http://192.168.109.111:8080/dwr/simple/text.html
Content-Length: 214
Cookie: DWRSESSIONID=bdNdKgBXPgXtOV62mJPycPkbeBj
Pragma: no-cache
Cache-Control: no-cache


callCount=1
windowName=
c0-scriptName=Demo
c0-methodName=sayHello
c0-id=0
c0-param0=string:test
batchId=1
instanceId=0
page=%2Fdwr%2Fsimple%2Ftext.html
scriptSessionId=bdNdKgBXPgXtOV62mJPycPkbeBj/MjGbeBj-k9QBh9RG0

And the response is:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/javascript;charset=utf-8
Content-Length: 156
Date: Wed, 22 Aug 2012 11:53:55 GMT
throw 'allowScriptTagRemoting is false.';
(function(){
var r=window.dwr._[0];
//#DWR-INSERT
//#DWR-REPLY
r.handleCallback("1","0","Hello, test");
})();

In this request ‘sayHello’ is the name of the exposed Java method that will be called in server-side. The method parameter in this case is the ‘c0-param0’. The returned data will usually processed by a callback function.

The other important part of the communication is the reverse AJAX technique to implement the server to client communication. There is no magic there, DWR supports different techniques Comet, Polling or Piggybacking.

Attack vectors

I wouldn’t write about DWR if there weren’t interesting attack vectors there. Bear in mind that most of these vectors are not bugs in DWR they are mostly opportunities where the progremmer can go wrong so it worths a shot to try them.

Test page

I think that is the first thing everybody checks in every framework: the debug and test pages. DWR has a great one as well and it can be found at:
<application root dir>/dwr/index.html

The index contains the list of exposed Java classes. From here one can navigate to the test page of each class where every callable method is described and can be easily tested. This is a great way to find out what methods are exposed and learn how they function.
dwr test page

Mitigation

It is fairly easy to turn off this feature in the production environment. You can turn it off in the web.xml as follows:

<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>false</param-value>
</init-param>
</servlet>

Authorization problems

I have seen serious authorization problems in DWR applications. However it is not the fault of DWR itself, but they were implementation mistakes. Programmers sometimes won’t even realise that when they expose a method to DWR they actually expose them to the world. Or even if they see the problem it can seem to be so ‘hidden’ and ‘covered’ feature which impose only low risk. But this is not true. Exposing a method means that it can be called from anywhere where the application is accessible.

Possible vulnerabilities

  • Test whether DWR methods can be called without authentication.
  • Test whether DWR methods can be called by an unauthorized user. For instance if there is a method that implements a functionality only for admins it might be available for other users as well.

Mitigation

  • Make sure that your application restricts the access to the exposed DWR methods.
  • If the application or the framework is not able to control the access, then make sure that the exposed DWR methods take care of authentication, authorization and accounting.

Information leakage

Although I didn’t experience tons of information leaking through DWR, but still there are bits and pieces that can be helpful for an attacker. For instance exceptions can get back to the client-side, it won’t give a full stack-trace but at least the exception name:

throw 'allowScriptTagRemoting is false.';
//#DWR-REPLY
if (window.dwr) dwr.engine._remoteHandleBatchException({ name:'java.lang.SecurityException', message:'Methods defined in java.lang.Object are not accessible' }, '0');
else if (window.parent.dwr) window.parent.dwr.engine._remoteHandleBatchException({ name:'java.lang.SecurityException', message:'Methods defined in java.lang.Object are not accessible' }, '0');

Mitigation

In some cases it can be fixed in implementation level by not allowing exceptions to get back to the client-side. However in other cases it can be an exception thrown by DWR itself. That case the risk introduced by this information leakage must be accepted by the company.

Manipulating the backend

Manipulating the backend is always possible so it is not at all a DWR specific issue. However the whole idea of exposing Java methods to the world makes it more straightforward. Basically every attack could be possible from code injection to OS command execution, but it always depends on the implementation of the exposed DWR functions. Examine the methods and try to guess what happens in the background also try to fuzz the parameters.

Mitigation

Since this is a really wide area of potential vulnerabilities there is no silver bullet against them. However when the risks of exposing a method to the world is understood then I think everybody will figure out how to change his code not to allow such attacks. The two most important rules are not to trust the input and do proper input validation.