Cracking JWT tokens: a tale of magic, Node.js and parallel computing - WebRebels Oslo, 5 June 2018

loige 251 views 126 slides Jun 12, 2018
Slide 1
Slide 1 of 126
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55
Slide 56
56
Slide 57
57
Slide 58
58
Slide 59
59
Slide 60
60
Slide 61
61
Slide 62
62
Slide 63
63
Slide 64
64
Slide 65
65
Slide 66
66
Slide 67
67
Slide 68
68
Slide 69
69
Slide 70
70
Slide 71
71
Slide 72
72
Slide 73
73
Slide 74
74
Slide 75
75
Slide 76
76
Slide 77
77
Slide 78
78
Slide 79
79
Slide 80
80
Slide 81
81
Slide 82
82
Slide 83
83
Slide 84
84
Slide 85
85
Slide 86
86
Slide 87
87
Slide 88
88
Slide 89
89
Slide 90
90
Slide 91
91
Slide 92
92
Slide 93
93
Slide 94
94
Slide 95
95
Slide 96
96
Slide 97
97
Slide 98
98
Slide 99
99
Slide 100
100
Slide 101
101
Slide 102
102
Slide 103
103
Slide 104
104
Slide 105
105
Slide 106
106
Slide 107
107
Slide 108
108
Slide 109
109
Slide 110
110
Slide 111
111
Slide 112
112
Slide 113
113
Slide 114
114
Slide 115
115
Slide 116
116
Slide 117
117
Slide 118
118
Slide 119
119
Slide 120
120
Slide 121
121
Slide 122
122
Slide 123
123
Slide 124
124
Slide 125
125
Slide 126
126

About This Presentation

Learn how you can use some JavaScript/Node.js black magic to crack JWT tokens and impersonate other users or escalate privileges. Just add a pinch of ZeroMQ, a dose of parallel computing, a 4 leaf clover, mix everything applying some brute force and you'll get a powerful JWT cracking potion!


Slide Content

Cracking JWT tokensCracking JWT tokens
a tale of a tale of magicmagic, , Node.jsNode.js and and parallel computingparallel computing
Oslo - 5 JUN 2018
Luciano Mammino (Luciano Mammino ( ))@loige@loige
loige.link/jwt-crack-oslo
1

loige.link/jwt-crack-oslo
2

Luciano... who?Luciano... who?
Visit my castles:
-  (@loige)
-  (lmammino)
-
-  (loige.co)
Twitter
GitHub
Linkedin
Blog
Solution Architect at
with @mariocasciaro
with @andreaman87
with @ Podgeypoos79
3

Based on prior workBased on prior work
Chapters 10 & 11 in (book)
2-parts article on RisingStack:
   " "
Node.js design patterns
ZeroMQ & Node.js Tutorial - Cracking JWT Tokens
github.com/lmammino/jwt-cracker
github.com/lmammino/distributed-jwt-cracker
4

AgendaAgenda
What's JWTWhat's JWT
How it worksHow it works
Testing JWT tokensTesting JWT tokens
Brute-forcing a token!Brute-forcing a token!
5

  — RFC 7519— RFC 7519
 
is a compact, URL-safe means of representing claims to be
transferred between two parties. The claims in a JWT are
encoded as a JSON object that is used as the payload of a JSON
Web Signature (JWS) structure or as the plaintext of a JSON
Web Encryption (JWE) structure, enabling the claims to be
digitally signed or integrity protected with a Message
Authentication Code (MAC) and/or encrypted.
JSON Web Token (JWT)JSON Web Token (JWT)
6

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZX
NzYWdlIjoiaGVsbG8gcGVvcGxlIn0.II7XQbjvDCNzYWdlIjoiaGVsbG8gcGVvcGxlIn0.II7XQbjvDC
Hkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8AHkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8A
7

OKOK
Let's try to make itLet's try to make it
simpler...simpler...
8

JWT is...
An URL safe, stateless protocol
for transferring claims
9

10

URL safe?
10

URL safe?
stateless?
10

URL safe?
stateless?
claims?
10

URL Safe...URL Safe...
It's a string that can be safely used as part of a URLIt's a string that can be safely used as part of a URL
(it doesn't contain URL separators like "(it doesn't contain URL separators like "==", "", "//", "", "##" or "" or "??")")
unicorntube.pl/?token= eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
11

Stateless?Stateless?
Token validity can be verified without having to interrogate aToken validity can be verified without having to interrogate a
third-party servicethird-party service
(Sometimes also defined as "self-contained")
12

What is a claim?What is a claim?
13

some information to transfersome information to transfer
identity identity (login session)(login session)
authorisation to perform actions authorisation to perform actions (api key)(api key)
ownership ownership (a ticket belongs to somebody)(a ticket belongs to somebody)
14

also...also...
validity constraintsvalidity constraints
token time constraints token time constraints (dont' use before/after)(dont' use before/after)
audience audience (a ticket only for a specific concert)(a ticket only for a specific concert)
issuer identity issuer identity (a ticket issued by a specific reseller)(a ticket issued by a specific reseller)
15

also...also...
protocol informationprotocol information
Type of tokenType of token
AlgorithmAlgorithm
16

In generalIn general
All the bits of information transferred with the tokenAll the bits of information transferred with the token
17

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZX
NzYWdlIjoiaGVsbG8gcGVvcGxlIn0.II7XQbjvDCNzYWdlIjoiaGVsbG8gcGVvcGxlIn0.II7XQbjvDC
Hkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8AHkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8A
18

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..eyJtZXeyJtZX
NzYWdlIjoiaGVsbG8gcGVvcGxlIn0NzYWdlIjoiaGVsbG8gcGVvcGxlIn0..II7XQbjvDCII7XQbjvDC
Hkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8AHkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8A
3 parts3 parts
separated by "."separated by "."
19

20

HEADERHEADER::
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpeyJhbGciOiJIUzI1NiIsInR5cCI6Ikp
XVCJ9XVCJ9
20

HEADERHEADER::
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpeyJhbGciOiJIUzI1NiIsInR5cCI6Ikp
XVCJ9XVCJ9
PAYLOADPAYLOAD::
eyJtZXNzYWdlIjoiaGVsbG8gcGVvceyJtZXNzYWdlIjoiaGVsbG8gcGVvc
GxlIn0GxlIn0
20

HEADERHEADER::
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpeyJhbGciOiJIUzI1NiIsInR5cCI6Ikp
XVCJ9XVCJ9
PAYLOADPAYLOAD::
eyJtZXNzYWdlIjoiaGVsbG8gcGVvceyJtZXNzYWdlIjoiaGVsbG8gcGVvc
GxlIn0GxlIn0
SIGNATURESIGNATURE::
II7XQbjvDCHkt3UOh6weHY6tRcemII7XQbjvDCHkt3UOh6weHY6tRcem
T0gxRVmA6W6uZ8AT0gxRVmA6W6uZ8A
20

HeaderHeader and and PayloadPayload are are
encoded encoded
let's decode them!let's decode them!
Base64UrlBase64Url
21

22

HEADERHEADER::
22

HEADERHEADER::
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
22

HEADERHEADER::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
22

HEADERHEADER::
PAYLOADPAYLOAD::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
22

HEADERHEADER::
PAYLOADPAYLOAD::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
eyJtZXNzYWdlIjoiaGVsbG8gcGVvceyJtZXNzYWdlIjoiaGVsbG8gcGVvc
GxlIn0GxlIn0
22

HEADERHEADER::
PAYLOADPAYLOAD::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
{"message":"hello people"}{"message":"hello people"}
22

HEADERHEADER::
The decoded info is JSON!The decoded info is JSON!
PAYLOADPAYLOAD::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
{"message":"hello people"}{"message":"hello people"}
22

HEADERHEADER::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
alg: alg: the kind of algorithm usedthe kind of algorithm used
"HS256" "HS256" HMACSHA256 Signature HMACSHA256 Signature (secret based hashing)(secret based hashing)
""RS256RS256" RSASHA256 Signature " RSASHA256 Signature (public/private key hashing)(public/private key hashing)
""nonenone" NO SIGNATURE!" NO SIGNATURE! (This is " (This is " ")")infamousinfamous
23

PAYLOADPAYLOAD::
{"message":"hello people"}{"message":"hello people"}
  
Payload can be anything thatPayload can be anything that
you can express in JSONyou can express in JSON
24

PAYLOADPAYLOAD::
"registered" (or standard) claims:"registered" (or standard) claims:
iss: issuer ID ("auth0")
sub: subject ID ("[email protected]")
aud: audience ID ("https://someapp.com")
exp: expiration time ("1510047437793")
nbf: not before ("1510046471284")
iat: issue time ("1510045471284")
25

PAYLOADPAYLOAD::
"registered" (or standard) claims:"registered" (or standard) claims:

  "iss": "auth0", 
  "sub": "[email protected]",  
  "aud": "https://someapp.com",  
  "exp": "1510047437793", 
  "nbf": "1510046471284", 
  "iat": "1510045471284" 
}
26

So far it's just metadata...So far it's just metadata...
What makes it safe?What makes it safe?
27

SIGNATURESIGNATURE::
II7XQbjvDCHkt3UOh6weHY6II7XQbjvDCHkt3UOh6weHY6
tRcemT0gxRVmA6W6uZ8AtRcemT0gxRVmA6W6uZ8A
  
A A Base64URLBase64URL encoded encoded cryptographiccryptographic
signaturesignature of the header and the payload of the header and the payload
28

With HS256With HS256
signature = HMACSHA256( 
  base64UrlEncode(header) + "." + 
    base64UrlEncode(payload), 
  secret 
)
header payload secret SIGNATURE+ + =
29

If a system knows the If a system knows the secretsecret
It can verify the authenticityIt can verify the authenticity
of the tokenof the token
With HS256With HS256
30

Let's create a token from scratchLet's create a token from scratch
runkit.com/lmammino/create-jwt-token
31

Playground for JWTPlayground for JWT
JWT.ioJWT.io
32

An exampleAn example
Session token
33

Classic implementationClassic implementation
cookie/session basedcookie/session based
34

35

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
35
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
35
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
35
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
3. session cookie
SID:"Y4sHySEPWAjc" 
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
35
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
3. session cookie
SID:"Y4sHySEPWAjc" 
4. GET /profile
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
35
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"SID:"Y4sHySEPWAjc" 

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
3. session cookie
SID:"Y4sHySEPWAjc" 
4. GET /profile
5. query
id:"Y4sHySEPWAjc" 
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
35
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"SID:"Y4sHySEPWAjc" 

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
3. session cookie
SID:"Y4sHySEPWAjc" 
4. GET /profile
5. query
id:"Y4sHySEPWAjc" 
6. record
id:"Y4sHySEPWAjc" 
user:"luciano"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
35
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"SID:"Y4sHySEPWAjc" 

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
3. session cookie
SID:"Y4sHySEPWAjc" 
4. GET /profile
5. query
id:"Y4sHySEPWAjc" 
6. record
id:"Y4sHySEPWAjc" 
user:"luciano"
7. (page)
<h1>hello luciano</h1>
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
35
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"SID:"Y4sHySEPWAjc" 

JWT implementationJWT implementation
36

37

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
37

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
37

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
Create Token for "luciano"
Add signature
2. create
JWT
37

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
3. JWT Token
{"sub":"luciano"}
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
Create Token for "luciano"
Add signature
2. create
JWT
37

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
3. JWT Token
{"sub":"luciano"}
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
4. GET /profile
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
Create Token for "luciano"
Add signature
2. create
JWT
37

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
3. JWT Token
{"sub":"luciano"}
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
4. GET /profile
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
Token says this is "luciano"
Signature looks OK
5. verify
Create Token for "luciano"
Add signature
2. create
JWT
37

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
3. JWT Token
{"sub":"luciano"}
user:"luciano" 
pass:"mariobros"
6. (page)
<h1>hello luciano</h1>
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
4. GET /profile
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
Token says this is "luciano"
Signature looks OK
5. verify
Create Token for "luciano"
Add signature
2. create
JWT
37

 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
3. JWT Token
{"sub":"luciano"}
user:"luciano" 
pass:"mariobros"
6. (page)
<h1>hello luciano</h1>
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
4. GET /profile
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
Token says this is "luciano"
Signature looks OK
5. verify
Create Token for "luciano"
Add signature
2. create
JWT
Note: Only the server
knows the secret
37

Cookie/sessionCookie/session
Needs a database to store the
session data
The database is queried for every
request to fetch the session
A session is identified only by a
randomly generated string
(session ID)
No data attached
Sessions can be invalidated at any
moment
JWTJWT
Doesn't need a session database
The session data is embedded in
the token
For every request the token
signature is verified
Attached metadata is readable
Sessions can't be invalidated, but
tokens might have an expiry flag
VSVS
38

Another great JWT use caseAnother great JWT use case
Creating Secure Password Reset LinksCreating Secure Password Reset Links
loige.link/jwt-pwd-reset
39

JWT LOOKS GREAT!JWT LOOKS GREAT!
But there are pitfalls...But there are pitfalls...
40

Data is public!Data is public!
41

Data is public!Data is public!
If you have a token,If you have a token,
you can easily read the claims!you can easily read the claims!
41

Data is public!Data is public!
If you have a token,If you have a token,
you can easily read the claims!you can easily read the claims!
You only have to Base64Url-decode the
token header and payload
and you have a readable JSON
41

There's no token database...There's no token database...
  
...if I can forge a token...if I can forge a token
nobody will know it's notnobody will know it's not
authentic!authentic!
42

DEMODEMO
JWT based web app
github.com/lmammino/sample-jwt-webapp
BUILT WITH
43

Given an HS256 signed JWTGiven an HS256 signed JWT
We can try to "We can try to "guessguess" the " the secretsecret!!
44

How difficult can it be?How difficult can it be?
45

Let's build a distributedLet's build a distributed
JWT token cracker!JWT token cracker!
 
npm.im/distributed-jwt-crackernpm.im/distributed-jwt-cracker
46

The idea...The idea...
47

The idea...The idea...
Take a valid JWT tokenTake a valid JWT token
47

The idea...The idea...
try to "guess" the secret and validate the token against ittry to "guess" the secret and validate the token against it
Take a valid JWT tokenTake a valid JWT token
47

The idea...The idea...
if the token is validated, then you found the if the token is validated, then you found the secretsecret!!
try to "guess" the secret and validate the token against ittry to "guess" the secret and validate the token against it
Take a valid JWT tokenTake a valid JWT token
47

The idea...The idea...
YOU CAN NOW YOU CAN NOW CREATE AND SIGNCREATE AND SIGN
ANY JWT TOKEN ANY JWT TOKEN FOR THISFOR THIS
APPLICATIONAPPLICATION!!
if the token is validated, then you found the if the token is validated, then you found the secretsecret!!
try to "guess" the secret and validate the token against ittry to "guess" the secret and validate the token against it
Take a valid JWT tokenTake a valid JWT token
47

Magic weaponsMagic weapons
48

Magic weaponsMagic weapons
Node.jsNode.js
48

Magic weaponsMagic weapons
Node.jsNode.jsZeroMQZeroMQ
48

Magic weaponsMagic weapons
Node.jsNode.js
modulemodule
jsonwebtokenjsonwebtoken
ZeroMQZeroMQ
48

ZeroMQZeroMQ
an open source embeddable an open source embeddable networkingnetworking
librarylibrary and a and a concurrency frameworkconcurrency framework
49

The brute force problemThe brute force problem
"virtually infinite" solutions space"virtually infinite" solutions space
all the strings (of any length) that can be generated within a given alphabet
(empty string), a, b, c, 1, aa, ab, ac, a1, ba, bb, bc, b1, ca, cb, cc, c1, 1a, 1b, 1c, 11, aaa,
aab, aac, aa1, aba, ...
50

bijection (int) ⇒ (string)bijection (int) ⇒ (string)
if we sort all the possible strings over an alphabet
 
Alphabet = [a,b]0 ⟶ (empty string) 
1 ⟶ a 
2 ⟶ b 
3 ⟶ aa 
4 ⟶ ab 
5 ⟶ ba 
6 ⟶ bb
7 ⟶ aaa
8 ⟶ aab
9 ⟶ aba
10 ⟶ abb 
11 ⟶ baa 
12 ⟶ bab 
13 ⟶ bba 
14 ⟶ bbb 
15 ⟶ aaaa 
16 ⟶ aaab
17 ⟶ aaba
18 ⟶ aabb
...
51

ArchitectureArchitecture
ServerServer ClientClient
Initialised with a valid JWT token
and an alphabet
coordinates the brute force
attempts among connected clients
knows how to verify a token against
a given secret
receives ranges of secrets to check
52

Networking patternsNetworking patterns
Router channels:
dispatch jobs
receive results
 
Pub/Sub channel:
termination
signal
53

Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size) of fixed length (batch size)
54

Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size) of fixed length (batch size)
0 3 6 9...
54

Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size) of fixed length (batch size)
0
batch 1
3 6 9...
54

Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size) of fixed length (batch size)
0
batch 1 batch 2
3 6 9...
54

Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size) of fixed length (batch size)
0
batch 1 batch 2 batch 3
3 6 9...
54

Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size) of fixed length (batch size)
0
...batch 1 batch 2 batch 3
3 6 9...
54

Initial server stateInitial server state

  "cursor": 0, 
  "clients": {} 
}
55

The first client connectsThe first client connects

  "cursor": 3, 
  "clients": { 
    "client1": [0,2] 
  } 
}
[0,2]
56


  "cursor": 9, 
  "clients": { 
    "client1": [0,2],     
    "client2": [3,5],
    "client3": [6,8] 
  } 
}
Other clients connectOther clients connect
[0,2]
[3,5][6,8]
57

Client 2 finishes its jobClient 2 finishes its job

  "cursor": 12, 
  "clients": { 
    "client1": [0,2],     
    "client2": [9,11],
    "client3": [6,8] 
  } 
}
[0,2]
[9,11][6,8]
58

let cursor = 0
const clients = new Map()

const assignNextBatch = client => {
const from = cursor
const to = cursor + batchSize - 1
const batch = [from, to]
cursor = cursor + batchSize
client.currentBatch = batch
client.currentBatchStartedAt = new Date()

return batch
}

const addClient = channel => {
const id = channel.toString('hex')
const client = {id, channel, joinedAt: new Date()}
assignNextBatch(client)
clients.set(id, client)

return client
}
Server
59

Messages flowMessages flow
60

Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
60

Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
1. JOIN
60

Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
1. JOIN
2. START
{token, alphabet, firstBatch}
60

Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
1. JOIN
2. START
{token, alphabet, firstBatch}
3. NEXT
60

Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
1. JOIN
2. START
{token, alphabet, firstBatch}
3. NEXT
4. BATCH
{nextBatch}
60

Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
1. JOIN
2. START
{token, alphabet, firstBatch}
3. NEXT
4. BATCH
{nextBatch}
5. SUCCESS
{secret}
60

const router = (channel, rawMessage) => {
const msg = JSON.parse(rawMessage.toString())

switch (msg.type) {
case 'join': {
const client = addClient(channel)
const response = {
type: 'start',
id: client.id,
batch: client.currentBatch,
alphabet,
token
}
batchSocket.send([channel, JSON.stringify(response)])
break
}

case 'next': {
const batch = assignNextBatch(clients.get(channel.toString('hex')))
batchSocket.send([channel, JSON.stringify({type: 'batch', batch})])
break
}

case 'success': {
const secret = msg.secret
// publish exit signal and closes the app
signalSocket.send(['exit', JSON.stringify({secret, client: channel.toString('hex')})], 0, () => {
batchSocket.close()
signalSocket.close()
exit(0)
})

break
}
}
}
Server
61

let id, variations, token

const dealer = rawMessage => {
const msg = JSON.parse(rawMessage.toString())

const start = msg => {
id = msg.id
variations = generator(msg.alphabet)
token = msg.token
}

const batch = msg => {
processBatch(token, variations, msg.batch, (secret, index) => {
if (typeof secret === 'undefined') {
// request next batch
batchSocket.send(JSON.stringify({type: 'next'}))
} else {
// propagate success
batchSocket.send(JSON.stringify({type: 'success', secret, index}))
exit(0)
}
})
}

switch (msg.type) {
case 'start':
start(msg)
batch(msg)
break

case 'batch':
batch(msg)
break
}
}
Client
62

How a chunk is processedHow a chunk is processed
Given chunk [3,6] over alphabet "ab"
[3,6] ⇒
3 ⟶ aa 
4 ⟶ ab 
5 ⟶ ba 
6 ⟶ bb
⇠ check if one of the
strings is the secret
that validates the
current token
63

const jwt = require('jsonwebtoken')
const generator = require('indexed-string-variation').generator;
const variations = generator('someAlphabet')

const processChunk = (token, from, to) => {
let secret

for (let i = from; i < to; i++) {
try {
secret = variations(i)

jwt.verify(token, pwd, {
ignoreExpiration: true,
ignoreNotBefore: true
})

// finished, password found
return ({found: secret})
} catch (err) {} // password not found, keep looping
}

// finished, password not found
return null
}
Client
64

DemoDemo
65

Closing offClosing off
66

Is JWT safe to use?Is JWT safe to use?
67

DefinitelyDefinitely
YES!YES!
Heavily used by:
68

but...but...
69

Use a strong (≃long) Use a strong (≃long) secretsecret and keep it SAFE! and keep it SAFE!
Or, even better
Use RS256 (RSA public/private key pair) signatureUse RS256 (RSA public/private key pair) signature
Use it wisely!Use it wisely!
70

But, what if I createBut, what if I create
onlyonly
short lived tokensshort lived tokens......
71

JWT is STATELESS!JWT is STATELESS!
the expiry time is contained in the token...
if you can edit tokens, you can extend the expiry time as needed!
72

Should I be worried aboutShould I be worried about
brute forcebrute force??
73

Not reallyNot really
... As long as you know the basic rules... As long as you know the basic rules
(and the priorities) to defend yourself(and the priorities) to defend yourself
74

TLDR;TLDR;
JWT is a JWT is a cool & stateless™cool & stateless™ way to way to
transfer claims!transfer claims!
 
Choose the right Algorithm
With HS256, choose a good secret and keep it safe
Don't disclose sensitive information in the payload
Don't be too worried about brute force, but understand how it works!
75

Takk!
@loige@loige
https://loige.cohttps://loige.co
loige.link/jwt-crack-oslo
76

CreditsCredits
vector imagesvector images
designed by freepikdesigned by freepik
an      heartfelt thank you to:
@AlleviTommaso
@andreaman87
@cirpo
@katavic_d
@Podgeypoos79
@quasi_modal
77