|
|
|
---
|
|
|
|
output: rmarkdown::github_document
|
|
|
|
editor_options:
|
|
|
|
chunk_output_type: console
|
|
|
|
---
|
|
|
|
```{r pkg-knitr-opts, include=FALSE}
|
|
|
|
hrbrpkghelpr::global_opts()
|
|
|
|
```
|
|
|
|
|
|
|
|
```{r badges, results='asis', echo=FALSE, cache=FALSE}
|
|
|
|
hrbrpkghelpr::stinking_badges()
|
|
|
|
```
|
|
|
|
|
|
|
|
```{r description, results='asis', echo=FALSE, cache=FALSE}
|
|
|
|
hrbrpkghelpr::yank_title_and_description()
|
|
|
|
```
|
|
|
|
|
|
|
|
## What's Inside The Tin
|
|
|
|
|
|
|
|
The following functions are implemented:
|
|
|
|
|
|
|
|
```{r ingredients, results='asis', echo=FALSE, cache=FALSE}
|
|
|
|
hrbrpkghelpr::describe_ingredients()
|
|
|
|
```
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
|
|
```{r install-ex, results='asis', echo=FALSE, cache=FALSE}
|
|
|
|
hrbrpkghelpr::install_block()
|
|
|
|
```
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
```{r lib-ex}
|
|
|
|
library(brimr)
|
|
|
|
library(tibble)
|
|
|
|
|
|
|
|
# current version
|
|
|
|
packageVersion("brimr")
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
### Available Brim "spaces"
|
|
|
|
|
|
|
|
```{r available-brim-spaces, cache=TRUE}
|
|
|
|
brim_spaces()
|
|
|
|
```
|
|
|
|
|
|
|
|
### Sample ZQL query
|
|
|
|
|
|
|
|
```{r sample-zql-query, cache=TRUE}
|
|
|
|
# Z query to fetch Zeek connection data to create our network connection graph
|
|
|
|
zql1 <- '_path=conn | count() by id.orig_h, id.resp_h, id.resp_p | sort id.orig_h, id.resp_h, id.resp_p'
|
|
|
|
|
|
|
|
cat(
|
|
|
|
substr(jsonlite::toJSON(jsonlite::fromJSON(brim_ast(zql1)), pretty = TRUE), 1, 100), "..."
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
### Let's execute the query
|
|
|
|
|
|
|
|
```{r zeek-query-execution, cache=TRUE}
|
|
|
|
space <- "2021-02-17-Trickbot-gtag-rob13-infection-in-AD-environment.pcap"
|
|
|
|
|
|
|
|
r1 <- brim_search(space, zql1)
|
|
|
|
|
|
|
|
r1
|
|
|
|
|
|
|
|
(r1 <- as_tibble(tidy_brim(r1)))
|
|
|
|
```
|
|
|
|
|
|
|
|
### Let's try one that processes the Suricata alerts
|
|
|
|
|
|
|
|
```{r suricata-query-execution, cache=TRUE}
|
|
|
|
# Z query to fetch Suricata alerts including the count of alerts per source:destination
|
|
|
|
zql2 <- "event_type=alert | count() by src_ip, dest_ip, dest_port, alert.severity, alert.signature | sort src_ip, dest_ip, dest_port, alert.severity, alert.signature"
|
|
|
|
|
|
|
|
r2 <- brim_search(space, zql2)
|
|
|
|
|
|
|
|
r2
|
|
|
|
|
|
|
|
(r2 <- (as_tibble(tidy_brim(r2))))
|
|
|
|
```
|
|
|
|
|
|
|
|
```{r graph, fig.width = 9, cache=TRUE}
|
|
|
|
library(igraph)
|
|
|
|
library(ggraph)
|
|
|
|
library(tidyverse)
|
|
|
|
|
|
|
|
gdf <- count(r1, orig_h, resp_h, wt=count)
|
|
|
|
|
|
|
|
count(gdf, node = resp_h, wt=n, name = "in_degree") %>%
|
|
|
|
full_join(
|
|
|
|
count(gdf, node = orig_h, name = "out_degree")
|
|
|
|
) %>%
|
|
|
|
mutate_at(
|
|
|
|
vars(in_degree, out_degree),
|
|
|
|
replace_na, 1
|
|
|
|
) %>%
|
|
|
|
arrange(in_degree) -> vdf
|
|
|
|
|
|
|
|
g <- graph_from_data_frame(gdf, vertices = vdf)
|
|
|
|
|
|
|
|
ggraph(g, layout = "linear") +
|
|
|
|
geom_node_point(
|
|
|
|
aes(size = in_degree), shape = 21
|
|
|
|
) +
|
|
|
|
geom_edge_arc(
|
|
|
|
width = 0.125,
|
|
|
|
arrow = arrow(
|
|
|
|
length = unit(5, "pt"),
|
|
|
|
type = "closed"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
### Use `zq` directly
|
|
|
|
|
|
|
|
```{r zq_cmdline, cache=TRUE}
|
|
|
|
zq_cmd(
|
|
|
|
c(
|
|
|
|
'"* | cut ts,id.orig_h,id.orig_p"', # note the quotes
|
|
|
|
system.file("logs", "conn.log.gz", package = "brimr")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
## brimr Metrics
|
|
|
|
|
|
|
|
```{r cloc, echo=FALSE}
|
|
|
|
cloc::cloc_pkg_md()
|
|
|
|
```
|
|
|
|
|
|
|
|
## Code of Conduct
|
|
|
|
|
|
|
|
Please note that this project is released with a Contributor Code of Conduct.
|
|
|
|
By participating in this project you agree to abide by its terms.
|