从上往下依次是:
单独的进程中执行指定的字符串命令
单独的进程中执行指定的命令并传入变量
在指定环境的独立进程执行命令和传入变量
在指定环境和工作目录的独立进程执行中执行命令
在指定环境和工作目录的独立进程执行中执行命令和传入变量
有回显的命令
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Exec {
public static void main(String[] args) throws IOException {
BufferedReader br = null;
try{
Process p = Runtime.getRuntime().exec("ping 127.0.0.1");
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
StringBuilder sb = new StringBuilder();
while((line= br.readLine())!=null){
sb.append(line+"n");
}
System.out.println(sb.toString());
}catch (Exception e){
e.printStackTrace();
}finally {
if(br != null){
try{
br.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
进一步地,命令执行在不同系统下做一个判断
windows
String [] cmd = {"cmd","/c","calc.exe"};
Process ps = Runtime.getRuntime().exec(cmd);
linux
String [] cmd = {"/bin/sh","-c","ls"};
Process ps = Runtime.getRuntime().exec(cmd);
判断方法可以使用getProperty获取系统变量
查看getproperties描述可以看到可以获取很多系统变量的键值对
判断系统
if(property.contains(‘linux’))
if (properties.contains(“windows”)||properties.contains(“Windows”))
具有回显的命令,使用IO流读出来输出
Process p = Runtime.getRuntime().exec("");
InputStream io = p.getInputStream();//获得命令结果
InputStreamReader reader = new InputStreamReader(io);//读取结果
BufferedReader BuffRead = new BufferReader(reader);//创建缓冲器
StringBuilder sb = new StringBuilder();
String line = null;
while((line = BuffRead.readline())!=null){
sb.append(line);
System.out.println(line);
}
关闭流....
反射
类加载器
java虚拟机加载类的时候,ClassLoader根据类名加载类,类名是类的完整路径,比如java.lang.Runtime
反射里面的几个重要方法
forName 获取类的方法
newInstance 获取实例化类对象的方法
getMethod 获取函数的方法
invoke 执行函数的方法
Java.lang.reflect.Constructor;
Java.lang.reflect.Field;
Java.lang.reflect.Method;
Java.lang.reflect.Modifier;
在获取类还有几种方式:
- 如果上下文存在某个类的实例a,可以通过**a.getClass()**获取加载了某个类,获取它的java.lang.Class对象,访问它的属性class即可(不属于反射)知道某个类的名字,获取这个类就可以使用forName来获取
其中forName有两个函数重载
Class.forName(className)
Class.forName(className, true, currentLoader)
构造器
写payload的时候,newInstance()不成功原因有其一:1. 该类没有无参构造函数 2. 该类的构造函数时私有的
**getDeclaredConstructor()**获得构造方法,Runtime的构造方法是private,利用反射修改其访问权限
**getConstructor()**无论是否设置setAccessible(),都不可获取到类的私有构造器.
Constructor ct = a.getDeclaredConstructor(); ct.setAccessible(true);//修改访问权限 setAccessible
Object类是所有类的父类
实例化对象
在刚刚获得的构造器进行实例化一个对象
Object instance = ct.newInstance(); //等价于 Runtime rt = new Runtime();
获取方法
Method runMethod = a.getMethod("exec",String Class);
//获取当前类的所有成员方法
Method[] methods = class.getDeclaredMethod() ;
//获取指定类成员方法
Method method = class.getDeclaredMethod("func");
Method method = class.getDeclaredMethod("func",int,double,...)//详见重载
执行方法
Process ps = (Process) runMethod.invoke(instance,"clac")
method.invoke(instance,var1,var2…)
获取成员变量
Field var1 = class.getDeclaredField();
Field var2 = class.getDeclaredField("apple");//指定变量
Object obj = field.get(instance);//获取变量值
field.set(instance,setValue);//修改变量值
序列化
- 类要实现java.io.Serlalizable接口所类的属性必须是可序列化,static,transient 修饰的变量不可被序列化
ObjectOutputStream类->writeObject():对参数指定的Obj文件序列化后写入一个ser文件
反序列化
ObjectInputStream类->readObject():从文件输入流读入,序列化成对象返回
当readObject()可控时,恶意构造后可以命令执行
一道简单的反序列化题
Recaf工具导入war包(java字节码,直接解压看不到源码)
上传的地方和读取的地方一致,考察文件上传木马了
Recaf将tools包导入进idea后,创建一个用来伪造cinfo的Test.java
成功进入,上传一句话木马



