服务端常见安全漏洞学习笔记(上) | 青训营

112 阅读3分钟

第三方组件漏洞

课上举了利用 fastjson 1.2.23版本,log4j 2.14.1版本使服务端执行一些非预期代码的例子。

总结一下 Fastjson 利用 TemplatesImpl 执行恶意代码的流程:

  1. TemplatesImpl 是javax.xml.transform包中的一个类,它可以用来执行 XSLT 转换。
  2. Fastjson 在反序列化时,会调用对象符合条件的 getter 和 setter 方法,如果遇到@type指定了 TemplatesImpl 类,它会调用其setTransletBytecodes方法,将_bytecodes字段的值作为字节码数组传入。
  3. 当调用 TemplatesImpl 的 getOutputProperties 方法时,它会触发 newTransformer 方法,从而实例化字节码数组中的类,并调用其构造方法。
  4. 攻击者则可以在这个构造方法中植入任意代码来达到自己的目的。

log4j 2.14.1版本的漏洞则是一个远程代码执行漏洞,它的编号是 CVE-2021-44228。它的原理是 log4j 在解析日志时,如果遇到${}的格式,它会尝试执行其中的代码。如果日志中包含了恶意的代码,例如 ldap 或 rmi 协议的地址,那么 log4j 会从远程服务器获取并执行恶意的类文件。这样就可以让攻击者在服务器上执行任意命令。

防护方式:Java 可以选择使用 dependency-check-maven 检查项目以来的组件是否存在安全漏洞。

SQL 注入漏洞

SQL 注入是大家耳熟能详的一种攻击方式了,假如有个用户叫user1'; DROP TABLE user;,那么就会在执行查询语句SELECT * FROM user WHERE name='user1'; DROP TABLE user;';的时候把整个 user 表 drop 掉。

好在大多数 orm 框架都有防 SQL 注入的功能,这里以 Mybatis 框架为例,以名字查询用户。

<select id="getUserByName" parameterType="String" resultType="User">
  SELECT *
  FROM user
  WHERE name=#{name}
</select>

Mybatis 将用#{}声明的参数预编译成为以下这样的语句,在执行setString方法的时候,自动为危险符号加上转义字符。

String getUserByName = "SELECT * FROM user WHERE name=?";
PreparedStatement ps = conn.prepareStatement(getUserByName);
ps.setString(1, name);

最终发送给 MySQL 执行的语句是这样的,这样会把user1'; DROP TABLE user;看成是一个完整的字符串。

SELECT *
FROM user
WHERE name='user1\'; DROP TABLE user;';

在使用各种 orm 框架时应使用带有预编译功能的方法,而不要直接拼接 SQL 字符串,如果遇到必须拼接的场景,则需要对用户输入的字符串进行转义。

命令执行漏洞

有些时候需要执行一些 shell 命令来完成业务需求,用户可以在|;&&||等命令分隔符后面注入自己想执行的命令

cat a.txt|ls

防护方式:

  1. 对动态的值尽可能设置白名单进行验证。
  2. 如果某些位置无法白名单,需要尝试对数据类型进行校验。
  3. 对含有这些命令分隔符的输入进行拦截。

也可以把用户输入的内容用""括起来,然后对特殊字符进行转义,例如用户输入为"a.txt|ls;",则执行

cat "\"a.txt|ls;\""

参考资料

  1. Java安全之Fastjson反序列化漏洞分析
  2. log4j 2.0~2.14.1版本远程执行代码漏洞复现
  3. 简单说说MySQL Prepared Statement
  4. MyBatis框架中常见的SQL注入
  5. Linux OS 命令注入指北