Java安全之Javassist动态编程

Java安全之Javassist动态编程0x00前言在调试CC2链前先来填补知识盲区,先来了解一下Javassist具体的作用。在CC2链会用到Javassist以及PriorityQueue来

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

Java安全之Javassist动态编程

0x00 前言

在调试CC2链前先来填补知识盲区,先来了解一下Javassist具体的作用。在CC2链会用到Javassist以及PriorityQueue来构造利用链

0x01 Javassist 介绍

Java 字节码以二进制的形式存储在 class 文件中,每一个 class 文件包含一个 Java 类或接口。Javaassist 就是一个用来处理 Java 字节码的类库。

Javassist是一个开源的分析、编辑和创建Java字节码的类库。

0x02 Javassist 使用

这里主要讲一下主要的几个类:

ClassPool

ClassPool:一个基于哈希表(Hashtable)实现的CtClass对象容器,其中键名是类名称,值是表示该类的CtClass对象(HashtableHashmap类似都是实现map接口,hashmap可以接收null的值,但是Hashtable不行)。

常用方法:

static ClassPool	getDefault()
	返回默认的类池。
ClassPath	insertClassPath(java.lang.String pathname)	
	在搜索路径的开头插入目录或jar(或zip)文件。
ClassPath	insertClassPath(ClassPath cp)	
	ClassPath在搜索路径的开头插入一个对象。
java.lang.ClassLoader	getClassLoader()	
	获取类加载器toClass(),getAnnotations()在 CtClass等
CtClass	get(java.lang.String classname)	
	从源中读取类文件,并返回对CtClass 表示该类文件的对象的引用。
ClassPath	appendClassPath(ClassPath cp)	
	将ClassPath对象附加到搜索路径的末尾。
CtClass	makeClass(java.lang.String classname)
	创建一个新的public类

CtClass

CtClass表示类,一个CtClass(编译时类)对象可以处理一个class文件,这些CtClass对象可以从ClassPoold的一些方法获得。

常用方法:

void	setSuperclass(CtClass clazz)
	更改超类,除非此对象表示接口。
java.lang.Class<?>	toClass(java.lang.invoke.MethodHandles.Lookup lookup)	
	将此类转换为java.lang.Class对象。
byte[]	toBytecode()	
	将该类转换为类文件。
void	writeFile()	
	将由此CtClass 对象表示的类文件写入当前目录。
void	writeFile(java.lang.String directoryName)	
	将由此CtClass 对象表示的类文件写入本地磁盘。
CtConstructor	makeClassInitializer()	
	制作一个空的类初始化程序(静态构造函数)。

CtMethod

CtMethod:表示类中的方法。

CtConstructor

CtConstructor的实例表示一个构造函数。它可能代表一个静态构造函数(类初始化器)。

常用方法

void	setBody(java.lang.String src)	
	设置构造函数主体。
void	setBody(CtConstructor src, ClassMap map)	
	从另一个构造函数复制一个构造函数主体。
CtMethod	toMethod(java.lang.String name, CtClass declaring)	
	复制此构造函数并将其转换为方法。

ClassClassPath

该类作用是用于通过 getResourceAsStream() 在 java.lang.Class 中获取类文件的搜索路径。

构造方法:

ClassClassPath(java.lang.Class<?> c)	
	创建一个搜索路径。

常见方法:

java.net.URL	find (java.lang.String classname)	
	获取指定类文件的URL。
java.io.InputStream	openClassfile(java.lang.String classname)	
	通过获取类文getResourceAsStream()。

代码实例:

ClassPool pool = ClassPool.getDefault();

在默认系统搜索路径获取ClassPool对象。

如果需要修改类搜索的路径需要使用insertClassPath方法进行修改。

pool.insertClassPath(new ClassClassPath(this.getClass()));

将本类所在的路径插入到搜索路径中

toBytecode

package com.demo;

import javassist.*;


import java.io.IOException;
import java.util.Arrays;

public class testssit {
    public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(demo.class.getClass()));
        CtClass ctClass = pool.get("com.demo.test");
        ctClass.setSuperclass(pool.get("com.demo.test"));
//        System.out.println(ctClass);
        byte[] bytes = ctClass.toBytecode();
        String s = Arrays.toString(bytes);
        System.out.println(s);
    }

}

Java安全之Javassist动态编程

toClass

Hello类:
public class Hello {
    public void say() {
        System.out.println("Hello");
    }
}
Test 类
public class Test {
    public static void main(String[] args) throws Exception {
        ClassPool cp = ClassPool.getDefault();//在默认系统搜索路径获取ClassPool对象。
        CtClass cc = cp.get("com.demo.Hello");  //获取hello类的
        CtMethod m = cc.getDeclaredMethod("say"); //获取hello类的say方法
        m.insertBefore("{ System.out.println(\"Hello.say():\"); }");//在正文的开头插入字节码
        Class c = cc.toClass();//将此类转换为java.lang.Class对象
        Hello h = (Hello)c.newInstance(); //反射创建对象并进行强转
        h.say();调用方法say
    }
}

Java安全之Javassist动态编程

0x03 一些小想法

按照我的理解来说就是可以去将类和字节码进行互相转换。那么按照这个思路来延申的话,我们可以做到什么呢?我首先想到的可能就是webshell的一些免杀,例如说Jsp的最常见的一些webshell,都是采用RuntimeProcessBuilder这两个类去进行构造,执行命令。按照WAF的惯性这些设备肯定是把这些常见的执行命令函数给拉入黑名单里面去。那么如果说可以转换成字节码的话呢?字节码肯定是不会被杀的。如果说这时候将Runtime这个类转换成字节码,内嵌在Jsp中,后面再使用Javassist来将字节码还原成类的话,如果转换的几个方法没被杀的话,是可以实现过WAF的。当然这些也只是我的一些臆想,因为Javassist并不是JDK中自带的,实现的话后面可以再研究一下。但是类加载器肯定是可以去加载字节码,然后实现执行命令的。这里只是抛砖引玉,更多的就不细说了。如果有更好的想法也可以提出来一起去交流。

0x04 想法实现

这里可以来思考一个问题,该怎么样才能动态传入参数去执行呢?那能想到的肯定是反射。如果我们用上面的思路,把全部代码都转换成字节码的话,其实就没有多大意义了。因为全是固定死的东西,他也只会执行并且得到同一个执行结果。

我在这里能想到的就是将部分在代码里面固定死的代码给转换成字节码,然后再使用反射的方式去调用。

public class test {
    public static void main(String[] args) {
        String string ="java.lang.Runtime";
        byte[] bytes1 = string.getBytes();
        System.out.println(Arrays.toString(bytes1));
        


    }
}

获取结果:

[106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 80, 114, 111, 99, 101, 115, 115, 73, 109, 112, 108]

现在已经是把结果给获取到了,但是我们需要知道字节码怎么样还原为String类型。

在后面翻阅资料的时候,发现String的构造方法就直接能执行,来看看他的官方文档。

Java安全之Javassist动态编程

使用bytes去构造一个新的String

代码:

public class test {
    public static void main(String[] args) {
        byte[] bytes = new byte[]{106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101};
        String s = new String(bytes);
        System.out.println(s);
    }
}

Java安全之Javassist动态编程

public class test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
        byte[] b1 = new byte[]{106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101};
        String run = new String(b1);
        String command = "ipconfig";


        Class aClass = Class.forName(run);
        Constructor declaredConstructor = aClass.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        Object o = declaredConstructor.newInstance();
        Method exec = aClass.getMethod("exec", String.class);
        Process process = (Process) exec.invoke(o,command);
        InputStream inputStream = process.getInputStream();    //获取输出的数据
        String ipconfig = IOUtils.toString(inputStream,"gbk"); //字节输出流转换为字符
        System.out.println(ipconfig);



    }
}

Java安全之Javassist动态编程

命令执行成功。

那么这就是一段完整的代码,但是还有些地方处理得不是很好,比如:

 Method exec = aClass.getMethod("exec", String.class);

这里是反射获取exec方法,这里的exec是固定的。exec这个对于一些设备来说也是严杀的。

那么在这里就可以来处理一下,也转换成字节码。

转换后的字节码:

[101, 120, 101, 99]

改进一下代码:

public class test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
        String command = "ipconfig";
        byte[] b1 = new byte[]{106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101};
        String run = new String(b1);
        byte[] b2 = new byte[]{101, 120, 101, 99};
        String cm = new String(b2);
        


        Class aClass = Class.forName(run);
        Constructor declaredConstructor = aClass.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        Object o = declaredConstructor.newInstance();
        Method exec = aClass.getMethod(cm, String.class);
        Process process = (Process) exec.invoke(o,command);
        InputStream inputStream = process.getInputStream();    //获取输出的数据
        String ipconfig = IOUtils.toString(inputStream,"gbk"); //字节输出流转换为字符
        System.out.println(ipconfig);

    }
}

实际中运用就别用啥ipconfigcommand这些来命名了,这些都是一些敏感词。这里只是为了方便理解。

在真实情况下应该是request.getInputStream()来获取输入的命令的。那么这里也还需要注意传输的时候进行加密,不然流量肯定也是过不了设备的。

0x05 结尾

其实后面这些内容是跑偏题了,因为是后面突然才想到的这么一个东西。所以将他给记录下来。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119907.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • imfilter函数matlab_matlab too many input argument

    imfilter函数matlab_matlab too many input argument认真研读一下MATLAB的help文档吧,解释最权威:BWFILLFillbackgroundregionsinbinaryimage.BWFILLisagrandfatheredfunctionthathasbeenreplacedbyIMFILL.BW2=BWFILL(BW1,C,R,N)performsaflood-filloperationont…

    2022年9月13日
    4
  • RC522 射频读卡器模块(MINI型)

    RC522 射频读卡器模块(MINI型)一、硬件:二、[主芯片介绍]MFRC522是应用于13.56MHz非接触式通信中高集成度的读写卡芯片,是NXP公司针对“三表”应用推出的一款低电压、低成本、体积小的非接触式读写卡芯片,是智能仪表

    2022年7月1日
    37
  • 超全的英语短句汇集

    English900英语九百句常用职位英文译名超级短句成语集锦打开话匣子PC电脑词汇一百个绝佳句型李阳英语365句托福听力常用短语校园英语迷你惯用语洋话连篇至理名言English 900 英语九百句第一册一、 Greetings 问候语 1. hello! / hi! 你好! 2. good morning / afternoon / evening! 早晨(下午/晚上)好! 3. i

    2022年4月8日
    5.2K
  • PHP借用Redis消息队列实现高并发下发送邮件功能

    PHP借用Redis消息队列实现高并发下发送邮件功能

    2022年2月18日
    65
  • 国内机床企业名录

    国内机床企业名录珠江机床有限公司北京第三机床厂北京市机电研究院北京市华德液压泵厂机床厂北京市仪表机床厂北京市电加工机床厂北京市电加工研究所北京阿奇工业电子有限公司中国航天工业总公司二八四厂(北京长峰机械动力厂)北京机床研究所北京良乡锻压机床厂北京市京良机械制造有限公司北京长空机械公司北京北方车辆制造厂十五分厂北京机电研究所北京工业大学科技开发管理部(数控机床配件研究所)北京光电量仪研究中心北京工大光电机械厂北京液

    2022年6月30日
    81
  • 大一vb程序设计基础_大一c语言程序设计答案

    大一vb程序设计基础_大一c语言程序设计答案spContent=50年前,Basic的诞生结束了计算机只能由专业人员使用的历史,推动了计算机的普及。Windows操作系统的出现又将Basic推向一个新的高度——VisualBasic。它是一个以结构化Basic语言为基础、以事件驱动为机制的“可视”的程序设计语言,能够支持多媒体、数据库、网络等应用,可方便、轻松地开发应用软件。——课程团队课程概述虽然VisualBasic推出已经很多年…

    2022年8月31日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号