Tools · AWS detection and investigation · 06 / 24
GuardDuty: what the actor fields do not prove
Record the access key id, the user type, and the source IP. Treat the city and organization text as a lookup, and the user name as a label that may be a session name.
The principal fields are labels on a credential
Resource.AccessKeyDetails names the credential GuardDuty associated with the finding: an access key id, a user type, and a user name. Copy those three. The user type tells you the kind of principal, such as an IAM user or an assumed role. The user name is whatever string is on that credential. On an assumed role it is often the session name, which an instance can set to its own id.
Impact of reading the user name as a person: the note names an employee who was not at the keyboard. Control: write “user name (as recorded)” and the user type beside it, and do not translate a session name into a human without a directory check you can cite.
The IP is observed; the city is attached
Service.Action includes a caller address when the finding is about an API call. That address is the field to copy. City, country, and organization are a lookup the service attached to the address. A lookup can point at a VPN exit, a hosting provider, or a registry entry that has nothing to do with where a person sits.
What not to trust: a sentence such as “the user was in Frankfurt” when the only source is that lookup. The note says “source IP” and, if you include the lookup, “lookup text,” so a reader can tell which is which.
A short actor block for the note
Keep the finding id on the same lines so the actor block cannot get separated from the record. You do not need the whole JSON in the ticket. You do need enough that someone else can run get-findings and see the same strings.
finding: <id> accessKeyId: <from AccessKeyDetails> userType: <from AccessKeyDetails> userName: <as recorded> sourceIp: <from the action’s remote IP> ipLookup: <city / org text, marked as lookup>
Worked case: a user name that is an instance id
A sandbox finding shows user type AssumedRole, user name i-0abc1234example, and a source IP in the documentation range 203.0.113.44. The lookup text says a cloud provider and a city. No IAM user by that name exists in the account, because the string is a session name shaped like an instance id.
The note records the key id, AssumedRole, the session name, and the IP. It says the city is lookup text. It does not name a person, and it does not claim anyone traveled. The next check, in a later lesson’s style of work, is the API history for that key id in CloudTrail Lake, still inside the sandbox.
Diagram
A claim versus the field it has to come from
If the field is a lookup, the note says so.
Says. “The user was in Frankfurt.”
Based on. City text attached to an IP
Problem. The lookup is not a witness
Says. “Source IP 203.0.113.44; lookup text names Frankfurt.”
Based on. The IP field, plus the lookup labeled as a lookup
Problem. None, until a directory check adds a person
Check yourself
1. On an assumed role, what is AccessKeyDetails.UserName often holding?
2. Which actor value is safe to call an observed address?
3. Why keep the finding id on the actor lines?