Documentation ¶
Index ¶
- Variables
- func GetComparator(ts *TokenStream) (query.ComparatorType, error)
- func ParseObjectTypeStrings(typeslice []string) (map[engine.ObjectType]struct{}, error)
- func ResolveWithOptions(resolver AQLresolver, opts ResolverOptions) (*graph.Graph[*engine.Object, engine.EdgeBitmap], error)
- func TokenIDStrings() []string
- type AQLquery
- type AQLqueryUnion
- type AQLresolver
- type EdgeMatcher
- type EdgeSearcher
- type FirstLimiter
- type IndexLookup
- type NodeLimiter
- type NodeMatcher
- type NodeQuery
- type NodeSorter
- type NodeSorterImpl
- type QueryDefinition
- type QueryMode
- type ResolverOptions
- type SkipLimiter
- type Token
- type TokenID
- type TokenStream
- func (ts *TokenStream) EOF() bool
- func (ts *TokenStream) Next() bool
- func (ts *TokenStream) NextIfIs(id TokenID) bool
- func (ts *TokenStream) PeekNextRawToken() Token
- func (ts *TokenStream) PeekNextToken() Token
- func (ts *TokenStream) Prev() bool
- func (ts *TokenStream) SnarfTextUntil(id TokenID) string
- func (ts *TokenStream) Token() Token
Constants ¶
This section is empty.
Variables ¶
View Source
var (
DefaultQuerySettings = QueryDefinition{
MaxDepth: 99,
}
)
View Source
var Keywords []string // The keyword tokens
View Source
var Lexer *lexmachine.Lexer // The lexer object. Use this to construct a Scanner
View Source
var Literals []string // The tokens representing literal strings
View Source
var ( PredefinedQueries = []QueryDefinition{ { Name: "High Value Targets", Query: "ACYCLIC start:(tag=hvt)<-[]{1,10}-end:(&(dataLoader=Active Directory)(|(&(tag=account_enabled)(type=Person))(type=Group)))", Description: "High value targets in the network, that will compromise the entire AD if they're reached. This is the query to rule them all.", Default: true, }, { Name: "Reach Domain Admin, Administrators and Enterprise Admins", Query: "ACYCLIC start:(&(dataLoader=Active Directory)(type=Group)(|(objectSid=S-1-5-32-544)(objectSid=S-1-5-21-*-512)(objectSid=S-1-5-21-*-519)))<-[]{1,10}-end:(|(type=Person)(type=Group))", Description: "Find all the paths to reach Domain Admins, Administrators and Enterprise Admins.", Category: "Active Directory", }, { Name: "Run DCsync", Query: "ACYCLIC start:(&(name=DCsync)(type=Callable-Service-Point))<-[]{1,10}-end:(|(type=Person)(type=Group))", Description: "Find all the paths to run DCsync, enabling the attacker to dump all the hashes from the domain.", Category: "Active Directory", }, { Name: "Unconstrained Delegation", Query: "ACYCLIC start:(tag=unconstrained)<-[]{1,10}-end:(|(type=Person)(type=Group))", Description: "How to reach machines that have computer accounts with unconstrained delegation (non-DCs)", }, { Name: "What can accounts with no Kerberos preauth requirement reach? (ASREPROAST)", Query: "ACYCLIC start:(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304)(tag=account_active))-[]{1,10}->end:()", Category: "Active Directory", }, { Name: "Who can pwn your AD by sideloading a custom DLL on your DC? (Old DCs only)", Query: "ACYCLIC start:(distinguishedname=CN=MicrosoftDNS,CN=System,DC=*)<-[]{1,15}-end:(|(type=Person)(type=Group))", Category: "Active Directory", }, { Name: "Who can dump SAM/SYSTEM or your ntds.dit remotely or via RDP? (Server and Backup Operators)", Query: "ACYCLIC start:(&(dataLoader=Active Directory)(|(objectSid=S-1-5-32-551)(objectSid=S-1-5-32-549)))<-[]{1,10}-end:()", Category: "Active Directory", }, { Name: "Enroll in ESC1 vulnerable certificate templates (client auth + pose as anyone)", Query: "ACYCLIC start:(&(type=PKI-Certificate-Template)(msPKI-Certificate-Name-Flag:and:=1)(|(pKIExtendedKeyUsage=1.3.6.1.5.5.7.3.2)(pKIExtendedKeyUsage=1.3.5.1.5.2.3.4)(pKIExtendedKeyUsage=1.3.6.1.4.1.311.20.2.2)(pKIExtendedKeyUsage=2.5.29.37.0)(pKIExtendedKeyUsage:count:=0)))<-[CertificateEnroll]-()-[]{1,10}-end:(|(type=Person)(type=Group))", Category: "Certificate Services", }, { Name: "Enroll in ESC15 vulnerable certificate templates (v1 + pose as anyone)", Query: "ACYCLIC start:(&(type=PKI-Certificate-Template)(msPKI-Certificate-Name-Flag:and:=1)(msPKI-Template-Schema-Version=1))<-[CertificateEnroll]-()-[]{1,10}-end:(|(type=Person)(type=Group))", Category: "Certificate Services", }, { Name: "What can Domain Users, Authenticated Users and Everyone do?", Query: "ACYCLIC start:(&(dataLoader=Active Directory)(|(objectSid=S-1-5-21-*-513)(objectSid=S-1-5-11)(objectSid=S-1-1-0)))-[]{1,10}->end:()", Category: "Active Directory", }, { Name: "Who can dump a virtual DC? (hypervisor/SAN sounding groups)", Query: "ACYCLIC start:(&(dataLoader=Active Directory)(type=Group)(|(name=*vcenter*)(name=*vmware*)(name=*esxi*)(name=*vsan*)(name=*simplivity*)))<-[]{1,10}-end:()", Category: "Active Directory", }, { Name: "Who can wipe or access your backups? (backup sounding groups)", Query: "ACYCLIC start:(&(dataLoader=Active Directory)(type=Group)(|(name=*backup*)(name=*veeam*)(name=*tsm*)(name=*tivoli storage*)(name=*rubrik*)(name=*commvault*)))<-[]{1,10}-end:(|(type=Person)(type=Group))", Category: "Active Directory", }, { Name: "Who can change GPOs?", Query: "ACYCLIC start:(&(dataLoader=Active Directory)(type=Group-Policy-Container))<-[]{1,10}-end:(|(type=Person)(type=Group))", Category: "Active Directory", }, { Name: "What can users not required to have a password reach?", Query: "ACYCLIC start:(&(dataLoader=Active Directory)(type=Person)(userAccountControl:1.2.840.113556.1.4.803:=32))-[]{1,10}->end:()", Category: "Active Directory", }, { Name: "What can users that can't change password reach?", Query: "ACYCLIC start:(&(type=Person)(userAccountControl:1.2.840.113556.1.4.803:=64))-[]{1,10}->end:()", Category: "Active Directory", }, { Name: "What can users with never expiring passwords reach?", Query: "ACYCLIC start:(&(type=Person)(userAccountControl:1.2.840.113556.1.4.803:=65536))-[]{1,10}->end:()", Category: "Active Directory", }, { Name: "What can accounts that have a password older than 5 years reach?", Query: "ACYCLIC start:(&(objectClass=Person)(!(pwdLastSet=0))(pwdLastSet:since:<-5Y)(!(userAccountControl:and:=2)))-[]{1,10}->end:()", Category: "Active Directory", }, { Name: "What can accounts that have never set a password reach?", Query: "ACYCLIC start:(&(dataLoader=Active Directory)(objectClass=Person)(pwdLastSet=0)(|(logonCount=0)(!(logonCount=*)))(!(userAccountControl:and:=2)))-[]{1,10}->end:()", Category: "Active Directory", }, { Name: "Protected Users", Query: "ACYCLIC start:(&(type=Group)(distinguishedName=CN=Protected Users,*))<-[]{1,10}-end:(|(type=Person)(type=Group))", Description: "Who can tamper with the Protected Users group?", Category: "Active Directory", }, { Name: "What can kerberoastable user accounts reach? (all encryption types)", Query: "ACYCLIC start:(&(type=Person)(servicePrincipalName=*)(tag=account_active))<-[]{1,10}-end:(|(type=Person)(type=Group))", Category: "Roasting", }, { Name: "What can kerberoastable user accounts reach? (RC4 encryption)", Query: "ACYCLIC start:(&(type=Person)(servicePrincipalName=*)(|(msDS-SupportedEncryptionTypes:and:=0x4)(!msDS-SupportedEncryptionTypes=*))(tag=account_active))<-[]{1,10}-end:(|(type=Person)(type=Group))", Category: "Roasting", }, { Name: "Large groups", Query: "ACYCLIC start:(&(type=Group)(member:count:>100))-[]{1,10}->end:()", Description: "What can large groups (more than 100 members) reach?", Category: "Examples", }, { Name: "Domain Controllers", Query: "ACYCLIC start:(&(type=Machine)(out=MachineAccount,(&(type=Computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))))<-[]{1,10}-end:(|(type=Person)(type=Group))", Description: "Domain Controllers are critical servers in Active Directory environments. They authenticate users and services within the domain. Compromising these machines allows attackers to take over the entire AD.", Category: "Active Directory", }, { Name: "Who can reach Read-Only Domain Controllers (RODC)", Query: "ACYCLIC start:(&(type=Machine)(out=MachineAccount,(&(type=Computer)(primaryGroupId=521))))<-[]{1,10}-end:(|(type=Person)(type=Group))", Description: "Read-Only Domain Controllers (RODC) are used to reduce the risk of password replication. They only replicate a subset of the domain's data and are typically located in remote offices. Compromising RODCs can lead to unauthorized access to sensitive information, depending on how they're configured for caching credentials.", Category: "Active Directory", }, { Name: "Computers with unconstrained delegation (non DCs)?", Query: "ACYCLIC start:(&(type=Computer)(userAccountControl:1.2.840.113556.1.4.803:=524288)(!userAccountControl:1.2.840.113556.1.4.803:=8192))<-[]{1,10}-end:(|(type=Person)(type=Group))", Category: "Active Directory", }, { Name: "Computers with constrained delegation (non DCs)", Query: "ACYCLIC start:(&(objectCategory=computer)(msds-allowedtodelegateto=*)(!userAccountControl:1.2.840.113556.1.4.803:=8192))<-[]{1,10}-end:(|(type=Person)(type=Group))", Category: "Active Directory", }, { Name: "Users that are members of more than 25 groups", Query: "ACYCLIC start:(&(type=Person)(memberOf:count:>10))", Category: "Examples", }, { Name: "100 random machines", Query: "ACYCLIC start:(&(type=Machine)(out=MachineAccount,(userAccountControl:1.2.840.113556.1.4.803:=4096))) LIMIT 100", Category: "Examples", }, } )
View Source
var StaticLexers = map[string]TokenID{ "\\(": LParan, "\\)": RParan, "\\[": LBracket, "\\]": RBracket, "\\{": LBrace, "\\}": RBrace, "\\~": Tilde, "\\=": Equals, "\\<": LessThan, "\\<\\=": LessThanEquals, "\\>": GreaterThan, "\\>\\=": GreaterThanEquals, "\\&": BinaryAnd, "\\|": BinaryOr, "\\^": BinaryNot, "AND": And, "OR": Or, "NOT": Not, "TRUE": True, "FALSE": False, "\\*": Star, "\\/": Slash, "\\!": Exclamation, "\\.": Dot, "\\.\\.": Dotdot, "\\,": Comma, "\\:": Colon, "\\-": EdgeAnyDirection, "\\-\\>": EdgeOut, "\\<\\-": EdgeIn, "MATCH": Match, "IS": Is, "WHERE": Where, "SKIP": Skip, "OFFSET": Offset, "LIMIT": Limit, "ORDER BY": OrderBy, "DESC": Desc, "UNION": Union, `//[^\n]*\n?`: Comment, `/\*([^*]|\r|\n|(\*+([^*/]|\r|\n)))*\*+/`: Comment, `([a-zA-Z]|_)([a-zA-Z0-9]|_|-)*`: Identifier, `\\#([a-zA-Z]|_)([a-zA-Z0-9]|_)+`: HashIdentifier, `\\@([a-zA-Z]|_)([a-zA-Z0-9]|_)+`: AtIdentifier, `( |\t|\n|\r)+`: Whitespace, }
View Source
var TokenIds map[string]int // A map from the token names to their int ids
View Source
var Tokens []string // All of the tokens (including literals and keywords)
Functions ¶
func GetComparator ¶
func GetComparator(ts *TokenStream) (query.ComparatorType, error)
func ParseObjectTypeStrings ¶
func ParseObjectTypeStrings(typeslice []string) (map[engine.ObjectType]struct{}, error)
func ResolveWithOptions ¶
func ResolveWithOptions(resolver AQLresolver, opts ResolverOptions) (*graph.Graph[*engine.Object, engine.EdgeBitmap], error)
func TokenIDStrings ¶
func TokenIDStrings() []string
TokenIDStrings returns a slice of all String values of the enum
Types ¶
type AQLquery ¶
type AQLquery struct { Sources []NodeQuery // count is n Next []EdgeSearcher // count is n-1 Mode QueryMode Shortest bool OverAllProbability engine.Probability // contains filtered or unexported fields }
type AQLqueryUnion ¶
type AQLqueryUnion struct {
// contains filtered or unexported fields
}
Union of multiple queries
func (AQLqueryUnion) Resolve ¶
func (aqlqu AQLqueryUnion) Resolve(opts ResolverOptions) (*graph.Graph[*engine.Object, engine.EdgeBitmap], error)
type AQLresolver ¶
type AQLresolver interface {
Resolve(ResolverOptions) (*graph.Graph[*engine.Object, engine.EdgeBitmap], error)
}
func ParseAQLQuery ¶
func ParseAQLQuery(s string, ao *engine.Objects) (AQLresolver, error)
type EdgeMatcher ¶
type EdgeMatcher struct { Bitmap engine.EdgeBitmap Count int64 // minimum number of edges to match Comparator query.ComparatorType NoTrimEdges bool // don't trim edges to just the filter }
type EdgeSearcher ¶
type EdgeSearcher struct { PathNodeRequirement *NodeQuery // Nodes passed along the way must fulfill this filter FilterEdges EdgeMatcher // match any of these Direction engine.EdgeDirection MinIterations, MaxIterations int // there should be between min and max iterations in the chain ProbabilityValue engine.Probability ProbabilityComparator query.ComparatorType // contains filtered or unexported fields }
type FirstLimiter ¶
type FirstLimiter int
func (FirstLimiter) Limit ¶
func (fl FirstLimiter) Limit(o engine.ObjectSlice) engine.ObjectSlice
type IndexLookup ¶
type IndexLookup struct {
// contains filtered or unexported fields
}
type NodeLimiter ¶
type NodeLimiter interface {
Limit(engine.ObjectSlice) engine.ObjectSlice
}
type NodeMatcher ¶
type NodeQuery ¶
type NodeQuery struct { IndexLookup IndexLookup // Possible start of search, quickly narrows it down Selector query.NodeFilter // Where style boolean approval filter for objects OrderBy NodeSorter // Sorting Reference string // For cross result reference Skip int // Skipping Limit int // Limiting }
type NodeSorter ¶
type NodeSorter interface {
Sort(engine.ObjectSlice) engine.ObjectSlice
}
type NodeSorterImpl ¶
func (NodeSorterImpl) Sort ¶
func (nsi NodeSorterImpl) Sort(o engine.ObjectSlice) engine.ObjectSlice
type QueryDefinition ¶
type QueryDefinition struct { Name string `json:"name"` Query string `json:"query,omitempty"` Category string `json:"category,omitempty"` // Optional category for grouping queries in UI Description string `json:"description,omitempty"` MaxDepth int `json:"max_depth,omitempty"` MaxOutgoingConnections int `json:"max_outgoing_connections,omitempty"` Default bool `json:"default,omitempty"` MinAccumulatedProbability engine.Probability `json:"min_accumulated_probability,omitempty"` UserDefined bool `json:"user_defined,omitempty"` }
Can return built in queries and user defined persisted queries
func DefaultQueryDefinition ¶
func DefaultQueryDefinition() QueryDefinition
func ParseQueryDefinitionFromPOST ¶
func ParseQueryDefinitionFromPOST(ctx *gin.Context) (QueryDefinition, error)
func (QueryDefinition) ID ¶
func (q QueryDefinition) ID() string
func (QueryDefinition) Resolver ¶
func (qd QueryDefinition) Resolver(ao *engine.Objects) (AQLresolver, error)
Compiles the query and makes it a resolver
type ResolverOptions ¶
type ResolverOptions struct { MaxDepth int `json:"max_depth,omitempty"` MaxOutgoingConnections int `json:"max_outgoing_connections,omitempty"` MinEdgeProbability engine.Probability `json:"min_edge_probability,omitempty"` MinAccumulatedProbability engine.Probability `json:"min_accumulated_probability,omitempty"` PruneIslands bool `json:"prune_islands,omitempty"` NodeLimit int `json:"nodelimit,omitempty"` }
func NewResolverOptions ¶
func NewResolverOptions() ResolverOptions
type SkipLimiter ¶
type SkipLimiter int
func (SkipLimiter) Limit ¶
func (sl SkipLimiter) Limit(o engine.ObjectSlice) engine.ObjectSlice
type TokenID ¶
type TokenID int
const ( Invalid TokenID = iota Star Slash Exclamation Dot Dotdot Comma Colon Equals Tilde LessThan LessThanEquals GreaterThan GreaterThanEquals And Or Xor Not BinaryAnd BinaryOr BinaryNot LParan // ( RParan // ) LBracket // [ RBracket // ] LBrace // { RBrace // } EdgeAnyDirection // - EdgeIn // <- EdgeOut // -> Is Match Where Skip Offset Limit OrderBy Desc Union True False Literal Keyword Whitespace Integer Float UnquotedLDAPString QuotedString // Quoted string Identifier HashIdentifier AtIdentifier Comment MAXTOKEN = Comment )
func TokenIDString ¶
TokenIDString retrieves an enum value from the enum constants string name. Throws an error if the param is not part of the enum.
func (TokenID) IsATokenID ¶
IsATokenID returns "true" if the value is listed in the enum definition. "false" otherwise
type TokenStream ¶
type TokenStream struct {
// contains filtered or unexported fields
}
func Parse ¶
func Parse(input string) (*TokenStream, error)
func (*TokenStream) EOF ¶
func (ts *TokenStream) EOF() bool
func (*TokenStream) Next ¶
func (ts *TokenStream) Next() bool
func (*TokenStream) NextIfIs ¶
func (ts *TokenStream) NextIfIs(id TokenID) bool
func (*TokenStream) PeekNextRawToken ¶
func (ts *TokenStream) PeekNextRawToken() Token
func (*TokenStream) PeekNextToken ¶
func (ts *TokenStream) PeekNextToken() Token
func (*TokenStream) Prev ¶
func (ts *TokenStream) Prev() bool
func (*TokenStream) SnarfTextUntil ¶
func (ts *TokenStream) SnarfTextUntil(id TokenID) string
func (*TokenStream) Token ¶
func (ts *TokenStream) Token() Token
Click to show internal directories.
Click to hide internal directories.