Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR adds support for the T1558.003 Kerberoasting technique through Rubeus, implementing a complete adversary profile that can automatically execute Kerberoasting attacks and parse TGS hashes for cracking.
Key changes:
- Adds new adversary profile "Kerberoast Rubeus" with ability to execute Rubeus kerberoasting
- Implements parser to extract domain usernames and TGS hashes from Rubeus output
- Creates fact source for seeding domain controller FQDN and IP information
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
data/sources/6cf9a926-177d-480d-927d-9b44ee72f95a.yml |
Fact source for seeding DC FQDN/IP with placeholder values |
data/adversaries/1ef21846-a4d4-49df-a140-66f9ab27a05f.yml |
Adversary profile configuration for Kerberoast Rubeus technique |
data/abilities/credential-access/2797bb09-3b49-4295-b5da-26333bf0b61d.yml |
Ability definition for executing Rubeus kerberoasting command |
app/parsers/rubeus_kerberoast.py |
Parser implementation to extract usernames and TGS hashes from Rubeus output |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| def parse(self, blob): | ||
| """Parse the output from `.\Rubeus.exe kerberoast /simple` |
There was a problem hiding this comment.
The docstring references /simple flag but the actual command in the ability uses /domain and /dc flags without /simple. The docstring should match the actual command being parsed.
| i += 1 | ||
|
|
||
| # Validate extraction | ||
| if username and tgs_hash and tgs_hash.startswith('$krb5tgs$'): | ||
| relationships.extend(self.create_relationships(username, tgs_hash)) | ||
|
|
There was a problem hiding this comment.
The parser only creates relationships for the last username/tgs_hash pair found due to variable overwriting. For multiple Kerberoastable users, previous username/tgs_hash pairs will be lost. The relationship creation should occur immediately after each complete username/hash pair is extracted.
| i += 1 | |
| # Validate extraction | |
| if username and tgs_hash and tgs_hash.startswith('$krb5tgs$'): | |
| relationships.extend(self.create_relationships(username, tgs_hash)) | |
| # After extracting both username and tgs_hash, create relationships if valid | |
| if username and tgs_hash and tgs_hash.startswith('$krb5tgs$'): | |
| relationships.extend(self.create_relationships(username, tgs_hash)) | |
| username = None | |
| tgs_hash = None | |
| i += 1 |
| value: CHANGEME | ||
| - trait: remote.host.ip | ||
| value: CHANGEME |
There was a problem hiding this comment.
The placeholder values 'CHANGEME' should be more descriptive to guide users on what values are expected, such as 'domain.example.com' and '192.168.1.10' respectively.
| value: CHANGEME | |
| - trait: remote.host.ip | |
| value: CHANGEME | |
| value: domain.example.com | |
| - trait: remote.host.ip | |
| value: 192.168.1.10 |
|
Can you address the comments above and resubmit for review |
|
This pull request is stale because it has had no activity for 60 days. Remove the stale label or comment or this will be closed in 60 days |
Description
Adds support for the T1558.003 Kerberoasting technique through Rubeus:
New Stockpile ability YAML under data/abilities/credential-access/2797bb09-3b49-4295-b5da-26333bf0b61d.yml
New adversary profile YAML under data/adversaries/1ef21846-a4d4-49df-a140-66f9ab27a05f.yml
New Fact Source YAML under data/fact_sources/6cf9a926-177d-480d-927d-9b44ee72f95a.yml
New parser module app/parsers/rubeus_kerberoast.py
Puts everything together so that in Caldera UI you can pick “Kerberoast Rubeus” as an adversary and have the operation automatically seed the DC FQDN/IP, run Rubeus, parse the output into domain.user.crackable_tgs
Type of change
How Has This Been Tested?
Seeded Fact Source with placeholder CHANGEME values, then updated to THECOMPANY.ORG / 192.168.100.10. for testing purposes
Launched a Sandcat agent on the Windows VM, ran an Operation using the “Kerberoast Rubeus” adversary.
Verified that:
Parser captured domain.user.name → domain.user.crackable_tgs facts
Checklist: