第三方组件漏洞
课上举了利用 fastjson 1.2.23版本,log4j 2.14.1版本使服务端执行一些非预期代码的例子。
总结一下 Fastjson 利用 TemplatesImpl 执行恶意代码的流程:
- TemplatesImpl 是
javax.xml.transform包中的一个类,它可以用来执行 XSLT 转换。 - Fastjson 在反序列化时,会调用对象符合条件的 getter 和 setter 方法,如果遇到
@type指定了 TemplatesImpl 类,它会调用其setTransletBytecodes方法,将_bytecodes字段的值作为字节码数组传入。 - 当调用 TemplatesImpl 的 getOutputProperties 方法时,它会触发 newTransformer 方法,从而实例化字节码数组中的类,并调用其构造方法。
- 攻击者则可以在这个构造方法中植入任意代码来达到自己的目的。
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
防护方式:
- 对动态的值尽可能设置白名单进行验证。
- 如果某些位置无法白名单,需要尝试对数据类型进行校验。
- 对含有这些命令分隔符的输入进行拦截。
也可以把用户输入的内容用""括起来,然后对特殊字符进行转义,例如用户输入为"a.txt|ls;",则执行
cat "\"a.txt|ls;\""