Bloodhound GPT#
References:
https://towardsdatascience.com/langchain-has-added-cypher-search-cb9d821120d5
https://python.langchain.com/en/latest/modules/chains/examples/graph_cypher_qa.html
Run Neo4j Docker Image#
!docker run -it -d --rm --name neo4j -p 7474:7474 -p 7687:7687 -e NEO4J_AUTH=none neo4j-apoc
45538b6099608e5d6ad4d3a24b009f7ffb974991f21b1cfbd9499a4177349ff0
!docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
45538b609960 neo4j-apoc "tini -g -- /startup…" 9 seconds ago Up 8 seconds 0.0.0.0:7474->7474/tcp, 7473/tcp, 0.0.0.0:7687->7687/tcp neo4j
!docker logs neo4j
Installing Plugin 'apoc' from /var/lib/neo4j/labs/apoc-*-core.jar to /var/lib/neo4j/plugins/apoc.jar
Applying default values for plugin apoc to neo4j.conf
2023-05-29 07:46:39.976+0000 INFO Starting...
2023-05-29 07:46:40.785+0000 INFO This instance is ServerId{26af75fc} (26af75fc-cd09-4acf-ad9c-35d59f4767db)
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/var/lib/neo4j/plugins/apoc-5.8.0-extended.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/var/lib/neo4j/plugins/apoc.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]
2023-05-29 07:46:41.480+0000 INFO ======== Neo4j 5.8.0 ========
2023-05-29 07:46:48.380+0000 INFO Called db.clearQueryCaches(): Query cache already empty.
2023-05-29 07:46:48.543+0000 INFO Bolt enabled on 0.0.0.0:7687.
2023-05-29 07:46:49.391+0000 INFO Remote interface available at http://localhost:7474/
2023-05-29 07:46:49.401+0000 INFO id: 1ED160F2C343F7717EB3E6EE9B9D817136ED8CE99D8961B442B5766163273E41
2023-05-29 07:46:49.401+0000 INFO name: system
2023-05-29 07:46:49.402+0000 INFO creationDate: 2023-05-29T07:46:42.352Z
2023-05-29 07:46:49.402+0000 INFO Started.
Import Langchain Modules#
from langchain.chat_models import ChatOpenAI
from langchain.chains import GraphCypherQAChain
from langchain.graphs import Neo4jGraph
Initialize Neo4j Connection#
graph = Neo4jGraph(url="bolt://localhost:7687", username="neo4j", password="")
We can validate that we are connected to an empty neo4j server. We are going to add some data in a moment.
print(graph.get_schema)
Node properties are the following:
[]
Relationship properties are the following:
[]
The relationships are the following:
[]
Generate Bloodhound Database#
For this step we use the Bloodhound DBCreator python script to generate a randomized data set and import it to our plain neo4j database.
Install Python Modules#
%pip install -r DBCreator/requirements.txt
Requirement already satisfied: neo4j==5.9.0 in c:\users\robertorodriguez\appdata\local\programs\python\python311\lib\site-packages (from -r DBCreator/requirements.txt (line 1)) (5.9.0)
Requirement already satisfied: neobolt==1.7.16 in c:\users\robertorodriguez\appdata\local\programs\python\python311\lib\site-packages (from -r DBCreator/requirements.txt (line 2)) (1.7.16)
Requirement already satisfied: neotime==1.7.4 in c:\users\robertorodriguez\appdata\local\programs\python\python311\lib\site-packages (from -r DBCreator/requirements.txt (line 3)) (1.7.4)
Requirement already satisfied: pytz==2023.3 in c:\users\robertorodriguez\appdata\local\programs\python\python311\lib\site-packages (from -r DBCreator/requirements.txt (line 4)) (2023.3)
Requirement already satisfied: six==1.14.0 in c:\users\robertorodriguez\appdata\local\programs\python\python311\lib\site-packages (from -r DBCreator/requirements.txt (line 5)) (1.14.0)
Note: you may need to restart the kernel to use updated packages.
Generate Data and Import to Database#
!python DBCreator/DBCreator.py
Not connected to database. Use connect first
Database Connection Successful!
Starting data generation with nodes=500
Populating Standard Nodes
Adding Standard Edges
Generating Computer Nodes
Creating Domain Controllers
Generating User Nodes
Generating Group Nodes
Adding Domain Admins to Local Admins of Computers
Creating 15 Domain Admins (3% of users capped at 30)
Applying random group nesting
Adding users to groups
Calculated 7 groups per user with a variance of - 6
Adding local admin rights
Adding RDP/ExecuteDCOM/AllowedToDelegateTo
Adding sessions
Adding Domain Admin ACEs
Creating OUs
Creating GPOs
Adding outbound ACLs to 4 objects
Marking some users as Kerberoastable
Adding unconstrained delegation to a few computers
Database Generation Finished!
Refresh Graph Schema#
graph.refresh_schema()
print(graph.get_schema)
Node properties are the following:
[{'properties': [{'property': 'objectid', 'type': 'STRING'}, {'property': 'highvalue', 'type': 'BOOLEAN'}, {'property': 'domain', 'type': 'STRING'}, {'property': 'name', 'type': 'STRING'}, {'property': 'blocksInheritance', 'type': 'BOOLEAN'}, {'property': 'owned', 'type': 'BOOLEAN'}, {'property': 'operatingsystem', 'type': 'STRING'}, {'property': 'enabled', 'type': 'BOOLEAN'}, {'property': 'displayname', 'type': 'STRING'}, {'property': 'pwdlastset', 'type': 'INTEGER'}, {'property': 'lastlogon', 'type': 'INTEGER'}, {'property': 'hasspn', 'type': 'BOOLEAN'}], 'labels': 'Base'}, {'properties': [{'property': 'objectid', 'type': 'STRING'}, {'property': 'highvalue', 'type': 'BOOLEAN'}, {'property': 'domain', 'type': 'STRING'}, {'property': 'name', 'type': 'STRING'}, {'property': 'pwdlastset', 'type': 'INTEGER'}, {'property': 'owned', 'type': 'BOOLEAN'}, {'property': 'enabled', 'type': 'BOOLEAN'}, {'property': 'lastlogon', 'type': 'INTEGER'}, {'property': 'displayname', 'type': 'STRING'}], 'labels': 'Group'}, {'properties': [{'property': 'domain', 'type': 'STRING'}, {'property': 'name', 'type': 'STRING'}, {'property': 'highvalue', 'type': 'BOOLEAN'}], 'labels': 'Domain'}, {'properties': [{'property': 'domain', 'type': 'STRING'}, {'property': 'objectid', 'type': 'STRING'}, {'property': 'name', 'type': 'STRING'}], 'labels': 'GPO'}, {'properties': [{'property': 'blocksInheritance', 'type': 'BOOLEAN'}, {'property': 'domain', 'type': 'STRING'}, {'property': 'objectid', 'type': 'STRING'}, {'property': 'name', 'type': 'STRING'}], 'labels': 'OU'}, {'properties': [{'property': 'owned', 'type': 'BOOLEAN'}, {'property': 'domain', 'type': 'STRING'}, {'property': 'name', 'type': 'STRING'}, {'property': 'operatingsystem', 'type': 'STRING'}, {'property': 'enabled', 'type': 'BOOLEAN'}, {'property': 'objectid', 'type': 'STRING'}], 'labels': 'Computer'}, {'properties': [{'property': 'owned', 'type': 'BOOLEAN'}, {'property': 'domain', 'type': 'STRING'}, {'property': 'name', 'type': 'STRING'}, {'property': 'displayname', 'type': 'STRING'}, {'property': 'pwdlastset', 'type': 'INTEGER'}, {'property': 'enabled', 'type': 'BOOLEAN'}, {'property': 'lastlogon', 'type': 'INTEGER'}, {'property': 'objectid', 'type': 'STRING'}, {'property': 'hasspn', 'type': 'BOOLEAN'}], 'labels': 'User'}]
Relationship properties are the following:
[{'type': 'GpLink', 'properties': [{'property': 'enforced', 'type': 'BOOLEAN'}, {'property': 'isacl', 'type': 'BOOLEAN'}]}, {'type': 'Contains', 'properties': [{'property': 'isacl', 'type': 'BOOLEAN'}]}, {'type': 'GenericAll', 'properties': [{'property': 'isacl', 'type': 'BOOLEAN'}]}, {'type': 'Owns', 'properties': [{'property': 'isacl', 'type': 'BOOLEAN'}]}, {'type': 'WriteOwner', 'properties': [{'property': 'isacl', 'type': 'BOOLEAN'}]}, {'type': 'WriteDacl', 'properties': [{'property': 'isacl', 'type': 'BOOLEAN'}]}, {'type': 'DCSync', 'properties': [{'property': 'isacl', 'type': 'BOOLEAN'}]}, {'type': 'GetChanges', 'properties': [{'property': 'isacl', 'type': 'BOOLEAN'}]}, {'type': 'GetChangesAll', 'properties': [{'property': 'isacl', 'type': 'BOOLEAN'}]}, {'type': 'ForceChangePassword', 'properties': [{'property': 'isacl', 'type': 'BOOLEAN'}]}]
The relationships are the following:
['(:Base)-[:GenericAll]->(:Base)', '(:Base)-[:WriteOwner]->(:Base)', '(:Base)-[:WriteDacl]->(:Base)', '(:Base)-[:DCSync]->(:Base)', '(:Base)-[:GetChanges]->(:Base)', '(:Base)-[:GetChangesAll]->(:Base)', '(:Base)-[:AdminTo]->(:Base)', '(:Base)-[:Owns]->(:Base)', '(:Base)-[:GpLink]->(:Base)', '(:Base)-[:Contains]->(:Base)', '(:Base)-[:MemberOf]->(:Base)', '(:Base)-[:AllowedToDelegate]->(:Base)', '(:Base)-[:HasSession]->(:Base)', '(:Base)-[:CanRDP]->(:Base)', '(:Base)-[:ExecuteDCOM]->(:Base)', '(:Base)-[:ReadLAPSPassword]->(:Base)', '(:Base)-[:ForceChangePassword]->(:Base)', '(:Group)-[:GenericAll]->(:Base)', '(:Group)-[:WriteOwner]->(:Base)', '(:Group)-[:WriteDacl]->(:Base)', '(:Group)-[:DCSync]->(:Base)', '(:Group)-[:GetChanges]->(:Base)', '(:Group)-[:GetChangesAll]->(:Base)', '(:Group)-[:AdminTo]->(:Base)', '(:Group)-[:Owns]->(:Base)', '(:Group)-[:MemberOf]->(:Base)', '(:Group)-[:CanRDP]->(:Base)', '(:Group)-[:ExecuteDCOM]->(:Base)', '(:Group)-[:ForceChangePassword]->(:Base)', '(:Group)-[:ReadLAPSPassword]->(:Base)', '(:Domain)-[:GpLink]->(:Base)', '(:Domain)-[:Contains]->(:Base)', '(:GPO)-[:GpLink]->(:Base)', '(:OU)-[:Contains]->(:Base)', '(:Computer)-[:MemberOf]->(:Base)', '(:Computer)-[:AllowedToDelegate]->(:Base)', '(:Computer)-[:HasSession]->(:Base)', '(:User)-[:MemberOf]->(:Base)', '(:User)-[:CanRDP]->(:Base)', '(:User)-[:ExecuteDCOM]->(:Base)', '(:User)-[:AllowedToDelegate]->(:Base)', '(:User)-[:ReadLAPSPassword]->(:Base)']
Run a Basic Cypher Query Example#
Let’s run a basic cypher query that we could then use as an example for our next steps.
Let’s look for users that have a Service Principal Name Set.
graph.query(
"""
MATCH (u:User {hasspn:true})
RETURN u.name
"""
)
[{'u.name': 'LZUNICH00009@TESTLAB.LOCAL'},
{'u.name': 'VCERVENKA00027@TESTLAB.LOCAL'},
{'u.name': 'CBOOSE00074@TESTLAB.LOCAL'},
{'u.name': 'MZARRABI00096@TESTLAB.LOCAL'},
{'u.name': 'AMEDE00171@TESTLAB.LOCAL'},
{'u.name': 'DDOUYETTE00201@TESTLAB.LOCAL'},
{'u.name': 'RKNIFFEN00223@TESTLAB.LOCAL'},
{'u.name': 'MPAULIS00237@TESTLAB.LOCAL'},
{'u.name': 'WPUTNAL00248@TESTLAB.LOCAL'},
{'u.name': 'CSTAS00251@TESTLAB.LOCAL'},
{'u.name': 'NDAMANN00268@TESTLAB.LOCAL'},
{'u.name': 'EREDDER00272@TESTLAB.LOCAL'},
{'u.name': 'LEBERHEART00328@TESTLAB.LOCAL'},
{'u.name': 'ATASCHEREAU00345@TESTLAB.LOCAL'},
{'u.name': 'EENYEART00380@TESTLAB.LOCAL'},
{'u.name': 'AFINLAY00408@TESTLAB.LOCAL'},
{'u.name': 'ROREGON00445@TESTLAB.LOCAL'},
{'u.name': 'GCHRISP00455@TESTLAB.LOCAL'},
{'u.name': 'CMCKEITHAN00461@TESTLAB.LOCAL'},
{'u.name': 'JBERKHIMER00463@TESTLAB.LOCAL'}]
Enable Natural Language Search on Bloodhound Data#
Import OpenAI Module#
import os
import openai
from dotenv import load_dotenv
Set Open AI Key Variable#
# Get your key: https://platform.openai.com/account/api-keys
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
Initialize Langchain Graph Cypher Question & Answer Chain#
chain = GraphCypherQAChain.from_llm(
ChatOpenAI(temperature=0), graph=graph, verbose=True
)
Cypher Basic Example -> Natural Language#
chain.run("What Users have a Service Principal Name Set?")
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (u:User {hasspn: true}) RETURN u.name
Full Context:
[{'u.name': 'LZUNICH00009@TESTLAB.LOCAL'}, {'u.name': 'VCERVENKA00027@TESTLAB.LOCAL'}, {'u.name': 'CBOOSE00074@TESTLAB.LOCAL'}, {'u.name': 'MZARRABI00096@TESTLAB.LOCAL'}, {'u.name': 'AMEDE00171@TESTLAB.LOCAL'}, {'u.name': 'DDOUYETTE00201@TESTLAB.LOCAL'}, {'u.name': 'RKNIFFEN00223@TESTLAB.LOCAL'}, {'u.name': 'MPAULIS00237@TESTLAB.LOCAL'}, {'u.name': 'WPUTNAL00248@TESTLAB.LOCAL'}, {'u.name': 'CSTAS00251@TESTLAB.LOCAL'}, {'u.name': 'NDAMANN00268@TESTLAB.LOCAL'}, {'u.name': 'EREDDER00272@TESTLAB.LOCAL'}, {'u.name': 'LEBERHEART00328@TESTLAB.LOCAL'}, {'u.name': 'ATASCHEREAU00345@TESTLAB.LOCAL'}, {'u.name': 'EENYEART00380@TESTLAB.LOCAL'}, {'u.name': 'AFINLAY00408@TESTLAB.LOCAL'}, {'u.name': 'ROREGON00445@TESTLAB.LOCAL'}, {'u.name': 'GCHRISP00455@TESTLAB.LOCAL'}, {'u.name': 'CMCKEITHAN00461@TESTLAB.LOCAL'}, {'u.name': 'JBERKHIMER00463@TESTLAB.LOCAL'}]
> Finished chain.
'The following users have a Service Principal Name set: LZUNICH00009@TESTLAB.LOCAL, VCERVENKA00027@TESTLAB.LOCAL, CBOOSE00074@TESTLAB.LOCAL, MZARRABI00096@TESTLAB.LOCAL, AMEDE00171@TESTLAB.LOCAL, DDOUYETTE00201@TESTLAB.LOCAL, RKNIFFEN00223@TESTLAB.LOCAL, MPAULIS00237@TESTLAB.LOCAL, WPUTNAL00248@TESTLAB.LOCAL, CSTAS00251@TESTLAB.LOCAL, NDAMANN00268@TESTLAB.LOCAL, EREDDER00272@TESTLAB.LOCAL, LEBERHEART00328@TESTLAB.LOCAL, ATASCHEREAU00345@TESTLAB.LOCAL, EENYEART00380@TESTLAB.LOCAL, AFINLAY00408@TESTLAB.LOCAL, ROREGON00445@TESTLAB.LOCAL, GCHRISP00455@TESTLAB.LOCAL, CMCKEITHAN00461@TESTLAB.LOCAL, JBERKHIMER00463@TESTLAB.LOCAL.'
Other Cypher Queries -> Natural Language#
1.1 Cypher: Find what groups can RDP#
Reference: https://hausec.com/2019/09/09/bloodhound-cypher-cheatsheet/
graph.query(
"""
MATCH p=(m:Group)-[r:CanRDP]->(n:Computer) RETURN m.name, n.name ORDER BY m.name
"""
)
[{'m.name': 'IT00057@TESTLAB.LOCAL', 'n.name': 'COMP00034.TESTLAB.LOCAL'},
{'m.name': 'IT00057@TESTLAB.LOCAL', 'n.name': 'COMP00079.TESTLAB.LOCAL'},
{'m.name': 'IT00057@TESTLAB.LOCAL', 'n.name': 'COMP00297.TESTLAB.LOCAL'},
{'m.name': 'IT00108@TESTLAB.LOCAL', 'n.name': 'COMP00463.TESTLAB.LOCAL'},
{'m.name': 'IT00128@TESTLAB.LOCAL', 'n.name': 'COMP00158.TESTLAB.LOCAL'},
{'m.name': 'IT00128@TESTLAB.LOCAL', 'n.name': 'COMP00217.TESTLAB.LOCAL'},
{'m.name': 'IT00131@TESTLAB.LOCAL', 'n.name': 'COMP00447.TESTLAB.LOCAL'},
{'m.name': 'IT00131@TESTLAB.LOCAL', 'n.name': 'COMP00254.TESTLAB.LOCAL'},
{'m.name': 'IT00131@TESTLAB.LOCAL', 'n.name': 'COMP00168.TESTLAB.LOCAL'},
{'m.name': 'IT00146@TESTLAB.LOCAL', 'n.name': 'COMP00394.TESTLAB.LOCAL'},
{'m.name': 'IT00146@TESTLAB.LOCAL', 'n.name': 'COMP00099.TESTLAB.LOCAL'},
{'m.name': 'IT00146@TESTLAB.LOCAL', 'n.name': 'COMP00111.TESTLAB.LOCAL'},
{'m.name': 'IT00173@TESTLAB.LOCAL', 'n.name': 'COMP00139.TESTLAB.LOCAL'},
{'m.name': 'IT00173@TESTLAB.LOCAL', 'n.name': 'COMP00360.TESTLAB.LOCAL'},
{'m.name': 'IT00180@TESTLAB.LOCAL', 'n.name': 'COMP00461.TESTLAB.LOCAL'},
{'m.name': 'IT00180@TESTLAB.LOCAL', 'n.name': 'COMP00387.TESTLAB.LOCAL'},
{'m.name': 'IT00182@TESTLAB.LOCAL', 'n.name': 'COMP00104.TESTLAB.LOCAL'},
{'m.name': 'IT00183@TESTLAB.LOCAL', 'n.name': 'COMP00497.TESTLAB.LOCAL'},
{'m.name': 'IT00183@TESTLAB.LOCAL', 'n.name': 'COMP00195.TESTLAB.LOCAL'},
{'m.name': 'IT00205@TESTLAB.LOCAL', 'n.name': 'COMP00407.TESTLAB.LOCAL'},
{'m.name': 'IT00206@TESTLAB.LOCAL', 'n.name': 'COMP00261.TESTLAB.LOCAL'},
{'m.name': 'IT00206@TESTLAB.LOCAL', 'n.name': 'COMP00164.TESTLAB.LOCAL'},
{'m.name': 'IT00206@TESTLAB.LOCAL', 'n.name': 'COMP00127.TESTLAB.LOCAL'},
{'m.name': 'IT00231@TESTLAB.LOCAL', 'n.name': 'COMP00267.TESTLAB.LOCAL'},
{'m.name': 'IT00231@TESTLAB.LOCAL', 'n.name': 'COMP00186.TESTLAB.LOCAL'},
{'m.name': 'IT00231@TESTLAB.LOCAL', 'n.name': 'COMP00093.TESTLAB.LOCAL'},
{'m.name': 'IT00231@TESTLAB.LOCAL', 'n.name': 'COMP00024.TESTLAB.LOCAL'},
{'m.name': 'IT00233@TESTLAB.LOCAL', 'n.name': 'COMP00128.TESTLAB.LOCAL'},
{'m.name': 'IT00309@TESTLAB.LOCAL', 'n.name': 'COMP00463.TESTLAB.LOCAL'},
{'m.name': 'IT00309@TESTLAB.LOCAL', 'n.name': 'COMP00064.TESTLAB.LOCAL'},
{'m.name': 'IT00309@TESTLAB.LOCAL', 'n.name': 'COMP00295.TESTLAB.LOCAL'},
{'m.name': 'IT00309@TESTLAB.LOCAL', 'n.name': 'COMP00395.TESTLAB.LOCAL'},
{'m.name': 'IT00312@TESTLAB.LOCAL', 'n.name': 'COMP00393.TESTLAB.LOCAL'},
{'m.name': 'IT00346@TESTLAB.LOCAL', 'n.name': 'COMP00470.TESTLAB.LOCAL'},
{'m.name': 'IT00346@TESTLAB.LOCAL', 'n.name': 'COMP00267.TESTLAB.LOCAL'},
{'m.name': 'IT00359@TESTLAB.LOCAL', 'n.name': 'COMP00495.TESTLAB.LOCAL'},
{'m.name': 'IT00359@TESTLAB.LOCAL', 'n.name': 'COMP00293.TESTLAB.LOCAL'},
{'m.name': 'IT00359@TESTLAB.LOCAL', 'n.name': 'COMP00338.TESTLAB.LOCAL'},
{'m.name': 'IT00362@TESTLAB.LOCAL', 'n.name': 'COMP00231.TESTLAB.LOCAL'},
{'m.name': 'IT00362@TESTLAB.LOCAL', 'n.name': 'COMP00422.TESTLAB.LOCAL'},
{'m.name': 'IT00383@TESTLAB.LOCAL', 'n.name': 'COMP00254.TESTLAB.LOCAL'},
{'m.name': 'IT00383@TESTLAB.LOCAL', 'n.name': 'COMP00190.TESTLAB.LOCAL'},
{'m.name': 'IT00383@TESTLAB.LOCAL', 'n.name': 'COMP00373.TESTLAB.LOCAL'},
{'m.name': 'IT00404@TESTLAB.LOCAL', 'n.name': 'COMP00470.TESTLAB.LOCAL'},
{'m.name': 'IT00404@TESTLAB.LOCAL', 'n.name': 'COMP00095.TESTLAB.LOCAL'},
{'m.name': 'IT00418@TESTLAB.LOCAL', 'n.name': 'COMP00319.TESTLAB.LOCAL'},
{'m.name': 'IT00418@TESTLAB.LOCAL', 'n.name': 'COMP00209.TESTLAB.LOCAL'},
{'m.name': 'IT00460@TESTLAB.LOCAL', 'n.name': 'COMP00365.TESTLAB.LOCAL'},
{'m.name': 'IT00461@TESTLAB.LOCAL', 'n.name': 'COMP00425.TESTLAB.LOCAL'},
{'m.name': 'IT00461@TESTLAB.LOCAL', 'n.name': 'COMP00176.TESTLAB.LOCAL'}]
1.2 Natural Language: Find what groups can RDP#
chain.run("""
Return the name of 5 groups and the name of the computers that the groups can RDP to and order the results by the groups name.
""")
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (g:Group)-[:CanRDP]->(c:Computer)
RETURN g.name, c.name
ORDER BY g.name
LIMIT 5
Full Context:
[{'g.name': 'IT00057@TESTLAB.LOCAL', 'c.name': 'COMP00297.TESTLAB.LOCAL'}, {'g.name': 'IT00057@TESTLAB.LOCAL', 'c.name': 'COMP00034.TESTLAB.LOCAL'}, {'g.name': 'IT00057@TESTLAB.LOCAL', 'c.name': 'COMP00079.TESTLAB.LOCAL'}, {'g.name': 'IT00108@TESTLAB.LOCAL', 'c.name': 'COMP00463.TESTLAB.LOCAL'}, {'g.name': 'IT00128@TESTLAB.LOCAL', 'c.name': 'COMP00158.TESTLAB.LOCAL'}]
> Finished chain.
'Here are the names of 5 groups and the corresponding computers that they can RDP to, ordered by group name:\n\n- Group IT00057@TESTLAB.LOCAL can RDP to computers COMP00034.TESTLAB.LOCAL, COMP00079.TESTLAB.LOCAL, and COMP00297.TESTLAB.LOCAL.\n- Group IT00108@TESTLAB.LOCAL can RDP to computer COMP00463.TESTLAB.LOCAL.\n- Group IT00128@TESTLAB.LOCAL can RDP to computer COMP00158.TESTLAB.LOCAL.'
2.1 Cypher: Find all members of the domain admins group#
graph.query(
"""
MATCH (u:User)-[:MemberOf]->(g:Group {name:'DOMAIN ADMINS@TESTLAB.LOCAL'}) return u.name, u.displayname
"""
)
[{'u.name': 'ADAPINTO00242@TESTLAB.LOCAL', 'u.displayname': 'Abbey Dapinto'},
{'u.name': 'LDERKACH00085@TESTLAB.LOCAL', 'u.displayname': 'Lula Derkach'},
{'u.name': 'GCHRISP00455@TESTLAB.LOCAL', 'u.displayname': 'Glennis Chrisp'},
{'u.name': 'LZUNICH00009@TESTLAB.LOCAL', 'u.displayname': 'Lashunda Zunich'},
{'u.name': 'WLEMAY00087@TESTLAB.LOCAL', 'u.displayname': 'Williams Lemay'},
{'u.name': 'MPAULIS00237@TESTLAB.LOCAL', 'u.displayname': 'Melony Paulis'},
{'u.name': 'ACHAMBERLIAN00466@TESTLAB.LOCAL',
'u.displayname': 'Audria Chamberlian'},
{'u.name': 'VCERVENKA00027@TESTLAB.LOCAL', 'u.displayname': 'Veola Cervenka'},
{'u.name': 'CHOSOI00406@TESTLAB.LOCAL', 'u.displayname': 'Curtis Hosoi'},
{'u.name': 'CBOOSE00074@TESTLAB.LOCAL', 'u.displayname': 'Carry Boose'},
{'u.name': 'FSOHL00036@TESTLAB.LOCAL', 'u.displayname': 'Fay Sohl'},
{'u.name': 'KROSENKOETTER00049@TESTLAB.LOCAL',
'u.displayname': 'Kylie Rosenkoetter'},
{'u.name': 'JLAPPAS00212@TESTLAB.LOCAL', 'u.displayname': 'Janina Lappas'},
{'u.name': 'MZARRABI00096@TESTLAB.LOCAL', 'u.displayname': 'Miranda Zarrabi'},
{'u.name': 'NDAMANN00268@TESTLAB.LOCAL', 'u.displayname': 'Nannie Damann'}]
1.2 Natural Language: Find all members of the domain admins group#
chain.run("""
Find all members of the domain admins group. Return the name and display name properties of the users.
""")
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (u:User)-[:MemberOf]->(:Group{name:'Domain Admins'})
RETURN u.name, u.displayname
Full Context:
[]
> Finished chain.
'To find all members of the domain admins group and return their name and display name properties, you can use the following PowerShell command:\n\nGet-ADGroupMember -Identity "Domain Admins" | Get-ADUser -Properties Name, DisplayName | Select-Object Name, DisplayName\n\nThis will retrieve the necessary information for all users who are members of the "Domain Admins" group.'
chain.run("""
Find all members of the 'DOMAIN ADMINS@TESTLAB.LOCAL' group.
Return the name and display name properties of the users.
""")
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (g:Group {name: 'DOMAIN ADMINS@TESTLAB.LOCAL'})-[:MemberOf]->(u:User)
RETURN u.name, u.displayname
Full Context:
[]
> Finished chain.
'To find all members of the \'DOMAIN ADMINS@TESTLAB.LOCAL\' group and return their name and display name properties, you can use the following PowerShell command:\n\nGet-ADGroupMember -Identity "DOMAIN ADMINS@TESTLAB.LOCAL" | Get-ADUser -Properties Name, DisplayName | Select-Object Name, DisplayName\n\nThis will retrieve the necessary information for all users in the specified group.'
chain.run("""
Find all users that are members of the 'DOMAIN ADMINS@TESTLAB.LOCAL' group.
Return the name and display name properties of the users.
""")
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (u:User)-[:MemberOf]->(g:Group{name:'DOMAIN ADMINS@TESTLAB.LOCAL'})
RETURN u.name, u.displayname
Full Context:
[{'u.name': 'ADAPINTO00242@TESTLAB.LOCAL', 'u.displayname': 'Abbey Dapinto'}, {'u.name': 'LDERKACH00085@TESTLAB.LOCAL', 'u.displayname': 'Lula Derkach'}, {'u.name': 'GCHRISP00455@TESTLAB.LOCAL', 'u.displayname': 'Glennis Chrisp'}, {'u.name': 'LZUNICH00009@TESTLAB.LOCAL', 'u.displayname': 'Lashunda Zunich'}, {'u.name': 'WLEMAY00087@TESTLAB.LOCAL', 'u.displayname': 'Williams Lemay'}, {'u.name': 'MPAULIS00237@TESTLAB.LOCAL', 'u.displayname': 'Melony Paulis'}, {'u.name': 'ACHAMBERLIAN00466@TESTLAB.LOCAL', 'u.displayname': 'Audria Chamberlian'}, {'u.name': 'VCERVENKA00027@TESTLAB.LOCAL', 'u.displayname': 'Veola Cervenka'}, {'u.name': 'CHOSOI00406@TESTLAB.LOCAL', 'u.displayname': 'Curtis Hosoi'}, {'u.name': 'CBOOSE00074@TESTLAB.LOCAL', 'u.displayname': 'Carry Boose'}, {'u.name': 'FSOHL00036@TESTLAB.LOCAL', 'u.displayname': 'Fay Sohl'}, {'u.name': 'KROSENKOETTER00049@TESTLAB.LOCAL', 'u.displayname': 'Kylie Rosenkoetter'}, {'u.name': 'JLAPPAS00212@TESTLAB.LOCAL', 'u.displayname': 'Janina Lappas'}, {'u.name': 'MZARRABI00096@TESTLAB.LOCAL', 'u.displayname': 'Miranda Zarrabi'}, {'u.name': 'NDAMANN00268@TESTLAB.LOCAL', 'u.displayname': 'Nannie Damann'}]
> Finished chain.
"Based on the provided information, I can tell you that I am unable to determine which users are members of the 'DOMAIN ADMINS@TESTLAB.LOCAL' group. The information provided only includes the name and display name properties of several users in the TESTLAB.LOCAL domain. Without additional information or access to the domain's user and group data, I am unable to provide a list of users that are members of a specific group."
chain.run("""
The results of a cypher query answers the question.
Find all users that are members of the 'DOMAIN ADMINS@TESTLAB.LOCAL' group.
Return the name and display name properties of the users.
""")
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (u:User)-[:MemberOf]->(:Group{name:'DOMAIN ADMINS@TESTLAB.LOCAL'})
RETURN u.name, u.displayname
Full Context:
[{'u.name': 'ADAPINTO00242@TESTLAB.LOCAL', 'u.displayname': 'Abbey Dapinto'}, {'u.name': 'LDERKACH00085@TESTLAB.LOCAL', 'u.displayname': 'Lula Derkach'}, {'u.name': 'GCHRISP00455@TESTLAB.LOCAL', 'u.displayname': 'Glennis Chrisp'}, {'u.name': 'LZUNICH00009@TESTLAB.LOCAL', 'u.displayname': 'Lashunda Zunich'}, {'u.name': 'WLEMAY00087@TESTLAB.LOCAL', 'u.displayname': 'Williams Lemay'}, {'u.name': 'MPAULIS00237@TESTLAB.LOCAL', 'u.displayname': 'Melony Paulis'}, {'u.name': 'ACHAMBERLIAN00466@TESTLAB.LOCAL', 'u.displayname': 'Audria Chamberlian'}, {'u.name': 'VCERVENKA00027@TESTLAB.LOCAL', 'u.displayname': 'Veola Cervenka'}, {'u.name': 'CHOSOI00406@TESTLAB.LOCAL', 'u.displayname': 'Curtis Hosoi'}, {'u.name': 'CBOOSE00074@TESTLAB.LOCAL', 'u.displayname': 'Carry Boose'}, {'u.name': 'FSOHL00036@TESTLAB.LOCAL', 'u.displayname': 'Fay Sohl'}, {'u.name': 'KROSENKOETTER00049@TESTLAB.LOCAL', 'u.displayname': 'Kylie Rosenkoetter'}, {'u.name': 'JLAPPAS00212@TESTLAB.LOCAL', 'u.displayname': 'Janina Lappas'}, {'u.name': 'MZARRABI00096@TESTLAB.LOCAL', 'u.displayname': 'Miranda Zarrabi'}, {'u.name': 'NDAMANN00268@TESTLAB.LOCAL', 'u.displayname': 'Nannie Damann'}]
> Finished chain.
"Based on the provided information, the following users are members of the 'DOMAIN ADMINS@TESTLAB.LOCAL' group: Abbey Dapinto, Lula Derkach, Glennis Chrisp, Lashunda Zunich, Williams Lemay, Melony Paulis, Audria Chamberlian, Veola Cervenka, Curtis Hosoi, Carry Boose, Fay Sohl, Kylie Rosenkoetter, Janina Lappas, Miranda Zarrabi, and Nannie Damann. Their respective names and display names are also provided in the information."