워게임/CryptoHack

[CryptoHack] CRYPTO ON THE WEB(JWT Secrets)

작성자 - ikbak_2

 

JWT Secrets

 

문제 및 개념

 JWT에 사용되는 가장 공통적인 서명 알고리즘은 HS256 및 RS256입니다. 첫 번째 HS256은 SHA256 해시 함수가 있는 HMAC를 사용하는 대칭 서명 체계입니다. 두 번째 RS256은 RSA를 기반으로 하는 비대칭 서명 체계입니다.

 인터넷에 있는 많은 안내글에서는 HS256을 사용하는 것이 더 간단하기 때문에 추천합니다. 토큰 서명에 사용된 비밀 키는 토큰을 확인하는 데 사용된 키와 동일합니다.


 그러나 비밀 서명 키가 손상되면 공격자는 임의 토큰에 서명하고, 다른 사용자의 세션을 위조하여 웹앱을 완전히 손상시킬 수 있습니다. HS256은 HS256 토큰을 확인하는 모든 서버에서 키를 사용할 수 있어야 하기 때문에 비대칭 키 쌍보다 보안을 유지하기가 어렵습니다.(일반적으로 더 나은 별도의 토큰 확인 서비스를 인프라 시설이 없는 경우) 반대로 RS256의 비대칭 방식을 사용하면 검증 키가 자유롭게 배포되는 동안 서명 키를 더 잘 보호할 수 있습니다.

💡더 나쁜건, 개발자들이 때때로 디폴트키나 취약한 HS256 비밀키를 사용한다는 것 입니다. 

 다음은 세션을 생성하는 기능과 세션을 인증하고 관리자 권한을 확인하는 기능이 포함된 소스 코드의 일부입니다.
그런데 비밀키에 대한 이상한 주석이 있습니다. 어떻게 하실건가요?

https://web.cryptohack.org/jwt-secrets/

풀이

더보기

 이번 문제는 비밀키가 디폴트 값이거나 취약한 값일 때, 발생하는 문제이다.

제공된 사이트 및 코드

 

import jwt # note this is the PyJWT module, not python-jwt


SECRET_KEY = ? # TODO: PyJWT readme key, change later
FLAG = ?


@chal.route('/jwt-secrets/authorise/<token>/')
def authorise(token):
    try:
        decoded = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
    except Exception as e:
        return {"error": str(e)}

    if "admin" in decoded and decoded["admin"]:
        return {"response": f"Welcome admin, here is your flag: {FLAG}"}
    elif "username" in decoded:
        return {"response": f"Welcome {decoded['username']}"}
    else:
        return {"error": "There is something wrong with your session, goodbye"}


@chal.route('/jwt-secrets/create_session/<username>/')
def create_session(username):
    encoded = jwt.encode({'username': username, 'admin': False}, SECRET_KEY, algorithm='HS256')
    return {"session": encoded}

 

해당 코드를 보면 

지난 No Way JOSEauthorise 함수

헤더, 페이로드, 시그니처 부분을 직접 Base64로 디코딩을 하게 되지만

이번엔 Pyjwt의 decode함수를 사용하여 키값을 포함하여 이를 디코딩을 한다.

그다음 과정은 admin이 확인될 경우

플래그값을 준다.

 

그리고 create_session함수는 지난 문제와 같이

admin값을 false로 생성하는 모습을 볼 수 있다.

 

문제

문제에 따르면 비밀키에 대한 이상한 주석이 있다고 한다.

이에 대해 SECRET_KEY의 주석을 보게 되면

'TODO: PyJWT readme key, change later'

'할 것 : PyJWT 리드미 키, 추후에 바꿔라' 인데

 

실제 PyJWT의 README 문서의 간단한 Usage

README문서의 Documentation에 있는 Usage Example을 보게 되면

README문서의 Usage
Usage Examples-Encoding & Decoding Tokens with HS256의 예시

 

Usage의 encode함수를 보게 되면

키를 넣을 부분에 "secret",

그리고 'Usage Examples - Encoding & Decoding Tokens with HS256'예시에서의 key변수에

"secret"을 저장하는 걸 볼 수 있다.

 

import jwt

SECRET_KEY='secret'
username='userMSS'
jwt_encoded = jwt.encode({'username': username, 'admin': True}, SECRET_KEY, algorithm='HS256')

print('변경된 JWT : ', jwt_encoded)
변경된 키값
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXJNU1MiLCJhZG1pbiI6dHJ1ZX0.ZqUsnznjNq26k8_qGPglOD5YijxYkzt67o5fb_weWHM

 

유저이름을 userMSS,

키값을 "secret",

'admin' : False에서 'admin' : True으로 바꾸어 

JWT생성을 하였다.

정답

 

 

이를 대입하니 플래그값인

crypto{jwt_secret_keys_must_be_protected}

가 나오게 된다.

 

이번 문제와 설명을 통해

키값에 대한 중요성을 보여 주었고,

문제 및 설명에서 RSA256이 서명키 보호에 더 좋고,

공식 예시에서도 이에 대한 예시를 보여주기 때문에

추후에 나올 문제에 대비하여

미리 알고 가는 것도 좋을 것 같다. 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.