MatesCTF 2018 WutFaces & CVE-2013-2165

Challenge

Intended Solution

  • Analyze CVE-2013-2165 to find Java Deserialization entry point
  • Make custom gadget chain based on source code to form RCE

Other Solution

  • Analyze CVE-2015-0279 for straight-up EL Injection

Write Up

I made this challenge based on a pentest scenario I encountered recently. Both of the CVEs don’t have a publicly usable PoCs, so you will need some 1-day analyzing skills.

First off I intentionally gave away the environment settings to save you some time fuzzing the webapp. Click “Change Book Again!” until the counter reaches 5, it will gives an url to the .war source code.

Inspect the file, you’ll find that the server is utilizing Richfaces 4.3.2. There are a couple of ways to know this:

  • Go through WEB-INF/lib
  • Find a leftover pom.xml in META-INF, in this case located at META-INF/maven/com.tint0.matesctf/wutfaces/pom.xml

Richfaces 4.3.2 is vulnerable to both CVE-2013-2165 and CVE-2015-0279. In this writeup, I’m gonna cover the CVE-2013-2165 Java arbitrary deserialization, however the two CVEs are equal in difficulty to analyze and exploit. (IMO CVE-2015-0279 is much more fun and exciting, but it’ll take much more time to understand it thoroughly)

1. Info gathering

Getting some info about the CVE through the Richfaces developer’s blog at http://www.bleathem.ca/blog/richfaces-security-advisory-cve-2013-2165/ and see that the bug is fixed in Richfaces 4.3.3.

Make a diff between the two Richfaces 4.3.3 and 4.3.2 to find the vulnerable code. We could see that the only difference in the diff is a code change fixing deserialization issue, via adding a new LookAheadObjectInputStream class and using it instead of the usual ObjectInputStream for deserialization’s readObject(). If you have had previous experiences with Java deserialization, you should already know that this is in fact a technique to prevent Java Arbitrary Deserialization, namely Look-ahead Deserialization. So now we’ve found our entry point, which is the line in.readObject() in org.richfaces.util.Util#decodeObjectData.

2. Making a PoC

Build a sample Richfaces webapp, or you can just deploy my source .war on your local environment, download the necessary 3rd-party lib’s source for debugging and we’re ready. Now normally during a 1-day analysis we can just put a breakpoint at the vulnerable code line, and hope for the best waiting until a request reaches that point. That’s boring and not applicable in this case, no normal requests from my .war will hit the vulnerable code. So now to build the request ourselves, trace up the code (e.g. continuously analyze and find method’s usage) until you find org.richfaces.resource.ResourceHandlerImpl#handleResourceRequest. Put a breakpoint in this method here and notice that all Richfaces resource request will route through that method. Analyze the code from there line by line, fulfill the conditions needed to reach the Deserialization point. After a while you’ll figure out that the conditions are:

  • The request must starts with /rfRes
  • The URI after /rfRes needs to be a resource existing on the server (You can just use a default Richfaces resource, e.g. buttonHoverBackgroundImage.png.jsf)
  • The request needs a param named ln pointing to an existent resource library (Again, just use the Richfaces default, e.g. org.richfaces.images)
  • The request needs a param named do and it needs to be encoded using DEFLATE

The data in param do will eventually be passed to the Deserialization point.

3. Exploiting

So now we have figured out the “source”. Time to find the “sink”.

Exploiting this vulnerability into RCE is not that straightforward like usual. I intentionally made this so that there are no exploit chains available in the tool Ysoserial that could work. You have to customize your own gadget chain based on the source code I gave.

First to confirm the deserialization exists, you could use the URLDNS gadget chain to make the web server make a DNS resolve request toward your designated server. The tool I would recommend for this is http://requestbin.net/dns (Props to @mxcxvn).
dns query

Now onto RCE. Decompile and inspect the .class source code, you’ll find that there is an easily noticable dangerous method that use Runtime.exec() in com.tint0.wutfaces.BookHolder#hashCode.

If you have understood Java deserialization by now, you should be able to figure out that what we need to do is to make a custom gadget chain that goes from ObjectInputStream.readObject() to BookHolder.hashCode(). Skimming through the example exploit chains in Ysoserial, you’ll notice that many of them goes through an object’s hashCode function.

You could make up any gadget as you seem fit. Here’s mine:

java.io.ObjectInputStream.readObject()
-> java.util.HashMap.readObject()
--> java.util.HashMap.putVal()
---> java.util.HashMap.hash()
----> com.tint0.wutfaces.BookHolder.hashCode()

Implement a custom class in Ysoserial to make use of the gadget chain. My sample code could be found in the attachments.

And the flag.
reverse shell

Here’s the .war source code, a PoC request to reach the Deserialization entry point and the code for Ysoserial custom gadget chain: ctf_wutfaces_resources.zip

I’ll keep the server at http://wutfaces.ctf.tint0.com/ up for some more time for anyone interested in further testing.

That’s it. Happy hacking.

P/s: There was a bug in my webapp, which is a wrong jsf library dependency making the webapp sometimes return 500 error code. However since it didn’t affect the exploits and I didn’t want to alter the codes during contest, I left it untouched. Sorry for that :)

12 Replies to “MatesCTF 2018 WutFaces & CVE-2013-2165”

  1. Can you help me this challenge ?
    I used BurpSuit and Java Deserialization Scanner v0.5 Ex to attack with your POC
    and tried ysoserial-0.0.4-all.jar CommonsCollections1 “ping mydatahere.37a7b54d9e411b8b18f2.d.requestbin.net” in BurpSuit but not successful

    1. Thứ nhất là không dùng chain CommonsCollections1 được.
      Thứ hai là bạn tạo payload Ysoserial rồi phải compress dạng DEFLATE mới đưa vào param “do” trong PoC. Hàm compress deflate của Richfaces nằm ở org.richfaces.util.Util#encodeBytesData.

      1. Cứ tưởng là khồng thể comment tiếng Việt.
        Bài này theo code em hiểu là chèn 1 field vào đối tượng sau đó serialization sau đó gửi lên để nó Deserialization và thực thi mã vậy “tạo payload Ysoserial rồi phải compress dạng DEFLATE ” là nằm trong quá trình nào ạ ?

        1. Compress lại là tại Richfaces trước khi đưa data trong param “do” tới hàm deserialize nó cần đi qua hàm decompress, bạn thử dựng local rồi debug xem flow nó cho dễ hiểu. Hơn nữa mình nghĩ bạn cũng chưa hiểu kỹ lắm về Java deserialize, bài này yêu cầu khá chắc về kiến thức căn nguyên của nó nên bạn tham khảo thêm nhé.

  2. Hey, very nice writeup. One question how you DEFLATED the serialized object? I tried it with python and also implemented it with java.util.zip.DeflaterOutputStream. But I always get a compressed object starting with a full zlib header 0x789C. Looking at your poc your compressed object is only starting with 0x79 . Can you help me 😉 ?

        1. Code is in the Richfaces library, so you can write a simple application with the Richfaces jar and then use the function from it. Or you can copy the source code from that method and write a new class for it.

  3. #TooMuchRespect
    Thank you so much!
    p/s: cmt này chỉ để gởi lời cảm ơn và nể phục tới a, ko cần thiết approve đâu ạ!

  4. Very nice writeup.
    I am trying with the yso serial payload “java -jar ysoserial.jar Myfaces1 “touch /tmp/test.txt” > serialize_object and passing serialize object to the below website
    http://www.txtwizard.net/compression to compress with deflate. But my attack did not work
    Did I choose the wrong ysoserial payload or any thing I am doing wrong here . Please help

Leave a Reply

Your email address will not be published.