Java安全基础-反射学习

Java执行系统命令

cmd相关参数

cmd /c dir 是执行完dir命令后关闭命令窗口。

cmd /k dir 是执行完dir命令后不关闭命令窗口。

cmd /c start dir 会打开一个新窗口后执行dir指令,原窗口会关闭。

cmd /k start dir 会打开一个新窗口后执行dir指令,原窗口不会关闭。

windows下执行命令的几种方式

  1. Windows下调用程序

Process proc =Runtime.getRuntime().exec(“exefile”);

1
Process proc1 =Runtime.getRuntime().exec("notepad");
  1. Windows下调用系统命令

String [] cmd={“cmd”,”/C”,”copy exe1 exe2”};
Process proc =Runtime.getRuntime().exec(cmd);

1
2
3
4
5
6
7
8
9
String cmd[]={"cmd","/c","whoami"};
Process proc2=Runtime.getRuntime().exec(cmd);
InputStream is=proc2.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String res;
while ((res=br.readLine())!=null)
{
System.out.println(res);
}
  1. Windows下调用系统命令并弹出命令行窗口

String [] cmd={“cmd”,”/C”,”start copy exe1 exe2”};
Process proc =Runtime.getRuntime().exec(cmd);

1
2
String cmd[]={"cmd","/c","start","dir"};
Process proc2=Runtime.getRuntime().exec(cmd);

image-20220307222310392

Linux下执行命令的几种方式

  1. Linux下调用程序

Process proc =Runtime.getRuntime().exec(“./exefile”);

  1. Linux下调用系统命令

String [] cmd={“/bin/sh”,”-c”,”ln -s exe1 exe2”};
Process proc =Runtime.getRuntime().exec(cmd);

  1. Linux下调用系统命令并弹出命令行窗口

String [] cmd={“/bin/sh”,”-c”,”xterm -e ln -s exe1 exe2”};
Process proc =Runtime.getRuntime().exec(cmd);

Java反射相关知识

先说一个不成熟的结论,个人对Java反射的理解类似python jinja2模板渲染引擎SSTI漏洞中找RCE利用链一样:从当前类找到object类(forName/__base__),在从object类的子类中找到存在命令执行方法的子类(runtime.getruntime()/subclasses()),最后找到命令执行方法(exec/popen)

Java反射是在运行状态中对于任意一个类都可以找到这个类的类名,构造方法,成员方法,属性。这种动态获取对象属性的机制称为Java的反射机制。

反射的优点与缺点

优点:
反射机制可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发者他的灵活性就表现得十分明显。例如,在一个大型软件的开发中,当程序被编译后发布,如果以后需要更新某些功能的时候,我们不可能要用户把以前软件的卸载,再重新安装新的版本。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。

缺点:
对性能有影响。反射机制其实是一种解释操作,我们通过告诉JVM,我们希望做什么并且他们组我们的要求。这类操作总是慢于只直接执行相同的操作

Class类

Class类是所有类的类,对于普通的对象,新建一个对象的实例如下:

Demo demo = new Demo();

但是不能直接用Class cls=new Class();去创建一个class类,因为Class类的构造方法是私有的,不允许被外部调用构建。

然而我们可以通过其他方法获取到class类:

  1. ```java
    Demo demo=new Demo(); Class cls=demo.getclass();

    1
    2
    3

    2. ```java
    Class cls2=Demo.class;
  2. ```java
    Class cls3=Class.forName(“com.org.ReflectDemo.Demo”)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    获取到Class对象之后,可以通过反射机制获取到对象的信息。

    ## Java反射相关方法

    ```java
    public Method getDeclaredMethod(String name, Class<?>... parameterTypes) //获得该类所有的方法,不包括父类
    public Method getMethod(String name, Class<?>... parameterTypes)//获得该类所有public的方法,包括父类。第一二个参数可以指定特定的方法,比如exec(String)和exec(String[]),通过第一个参数指定exec,第二个参数指定String 或者String[] 可以定位不同的方法。
    public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)//获得该类所有的构造方法
    public Constructor<T> getConstructor(Class<?>... parameterTypes)//获得该类所有的public构造方法 包括父类
    public Field getDeclaredField(String name)//获得该类所有的声明变量,不包括父类
    public Field getField(String name)//获得该类所有的public声明变量,包括父类
    writeObject()//序列化,将Object输出成Byte流
    readObject()//反序列化,将Byte流输出成Object
    invoke()

invoke()的作用是执行(call)方法,正常的方法调用顺序为 object.method(p1,p2,p3)

使用invoke的调用顺序为method.invoke(object,p1,p2,p3)

getMethod方法重载:通过指定方法名和方法参数类型确定唯一一个方法。image-20220307234218733

java 单例模式

Runtime的构造器是私有的,所以不可以直接new一个Runtime的对象。

这里搬运下runoob的介绍:

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

个人理解单例模式就是一个类只有一个实例化对象在类内部,需要的时候就调用,全局仅维护这一个实例化对象,调用的时候没有就创建,有就返回实例化对象。这个实例化对象有的话只能有一个。

示例一:

Runtime的构造器属性为私有是有原因的,这是一种”单例模式”,对于Web应用来说,数据库连接只需要建立一次,而不是每次用到数据库的时候再新建立一个连
接,此时作为开发者你就可以将数据库连接使用的类的构造函数设置为私有,然后编写一个静态方法来获取:

1
2
3
4
5
6
7
8
9
10
public class TrainDB {
private static TrainDB instance = new TrainDB();
public static TrainDB getInstance() {
return instance;
}
private TrainDB() {
db.conn();
// 建立连接的代码...
}
}

示例二:

创建一个 Singleton 类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class SingleObject {

//创建 SingleObject 的一个对象
private static SingleObject instance = new SingleObject();

//让构造函数为 private,这样该类就不会被实例化
private SingleObject(){}

//获取唯一可用的对象
public static SingleObject getInstance(){
return instance;
}

public void showMessage(){
System.out.println("Hello World!");
}
}

从 singleton 类获取唯一的对象。\

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class SingletonPatternDemo {
public static void main(String[] args) {

//不合法的构造函数
//编译时错误:构造函数 SingleObject() 是不可见的
//SingleObject object = new SingleObject();

//获取唯一可用的对象
SingleObject object = SingleObject.getInstance();

//显示消息
object.showMessage();
}
}

java反射demo

1
2
3
4
//reflection demo 1
Class c2=Class.forName("java.lang.Runtime");
Object o1=c2.getMethod("getRuntime").invoke(null,null);
c2.getMethod("exec", String.class).invoke(o1,"calc");

如果一个类的构造方法为私有,可以执行,不过需要一些操作:使用getDeclearedConstructor获取所有构造方法,设置可访问标记为true即可。

1
2
3
4
5
//reflection demo 2
Class c1=Class.forName("java.lang.Runtime");
Constructor cs=c1.getDeclaredConstructor();
cs.setAccessible(true);
c1.getMethod("exec",String.class).invoke(cs.newInstance(),"notepad");

java反射rce-SSTI

velocity ssti,参考链接https://samny.blog.csdn.net/article/details/104881477

具体模板语言不讲了,根据payload

1
?template=%23set($e="e");$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("calc.exe")

直接debug

image-20220307235823301

image-20220307235841610

一步步跟踪,跟踪到evaluate方法发现将String类型的输入转为了Reader类型:Reader是一个抽象类,它是以字符为单位的输入流的公共父类。

继续跟踪到parse方法

image-20220308000025688

继续跟parse方法

image-20220308000210699

image-20220308000719740

进入init方法后 继续跟,跟到render方法

image-20220308001022402

image-20220308001238023

image-20220308001303577

继续跟进去看render方法

跟到后面发现execute方法,像invoke的调用方法,继续跟进去看看

image-20220308001522947

又是一个execute方法,继续跟

image-20220308001654919

哈哈,终于找到了眼熟的getMethodinvoke方法

image-20220308001749767

这样循环走下去,接下来是runtime,Runtime.getruntime(),exec(“calc”)。

image-20220308001902056

image-20220308001936027

最终弹出来了计算器

image-20220308002715772
#参考链接

https://samny.blog.csdn.net/article/details/104881477
https://www.sec-in.com/article/307
https://le1a.gitee.io/posts/916c2e64/
https://blog.csdn.net/m0_38103658/article/details/105482035
https://cloud.tencent.com/developer/article/1607776