原因
今天在项目中,碰到了waf,本着学习研究的原则,刚好最近在学习java,就顺便研究java命令执行的东西。
简单说waf绕过
网上绕过的方法花里胡哨,这里就简单的说一下本人常用的绕过方法。
-
参数污染,主要是双写参数,或者对参数进行简单的变形,去除双引号等,主要是为了让waf无需检测这一类参数,或者根据操作系统特性,服务器特性进行绕过,这里感觉越来越难绕了就不多少。
-
垃圾数据填充,这一招能过的还是挺多的,主要还是通过填充垃圾数据,超出检测字节,让waf检测不到。
-
分块传输,主要是绕过waf的特征匹配检测,这招我平时绕过的情况不多。
-
关键词替换。检测的大多数是检测到有关键字,然后拦截了。这种情况只需要让waf不检测关键字,或者说对关键词进行等效替换,使用waf不拦截的函数或者名称就行了。这就是本次进行研究的基础。对于一些找真实ip一类的就不在本次讨论范围了。
常用命令执行函数
java.lang.Runtime.getRuntime().exec("calc")
new ProcessBuilder('calc')
众所周知的,java命令执行常用的函数是上面两个。当然这也是被很多安全厂家杀的对象。(事实证明登录了waf查看了一下,果然ProcessBuilder和java.lang.Runtime.getRuntime().exec被爆了命令注入攻击。这个就不截图了,总之,其实测试出来时new 和ProcessBuilder在一起的时候被干掉了。这时候有两个方向,一是寻找其他的命令执行函数(pass),还有就是需要一个不需要new就能创建类对象的方法。)
Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。使用该类可以获取到底层的控制权,该类在sun.misc包,默认是BootstrapClassLoader加载的。
传入一个Class对象并创建该实例对象,但不会调用构造方法
public native Object allocateInstance(Class<?> cls) throws InstantiationException;
也就是说,这里我们可以不用new去创建一个ProcessBuilder,这里贴了一张利用的图。
Class<?> aClass = Class.forName("sun.misc.Unsafe");
Field theUnsafe = aClass.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe o = (Unsafe)theUnsafe.get(null);
ProcessBuilder p = (ProcessBuilder)
o.allocateInstance(ProcessBuilder.class);
p.command("touch","/tmp/3.txt");
p.start();
下面是被拦截的时候的截图。登上waf看了一下,拦截的主要是java.lang.Runtime.getRuntime().exec() new ProcessBuilder()触发到了规则。而利用unsafe就绕过了检测规则。但是这里情况有点特殊太晚了没有继续尝试,第二次利用好像出了点问题。
既然是要寻找等效替代的方法。第一种就是直接找一个能执行的函数。这种还是直接放弃了。转战第二种,就是跟一下runtime的执行流程,看看哪里是执行的黑心点。如果在执行过程中有函数被其他函数调用了,而其他函数通常不在黑名单中,那就可以更换另外一个函数做命令执行了。或者说如果情况允许,可以直接反射调用的话,那也能反射调用底层函数进行命令执行。
这里跟进一下runtime的exec
发现new了一个processBuilders,因为它还在黑名单中,所以继续向下跟进processBuilders,发现这下面调用了ProcessImpl的start方法
ProcessImpl.start()
Process p = new ProcessImpl native Java Native Interface (Java本地接口)。
到这里就差不多结束了。理一下逻辑
java.lang.Runtime.getRuntime().exec(request.getParameter("cmd")
new ProcessBuilder(‘calc.exe’).start()
publicProcessImpl.start()
new ProcessImpl
如果我们能找到函数调用了ProcessImpl.start(),ProcessBuilder(‘calc.exe’).start(),甚至说new ProcessImpl,只要我们能传入我们的恶意参数,更换函数的目的也就达到了。很可惜今天实在太忙了,没有时间去找一下。这里就贴一下反射调用ProcessImpl.start()的图。
String Pro = "java.lang.ProcessImpl";
Class zz = Class.forName(Pro);
Object ob = zz.getModifiers();
System.out.println(zz);
String[] strcmd = new String[]{"calc"};
Method ProStart = zz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
ProStart.setAccessible(true);
System.out.println(ProStart);
ProStart.invoke("ob",strcmd,null,null,null,false);
最后总结一下
- 因为存在waf,所以想用绕过黑名单的方式进行命令执行,就开始寻找等效替代的函数。
- 根据已有的黑名单函数,进入底层寻找功能的实现函数。
- 可以利用反射调用实现函数,进行命令执行。
- 可以利用寻找实现了相关函数的其他未在黑名单的函数,进行等效替代命令执行。
- 根据实际情况选择合适的方式进行利用。
- 当碰到需要new一个对象的这种情况,可以尝试利用unsafe进行调用
阅读原文:https://www.kali.net.cn/thread/51605