JAVA安全—JWT安全及预编译CASE注入等

JAVA安全—JWT安全及预编译CASE注入等
Yatming的博客JAVA安全—JWT安全及预编译CASE注入等
什么是JSON
- JSON Web Token(JSON Web 令牌)是一种跨域验证身份的方案。JWT 不加密传输的数据,但能够通 过数字签名来验证数据未被篡改(但是做完下面的 WebGoat 练习后我对这一点表示怀疑)。
- JWT 分为三部分,头部(Header),声明(Claims),签名(Signature),三个部分以英文句号.隔开。JWT 的内容以 Base64URL 进行了编码。
头部(Header)
- alg : 是说明这个 JWT 的签名使用的算法的参数,常见值用 HS256(默认),HS512 等,也可以为 None。HS256 表示 HMAC SHA256。
- typ : 说明这个 token 的类型为 JWT
1 | { |
声明(Claims)
- iss : 发行人
- exp : 到期时间
- sub : 主题
- aud : 用户
- nbf : 在此之前不可用
- iat : 发布时间
- jti : JWT ID 用于标识该 JWT
1 | { |
签名(Signature)
- 服务器有一个不会发送给客户端的密码(secret),用头部中指定的算法对头部和声明的内容用此密 码进行加密,生成的字符串就是 JWT 的签名。
1 | // 下面是一个用 HS256 生成 JWT 的代码例子 |
Javaweb-SQL 注入攻击-预编译机制绕过
- 在使用参数化查询的情况下,数据库系统不会将参数的内容视为SQL指令的一部分来处理
- 而是在数据库完成SQL指令的编译后,才套用参数运行,因此就算参数中含有破坏性的指令,也不会被数据库所运行。
- 这个方式也不是能够绝对的进行 sql 注入防御,只是减轻。如参数绑定方式可以使用下面方式绕过。
- 通过使用
case when
语句可以将order by
后的orderExpression
表达式中添加select
语句。(原理类似堆叠注入,一条语句出现多条命令)
1 | String query = "SELECT * FROM users WHERE last_name = ?";// 不允许一个占位符(?)有多个值 |
进入靶场
数据包分析(发送的请求指向的是源代码中的server)
发现SQL语句,并且语句后面有order by(传递column参数),寻找传参column的地方
我这里抓包有问题,抓不到数据包(理论分析一波)
IP改为i,发现报错
报错的时候存在order by
,因此可以用case when
语句
case when
原理:普通的按某一个字段或者多个字段排序没办法满足我们的需求时,可以通过case when来排序
- 根据报错构造Python脚本(webgoat在虚拟机里,不能用Python脚本跑)
- 设置请求数据的数据头,和cookie
- 设置请求的代理,也就是先发送给抓包工具
- resp为request请求(目标URL,请求头(XML格式),cookie,代理)
1 | import requests |
完成
Javaweb-身份验证攻击-JWT 修改伪造攻击
选择汤姆这个用户,获取对应的数据包
但是替换之后,还是会报错,原因是本身的签名不对,那么可以尝试更改第一个头部为不加密形式
修改之后,成功过关
上面这种情况是建立在对方服务器没有一定要一个签名导致,如果一定要签名,那么就必须要密钥了
Javaweb-身份验证攻击-jwt密匙爆破攻击
—一旦找出密钥就就可以创建新令牌进行签名。因此,只要密钥足够强大,暴力破解字典就不可行
—通过以下令牌找出密钥,并将用户名改为WebGoat
-令牌解密(iat:开始时间,exp:失效时间)
得出答案:victory
Javaweb-身份验证攻击-jwt修改伪造冒充
—通过伪造让Tom进行支付
—查看日志进行分析(这里发现一个token传参使用的JWT令牌)
—解析jwt令牌(发现为Tom的数据包)
—修改exp,并且将首部改为None,去掉签名部分构造JWT
点击checkout抓包(查找与token匹配的数据包)
—在授权这里写入jwt(有些疑惑为什么不加上前面的参数token)
—返回成功(这里没有检测签名和失效时间的条件下)
Javaweb-身份验证攻击-jwt安全结合SQL注入
抓取删除汤姆时产生的数据包
删除汤姆只能自己删除自己,这里由于是杰瑞所以删除不了,所以要将这个杰瑞改成汤姆就行了,但是这里涉及到一个签名的问题,首先要知道key是什么
源代码分析
—这里执行了一条SQL语句,传递的参数是kid
—这个函数传递的参数是token,如果token不为空,就创建一个令牌的对象,并且将令牌解密
— .Jwts.parser().setSigningKeyResolver(自定义方法获取签名KEY).parseClaimsJws(token);//通过自定义方法获取签名key然后对token进行JWT解析
—kid为令牌的首部里面的kid(也就是说,这里没有预编译函数,所以存在注入点)
—利用sql inject,控制查询语句的查询值来控制JWT的密钥,从而伪造JWT,完成任务。
#数据库查询语句(说明jwt_keys表中有一个id的值是:“webgoat_key”):SELECT key FROM jwt_keys WHERE id = ‘webgoat_key‘
构造注入语句
SELECT key FROM jwt_keys WHERE id = ‘y’ and 1=2 union select id from jwt_keys where id =’webgoat_key”
—查询id为webgoat_key中的所有信息(主要是查看签名信息的密钥)
CTF-Node.js-前端JWT登录安全-伪造admin实现getflag
https://www.ctfhub.com/#/challenge
先注册一个用户,登陆,在登陆的时候进行抓包,这里的抓包之后,如下图
由于我没有密钥所以还是之前的思路
第一步先改这里的alg为none
1 | { |
第二步改第二部分这里的secretid要改为空[],就代表空
1 | { |
然后用点号进行连接
1 | ew0KICAiYWxnIjogIm5vbmUiLA0KICAidHlwIjogIkpXVCINCn0.ew0KICAic2VjcmV0aWQiOiBbXSwNCiAgInVzZXJuYW1lIjogImFkbWluIiwNCiAgInBhc3N3b3JkIjogIjEyM3F3ZSIsDQogICJpYXQiOiAxNjU0NzM0NTQwDQp9. |
先抓取一个正常登陆的数据包
来到下图页面后,抓取点击获取flag的数据包之后
将这个数据包放出去一次,就可以看到了flag
参考链接
1 | https://www.bilibili.com/read/cv14490694?spm_id_from=333.999.0.0 |