2020-01-15 14:40:47 +01:00
|
|
|
# Styx
|
2020-05-13 11:51:54 +02:00
|
|
|
|
2020-06-12 12:04:59 +02:00
|
|
|
## What are we trying to solve
|
2020-05-18 10:22:08 +02:00
|
|
|
|
2020-06-12 12:04:59 +02:00
|
|
|
Styx is the passive sibling of Vader. When Vader allows users to get "on-demand"
|
|
|
|
data from connectors, Styx will just ingest streams and streams of data. Styx
|
|
|
|
will find things when they are happening on the contrary of retro-hunting, Styx
|
|
|
|
find patterns in the current events and flags them on the spot. It's not
|
|
|
|
retro-hunting, it's present-hunting or even future-hunting as we hope to find
|
|
|
|
actors movement when they happen.
|
2020-05-18 10:22:08 +02:00
|
|
|
|
2020-05-13 11:51:54 +02:00
|
|
|
## Prerequisites
|
|
|
|
|
|
|
|
Styx uses a couple of other services to run:
|
|
|
|
|
2020-06-12 12:04:59 +02:00
|
|
|
* Kafka for messaging (not implemented yet in the docker, but currently not necessary)
|
2020-05-13 11:51:54 +02:00
|
|
|
* Dgraph for graph representation of results
|
2020-05-18 10:22:08 +02:00
|
|
|
* Docker-compose to launch everything
|
2020-05-13 11:51:54 +02:00
|
|
|
|
|
|
|
For that purposes, there is a `docker-compose.yml` file that you can spin up
|
|
|
|
with the following command when in the directory:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
docker-compose up -d
|
|
|
|
```
|
|
|
|
|
|
|
|
*Note*: for some reasons, OpenVPN blocks the establishment of the docker
|
|
|
|
compose, you can alternatively run Dgraph manually as such:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
docker run --rm -it -p 8080:8080 -p 9080:9080 -p 8000:8000 -v ~/dgraph:/dgraph dgraph/standalone:v20.03.0
|
|
|
|
```
|
|
|
|
|
2020-01-15 14:40:47 +01:00
|
|
|
## Install
|
|
|
|
|
|
|
|
```sh
|
|
|
|
go get -u gitlab.dcso.lolcat/LABS/styx
|
|
|
|
cd $GOPATH/src/gitlab.dcso.lolcat/LABS/styx
|
2020-08-24 16:25:49 +02:00
|
|
|
go build gitlab.dcso.lolcat/LABS/styx/cmd/styxd
|
2020-06-12 12:04:59 +02:00
|
|
|
docker-compose up -d # or the other docker command
|
2020-08-24 16:25:49 +02:00
|
|
|
./styxd
|
|
|
|
|
|
|
|
# build the loader helper binary
|
|
|
|
go build gitlab.dcso.lolcat/LABS/styx/cmd/iocloader
|
|
|
|
# update the IOC list while the programm is already running
|
2020-08-28 13:34:08 +02:00
|
|
|
./iocloader
|
2020-01-15 14:40:47 +01:00
|
|
|
```
|
2020-02-07 15:49:42 +01:00
|
|
|
|
2020-05-18 10:22:08 +02:00
|
|
|
*Note*: if you have issues with the docker compose, make sure it runs on the
|
|
|
|
same subnet. Check [this](https://serverfault.com/questions/916941/configuring-docker-to-not-use-the-172-17-0-0-range) for inspiration.
|
|
|
|
|
2020-02-10 14:40:33 +01:00
|
|
|
### Example configuration:
|
2020-08-24 16:25:49 +02:00
|
|
|
|
|
|
|
*Note*: For Pastebin, you will have to authorise your IP address when you login through the web interface.
|
|
|
|
|
2020-02-10 14:40:33 +01:00
|
|
|
```
|
2020-02-14 11:30:59 +01:00
|
|
|
certstream:
|
2020-05-20 10:03:28 +02:00
|
|
|
activated: true
|
2020-02-14 11:30:59 +01:00
|
|
|
|
|
|
|
pastebin:
|
2020-05-20 10:03:28 +02:00
|
|
|
activated: true
|
2020-02-14 11:30:59 +01:00
|
|
|
|
2020-02-10 14:40:33 +01:00
|
|
|
shodan:
|
2020-05-20 10:03:28 +02:00
|
|
|
activated: true
|
|
|
|
key: "SHODAN_KEY"
|
|
|
|
ports:
|
|
|
|
- 80
|
|
|
|
- 443
|
2020-02-10 14:40:33 +01:00
|
|
|
```
|
|
|
|
|
2020-05-13 14:52:38 +02:00
|
|
|
## Dgraph Interface
|
|
|
|
|
2020-08-24 16:25:49 +02:00
|
|
|
You can connect to the Dgraph interface at this default address: http://localhost:8000.
|
2020-05-13 14:52:38 +02:00
|
|
|
There you would be able to run GraphQL+ queries, here to query a node.
|
|
|
|
|
|
|
|
```graphql
|
|
|
|
query {
|
2020-08-24 16:25:49 +02:00
|
|
|
Node(func: eq(uid, 0x23)) {
|
2020-05-18 16:09:04 +02:00
|
|
|
uid
|
|
|
|
ndata
|
|
|
|
modified
|
2020-08-28 13:34:08 +02:00
|
|
|
nodeType
|
2020-05-18 16:09:04 +02:00
|
|
|
id
|
|
|
|
}
|
2020-05-13 14:52:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
2020-05-18 10:22:08 +02:00
|
|
|
Or filter node by type, this example works for certstream nodes:
|
|
|
|
|
|
|
|
```graphql
|
|
|
|
query {
|
2020-05-18 16:09:04 +02:00
|
|
|
Node(func: eq(type, "certstream")) {
|
|
|
|
uid
|
|
|
|
created
|
|
|
|
modified
|
2020-08-28 13:34:08 +02:00
|
|
|
nodeType
|
2020-05-18 16:09:04 +02:00
|
|
|
ndata
|
|
|
|
certNode {
|
2020-05-18 10:22:08 +02:00
|
|
|
uid
|
|
|
|
fingerprint
|
|
|
|
cn
|
|
|
|
raw {
|
|
|
|
uid
|
|
|
|
id
|
|
|
|
}
|
|
|
|
chain {
|
|
|
|
uid
|
|
|
|
id
|
|
|
|
}
|
|
|
|
sourceName
|
|
|
|
serialNumber
|
|
|
|
basicConstrains
|
|
|
|
notBefore
|
|
|
|
notAfter
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2020-05-19 10:10:42 +02:00
|
|
|
Example query for pastebin data:
|
|
|
|
|
|
|
|
```graphql
|
|
|
|
query {
|
|
|
|
Node(func: eq(type, "pastebin")) {
|
|
|
|
uid
|
|
|
|
created
|
|
|
|
modified
|
2020-08-28 13:34:08 +02:00
|
|
|
nodeType
|
2020-05-19 10:10:42 +02:00
|
|
|
ndata
|
|
|
|
pasteNode {
|
|
|
|
id
|
|
|
|
type
|
|
|
|
created
|
|
|
|
modified
|
|
|
|
fullPaste {
|
|
|
|
full
|
|
|
|
meta {
|
|
|
|
full_url
|
|
|
|
size
|
|
|
|
expire
|
|
|
|
title
|
|
|
|
syntax
|
|
|
|
user
|
|
|
|
scrape_url
|
|
|
|
date
|
|
|
|
key
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
2020-05-20 10:03:28 +02:00
|
|
|
Dgraph also supports full text search, so you can query things like:
|
|
|
|
|
2020-08-24 16:25:49 +02:00
|
|
|
```graphql
|
2020-05-20 10:03:28 +02:00
|
|
|
query {
|
|
|
|
Node(func: allofterms(full, "code")) {
|
|
|
|
uid
|
|
|
|
created
|
|
|
|
modified
|
2020-08-28 13:34:08 +02:00
|
|
|
nodeType
|
2020-05-20 10:03:28 +02:00
|
|
|
full
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The following fields have can be used as index for searches:
|
|
|
|
|
|
|
|
* id
|
|
|
|
* type
|
|
|
|
* sourceName
|
|
|
|
* cn
|
|
|
|
* serialNumber
|
|
|
|
* hostnames
|
|
|
|
* organization
|
|
|
|
* full (full text of a pastbin)
|
|
|
|
* title
|
|
|
|
* user
|
|
|
|
|
|
|
|
By design, each node has a `type` field so you know which field you should query
|
|
|
|
each time you query something.
|
|
|
|
|
2020-02-07 15:49:42 +01:00
|
|
|
## Datastructure
|
|
|
|
|
|
|
|
### Meta
|
|
|
|
|
2020-08-24 16:25:49 +02:00
|
|
|
Edges provide an existing relation between two nodes of different origin. They are part of Dgraph features.
|
2020-05-20 10:03:28 +02:00
|
|
|
|
2020-02-10 10:36:36 +01:00
|
|
|
Node --[Edge]-- Node
|
2020-02-07 17:50:07 +01:00
|
|
|
|
2020-02-07 15:49:42 +01:00
|
|
|
```go
|
|
|
|
type Node struct {
|
|
|
|
ID string `json:"id"`
|
2020-08-28 13:34:08 +02:00
|
|
|
NodeType string `json:"nodeType"`
|
2020-02-07 15:49:42 +01:00
|
|
|
Data string `json:"data"` // For plain Node, the data is the ID of another typed node or a unique value like a domain or a host name.
|
|
|
|
Created string `json:"created"`
|
|
|
|
Modified string `json:"modified"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Edge defines a relation between two nodes.
|
|
|
|
type Edge struct {
|
|
|
|
ID string `json:"id"`
|
|
|
|
NodeOneID string `json:"nodeOneID"`
|
|
|
|
NodeTwoID string `json:"nodeTwoID"`
|
|
|
|
Timestamp string `json:"timestamp"`
|
|
|
|
Source string `json:"source"`
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
### Certstream
|
|
|
|
|
2020-05-20 10:03:28 +02:00
|
|
|
Node -- CertNode -- CertStreamRaw
|
2020-02-07 17:50:07 +01:00
|
|
|
|
2020-02-07 15:49:42 +01:00
|
|
|
```go
|
|
|
|
|
|
|
|
// CertStreamRaw is a wrapper around the stream function to unmarshall the
|
|
|
|
// data receive in a Go structure.
|
|
|
|
type CertStreamRaw struct {
|
|
|
|
ID string `json:"id"`
|
2020-08-28 13:34:08 +02:00
|
|
|
NodeType string `json:"nodeType"`
|
2020-02-07 15:49:42 +01:00
|
|
|
Data CertStreamStruct `json:"data"`
|
|
|
|
Created string `json:"created"`
|
|
|
|
Modified string `json:"modified"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// CertNode represents our custom struct of data extraction from CertStream.
|
|
|
|
type CertNode struct {
|
|
|
|
ID string `json:"id"`
|
|
|
|
Fingerprint string `json:"fingerprint"`
|
|
|
|
NotBefore string `json:"notBefore"`
|
|
|
|
NotAfter string `json:"notAfter"`
|
|
|
|
CN string `json:"cn"`
|
|
|
|
SourceName string `json:"sourceName"`
|
|
|
|
SerialNumber string `json:"serialNumber"`
|
|
|
|
BasicConstraints string `json:"basicConstraints"`
|
|
|
|
RawUUID string `json:"rawUUID"`
|
|
|
|
Chain []CertNode `json:"chainedTo"`
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
### Pastebin
|
|
|
|
|
2020-05-20 10:03:28 +02:00
|
|
|
Node -- PasteNode -- FullPaste
|
2020-02-07 17:50:07 +01:00
|
|
|
|
2020-02-07 15:49:42 +01:00
|
|
|
```go
|
|
|
|
// PasteNode is a node from PasteBin.
|
|
|
|
type PasteNode struct {
|
|
|
|
ID string `json:"id"`
|
2020-08-28 13:34:08 +02:00
|
|
|
NodeType string `json:"nodeType"`
|
2020-02-07 15:49:42 +01:00
|
|
|
Data FullPaste `json:"data"`
|
|
|
|
Created string `json:"create"`
|
|
|
|
Modified string `json:"modified"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// FullPaste wrapes meta and information from Pastebin.
|
|
|
|
type FullPaste struct {
|
2020-08-28 13:34:08 +02:00
|
|
|
Meta PasteMeta `json:"meta"`
|
|
|
|
Full string `json:"full"`
|
|
|
|
NodeType string `json:"nodeType"`
|
2020-02-07 15:49:42 +01:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Shodan
|
2020-02-07 17:50:07 +01:00
|
|
|
|
2020-05-20 10:03:28 +02:00
|
|
|
Node -- ShodanNode -- Node(s) (hostnames and domains)
|
2020-02-07 17:50:07 +01:00
|
|
|
|
2020-02-07 15:49:42 +01:00
|
|
|
```go
|
|
|
|
type ShodanNode struct {
|
2020-08-28 13:34:08 +02:00
|
|
|
ID string `json:"id"`
|
|
|
|
NodeType string `json:"nodeType"`
|
|
|
|
Data *shodan.HostData `json:"data"`
|
|
|
|
Created string `json:"created"`
|
|
|
|
Modified string `json:"modified"`
|
2020-02-07 15:49:42 +01:00
|
|
|
}
|
|
|
|
```
|
2020-02-07 17:39:33 +01:00
|
|
|
|
2020-05-20 10:03:28 +02:00
|
|
|
### Balboa (not in Dgraph yet)
|
2020-02-07 17:45:37 +01:00
|
|
|
|
|
|
|
Balboa enrichment happens on domains and hostnames extracted from Certstream
|
|
|
|
and Shodan streams and the node is created only if Balboa returns data.
|
|
|
|
|
2020-05-20 10:03:28 +02:00
|
|
|
Node -- ShodanNode -- Node (domain) -- BalboaNode
|
2020-02-07 17:45:37 +01:00
|
|
|
|
|
|
|
```go
|
|
|
|
type BalboaNode struct {
|
2020-08-28 13:34:08 +02:00
|
|
|
ID string `json:"id"`
|
|
|
|
NodeType string `json:"nodeType"`
|
|
|
|
Data []balboa.Entries `json:"data"`
|
|
|
|
Created string `json:"created"`
|
|
|
|
Modified string `json:"modified"`
|
2020-02-07 17:45:37 +01:00
|
|
|
}
|
|
|
|
```
|