身份认证绕过
介绍
利用配置和逻辑缺陷,通过篡改数据达到认证绕过
攻击方式
通过html中隐藏的input标签值
通过移除/修改提交的参数来确认程序的响应
通过猜测和暴力破解强制访问站点的某些URL
JWT
介绍
JWT全称JSON Web
Token,是在RFC7519中定义的一种在客户端和服务器之间使用JSON对象,以自包含的方式安全的传输数据。数据是被签名的,可被验证和信任,签名方式可以选择HMAC也可以选择基于公私钥的RAS
JWT用于携带身份标识和客户端的特征,内容经过服务器签名为防止客户端篡改,签名方式可以选择HMAC也可以选择基于公私钥的RAS。token创建在身份被服务器端认证客户端成功以后的任何时期,后续客户端通过token向服务器提供期身份并由服务器验证其有效性和完整性,是便携的和无状态的
令牌结构
令牌格式为Header.claims.Signature
-
Header中存放加密的算法和类型,数据为JSON经过BASE64URL算法的编码结果,JSON字符串格式为:
-
Claims中存放实际传递的数据(注意该部分非加密格式,可任意读取),数据为JSON经过BASE64URL算法的编码结果,JSON字符串格式为:
字段可以为JWT官方定义的标准字段,也可以自定义,标准字段有7个,分别为:
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (not Before):生效时间
iat (issued at):签发时间
jti (JWT ID):编号
-
Signature中存放通过secret对header和claims计算签名并经过BASE64URL算法的编码结果,算法格式为:
Base64URL编码与Base64类似,主要是将Base64编码中的=省略,+替换为-,/替换为_
签名算法:
HS256:HMAC using SHA-256
HS384:HMAC using SHA-384
HS512:HMAC using SHA-512
RS256:RSASSA-PKCS1-v1_5 using SHA-256
RS384:RSASSA-PKCS1-v1_5 using SHA-384
RS512:RSASSA-PKCS1-v1_5 using SHA-512
ES256:ECDSA using P-256 and SHA-256
ES384:ECDSA using P-384 and SHA-384
ES512:ECDSA using P-521 and SHA-512
PS256:RSASSA-PSS using SHA-256 and MGF1 with SHA-256
PS384:RSASSA-PSS using SHA-384 and MGF1 with SHA-384
PS512:RSASSA-PSS using SHA-512 and MGF1 with SHA-512
none:No digita signature or MAC performed
令牌获取流程
客户端向服务器提交身份认证(用户名和密码)
服务器对提交的用户名和密码进行认证后生成一个jwt信息,并通过HTTP response返回给客户端
客户端在后续请求中通过HTTP request 头传递jwt信息给服务器
服务器对jwt信息进行验证,并返回数据给客户端
Token分类
access token(访问令牌): 用于调用API时使用,具有一定的生命周期
-
refresh token(刷新令牌):
当访问令牌不在有效,可以向服务器端提交的刷新令牌到获取一个新的有效访问令牌。刷新令牌具有比访问令牌更长的有效生命周期(解决用户需要再次使用身份凭证进行认证的问题)在用户认证成功后服务器端生成refresh token和access token,并对refresh token及access token进行存储(在通过刷新令牌生成新的access token时需要对用户提交的refresh token及access token与refresh token的关系进行验证),并将refresh token和access token响应给客户端。在access token有效时间范围内,认证信息在客户端自包含,服务器端不存储用户的session信息,依然是无状态的。当access token失效,客户端需要向服务器端提交refresh token和access token并由服务器进行验证,验证通过后生成新的refresh token和access token并响应给客户端
刷新令牌也可以是无状态的,引起问题:用户无法对令牌进行吊销
攻击方式
将签名算法设置为none从而绕过签名验证
密钥暴力破解token信息
利用refresh token逻辑错误,对其他账号的access token进行刷新
密码重置
介绍
Web站点常提供忘记密码功能以应对用户在密码遗忘情况下可以找回或重置密码,常采用的思路为:
让用户提供设置的密码问题答案
为用户认证的邮箱或手机发送一个验证码或重置密码连接
在验证中过程中可能存在被利用的逻辑错误
攻击方式
利用此功能逻辑缺陷可被用于:
验证用户名/邮箱/手机号是否注册
暴力破解问题答案,后进行重置密码
通过钓鱼方式获取用户重置密码验证码或重置链接后进行重置
针对弱算法生成的验证码或重置链接进行暴力破解
防御
在重置密码失败3次以上,提供后端验证码生成,提示用户输入,并在后端进行验证
针对使用问题答案进行重置密码功能,不应限制问题答案范围
提供发送验证码和重置链接,选择随机性强算法,并记录验证码和用户的关系,同时需要设置验证码和重置连接的有效时间,并保证验证码和重置链接至多使用一次
解题
-
Authentication Bypasses 02
-
JWT tokens 04
-
JWT tokens 05
准备暴力破解脚本及密码字典,并将赋值的token替换到脚本中(这里尝试了使用a-zA-Z0-9生成密码进行暴力破解使用python和go分别进行了实现,但是当密钥超过5位时,破解时间会远远增长,所以在暴力破解中使用提前准备好的弱口令密码字典进行破解效果会更好)
-
JWT tokens 07
疑问:
a. 如何获取refresh token信息?
猜测:日志中记录的/refresh/login应该是用于登陆,并返回refresh_token
尝试:
使用zap重放攻击请求/refresh/login接口,提示Content type:application/x-www-form-urlencoded;charset=UTF-8 not supported
修改请求头重的Content-Type为application/json;charset=UTF-8,重新发起请求,提示Required request body is missing
修改request body为{},重新发起请求,提示401状态码
-
修改request body为{"username" : "silence", "password" : "123456"}(为webgoat登陆账号密码信息),重新发起请求,提示401状态码
结论:尝试失败
b. 如何通过refresh token刷新access_token?
通过luyten反编译jar包或查看WebGoat源码得知结果:
a. 如何获取refresh token信息?
向URL /refresh/login提交json数据{"user" : "Jerry", "password" :"bm5nhSkxCXZkKRy4"},为用户Jerry创建access_token和refresh_token
b. 如何通过refresh token刷新access_token?
向URL/refresh/newToken提交json数据{"refresh_token" : xxx}和request header Authorization: xxx token,为token中用户Tom重置token
-
JWT tokens 08
疑问:
a. 如何影响提交参数影响签名查询结果为自己定义的
是否可以通过;指定查询链,改写kid查询的结果控制输出(签名)
分别将kid修改为:
webgoat_key';select 'test
(失败,hsqldb语法不支持改语法,但支持SELECT 1 FROM
INFORMATION_SCHEMA.SYSTEM_USERS)webgoat_key';create table tk(key varchar(32));insert into tk values('test');select key from tk where key='test
(失败,未知原因)
结论:尝试失败
通过luyten反编译jar包或查看WebGoat源码得知结果:
根据代码,可借助jwt_keys表查询将secret自定义,且secret必须为base64编码
-
Password reset 02
-
Password reset 04
-
Password reset 05
注意此题目不能使用ZAP代理,原因ZAP代理会自动修改HOST头信息为请求地址
疑问:
a. 如何得知tom@webgoat-cloud.org用户的重置密码时的唯一标识
查看WebGoat源码得知结果: