news 2026/5/1 5:04:59

java常见漏洞的代码审计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
java常见漏洞的代码审计

SQL注入漏洞审计

靶场:Hello-Java-Sec

java中由于数据库连接的方式有多种 所以它们对应的漏洞利用方式也是不同的

原生JDBC

JDBC有两种⽅法执⾏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("<br>Result: "+ 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注入的产生

MyBatis

MyBatis 是⼀个流⾏的持久层框架,它提供了⼀种优雅⽽简单的⽅式来管理数据库访问。通常,框架底层已经实现了对SQL注⼊的防御,但在研发⼈员未能恰当使⽤框架的情况下,仍然可能存在SQL注⼊的⻛险。

在 MyBatis 中,动态 SQL 拼接字符串可能导致 SQL 注⼊漏洞。

直接拼接

<select id="QueryByName" parameterType="String" resultType="com.demo.bean.U ser"> select * from user where name = ${name} </select>

orderby注入

点击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

命令注入

命令注⼊是注⼊操作系统命令并执⾏命令

学习的重点不仅仅只是看出来有命令注入漏洞 还要会利用会验证 会构造参数命令

ProcessBuilder

java.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参数用户可控

产生了命令注入

Runtime

java.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 dir

SSRF

SSRF(Server-Side Request Forgery)服务端请求伪造 是⼀种由攻击者构造形成由服务端发起请求的⼀个安全漏洞。

很多web应⽤都提供了从其他的服务器上获取数据的功能。使⽤ 户指定的URL,web应⽤可以获取图⽚,下载⽂件,读取⽂件内容等。这个功能如果被恶意使⽤,可以利⽤存在缺陷的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地址

访问网址的话当然是可以的

可以把内网地址转换成短网址传入去进行绕过

要防御就需要去做限制 不允许重定向

信息泄露

Actuator

Spring Boot Actuator 模块提供了健康检查,审计,指标收集,HTTP 跟踪等,是帮助我们监控和管理Spring Boot 应⽤的模块。如果没有正确使⽤Actuator,可能造成信息泄露等严重的安全隐患(外部⼈员⾮授权访问Actuator端点)。其中heapdump作为Actuator组件最为危险的Web端点,heapdump因未授权访问被恶意⼈员获取后进⾏分析,可进⼀步获取敏感信息。

Actuator的使用:1.加⼊相关的 maven dependency 2.开启了所有端点未授权访问的配置

查看有哪些actuator的端点开放了

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/24 10:48:52

__acrtused 是什么

这是 Microsoft C/C 运行时库使用的一个特殊符号&#xff0c;用于表示正在使用 C 运行时库。值 9876h&#xff08;十进制为 39030&#xff09;是一个魔法数字&#xff0c;告诉链接器需要 CRT&#xff08;C 运行时&#xff09;初始化。例子.MODEL TINY .8086.code ORG 100h …

作者头像 李华
网站建设 2026/4/17 22:17:54

AMD Ryzen处理器深度调试利器:SMUDebugTool专业使用全解析

AMD Ryzen处理器深度调试利器&#xff1a;SMUDebugTool专业使用全解析 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https:…

作者头像 李华
网站建设 2026/4/29 3:18:51

如何轻松实现B站4K视频下载:3个步骤掌握bilibili-downloader

如何轻松实现B站4K视频下载&#xff1a;3个步骤掌握bilibili-downloader 【免费下载链接】bilibili-downloader B站视频下载&#xff0c;支持下载大会员清晰度4K&#xff0c;持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 还在为无法下…

作者头像 李华
网站建设 2026/4/18 12:39:21

m3u8下载器完全使用手册:网页视频一键保存的终极解决方案

m3u8下载器完全使用手册&#xff1a;网页视频一键保存的终极解决方案 【免费下载链接】m3u8-downloader m3u8 视频在线提取工具 流媒体下载 m3u8下载 桌面客户端 windows mac 项目地址: https://gitcode.com/gh_mirrors/m3u8/m3u8-downloader 在数字化内容爆炸的时代&am…

作者头像 李华
网站建设 2026/4/25 22:04:04

QQ防撤回黑科技:让消失的消息无处可逃

QQ防撤回黑科技&#xff1a;让消失的消息无处可逃 【免费下载链接】LiteLoaderQQNT-Anti-Recall LiteLoaderQQNT 插件 - QQNT 简易防撤回 项目地址: https://gitcode.com/gh_mirrors/li/LiteLoaderQQNT-Anti-Recall 小伙伴们&#xff0c;你们有没有遇到过这种尴尬时刻&a…

作者头像 李华
网站建设 2026/4/30 9:49:17

LyricsX桌面歌词插件:让音乐与文字完美交融的终极解决方案

LyricsX桌面歌词插件&#xff1a;让音乐与文字完美交融的终极解决方案 【免费下载链接】Lyrics Swift-based iTunes plug-in to display lyrics on the desktop. 项目地址: https://gitcode.com/gh_mirrors/lyr/Lyrics 还在为macOS上缺乏专业歌词显示工具而苦恼吗&#…

作者头像 李华