BloodHound
BloodHound copied to clipboard
Collect domain accounts used to run services
As discussed on Slack, I'm opening an issue to keep track of this conversation on GitHub.
@SAERXCIT:
Hi ! I've been working on adding a new edge to BloodHound, RunsServiceAs
, extracting domain accounts used to run local services on machines.
However, I realized that from an attack path point of view, this edge does not teach us much, as we already had this link with HasSession
(a running service will have its user show up in NetWkstaUserEnum
), and probably with ReadGMSAPassword
if a gMSA is used. This new edge just covers some edge cases like services configured but not running or disabled, though I'm not sure how common that is. This could also be useful for reporting/documenting, as BH would be able to list machines using highly-privileged domain accounts to run services.
After seeing your recent blog post on the complexity impact of adding a new edge to BloodHound, I wonder if this new edge is worth a PR to mainline, or if it should just stay in my own tree for my own use. You can check out the first draft on my GitHub forks.
@dirkjanm:
it's still useful as the service does not have to be running for the password to be stored there
there is no need for an extra edge though as you can use the HasSession edge with some more data :slightly_smiling_face:
@andyrobbins:
I've thought it would be really cool to be able to see principals configured to run services on different hosts as, like you and @dirkjanm mention, that principal's credentials will be available on the system whether the service is running or not. The biggest problem I have, which I'm not sure how to solve, is that you can't guarantee that the stored password is the same password for that user - at least I'm personally not aware of a way to do so.
Otherwise, that's a VERY good thought and idea, and if there's a way to somehow validate, or produce a confidence score that the credential is correct, I could see that being added in to BH
@SAERXCIT:
Glad to hear that's something you'd be interested in. I understand your point regarding being confident about the password. My team and I tried to come up with ways to ensure this, but so far we weren't able to find a satisfying answer.
I think the only way to ensure the credential is correct is if the service is in a running state, in which case we'll already have a HasSession
edge and @dirkjanm's idea of a IsService
property on that edge could be a way to have this info in BH without a big complexity impact (on the BH side at least). However this means discarding the edge cases we mentioned (non-running/disabled services), though once again I'm not sure how common that is.
We can also ensure the credential is incorrect by checking if the principal's pwdLastSet
is after the service's last config change time (though this won't ensure it's correct). There are multiple ways of getting this info, though none is entirely satifying:
- The actual password last change time is in
HKEY_LOCAL_MACHINE\SECURITY\Policy\Secrets\_SC_<service>\CupdTime
, but only readable by SYSTEM. I think that makes it unusable for SH. - We might be able to get it using the
lpftLastWriteTime
out parameter ofRegQueryInfoKey
onHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<service>
. However, I'd have to test if this parameter is updated when changing just the password (might not be as the password itself is not stored in this key). Also, this timestamp would be overwritten when changing any service parameter, not just the password. - Checking the event log for service activity, though that would add a lot of complexity to SH as we'd need to interface with the event log RPC. Also, event logs could be huge leading to long computation time, or the interesting info could have gotten overwritten.
@dirkjanm:
not knowing whether credentials are current isn't exactly unique to services. you could have an RDP session open for months with an expired ticket and old password hashes as well
For what it's worth I'm currently doing the same thing for Scheduled Tasks (domain account credentials are stored DPAPI-encrypted on the machine's file system) and this might be more interesting from an attack path point of view as the HasSession
edge might not always be present in this case, when the task is not being executed.