当前位置: 首页 > news >正文

小迪安全v2023学习笔记(六十九讲)—— Java安全JWT攻防监控组件泄露接口

文章目录

  • 前记
  • WEB攻防——第六十九天
    • Java安全&JWT攻防&Swagger自动化&算法&签名&密钥&Druid泄露
      • Java安全 - Druid泄露-未授权访问&信息泄露
        • 介绍
        • 发现
        • 攻击点
        • 案例演示
      • Java安全 - Swagger接口-导入&联动批量测试
        • 介绍
        • 发现
        • 案例演示(联动抓包)
      • Java安全 - JWT令牌-空算法&未签名&密钥获取
        • 介绍
        • JWT识别
        • JWT安全
        • JWT利用
          • 项目
          • jwt_tool简单使用
          • 案例演示
            • Web345(空加密)
            • Web346(未校验签名)
            • Web347-348(弱密钥破解)
            • Web349(源码泄露)
            • Web350(密钥混淆)
          • 黑盒测试思路

前记

  • 今天是学校小迪安全的第六十九天,本节课是Java安全的最后一讲,内容围绕JWT安全、SpringBoot的监控组件Swagger,以及Durid展开
  • 重点就是理解JWT在实战中的测试思路,和工具的使用,以实战为主

WEB攻防——第六十九天

Java安全&JWT攻防&Swagger自动化&算法&签名&密钥&Druid泄露

Java安全 - Druid泄露-未授权访问&信息泄露

介绍
  • 参考文章:Druid未授权访问 漏洞复现-阿里云开发者社区
  • Druid 是阿里巴巴数据库事业部出品,为监控而生的数据库连接池。Druid 提供的监控功能,监控 SQL 的执行时间、监控 Web URI 的请求、Session 监控。当开发者配置不当时就可能造成未授权访问漏洞。
发现
  • 黑盒:直接访问http://xxx/druid/index.html看页面是否存在
  • 白盒:全局搜索druid看有没有,或者配置文件中查看
攻击点
  1. 直接拼接URL路径,尝试能否直接未授权访问系统功能点
  2. 结合泄露URL路径和Session信息,利用BurpSuite尝试进行登录
  3. 利用Cookie编辑器替换Session,再次访问后台路径尝试进入后台
案例演示
  • 直接fofa上搜一下,语法title="Druid Stat Index",然后访问/druid/index.html即可:
    在这里插入图片描述

  • 可以看到这里就可以到处点点点,然后发现一些泄露信息,可以直接利用

Java安全 - Swagger接口-导入&联动批量测试

介绍
  • Swagger 是一个用于生成、描述和调用 RESTful 接口的 Web 服务。就是将项目中所有(想要暴露的)接口展现在页面上,并可以进行接口调用和测试的服务。
  • 我们可以对这个接口进行漏洞测试,看是否存在未授权访问、sql 注入、文件上传等漏洞。由于接口太多,一个个接口测试的话太费时间,所以一般会采用自动化接口漏洞安全测试
发现
  • 黑盒
    1. URL路径拼接
      • Swagger2:默认路径为http://xxx/swagger-ui.html
      • Swagger3:默认路径为http://xxx/swagger-ui/index.html
    2. 插件扫描
      • 昨天的SpringBoot-Scan工具就可以直接扫到
  • 白盒:直接在pom.xml或者全局搜索即可
案例演示(联动抓包)
  • 在实战中发现了它泄露Swagger,一般是通过自动化去发包测,基本不会手测,太多了
  • 这里主要是通过Postman去发包,然后走代理让流量经过BurpSuite,通过BP再将流量转发给Xray等测试工具去帮我们探测是否有漏洞,大概是这样的:
Postman --->  BurpSuite    --->    Xray...
  • 这里就演示怎么去进行一个导入,首先我们找到一个Swagger平台,这里我就用之前安全开发搭过的平台了:
    在这里插入图片描述

  • 打开Postman,进入工作区,点击import导入,输入Api Documentation下面的那个网址:
    在这里插入图片描述

  • 如果提示导入错误的,目前我不知道是什么原因,但是我们可以自己访问这个链接,然后将内容复制到它这里面:
    在这里插入图片描述

  • 然后回车它就能够识别了,这是导入成功的样子:
    在这里插入图片描述

  • 现在呢,我们右击根目录,然后点击Run进入控制页面:
    在这里插入图片描述

  • 这里可以自定义怎么测试,可以传入文件等等,这里就直接跑了:
    在这里插入图片描述

  • 这里如果发生报错,就看一下请求头和响应头,我这里是因为前面多识别了//,到这里删掉就好了:
    在这里插入图片描述

  • 然后继续跑:
    在这里插入图片描述

  • 这里就可以看到有的页面是200,说明这个接口能够直接访问;有的页面是500,说明服务器内部出了问题,一般是因为没有权限

  • 现在我们通过postman设置 -> 代理 -> 添加自定义代理配置,代理服务器 ip127.0.0.1 (自选),端口配置 8080 (自选),让其走BP的代理:
    在这里插入图片描述

  • 然后打开我们的BP,再跑一遍即可看到数据包:
    在这里插入图片描述

  • 联动Xray的话,需要到BP:设置 ->Network->Connections->Upstream proxy servers-> 添加 ip:127.0.0.1,端口 7777 (自选),让它再将流量发送到Xray里:
    在这里插入图片描述

  • 点击确定,然后打开我们的Xray,输入命令:

.\xray_windows_amd64.exe webscan --listen 127.0.0.1:7777 --html-output example.html
  • 再重新发包,我们的Xray就会帮我们自动测试漏洞了:
    在这里插入图片描述

Java安全 - JWT令牌-空算法&未签名&密钥获取

介绍
  • JSON Web Token(JWT)。它遵循 JSON 格式,将用户信息加密到 token 里,服务器不保存任何用户信息,只保存密钥信息,通过使用特定加密算法验证 token,通过 token 验证用户身份。基于 token 的身份验证可以替代传统的 cookie+session 身份验证方法。
  • 这使得 JWT 成为高度分布式网站的热门选择,在这些网站中,用户需要与多个后端服务器无缝交互。
  • 它的验证流程如下:
    在这里插入图片描述
JWT识别

在这里插入图片描述

  • JWT一般有三部分,分别用三个点分隔开,每个部分都是JSON格式经过Base64编码后的结果:
    1. 标头(Header)
      • Header是JWT的第一个部分,主要声明了JWT的签名算法
      • alg字段通常用于表示加密采用的算法,如HS256RS256
      • typ字段通常用于表示类型
      • 另外还有kidjkux5u等字段
    2. 有效载荷(Payload)
      • Payload是JWT的第二个部分,主要承载了各种声明并且传递明文数据,用于存储用户的信息
      • iss:该字段表示 jwt 的签发者。
      • sub:该 jwt 面向的用户。
      • aud:jwt 的接收方。
      • exp:jwt 的过期时间,通常来说是一个时间戳。
      • iat:jwt 的签发时间,常来说是一个时间戳。
      • jti:此 jwt 的唯一标识。通常用于解决请求中的重放攻击。该字段在大多数地方没有被提及或使用。因为使用此字段就意味着必须要在服务器维护一张 jti 表, 当客户端携带 jwt 访问的时候需要在 jti 表中查找这个唯一标识是否被使用过。使用这种方式防止重放攻击似乎让 jwt 有点怪怪的感觉,毕竟 jwt 所宣称的优点就是无状态访问
    3. 签名(Signature)
      • Signature是JWT的第三部分,主要是用于对Header和Payload部分进行签名
      • 同时拥有该部分的 JWT 被称为 JWS,也就是签了名的 JWT。
JWT安全
  • 对于JWT来说,常见的利用方法有三种:
  1. 常规三把手(源代码逻辑漏洞)
    • JWT置空
    • JWT删除
    • JWT超时重发
  2. 空加密算法(攻击头部不使用加密)
    • 签名算法可被修改为 none,JWT 支持将算法设定为 “None”。如果 “alg” 字段设为 “None”,那么签名会被置空,这样任何 token 都是有效的。
  3. 未校验签名(攻击签名不使用签名认证)
    • 某些服务端并未校验 JWT 签名,可以尝试修改 payload 后然后直接请求 token 或者直接删除 signature 再次请求查看其是否还有效。
  4. 暴力破解密钥(攻击签名知道密钥实现重组)
    • 针对是对称加密算法(非对称没有用)
    • 非对称要使用方法:获取源码得到公钥私钥文件、或者利用其逻辑漏洞(密钥混淆攻击)
    • 某些签名算法,例如 HS256(HMAC+SHA-256),会像密码一样使用一个任意的、独立的字符串作为秘密密钥。这个秘钥如被轻易猜到或暴力破解,则攻击者能以任意的头部和载荷值来创建 JWT,然后用密钥重新给令牌签名。
  5. 其他安全参考(头部注入、Kid注入等)
    • 参考文章:细说——JWT攻击_jwt漏洞-CSDN博客
JWT利用
项目
  • 还是一样,我们测试JWT也会使用一些好用的工具
    • JWT在线识别网站:https://www.jwt.io/
    • JWT最好用工具:https://github.com/ticarpi/jwt_tool
    • BP插件
      • 识别:HaE/README_CN.md at master · gh0stkey/HaE
      • 攻击:JSON Web Token Attacker - PortSwigger
  • 注意,如果你的BP版本是2023.12以下的,只能使用2.xjar
jwt_tool简单使用
  • 使用 None 算法:
python3 jwt_tool.py JWT_HERE -X a
  • 自定义修改生成
python3 jwt_tool.py JWT_HERE -T
  • 使用字典破解
python3 jwt_tool.py JWT_HERE -C -d dictionary.txt
  • 指定密钥测试
python3 jwt_tool.py JWT_HERE -C -p password_here
  • 实战将JWT_HERE改成需要处理的JWT值即可
案例演示
Web345(空加密)
  • 打开是这样的一个页面:
    在这里插入图片描述

  • 一般来说呢,思路就是看源码、抓包、扫目录,这里也不卖关子,就是抓包然后HaE插件自动识别到了JWT:
    在这里插入图片描述

  • 当然我们自己看都能看出来,JWT的流量特征就是三部分,然后以eyJ开头嘛!

  • 我们将第二个数据包发送到Repeater模块,为什么是这个包呢?因为它在请求包中就带有JWT信息
    在这里插入图片描述

  • 这里我们的Jwt Attacker并没有识别到信息,那我们就直接放到jwt.io中看能不能解出来:
    在这里插入图片描述

  • 这里好像也不行,原因是因为这个JWT它没有签名部分,他只有头部和载荷部分

  • 那我们就想到,既然没有签名,那我们是不是就可以直接伪造用户了啊?因为JWT实现身份验证的核心就是这个签名机制啊

  • 这里我们关注到Payload部分如果变成JSON格式是这样的:

{"iss": "admin","iat": 1755778739,"exp": 1755785939,"nbf": 1755778739,"sub": "user","jti": "5e21f8b6def8204f1e38d36190f8c75b"
}
  • 我们注意到有sub这个键,它的意思是该JWT面向的用户,这里是user,也就是普通用户,如果我们伪造成admin是不是就变成管理员了呢

  • 我们知道JWT是JSON格式Base64编码后的结果,那我们直接先解码然后再编码不就行了吗

  • 转到Decode模块,Base64解码,然后该值编码:
    在这里插入图片描述

  • 将这个编码结果替换原来的JWT,发包,注意这里它在源码里面提示我们在/admin/路径,所以要发包到这个路径下:
    在这里插入图片描述

Web346(未校验签名)
  • 和上一题一样,抓包得到JWT信息,转到Repeater模块:
    在这里插入图片描述

  • Jwt Attacker插件依旧没生效,不知道什么原因啊,然后我们拿到jwt.io上解码看一下:
    在这里插入图片描述

  • 这次就成功解码了,我们直接尝试修改sub肯定是不行了,因为它有签名啊,我们不知道密钥加密出来的结果肯定是错的

  • 于是我们想其他的方法,置空、删除都没用,那就换空加密试一下子,将alg的值改成None,这里用jwt.io它是弄不出来的

  • 我们需要换成jwt_tool这个工具,输入上面提到过的命令:
    在这里插入图片描述

  • 这里我们自定义修改,然后跟着将alg改成None,将sub改成admin即可,它就会自动帮我们生成:
    在这里插入图片描述

  • 复制粘贴放包:
    在这里插入图片描述

  • 诶,这里还需要注意一个细节,就是设置algNone之后,第三部分的签名就需要删掉(但保留 . 表示空加密),不然它还是有问题:
    在这里插入图片描述

Web347-348(弱密钥破解)
  • 同样,访问抓包得到JWT

  • 然后我们尝试上面两题的方法没用,此时需要新的思路,就是猜测是否为弱密钥签名,然后尝试爆破

  • 使用的工具还是我们的jwt_tool,命令上面也写过,这里直接用字典爆破即可:
    在这里插入图片描述

  • 字典地址:jwt-secrets/jwt.secrets.list at master · wallarm/jwt-secrets

  • 这里就得到了JWT的密钥,于是我们就可以随意伪造对象了:
    在这里插入图片描述
    在这里插入图片描述

Web349(源码泄露)
  • 这个题给了一个源码:
/* GET home page. */
router.get('/', function(req, res, next) {res.type('html');var privateKey = fs.readFileSync(process.cwd()+'//public//private.key');var token = jwt.sign({ user: 'user' }, privateKey, { algorithm: 'RS256' });res.cookie('auth',token);res.end('where is flag?');});router.post('/',function(req,res,next){var flag="flag_here";res.type('html');var auth = req.cookies.auth;var cert = fs.readFileSync(process.cwd()+'//public/public.key');  // get public keyjwt.verify(auth, cert, function(err, decoded) {if(decoded.user==='admin'){res.end(flag);}else{res.end('you are not admin');}});
});
  • 简单审计一下代码,get请求/路径,会读取private.key文件获取私钥,用于签名加密,加密的方式是RSA,非对称加密,利用密钥爆破没用了
  • 然后是post请求/路径,会读取public.key文件获取公钥,用于验证解密,然后判断user是否为admin
  • 于是我们知道了它的一个签名逻辑是私钥加密,公钥解密;并且拿到flag的条件是让user==='admin'
  • 于是我们如果能拿到私钥,就可以破解这个JWT了,而这里刚好泄露了私钥的路径地址,直接下载下来:
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDNioS2aSHtu6WIU88oWzpShhkb+r6QPBryJmdaR1a3ToD9sXDb
eni5WTsWVKrmzmCk7tu4iNtkmn/r9D/bFcadHGnXYqlTJItOdHZio3Bi1J2Elxg8
IEBKx9g6RggTOGXQFxSxlzLNMRzRC4d2PcA9mxjAbG1Naz58ibbtogeglQIDAQAB
AoGAE+mAc995fvt3zN45qnI0EzyUgCZpgbWg8qaPyqowl2+OhYVEJq8VtPcVB1PK
frOtnyzYsmbnwjZJgEVYTlQsum0zJBuTKoN4iDoV0Oq1Auwlcr6O0T35RGiijqAX
h7iFjNscfs/Dp/BnyKZuu60boXrcuyuZ8qXHz0exGkegjMECQQD1eP39cPhcwydM
cdEBOgkI/E/EDWmdjcwIoauczwiQEx56EjAwM88rgxUGCUF4R/hIW9JD1vlp62Qi
ST9LU4lxAkEA1lsfr9gF/9OdzAsPfuTLsl+l9zpo1jjzhXlwmHFgyCAn7gBKeWdv
ubocOClTTQ7Y4RqivomTmlNVtmcHda1XZQJAR0v0IZedW3wHPwnT1dJga261UFFA
+tUDjQJAERSE/SvAb143BtkVdCLniVBI5sGomIOq569Z0+zdsaOqsZs60QJAYqtJ
V7EReeQX8693r4pztSTQCZBKZ6mJdvwidxlhWl1q4+QgY+fYBt8DVFq5bHQUIvIW
zawYVGZdwvuD9IgY/QJAGCJbXA+Knw10B+g5tDZfVHsr6YYMY3Q24zVu4JXozWDV
x+G39IajrVKwuCPG2VezWfwfWpTeo2bDmQS0CWOPjA==
-----END RSA PRIVATE KEY-----
  • 然后这里可以选择写个脚本去破解,当然也可以直接在线网站去解密,这里jwt.io不行,可以使用这个网站:jwt在线解密/加密 - JSON中文网
  • 当然,这里也可以自己写个脚本进行加密:
import jwt
public = open('private.key', 'r').read()
payload={"user":"admin"}
print(jwt.encode(payload, key=public, algorithm='RS256'))
  • 也可以通过jwt_tool去生成:
python jwt_tool.py <JWT_HERE> -T -S rs256 -p private.key
  • 按道理来说是可以的,但是好像是因为这里工具默认签名编码和网页签名编码不同,导致工具的签名结果在这里不可用

  • 填入JWT,然后填入公钥和私钥,改动自己想要的值即可:
    在这里插入图片描述

  • 然后去通过POST访问/路径,发包:
    在这里插入图片描述

Web350(密钥混淆)
  • 同样给了源码:
var express = require('express');  
var router = express.Router();  
var jwt = require('jsonwebtoken');  
var fs = require('fs');  /* GET home page. */  
router.get('/', function(req, res, next) {  res.type('html');  var privateKey = fs.readFileSync(process.cwd()+'//routes/private.key');  var token = jwt.sign({ user: 'user' }, privateKey, { algorithm: 'RS256' });  res.cookie('auth',token);  res.end('where is flag?');  });  router.post('/',function(req,res,next){  var flag="flag_here";  res.type('html');  var auth = req.cookies.auth;  var cert = fs.readFileSync(process.cwd()+'//routes/public.key');  // get public key  jwt.verify(auth, cert,function(err, decoded) {  if(decoded.user==='admin'){  res.end(flag);  }else{  res.end('you are not admin'+err);  }  });  
});  module.exports = router;
  • 还是审计一下,get请求/路径,会读取private.key文件获取私钥,用于签名加密,加密的方式是RSA
  • 然后是post请求/路径,会读取public.key文件获取公钥,用于验证解密,然后判断user是否为admin
  • 这里和上面那题的区别就是这里下载不了私钥了,因为它是在/routes目录下的
  • 但是这里我们在源码文件夹中能够拿到公钥,这个有什么用呢?原本在解密时verify应该要这么写:
jwt.verify(auth, cert, { algorithms: ['RS256'] }, function(err, decoded) {...
});
  • 需要指明解密的算法,但是这里并没有,于是我们就有一个骚操作,这里也不卖关子了,思路就是密钥混淆
  • 既然他没有指明解密的算法,然后用的还是公钥解密,这个公钥我们是知道的,于是我们就可以利用这个公钥去加密,正好他用公钥来解密 ==> 变成对称加密了
  • 这里就直接用原本的代码然后改点东西就可以了:
var jwt = require('jsonwebtoken');  
var fs = require('fs');  var publicKey = fs.readFileSync('./public.key');  
var token = jwt.sign({ user: 'admin' }, publicKey, { algorithm: 'HS256' });  
console.log(token);
  • 不知道为什么jwt_tool和在线网站用同样的方法生成的jwt都不行,不太理解,有热心的宝宝可以解释一下[比心]
黑盒测试思路
  • 首先找到需要 JWT 鉴权后才能访问的页面,如个人资料页面,将该请求包重放测试:
    1. 未授权访问:删除 Token 后仍然可以正常响应对应页面
    2. 敏感信息泄露:通过 jwt.io 解密出 Payload 后查看其中是否包含敏感信息,如弱加密的密码等
    3. 破解密钥 + 越权访问:通过 jwt.io 解密出 Payload 部分内容,通过空加密算法或密钥爆破等方式实现重新签发 Token 并修改 Payload 部分内容,重放请求包,观察响应包是否能够越权查看其他用户资料
    4. 检查 Token 时效性:解密查看 payload 中是否有 exp 字段键值对(Token 过期时间),等待过期时间后再次使用该 Token 发送请求,若正常响应则存在 Token 不过期
    5. 通过页面回显进行探测:如修改 Payload 中键值对后页面报错信息是否存在注入,payloadkid 字段的目录遍历问题与 sql 注入问题
  • 其实也就是我们上面那几个测试思路
http://www.dtcms.com/a/343917.html

相关文章:

  • 北斗导航 | 基于MCMC粒子滤波的接收机自主完好性监测(RAIM)算法(附matlab代码)
  • 【C++组件】Elasticsearch 安装及使用
  • ODYSSEY:开放世界四足机器人的探索与操控,助力长范围任务
  • ref 简单讲解
  • 【前端教程】从基础到进阶:淘宝 HTML 界面“回到顶部”功能的交互升级实战
  • 刷题日记0822
  • Git 版本管理各模块知识点梳理
  • Logstash_Input插件
  • Chrome和Edge如何开启暗黑模式
  • 浏览器插件优化工具:bypass paywalls chrome
  • 【TrOCR】根据任务特性设计词表vocab.json
  • 今日科技热点 | NVIDIA AI芯片、5G加速与大数据平台演进——技术驱动未来
  • ESP32C5在espidf环境下报错5g bitmap contains only invalid channels= @xff
  • 龙虎榜——20250822
  • 线上日志排查问题
  • docker 查看容器 docker 筛选容器
  • 使用 Ragas 评估你的 Elasticsearch LLM 应用
  • 基于Python的伊人酒店管理系统 Python+Django+Vue.js
  • 基于Docker的高可用WordPress集群部署:Nginx负载均衡+Mysql主从复制+ProxySQL读写分离
  • Unreal Engine UFloatingPawnMovement
  • SpringBoot集成ELK
  • 【Dubbo】高性能的 RPC
  • 零基础从头教学Linux(Day 18)
  • Slither 审计自己写的智能合约
  • 《R for Data Science (2e)》免费中文翻译 (第5章) --- Data tidying
  • 园区 “一表多属” 电仪表能碳数据归集与编码实施文档
  • 《LINUX系统编程》笔记p3
  • 赛灵思ZYNQ官方文档UG585自学翻译笔记与代码示例:XILINX UART控制器详解:特性与功能
  • 新手向:计算机视觉入门OpenCV实战项目
  • elasticsearch 7.x elasticsearch 使用scroll滚动查询一页,删除一页,影响后面滚动的查询吗