Leveraging Altair to Visualize BloodHound Results


Import Libraries

from py2neo import Graph
import plotly.graph_objects as go
import altair as alt
alt.renderers.enable('notebook')
Copy to clipboard
RendererRegistry.enable('notebook')
Copy to clipboard

Initialize BloodHound neo4j Database Connection

g = Graph("bolt://206.189.85.93:7687", auth=("neo4j", "BloodHound"))
g
Copy to clipboard
<Graph database=<Database uri='bolt://206.189.85.93:7687' secure=False user_agent='py2neo/4.3.0 neobolt/1.7.15 Python/3.7.3-final-0 (linux)'> name='data'>
Copy to clipboard

Retrieve Security Groups with Local Admin Rights over Computers

Now we’ll construct the Cypher query that tells us the name of each security group in Active Directory and the number of computers that group has local admin rights on.

sg_computers_df = g.run("""
MATCH (g:Group)
OPTIONAL MATCH (g)-[:AdminTo]->(c1:Computer)
OPTIONAL MATCH (g)-[:MemberOf*1..]->(:Group)-[:AdminTo]->(c2:Computer)
WITH g, COLLECT(c1) + COLLECT(c2) AS tempVar
UNWIND tempVar AS computers
RETURN g.name AS GroupName,COUNT(DISTINCT(computers)) AS AdminRightCount
ORDER BY AdminRightCount DESC
""").to_data_frame()
Copy to clipboard
sg_computers_df
Copy to clipboard
GroupName AdminRightCount
0 DOMAIN ADMINS@TOKYO.JAPAN.LOCAL 6
1 DESKTOPADMINS@TOKYO.JAPAN.LOCAL 4
2 DOMAIN ADMINS@JAPAN.LOCAL 4
3 MACHINEADMINS@JAPAN.LOCAL 3
4 ENTERPRISE ADMINS@JAPAN.LOCAL 2
5 DOMAIN ADMINS@SINGAPORE.LOCAL 2
6 ENTERPRISE ADMINS@SINGAPORE.LOCAL 1
7 WORKSTATIONADMINS@SINGAPORE.LOCAL 1

Create Horizontal Bar Chart: Most Privileged Active Directory Security Groups

bars = alt.Chart(sg_computers_df, title="Most Privileged Active Directory Security Groups").mark_bar().encode(
    x='AdminRightCount:Q',
    y=alt.Y(
        "GroupName:N",
        sort=alt.EncodingSortField(
            field="AdminRightCount",
            order="descending"
        )
    )
)

text = bars.mark_text(
    align='left',
    baseline='middle',
    dx=3
).encode(
    text='AdminRightCount:Q'
)

(bars + text).properties(height=300)
Copy to clipboard
../../_images/03_altair_bloodhound_results_10_0.png

Create Horizontal Bar Chart: Most Privileged Active Directory Security Groups

users_to_da = g.run("""
MATCH (totalUsers:User {domain:'TOKYO.JAPAN.LOCAL'})
MATCH p=shortestPath((UsersWithPath:User {domain:'TOKYO.JAPAN.LOCAL'})-[r*1..]->(g:Group {name:'DOMAIN ADMINS@TOKYO.JAPAN.LOCAL'}))
WITH COUNT(DISTINCT(totalUsers)) as totalUsers, COUNT(DISTINCT(UsersWithPath)) as UsersWithPath
RETURN 100.0 * UsersWithPath / totalUsers AS percentUsersToDA
""").to_data_frame()
Copy to clipboard
users_to_da
Copy to clipboard
percentUsersToDA
0 13.580247
value_df = users_to_da['percentUsersToDA'].values[0]
value_df
Copy to clipboard
13.580246913580247
Copy to clipboard
fig = go.Figure(go.Indicator(
    domain = {'x': [0, 1], 'y': [0, 1]},
    value = (value_df),
    mode = "gauge+number",
    title = {'text': "Percentage of Users with a Path to Domain Admin"},
    gauge = {'axis': {'range': [None, 100]},
             'steps' : [{'range': [0, 250], 'color': "lightgray"}],
             'threshold' : {'line': {'color': "red", 'width': 4}, 'thickness': 0.75, 'value': 490}}))

fig.show()
         
Copy to clipboard