Skip to content
This repository has been archived by the owner on Dec 26, 2022. It is now read-only.

Commit

Permalink
New lens UX
Browse files Browse the repository at this point in the history
  • Loading branch information
insanitybit committed Oct 20, 2019
1 parent b731a9d commit fe7655d
Show file tree
Hide file tree
Showing 5 changed files with 707 additions and 231 deletions.
85 changes: 53 additions & 32 deletions README.md
@@ -1,16 +1,17 @@
## Grapl

Grapl is a Graph Platform for Detection and Response.
Grapl is a Graph Platform for Detection and Response with a focus on helping Detection Engineers stop fighting their data and start working with it. At its core, Grapl leverages graph data structures to ensure that you can and connect your data efficiently, model attacker behaviors, and easily expand suspicious behaviors to encompass a full attack scope.

For a more in depth overview of Grapl, [read this](https://insanitybit.github.io/2019/03/09/grapl).

In short, Grapl will take raw logs, convert them into graphs, and merge those graphs into a Master Graph. It will then orchestrate the execution of your attack signatures and provide tools for performing your investigations.
Essentially, Grapl will take raw logs, convert them into graphs, and merge those graphs into a Master Graph. It will then orchestrate the execution of your attack signatures, and provide tools for performing your investigations.

Grapl supports nodes for:

- Processes (Beta)
- Files (Beta)
- Networking (Alpha)
- Processes
- Files
- Networking
- Plugin nodes, which can be used to arbitrarily extend the graph

and currently parses Sysmon logs or a generic JSON log format to generate these graphs.

Expand All @@ -24,65 +25,79 @@ and currently parses Sysmon logs or a generic JSON log format to generate these

If you’re familiar with log sources like Sysmon, one of the best features is that processes are given identities. Grapl applies the same concept but for any supported log type, taking psuedo identifiers such as process ids and discerning canonical identities.

Grapl then combines this identity concept with its graph approach, making it easy to reason about entities and their behaviors. Further, this identity property means that Grapl stores only unique information from your logs, meaning that your data storage grows sublinear to the log volume.

This cuts down on storage costs and gives you central locations to view your data, as opposed to having it spread across thousands of logs. As an example, given a process’s canonical identifier you can view all of the information for it by selecting the node.

![](https://d2mxuefqeaa7sj.cloudfront.net/s_7CBC3A8B36A73886DC59F4792258C821D6717C3DB02DA354DE68418C9DCF5C29_1553026555668_image.png)


**Analyzers (Beta)**
**Analyzers**

Analyzers are your attacker signatures. They’re Python modules, deployed to Grapl’s S3 bucket, that are orchestrated to execute upon changes to grapl’s Master Graph.

Analyzers execute in realtime as the master graph is updated.
Rather than analyzers attempting to determine a binary "Good" or "Bad" value for attack behaviors Grapl leverges a concept of Risk, and then automatically correlates risks to surface the riskiest parts of your environment.

Analyzers execute in realtime as the master graph is updated, using constant time operations. Grapl's Analyzer harness will automatically batch, parallelize, and optimize your queries. By leveraging constant time and sublinear operations Grapl ensures that as your organization grows, and as your data volume grows with it, you can still rely on your queries executing efficiently.

Grapl provides an analyzer library (alpha) so that you can write attacker signatures using pure Python. See this [repo for examples](https://github.com/insanitybit/grapl-analyzers).
Grapl provides an analyzer library so that you can write attacker signatures using pure Python. See this [repo for examples](https://github.com/insanitybit/grapl-analyzers).

Here is a brief example of how to detect a suspicious execution of `svchost.exe`,
```python
valid_parents = get_svchost_valid_parents()
p = (
ProcessQuery()
.with_process_name(eq=valid_parents)
.with_children(
ProcessQuery().with_process_name(eq="svchost.exe")
class SuspiciousSvchost(Analyzer):

def get_queries(self) -> OneOrMany[ProcessQuery]:
invalid_parents = [
Not("services.exe"),
Not("smss.exe"),
Not("ngentask.exe"),
Not("userinit.exe"),
Not("GoogleUpdate.exe"),
Not("conhost.exe"),
Not("MpCmdRun.exe"),
]

return (
ProcessQuery()
.with_process_name(eq=invalid_parents)
.with_children(
ProcessQuery().with_process_name(eq="svchost.exe")
)
)
.query_first(client, contains_node_key=process.node_key)
)

def on_response(self, response: ProcessView, output: Any):
output.send(
ExecutionHit(
analyzer_name="Suspicious svchost",
node_view=response,
risk_score=75,
)
)
```
Keeping your analyzers in code means you can:

- Code review your alerts
- Write tests, integrate into CI
- Build abstractions, reuse logic, and generally follow best practices for maintaining software

**Engagements (alpha)**

Grapl provides a tool for investigations called an Engagement. Engagements are an isolated graph representing a subgraph that your analyzers have deemed suspicious.

Using AWS Sagemaker hosted Jupyter Notebooks, Grapl will (soon) provide a Python library for interacting with the Engagement Graph, allowing you to pivot quickly and maintain a record of your investigation in code.


![](https://d2mxuefqeaa7sj.cloudfront.net/s_7CBC3A8B36A73886DC59F4792258C821D6717C3DB02DA354DE68418C9DCF5C29_1553037156946_file.png)
Check out Grapl's [analyzer deployer plugin](https://github.com/insanitybit/grapl-analyzer-deployer) to see how you can keep your analyzers in a git repo that automatically deploys them upon a push to master.

**Engagements**

Grapl provides a live updating view of the engagement graph as you interact with it in the notebook, currently in alpha.
Grapl provides a tool for investigations called an Engagement. Engagements are an isolated graph representing a subgraph that your analyzers have deemed suspicious.

Using AWS Sagemaker hosted Jupyter Notebooks and Grapl's provided Python library you can expand out any suspicious subgraph to encompass the full scope of an attack.
As you expand the attack scope with your Jupyter notebook the Engagement Graph will update, visually representing the attack scope.

![](https://raw.githubusercontent.com/insanitybit/grapl/master/images/engagement.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/650602/images/6646682/Screenshot_from_2019-10-11_20-24-34.png)

**Event Driven and Extendable**

Grapl was built to be extended - no service can satisfy every organization’s needs. Every native Grapl service works by sending and receiving events, which means that in order to extend Grapl you only need to start subscribing to messages.

This makes Grapl trivial to extend or integrate into your existing services.

![](https://d2mxuefqeaa7sj.cloudfront.net/s_7CBC3A8B36A73886DC59F4792258C821D6717C3DB02DA354DE68418C9DCF5C29_1553040182040_file.png)



![](https://d2mxuefqeaa7sj.cloudfront.net/s_7CBC3A8B36A73886DC59F4792258C821D6717C3DB02DA354DE68418C9DCF5C29_1553040197703_file.png)

Grapl also provides a Plugin system, currently in beta, that allows you to expand the platforms capabilities - adding custom nodes and querying capabilities.

## Setup

Expand Down Expand Up @@ -111,6 +126,12 @@ It will require confirming some changes to security groups, and will take a few

This will give you a Grapl setup that’s adequate for testing out the service.

At this point you just need to provision the Graph databases. You can use the Graph Provision notebook in this repo, and
the newly created 'engagement' notebook in your AWS account.

![](https://s3.amazonaws.com/media-p.slid.es/uploads/650602/images/6396963/Screenshot_from_2019-07-27_22-27-35.png)


You can send some test data up to the service by going to the root of the grapl repo and calling:
`python ./gen-raw-logs.py <your bucket prefix>`.

Expand Down
1 change: 1 addition & 0 deletions engagement_ux/engagement_view/index.html
Expand Up @@ -18,6 +18,7 @@
<h1>Lenses</h1>
<div id="LenseTable"></div>


<script src="index.js"></script>

</body>
Expand Down
33 changes: 19 additions & 14 deletions engagement_ux/engagement_view/index.js
Expand Up @@ -2,7 +2,7 @@

console.log('Loaded index.js');

const engagement_edge = "";
const engagement_edge = "https://jzfee2ecp8.execute-api.us-east-1.amazonaws.com/prod/";

console.log(`Connecting to ${engagement_edge}`);

Expand All @@ -25,27 +25,24 @@ const nodeToTable = (lens) => {
header += `<th scope="col">score</th>`;
header += `<th scope="col">link</th>`;

output += `<td>${lens.lens}</td>>`;
output += `<td>${lens.score}</td>>`;
output += `<td>${lens.lens}</td>`;
output += `<td>${lens.score}</td>`;
// output += `<td><a href="${engagement_edge}lens.html?lens=${lens.lens}">link</td></a>>`;
output += `<td><a href="lens.html?lens=${lens.lens}">link</td></a>>`;

output += `<td><a href="lens.html?lens=${lens.lens}">link</a></td>`;

return `${header}</tr></thead>` + `${output}</tr><tbody>`;
};

const getLensesLoop = () => {

};

document.addEventListener('DOMContentLoaded', async (event) => {
console.log('DOMContentLoaded');

const getLensesLoop = async () => {
const lenses = (await getLenses()).lenses;
console.log(lenses);

if (lenses.length === 0) {
console.log("No active lenses");

setTimeout(async () => {
await getLensesLoop();
}, 1000);
return
}

Expand All @@ -59,10 +56,18 @@ document.addEventListener('DOMContentLoaded', async (event) => {
}
// Sort the lenses by their score
lensRows.sort((row_a, row_b) => {
return row_a.score - row_b.score
return row_a.score - row_b.score
});
const lensRowsStr = lensRows.join("")
const lensRowsStr = lensRows.join("");
lenseTable.innerHTML = `<table>${lensRowsStr}</table>`;


setTimeout(async () => {
await getLensesLoop();
}, 1000)
};

document.addEventListener('DOMContentLoaded', async (event) => {
console.log('DOMContentLoaded');
getLensesLoop();
});
18 changes: 10 additions & 8 deletions engagement_ux/engagement_view/lens.html
Expand Up @@ -8,17 +8,19 @@
<meta name="description" content="spooky">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!--<link rel="manifest" href="site.webmanifest">-->
<!--<link rel="apple-touch-icon" href="icon.png">-->
<!-- Place favicon.ico in the root directory -->

</head>

<body>
<h1>Lens</h1>
<canvas id="network" width="1000" height="600"></canvas>
<h1 id="LensHeader">Lens</h1>
<div id="nodes"></div>
<div id="graph"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.2/d3.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.2/d3.js"></script>
<script src="lens.js"></script>
<script src="https://unpkg.com/three"></script>
<script src="https://unpkg.com/three-spritetext"></script>
<script src="https://unpkg.com/3d-force-graph"></script>
<script src="https://unpkg.com/force-graph"></script>
<script src="lens.js"></script>
</body>

0 comments on commit fe7655d

Please sign in to comment.