This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Core Tasks

Find out about Storing, Modifying, Retrieving, and Analyzing your Attack Flow

Flow Manager provides three core capabilities:

  • Write flows to the database
  • Modify flows (under construction)
  • Read triples from the database. (this may be triples, but it may non-triple queries such as returning the created date for all flows.)

These three steps form the basic building blocks of the use cases laid out in the Tutorial section.

1 - Write Flows

How to upload a flow, written in json-schema, RDF, or SPARQL, to Flow Manager.

The first task you’ll take in Flow Manager is to store a flow.

POST /flows API

To store a flow, you’ll need two things:

  • A flow
  • an API token and associated graph

The flow can take three forms:

  • JSON that conforms to the Attack Flow json-schema. (Currently, Flow Manager supports V1 of the attack flow schema.) You can find a detailed explanation of how to use Flow Builder V1 to generate a flow in the Concepts section.
  • A RDF graph in json-ld format that conforms to the Attack Flow SHACL constraints.
  • A SPARQL query that creates a graph that conforms to the SHACL constraints.

The API itself is rather simple. Queries are passed as JSON in the body of a POST request.

{
    "token": TOKEN,
    "version": "0.0.1",
    "graph": "default",
    "attack_flow_version": "1",
    "builder": True,
    "best_practices": False,
    "flow": flow
}

token A random string used to identify the user.

version is the version of the API. The current version of the API can be found in the API Reference.

graph The graph is the named graph to store into. Flow Manager supports multiple distinct graph per token, however all tokens have a ‘default’ graph.

attack_flow_version This is the version of the Attack Flow schema used for the flow file. It is only applicable if flow is an Attack Flow json-schema object (as is created by Flow Builder). Supported versions are listed in the API Reference.

builder This indicates if the flow was generated in Flow Builder. Taken in combination with attack_flow_version, Flow Manager will make modifications to the flow such as correcting the flow namespace and giving actions and assets unique names.

best_practices (Currently not used) Best practices will attempt to apply best practices (such as using UUIDs in NamedIndividual IRIs). If builder is true, best_practices are applied regardless of this setting as Flow Builder V1 creates flows with some, we’ll say, issues. In general, best practices should be on, however it will be provided an an option for those who wish to write flows exactly as they are provided to the API.

flow The flow. For RDF and json-schema flows, a JSON object (not a string). For SPARQL queries, the SPARQL query string.

initNs Optionally, rather than specify PREFIXes in the SPARQL query, a dictionary of namespaces can be supplied to replace in the SELECT statement itself. The dictionary takes the form {"foaf": "http://xmlns.com/foaf/0.1/"} for example, then allowing foaf:workplaceHomepage \"http://infosecanalytics.com\" to be used in the query. If not using, do not include in the query.

POST /flows Responses

The returned response will return a JSON response.

{'id': 'deee77fe-d73c-4f34-843e-937e5132637e',
 'result': "35 triples added to graph 'default'",
 'success': True,
 'timestamp': '2022-12-07T22:23:09.098009'}

All responses will contain a few things: id A unique ID of the query timestamp A timestamp for the query success Logical value on if the query was successful or not result More detail about the result.

{'error': {'message': 'You did something wrong formulating either the URI or '
                      'your SPARQL query',
           'type': 'query_error'},
 'id': '9ab51e53-97de-408f-ae62-88bbe3c0a2f2',
 'result': 'error',
 'success': False,
 'timestamp': '2022-12-08T20:57:17.330628'}

In case of an error, the return will include an error property containing an object with both the error message and the type of error.

2 - Modify Flows

How to modify flows and context stored in Flow Manager.

Just a foreword, SPARQL, like any query language, can be picky. http://www.sparql.org/ has several validators you can use to find errors in your queries.

The Modify API is for making changes to the flow graph. It can be used to add, change, or remove from the graph.

WARNING The modify API is more like a SQL interface than the write API. It is possible with the modify API to do general things that SPARQL allows. This includes destructive changes. Be careful when using!

The modify API is very similar to the other APIs with the difference that it uses a PUT request.

PUT /flows API

To store a flow, you’ll need two things:

  • A valid SPARQL query
  • an API token and associated graph

The key to the modify API is the SPARQL request. It will likely take the form of an INSERT clause to add data to the graph or a DELETE clause to remove data from the graph. The modify API will not accept SELECT clauses. See the SPARQL Updates page for ideas on how to update the graph.

NOTE Due to a platform limitiation, PREFIX statements do not work in the modify API. Instead, use the initNs parameter to list namespaces that will be replaced in the query body itself.

Queries are passed as JSON in the body of a PUT request.

{
    "token": TOKEN,
    "version": "0.0.1",
    "graph": "default",
    "flow": sparql,
    "initNs": {"foaf": "http://xmlns.com/foaf/0.1/"}
}

token A random string used to identify the user.

version is the version of the API. The current version of the API can be found in the API Reference.

graph The graph is the named graph to store into. Flow Manager supports multiple distinct graph per token, however all tokens have a ‘default’ graph.

initNs Optionally, rather than specify PREFIXes in the SPARQL query, a dictionary of namespaces can be supplied to replace in the SELECT statement itself. The dictionary takes the form {"foaf": "http://xmlns.com/foaf/0.1/"} for example, then allowing foaf:workplaceHomepage \"http://infosecanalytics.com\" to be used in the query. If not using, do not include in the query.

The difference from the POST API is that builder, best_practices, and attack_flow_version will be ignored if provided.

PUT /flows Responses

The returned response will return a JSON response.

{
    "id": "aec7ccd5-d4cb-48a1-882f-23fa765c400c",
    "result": "Update succeeded.",
    "success": true,
    "timestamp": "2022-12-10T02:28:42.268548"
}

All responses will contain a few things: id A unique ID of the query timestamp A timestamp for the query success Logical value on if the query was successful or not result More detail about the result.

{'error': {'message': 'You did something wrong formulating either the URI or '
                      'your SPARQL query',
           'type': 'query_error'},
 'id': '9ab51e53-97de-408f-ae62-88bbe3c0a2f2',
 'result': 'error',
 'success': False,
 'timestamp': '2022-12-08T20:57:17.330628'}

In case of an error, the return will include an error property containing an object with both the error message and the type of error.

EXAMPLE

Mirroring the example on the Update Concepts page, we can implement similar queries in the Flow Manager API to replace Unspecified authors with a named one.

First we’ll insert the author:

{
    "token": TOKEN,
    "version": "0.0.1",
    "graph": "default",
    "flow": "INSERT DATA \
{ \
  flows:flow--41e0cd93-6fb2-4786-94ab-5adec21960cc af#author flows:person--4c49da73 .\
  <urn:absolute:flows#person--4c49da73> a foaf:Person, owl:NamedIndividual;\
      foaf:firstName "Gabriel";\
      foaf:family_name "Bassett";\
      foaf:workplaceHomepage "http://infosecanalytics.com" .\
}",
    "initNs": {"foaf": "http://xmlns.com/foaf/0.1/", 
               "flows": "urn:absolute:flows#",
               "owl": "http://www.w3.org/2002/07/owl#",
               "af": "https://attackflow.space/attack-flow#"}
}

Note that we don’t use PREFIX clauses, but instead initNs’s. We can then DELETE the previous Unidentified authors and connect the flows to the new author.

{
    "token": TOKEN,
    "version": "0.0.1",
    "graph": "default",
    "flow": "DELETE {\
      ?flow flows:author flows:Unspecified .\
} \
INSERT { \
  ?flow flows:author flows"person--4c49da73 .\
} \
WHERE {\
      ?flow flows:author flows:Unspecified .\
}",
    "initNs": {"foaf": "http://xmlns.com/foaf/0.1/", 
               "flows": "urn:absolute:flows#",
               "owl": "http://www.w3.org/2002/07/owl#",
               "af": "https://attackflow.space/attack-flow#"}
}

3 - Read Flows

How to read flows and context stored in Flow Manager.

Reading flows can be challenging. With graphs, there is not necessarily a specific place to ‘start’ the way there might be with a JSON tree. Instead you need to pick a starting place based on the question you want to answer.

  • Do you want to retrieve a specific flow? Look it up by IRI. You forgot the IRI? Humm, maybe by name. The name was something rather generic that you either don’t remember or there are multiple of? Maybe look it up by created time. (The time the flow was created, not the time it was uploaded or it actually happened.) Still not sure what it was? You’re going to have to do some searching, either by properties, or matching text in descriptions and such.
  • Do you want to collect general flows? Maybe try looking for nodes with no parents (i.e. edges that point to them)
  • Do you want to know more about a specific action? start with that node in your graph (maybe https://attackflow.spaces/veris#Phishing)

GET /flows API

The API is very similar to the POST API.

get_body = {
    "token": TOKEN,
    "version": "0.0.1",
    "graph": "default",
    "flow": query_sparql
}

token A random string used to identify the user.

version is the version of the API. The current version of the API can be found in the API Reference.

graph The graph is the named graph to store into. Flow Manager supports multiple distinct graph per token, however all tokens have a ‘default’ graph.

flow A SPARQL string query reading data. (INSERT, UPDATE, and DELETE queries will not be accepted.) See the SPARQL Concepts page for more details on SPARQL queries.

initNs Optionally, rather than specify PREFIXes in the SPARQL query, a dictionary of namespaces can be supplied to replace in the SELECT statement itself. The dictionary takes the form {"foaf": "http://xmlns.com/foaf/0.1/"} for example, then allowing foaf:workplaceHomepage \"http://infosecanalytics.com\" to be used in the query. If not using, do not include in the query.

The difference from the POST API is that builder, best_practices, and attack_flow_version will be ignored if provided.

GET /flows response

The returned response will return a JSON response.

{'id': 'deee77fe-d73c-4f34-843e-937e5132637e',
 'result': ...,
 'success': True,
 'timestamp': '2022-12-07T22:23:09.098009'}

All responses will contain a few things: id A unique ID of the query timestamp A timestamp for the query success Logical value on if the query was successful or not result More detail about the result. If successful, it will be the JSON SPARQL response stringified (requiring something such as json.loads(x.json()['result']) to read.)

{'error': {'message': 'You did something wrong formulating either the URI or '
                      'your SPARQL query',
           'type': 'query_error'},
 'id': '9ab51e53-97de-408f-ae62-88bbe3c0a2f2',
 'result': 'error',
 'success': False,
 'timestamp': '2022-12-08T20:57:17.330628'}

In case of an error, the return will include an error property containing an object with both the error message and the type of error.

SPARQL responses

Lets assune you’ve already loaded the json string from the result (result = json.loads(x.json()['result'])).

SPARQL does not return a graph. It can return information that can be formed back into a graph such as with select DISTINCT ?s ?p ?o ..., but it can also return more tabular data (for example select DISTINCT ?flow ?name ?description ?author ...).

Because of this, it’s on the user to parse the response in the way appropriate to what they requested.

{
  "head": {
    "vars": [...]
  },
  "results": {
    "bindings": [...]
  }
}

in general, sparql JSON results are a dictionary of two lists. Variables is a list of strings representing the variable names in the SELECT ... statement (For example "vars": ["s", "r", "d"]) while bindings is the actual data. Each item in “bindings” is an object with keys for the variables and values of objects containing a ’type’ and ‘value’, for example:

{
  "s": {
    "type": "uri",
    "value": "urn:absolute:flows#action_653f8cfb-dce0-40b9-89af-1af9c4172340"
  },
  "r": {
    "type": "uri",
    "value": "https://attackflow.space/attack-flow#flow"
  },
  "d": {
    "type": "uri",
    "value": "urn:absolute:flows#Flow_605eeda8-2628-4897-b68c-e54b144d4e97"
  }
}

The above item from the binding list represents the triple (urn:absolute:flows#action_653f8cfb-dce0-40b9-89af-1af9c4172340, https://attackflow.space/attack-flow#flow, urn:absolute:flows#Flow_605eeda8-2628-4897-b68c-e54b144d4e97).

If the SPARQL query returns triples, it can then be used to recreate the graph.