rootme.org - json web token 문제를 푸는 도중에
알게된 크랙기술이다.
제공된 문서를 정리한 내용하였다.
The JWT’s data is divided into three parts: headers, payloads, signatures (signature).
The three are then . divided by base64UrlEncode.
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'),
'=');
}
See example JWT
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUx
IiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkdWJoZTEyM
yJ9.XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1l
FqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5
VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQs
AuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSGQ1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5x
suw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUx IiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ
이것은 아래와 같다.
{“kid”:”keys/3c3c2ea1c3f113f649dc9389dd71b851",”typ”:”JWT”, ”alg”:”RS256"}
The headers contain information about the JWT configuration,
such as the signature algorithm (alg), type (JWT), and key file
used by the algorithm (used when the server requires multiple key
files)
eyJzdWIiOiJkdWJoZTEyMyJ9
유저 data이다. 여기선 test123
에 해당
※추가설명※
페이로드를 구성하는 각 요소정보를 클레임이라고 부른다.
클레임은 크게 세 가지로 나뉜다.
1) 등록된 클레임
iss: 토큰 발급자 (issuer)
sub: 토큰 제목 (subject)
aud: 토큰 대상자 (audience)
exp: 토큰의 만료시간 (expiraton), 시간은 NumericDate 형식으로 되어있어야 하며 (예: 1480849147370) 언제나 현재 시간보다 이후로 설정되어있어야합니다.
nbf: Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념입니다. 여기에도 NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않습니다.
iat: 토큰이 발급된 시간 (issued at), 이 값을 사용하여 토큰의 age 가 얼마나 되었는지 판단 할 수 있습니다.
jti: JWT의 고유 식별자로서, 주로 중복적인 처리를 방지하기 위하여 사용됩니다. 일회용 토큰에 사용하면 유용합니다.
2) 공개 클레임
{
"https://velopert.com/jwt_claims/is_admin": true
}
3) 비공개 클레임
{
'username' : 'woounnan'
}
ref: velopert - [JWT] JSON Web Token 소개 및 구조
나머지 부분
XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs 0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5Vidv rwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuen KzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSGQ1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5x suw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw
The signature is used to prevent data from being modified.
The signature object is base64UrlEncode(headers) + ‘.’ +
base64UrlEncode(‘signature’),
secret
살펴본 jwt를 크랙하는 방법에 대해서 살펴본다.
jwt의 시그니처는 서버에서 값이 수정되었는지 검사를 위해 존재한다.
헤더의 알고리즘 검사를 none으로 변경 후 시그니처 부분을 삭제하면, 서버는 조작된 jwt값을 그대로 신뢰한다.
After changing alg to none, remove the signature data from the
JWT (only header + ‘.’ + payload + ‘.’) and submit it to the server
RS256 알고리즘을 HS256으로 변경시킬 경우, 공개키를 서버에서 비밀키로 서 HS256로 해독하는데 사용하게 된다. 그리고 시그니처가 정상처리 된다고 한다.
예시를 보고 흐름만 파악하자.
import jwt
# eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9
# {"typ":"JWT","alg":"RS256"}
#
eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIs
ImlhdCI6MTUwNDAwNzg3NCwiZXhwIjoxNTA0MDA3OTk0LCJkYXRhIjp7Imhl
bGxvIjoid29ybGQifX0
# {"iss":"http:\/\/demo.sjoerdlangkemper.nl
\/","iat":1504007874,"exp":1504007994,"data":
{"hello":"world"}}
public = open('public.pem.1', 'r').read()
print public
print jwt.encode({"data":"test"}, key=public,
algorithm='HS256')
패스워드 강도가 약할 때, PyJWT를 사용하면 브루트포스 공격으로 크랙할 수 있다고 한다.