Hook机制类似于AOP机制(Aspect Oriented Programming,面向切面编程),使用基于Java Agent实现的Hook技术,RASP可以实现对Java类方法执行执行前后插入自定义逻辑,从而实现控制原本的程序执行的业务逻辑。

ProcessBuilder Hook示例

java.lang.ProcessBuilder常用于执行本地系统命令,为了便于理解Hook机制,这里以Hook ProcessBuilder类的start方法作为示例,演示如何Hook机制的工作原理。

示例 - 未经Hook的原始java.lang.ProcessBuilder类代码片段:

  1. package java.lang;
  2. import java.io.IOException;
  3. import java.util.List;
  4. public final class ProcessBuilder {
  5. private List<String> command;
  6. // 省略其他不相关类和成员变量
  7. public Process start() throws IOException {
  8. // 省去其他无关代码
  9. return ProcessImpl.start(command, environment, dir, redirects, redirectErrorStream);
  10. }
  11. }

ProcessBuilder类可以调用UNIXProcess/ProcessImpl类的native方法执行本地系统命令,默认情况下可以被任意的Java类调用,所以存在安全问题。RASP使用Agent机制动态修改了ProcessBuilder类的start方法字节码,在方法体的前后插入RASP防御代码,当start方法被调用时因为程序逻辑已被RASP更改,必须先执行RASP的防御逻辑之后才能够执行start方法的原始业务逻辑,如果RASP调用内部的检测逻辑后发现可能存在恶意攻击,RASP会终止start方法执行逻辑,从而避免了恶意攻击。

示例 - RASP的Hook逻辑代码片段:

  1. package org.javaweb.rasp.agent;
  2. import org.javaweb.rasp.agent.commons.RASPLogger;
  3. import org.javaweb.rasp.agent.hooks.advice.RASPMethodAdvice;
  4. import org.javaweb.rasp.agent.hooks.annotation.RASPClassHook;
  5. import org.javaweb.rasp.agent.hooks.annotation.RASPMethodHook;
  6. import org.javaweb.rasp.agent.utils.ClassUtils;
  7. import org.javaweb.rasp.loader.hooks.RASPHookResult;
  8. /**
  9. * Hook 本地命令执行
  10. */
  11. @RASPClassHook
  12. public class LocalCommandHook {
  13. /**
  14. * Hook 通用的ProcessBuilder类
  15. */
  16. @RASPMethodHook(className = "java.lang.ProcessBuilder", methodName = "start")
  17. public static class ProcessBuilderHook extends RASPMethodAdvice {
  18. @Override
  19. public RASPHookResult<?> onMethodEnter() {
  20. Object obj = getThisObject();
  21. try {
  22. // 获取ProcessBuilder类的command变量值
  23. List<String> command = ClassUtils.getFieldValue(obj, "command");
  24. // 将执行的系统命令转换成字符串数组
  25. String[] commands = command.toArray(new String[command.size()]);
  26. // 调用processCommand方法,检测执行的本地命令合法性
  27. return LocalCommandHookHandler.processCommand(commands, obj, this);
  28. } catch (Exception e) {
  29. RASPLogger.log(AGENT_NAME + "获取ProcessBuilder类command变量异常:" + e, e);
  30. }
  31. return new RASPHookResult(RETURN);
  32. }
  33. }
  34. // 省略其他本地命令执行Hook点
  35. }

示例 - 经过RASP修改后的java.lang.ProcessBuilder类

  1. package java.lang;
  2. import org.javaweb.rasp.loader.hooks.RASPHookHandlerType;
  3. import org.javaweb.rasp.loader.hooks.RASPHookProxy;
  4. import org.javaweb.rasp.loader.hooks.RASPHookResult;
  5. import java.io.IOException;
  6. import java.util.List;
  7. public final class ProcessBuilder {
  8. private List<String> command;
  9. public Process start() throws IOException {
  10. // 生成Object数组对象,存储方法参数值
  11. Object[] parameters = new Object[]{};
  12. // 生成try/catch
  13. try {
  14. // 调用RASP方法方法进入时检测逻辑
  15. RASPHookResult<?> enterResult = RASPHookProxy.onMethodEnter(parameters, ...);
  16. String HandlerType = enterResult.getRaspHookHandlerType().toString();
  17. if (RASPHookHandlerType.REPLACE_OR_BLOCK.toString().equals(HandlerType)) {
  18. // 如果RASP检测结果需要阻断或替换程序执行逻辑,return RASP返回结果中设置的返回值
  19. return (Process) enterResult.getReturnValue();
  20. } else if (RASPHookHandlerType.THROW.toString().equals(HandlerType)) {
  21. // 如果RASP检测结果需要往外抛出异常,throw RASP返回结果中设置的异常对象
  22. throw (Throwable) enterResult.getException();
  23. }
  24. // 执行程序原逻辑,执行本地系统命令并返回Process对象
  25. Process methodReturn = ProcessImpl.start(command, environment, dir, redirects, redirectErrorStream);
  26. // 调用RASP方法方法退出时检测逻辑,同onMethodEnter,此处省略对应代码
  27. return methodReturn;
  28. } catch (Throwable t) {
  29. // 调用RASP方法方法异常退出时检测逻辑,同onMethodEnter,此处省略对应代码
  30. }
  31. }
  32. }

RASP Hook与Java Web攻击

常见的Java Web攻击方式最终几乎都会调用对应的Java类方法执行,而RASP恰好可以使用Hook机制控制任意的Java类方法执行逻辑,因此RASP可以使用Hook机制将易受攻击的Java类进行监控,从而实现防止恶意的Java Web攻击。

Hook机制 - 图1