2026/1/10 10:31:20
网站建设
项目流程
深圳专业企业网站建设模板,wordpress支付无效,做美食网站首页怎么做,怎样在本机建设网站SQL注入漏洞审计靶场#xff1a;Hello-Java-Secjava中由于数据库连接的方式有多种 所以它们对应的漏洞利用方式也是不同的原生JDBCJDBC有两种⽅法执⾏SQL语句#xff0c;分别为PrepareStatement和Statement。两个⽅法的区别在PrepareStatement会对SQL语句进⾏预编译#xff…SQL注入漏洞审计靶场Hello-Java-Secjava中由于数据库连接的方式有多种 所以它们对应的漏洞利用方式也是不同的原生JDBCJDBC有两种⽅法执⾏SQL语句分别为PrepareStatement和Statement。两个⽅法的区别在PrepareStatement会对SQL语句进⾏预编译⽽Statement⽅法在每次执⾏时都需要编译会增⼤系统开销Statement注入点击靶场对应的代码发现是存在注入的现在问题来了我们该如何找到个这个接口对应在后端的代码呢毕竟它不像php和java原生的项目 有对应的目录 直接按照对应url的目录去找就可以看IDEA的端点 这个也是最常用最有效的方法也可以右键项目 在项目中搜索或者根据习惯 根据MVC 一般业务的逻辑都在controller中找到对应的SQLI一级目录 再去找二级三级目录需要注意的点SQLI/jdbc 虽然url是这样的 但是SQLI和jdbc它俩其实是没有连在一起的 去分析依赖or文件中查找 连在一起查找的话有可能是查不到的其实 SQLI相当于是一级目录 声明在某一个class 中 而jdbc只是当前这个class中的一个方法既然找到了对应的java代码 那我们就看看它是怎么写的吧。RequestMapping(/jdbc) public String sql_1(String id) { StringBuilder result new StringBuilder(); try { /* * 注册 JDBC 驱动 * com.mysql.jdbc.Driver 对应版本 5 * com.mysql.cj.jdbc.Driver 对应高版本 */ Class.forName(com.mysql.cj.jdbc.Driver); // 建立连接 Connection conn DriverManager.getConnection(db_url, db_user, db_pass); // 执行查询 Statement stmt conn.createStatement(); String sql select * from users where id id ; System.out.println([*] 执行SQL语句 sql); ResultSet rs stmt.executeQuery(sql); // 获取查询结果 while (rs.next()) { String res_name rs.getString(user); String res_pass rs.getString(pass); String info String.format(查询结果 %s: %s, res_name, res_pass); result.append(info); } rs.close(); conn.close(); } catch (Exception e) { // 输出错误用于报错注入。。。 return e.toString(); } return result.toString(); }这是直接做的拼接 肯定是有问题的构造执行了语句 进行了报错注入[*] 执行SQL语句select * from users where id 1 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)--当然也可以构造其他的语句PrepareStatement注⼊PrepareStatement支持进行预编译 正常的写法肯定是没有sql注入的问题的 但是不安全的写法同样会导致sql注入产生啊比如String sql select * from user where id req.getParameter(id); PrintWriter out resp.getWriter(); out.println(prepareStatement Demo); out.println(SQL: sql); try { PreparedStatement pst conn.prepareStatement(sql); ResultSet rs pst.executeQuery(); while (rs.next()){ out.println(brResult: rs.getObject(name)); } } catch (SQLException throwables) { throwables.printStackTrace(); }看似用了prepareStatement 实则还是拼接的的方式 没有进行预编译正确的写法应该是如何呢看靶场的代码RequestMapping(/jdbc/pre) public String sql_pre(String id) { StringBuilder result new StringBuilder(); try { Class.forName(com.mysql.cj.jdbc.Driver); Connection conn DriverManager.getConnection(db_url, db_user, db_pass); String sql select * from users where id ?; PreparedStatement st conn.prepareStatement(sql); st.setString(1, id); System.out.println([*] 执行SQL语句 st); ResultSet rs st.executeQuery(); while (rs.next()) { String res_name rs.getString(user); String res_pass rs.getString(pass); String info String.format(查询结果%n %s: %s%n, res_name, res_pass); result.append(info); } rs.close(); conn.close(); } catch (Exception e) { return e.toString(); } return result.toString(); }st.setString(1, id);的含义是指定第一个位置的参数为id使用了预编译的方式 有效防御了sql注入的产生MyBatisMyBatis 是⼀个流⾏的持久层框架它提供了⼀种优雅⽽简单的⽅式来管理数据库访问。通常框架底层已经实现了对SQL注⼊的防御但在研发⼈员未能恰当使⽤框架的情况下仍然可能存在SQL注⼊的⻛险。在 MyBatis 中动态 SQL 拼接字符串可能导致 SQL 注⼊漏洞。直接拼接select idQueryByName parameterTypeString resultTypecom.demo.bean.U ser select * from user where name ${name} /selectorderby注入点击oderBy函数查看函数详情这是传统的XML形式的配置 我们去根据oderBy这个接口名找到对应的xml写法${field}和${sort}确实存在问题 并且这俩参数都是String类型 存在sql注入的漏洞正确的写法查看MyBatis3提供了新的基于注解的配置通过注解不在需要配置繁杂的xml文件看写法还是错的啊 为什么就会避免了sql注入呢因为这里的id是int类型 输入字符串的话会被过滤掉 隐式转换在看一下其他的地方有没有问题呢我看到了除了这俩还有不少的函数1.queryById1存在sql注入错误写法字符串类型值2.orderBySafe安全他就没有去拼接用户的输入 它的order by后面的语句都是写好的XSS直接在 html ⻚⾯展示“⽤户可控数据”将直接导致跨站脚本威胁解决办法1.进⾏ html escape 转义2.在给⽤户设置认证 COOKIE 时加⼊ HTTPONLY命令注入命令注⼊是注⼊操作系统命令并执⾏命令学习的重点不仅仅只是看出来有命令注入漏洞 还要会利用会验证 会构造参数命令ProcessBuilderjava.lang.ProcessBuilder 中 start() ⽅法可以执⾏系统命令代码示例// String dir xxxx; String[] cmdList new String[]{sh, -c, ls -lh dir}; // ; | $() ProcessBuilder builder new ProcessBuilder(cmdList); builder.redirectErrorStream(true); Process process builder.start(); printOutput(process.getInputStream());看靶场为啥是空白啊看运行控制台有报错提示找不到sh因为sh是linux的命令行 win的是cmd.exe去看代码 cmd.exe/c果然是这样那我们把它改一下吧 改成win的指令改完后记得重新部署 要不然不会生效 filepath参数用户可控产生了命令注入Runtimejava.lang.Runtime 中 exec() 函数同样可以执⾏系统命令 本质上还是调用ProcessBuilder 的问题⽽直接传⼊ String 时会先经过 StringTokenizer 的分隔处理然后在使⽤ ProcessBuilder所以要知道StringTokenizer 是如何分割字符串命令的这样才可以去构造参数进行漏洞验证。经过测试 sh -c ls;id 形式的可以对于 sh -c curl example.com 来说 会把example.com作为前面的sh -c的参数执行 这肯定是不可以执行的看靶场空白页面 看运行控制台的报错应该是把id当做系统的可运行文件执行了RequestMapping(/runtime) public static String cmd2(String cmd) { StringBuilder sb new StringBuilder(); String line; try { // 执行命令 Process proc Runtime.getRuntime().exec(cmd); InputStream fis proc.getInputStream(); InputStreamReader isr new InputStreamReader(fis); BufferedReader br new BufferedReader(isr); while ((line br.readLine()) ! null) { System.out.println(line); sb.append(line); } } catch (IOException e) { e.printStackTrace(); } return sb.toString(); }嗯 符合猜想直接把传入的参数当做可执行的程序了效果相当于在运行窗口输入id 这肯定是有问题的啊这种情况下输入win命令行的命令也不行 因为没有名叫dir的可执行文件但是calc应该是可以的 因为它是有可执行的文件的那我如果是想执行dir 等命令行的命令应该怎么做要自己去构造命令 实现1.运行cmd.exe 2.把dir作为参数传入cmd.exe这也是我们前面要分析参数命令格式的原因参考格式sh -c ls;id 试一下这个cmd.exe /c dirSSRFSSRFServer-Side Request Forgery服务端请求伪造 是⼀种由攻击者构造形成由服务端发起请求的⼀个安全漏洞。很多web应⽤都提供了从其他的服务器上获取数据的功能。使⽤ 户指定的URLweb应⽤可以获取图⽚下载⽂件读取⽂件内容等。这个功能如果被恶意使⽤可以利⽤存在缺陷的web应⽤作为代理攻击远程和本地的服务器。URLConnection方式找不到路径是因为我们用的win部署的 没有file:///etc/password 换成win存在的目录即可代码如下GetMapping(/URLConnection) public String URLConnection(String url) { return Http.URLConnection(url); }// URLConnection类 public static String URLConnection(String url) { try { URL u new URL(url); URLConnection conn u.openConnection(); // 通过getInputStream() 读取 URL 所引用的资源数据 BufferedReader reader new BufferedReader(new InputStreamReader(conn.getInputStream())); String content; StringBuffer html new StringBuffer(); while ((content reader.readLine()) ! null) { html.append(content); } reader.close(); return html.toString(); } catch (Exception e) { return e.getMessage(); } }bypass查看代码GetMapping(/HTTPURLConnection/safe) public String HTTPURLConnection(String url) { if (!Security.is_http(url)){ return 不允许非http/https协议!!!; }else if (Security.is_intranet(url)) { return 不允许访问内网!!!; }else{ return Http.HTTPURLConnection(url); } }有对url参数的内容做检查看下Security.is_http函数的内容public static boolean is_http(String url) { return url.startsWith(http://) || url.startsWith(https://); }检查url的开头是不是http或者https开头 如果是其他协议的话返回false 这样就限定了url要访问的话只能是http协议再看下Security.is_intranet函数的内容public static boolean is_intranet(String url) { Pattern reg Pattern.compile(^(127\\.0\\.0\\.1)|(localhost)|(10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|(172\\.((1[6-9])|(2\\d)|(3[01]))\\.\\d{1,3}\\.\\d{1,3})|(192\\.168\\.\\d{1,3}\\.\\d{1,3})$); Matcher match reg.matcher(url); Boolean a match.find(); return a; }代码执行流程编译正则表达式Pattern.compile() 创建匹配模式创建匹配器reg.matcher(url) 对输入URL进行匹配查找匹配match.find() 查找是否有匹配的部分返回结果返回匹配结果true/false作用其实就是对url的ip做些过滤 过滤掉127 10 172 192 等内网的ip地址访问网址的话当然是可以的可以把内网地址转换成短网址传入去进行绕过要防御就需要去做限制 不允许重定向信息泄露ActuatorSpring Boot Actuator 模块提供了健康检查审计指标收集HTTP 跟踪等是帮助我们监控和管理Spring Boot 应⽤的模块。如果没有正确使⽤Actuator可能造成信息泄露等严重的安全隐患外部⼈员⾮授权访问Actuator端点。其中heapdump作为Actuator组件最为危险的Web端点heapdump因未授权访问被恶意⼈员获取后进⾏分析可进⼀步获取敏感信息。Actuator的使用1.加⼊相关的 maven dependency 2.开启了所有端点未授权访问的配置查看有哪些actuator的端点开放了