Exercise 3: Creating True-Positive Events
Estimated Time to Complete: 20 minutes
Objectives
- Execute the following techniques to generate true-positive log entries which will help build your detection and automation:
- Perform discovery of blob storage resources - ATT&CK Technique T1619 (Cloud Storage Object Discovery)
- Download an interesting file - ATT&CK Technique T1530 (Data from Cloud Storage)
Challenges
Challenge 1: Perform ATT&CK Technique T1619 (Cloud Storage Object Discovery)
Using the Azure Cloud Shell, perform reconnaissance of the storage account and the content of its blob containers. You will find that one has some interestingly named data that an attacker may be tempted to download.
Solution
-
Return to your Azure Cloud Shell session (you may need to refresh the page if it timed out).
-
Discovering cloud resources in Azure is best done with the
azcommand. Following the pattern ofaz-reference name-commandwe can programmatically interact with our cloud resources. First, verify which user theaztool is logged in with.az account show | jq .userSample results
{ "cloudShellID": true, "name": "abraulik@XXXXXXXXXX.onmicrosoft.com", "type": "user" } -
Now to your storage account in your DetectionWorkshop resource group. We pipe the result to jq and only want to see the
namevalues of the returning items.az storage account list --resource-group 'DetectionWorkshop' | jq .[].nameSample results
"proddatadj35l13m5693m5" -
You should see a storage account beginning with
proddatafollowed by some randomized numbers and lowercase characters. The storage account name is randomized for every run of the deployment script because storage account name need to be GLOBALLY unique. You want to store the name of your storage account (pun intended) in a variable to make the next steps easier to execute.Write-Output ($storageAccount = az storage account list --resource-group 'DetectionWorkshop' | jq -r '.[] | select(.name | startswith("proddata")) | .name' )Sample results
proddatadj35l13m5693m5 -
So, what content awaits us in this storage account?
az storage container list --account-name $storageAccount --auth-mode login | jq .Expected result
[ { "deleted": null, "encryptionScope": { "defaultEncryptionScope": "$account-encryption-key", "preventEncryptionScopeOverride": false }, "immutableStorageWithVersioningEnabled": false, "metadata": null, "name": "hr-documents", "properties": { "etag": "\"0x8DB4B0EE81F1ED0\"", "hasImmutabilityPolicy": false, "hasLegalHold": false, "lastModified": "2023-05-02T13:12:39+00:00", "lease": { "duration": null, "state": "available", "status": "unlocked" }, "publicAccess": null }, "version": null }, { "deleted": null, "encryptionScope": { "defaultEncryptionScope": "$account-encryption-key", "preventEncryptionScopeOverride": false }, "immutableStorageWithVersioningEnabled": false, "metadata": null, "name": "secretdata", "properties": { "etag": "\"0x8DB475AB5520450\"", "hasImmutabilityPolicy": false, "hasLegalHold": false, "lastModified": "2023-04-27T20:05:11+00:00", "lease": { "duration": null, "state": "available", "status": "unlocked" }, "publicAccess": null }, "version": null } ] -
Looking at the
namevalues here:hr-documentsandsecretdata? I wonder what´s in those containers...Let's list the content of those containers.az storage blob list --account-name $storageAccount --container 'hr-documents' --auth-mode login | jq .[].nameExpected result
"job-posting-personalassistent-draft.txt" "job-posting-secops-azure-draft.txt"az storage blob list --account-name $storageAccount --container 'secretdata' --auth-mode login | jq .[].nameExpected result
"final-instructions.txt" -
Looks like some job postings in the
hr-documentscontainer. Nothing out of the ordinary. Butsecretdatahas something more interesting:final-instructions.txt.I wonder...

Challenge 2: Perform ATT&CK Technique T1530 (Data from Cloud Storage)
That certainly looks like something an adversary could not leave untouched. And to be fair, neither can we 😉. Let´s download this file to our Azure Cloud Shell session!
Solution
-
Downloading can be easily achieved with the
azcommand and the right parameters. For the purpose of this workshop we want to make sure we use our Azure AD User Account for authentication.az storage blob download --account-name $storageAccount --container-name 'hr-documents' --name 'job-posting-personalassistent-draft.txt' --file '~/ex3-hr-data-job-posting-personalassistent-draft.txt' --auth-mode login | jq . ; az storage blob download --account-name $storageAccount --container-name 'hr-documents' --name 'job-posting-secops-azure-draft.txt' --file '~/ex3-hr-documents-job-posting-secops-azure-draft.txt' --auth-mode login | jq . ;az storage blob download --account-name $storageAccount --container-name 'secretdata' --name 'final-instructions.txt' --file '~/ex3-secretdata-final-instructions.txt' --auth-mode login | jq .Sample result
Finished[#############################################################] 100.0000% { "container": "hr-documents", "content": "", "contentMd5": null, "deleted": false, "encryptedMetadata": null, "encryptionKeySha256": null, "encryptionScope": null, "hasLegalHold": null, "hasVersionsOnly": null, "immutabilityPolicy": { "expiryTime": null, "policyMode": null }, "isAppendBlobSealed": null, "isCurrentVersion": null, "lastAccessedOn": null, "metadata": {}, "name": "job-posting-personalassistent-draft.txt", ---- SNIP ---- } Finished[#############################################################] 100.0000% { "container": "hr-documents", "content": "", "contentMd5": null, "deleted": false, "encryptedMetadata": null, "encryptionKeySha256": null, "encryptionScope": null, "hasLegalHold": null, "hasVersionsOnly": null, "immutabilityPolicy": { "expiryTime": null, "policyMode": null }, "isAppendBlobSealed": null, "isCurrentVersion": null, "lastAccessedOn": null, "metadata": {}, "name": "job-posting-secops-azure-draft.txt", ---- SNIP ---- } Finished[#############################################################] 100.0000% { "container": "secretdata", "content": "", "contentMd5": null, "deleted": false, "encryptedMetadata": null, "encryptionKeySha256": null, "encryptionScope": null, "hasLegalHold": null, "hasVersionsOnly": null, "immutabilityPolicy": { "expiryTime": null, "policyMode": null }, "isAppendBlobSealed": null, "isCurrentVersion": null, "lastAccessedOn": null, "metadata": {}, "name": "final-instructions.txt", ---- SNIP ---- } -
Just one more step and we can see what the final instructions are!
Get-Content ~/ex3-secretdata-final-instructions.txtSample result
Somehow I expected it would not be that easy.When all is done: ---- SNIP ---- -
Congratulations! You have just emulated an attacker finding a file or interest, downloading it, and reviewing it. We could now spend our time deciphering the message, but that is not what we are here for - so let´s move on 😊.
Conclusion
Now that you have successfully located and pulled down the honey file, the next exercise will explore how to identify this access.