Ejemplo n.º 1
0
def test_add_nodes_no_overlap(nx):
    proc = Process(process_id=10,
                   process_image="test.exe",
                   command_line="test.exe /c foobar")
    other_proc = Process(process_id=12,
                         process_image="best.exe",
                         command_line="best.exe /c 123456")

    proc.launched[other_proc].append(timestamp=1)

    backend = NetworkX(consolidate_edges=True, nodes=[proc, other_proc])
    G = backend.graph()

    assert len(G.nodes()) == 2
    assert len(G.edges()) == 1

    # Add in a new pair of nodes.
    proc2 = Process(process_id=4,
                    process_image="malware.exe",
                    command_line="malware.exe /c foobar")
    f = File(file_name="foo", file_path="bar")
    proc2.wrote[f]

    G = backend.add_nodes([proc2, f])

    # Graph grew
    assert len(G.nodes()) == 4
    assert len(G.edges()) == 2
Ejemplo n.º 2
0
def adhoc():
    """Allows for ad-hoc transformation of generic JSON Data based on one of two CIM models:

    1. The Beagle CIM Model (defined in `constants.py`)
    2. The OSSEM Model (defined in https://github.com/Cyb3rWard0g/OSSEM)
    """

    valid_cim_formats = ["beagle"]
    data = request.get_json()
    events = data["data"]
    cim_format = data.get("cim", "beagle")

    if str(cim_format).lower() not in valid_cim_formats:
        response = jsonify({"message": f"cim_format must be in {cim_format}"})

        return response

    if not isinstance(events, list):
        events = [events]

    logger.info(f"Beginning ad-hoc graphing request")

    g = JSONData(events).to_graph(consolidate_edges=True)

    logger.info(f"Completed ad-hoc graphing request")

    return jsonify({"data": NetworkX.graph_to_json(g)})
Ejemplo n.º 3
0
def test_from_datasources():
    packets_1 = [
        Ether(src="ab:ab:ab:ab:ab:ab", dst="12:12:12:12:12:12") /
        IP(src="127.0.0.1", dst="192.168.1.1") / TCP(sport=12345, dport=80) /
        HTTP() /
        HTTPRequest(Method="GET", Path="/foo", Host="https://google.com")
    ]

    packets_2 = [
        # HTTP Packet
        Ether(src="ab:ab:ab:ab:ab:ab", dst="12:12:12:12:12:12") /
        IP(src="127.0.0.1", dst="192.168.1.1") / TCP(sport=12345, dport=80) /
        HTTP() /
        HTTPRequest(Method="GET", Path="/foo", Host="https://google.com"),
        # DNS Packet
        Ether(src="ab:ab:ab:ab:ab:ab", dst="12:12:12:12:12:12") /
        IP(src="127.0.0.1", dst="192.168.1.1") / UDP(sport=80, dport=53) /
        DNS(rd=1,
            qd=DNSQR(qtype="A", qname="google.com"),
            an=DNSRR(rdata="123.0.0.1")),
        # TCP Packet
        Ether(src="ab:ab:ab:ab:ab:ab", dst="12:12:12:12:12:12") /
        IP(src="127.0.0.1", dst="192.168.1.1") / TCP(sport=80, dport=5355),
    ]

    nx = NetworkX.from_datasources([
        packets_to_datasource_events(packets)
        for packets in [packets_1, packets_2]
    ])

    # Make the graph
    nx.graph()

    assert not nx.is_empty()
Ejemplo n.º 4
0
def test_from_json_object(nx):
    proc = Process(process_id=10, process_image="test.exe", command_line=None)
    other_proc = Process(process_id=12, process_image="best.exe", command_line="best.exe /c 123456")

    proc.launched[other_proc]

    G = nx(nodes=[proc, other_proc])

    _json_output = NetworkX.graph_to_json(G)

    assert isinstance(_json_output, dict)

    G2 = NetworkX.from_json(_json_output)

    # Graphs should be equal.
    assert networkx.is_isomorphic(G, G2)
Ejemplo n.º 5
0
def test_from_json_path(nx, tmpdir):
    proc = Process(process_id=10, process_image="test.exe", command_line=None)
    other_proc = Process(process_id=12, process_image="best.exe", command_line="best.exe /c 123456")

    proc.launched[other_proc]

    G = nx(nodes=[proc, other_proc])

    _json_output = NetworkX.graph_to_json(G)

    # Save to file
    p = tmpdir.mkdir("networkx").join("data.json")
    p.write(json.dumps(_json_output))

    G2 = NetworkX.from_json(p)

    # Graphs should be equal.
    assert networkx.is_isomorphic(G, G2)
Ejemplo n.º 6
0
def test_add_node_overlaps_existing(nx):
    proc = Process(process_id=10,
                   process_image="test.exe",
                   command_line="test.exe /c foobar")
    other_proc = Process(process_id=12,
                         process_image="best.exe",
                         command_line="best.exe /c 123456")

    proc.launched[other_proc].append(timestamp=1)

    backend = NetworkX(consolidate_edges=True, nodes=[proc, other_proc])
    G = backend.graph()

    assert len(G.nodes()) == 2
    assert len(G.edges()) == 1

    # Add a new node that *overlaps* an existing node (note - not the same node object.)
    proc2 = Process(process_id=10,
                    process_image="test.exe",
                    command_line="test.exe /c foobar")
    f = File(file_name="foo", file_path="bar")
    proc2.wrote[f]

    G = backend.add_nodes([proc2, f])

    # Graph grew, but only 3 nodes.
    assert len(G.nodes()) == 3
    assert len(G.edges()) == 2

    # Process should have both write and launched edges.

    u = hash(proc2)
    v = hash(other_proc)
    v2 = hash(f)

    assert networkx.has_path(G, u, v)
    assert networkx.has_path(G, u, v2)
    assert "Launched" in G[u][v]
    assert "Wrote" in G[u][v2]
Ejemplo n.º 7
0
def test_from_json_fails_on_invalid(nx, tmpdir):
    with pytest.raises(ValueError):

        NetworkX.from_json({})
    with pytest.raises(ValueError):

        NetworkX.from_json({"nodes": []})
    with pytest.raises(ValueError):

        NetworkX.from_json({"links": []})
Ejemplo n.º 8
0
def _save_graph_to_db(backend: NetworkX, category: str, graph_id: int = None) -> dict:
    """Saves a graph to the database, optionally forcing an overwrite of an existing graph.

    Parameters
    ----------
    backend : NetworkX
        The NetworkX object to save
    category : str
        The category
    graph_id: int
        The graph ID to override.

    Returns
    -------
    dict
        JSON to return to client with ID and path.
    """
    # Take the SHA256 of the contents of the graph.
    contents_hash = hashlib.sha256(
        json.dumps(backend.to_json(), sort_keys=True).encode("utf-8")
    ).hexdigest()

    # See if we have previously generated this *exact* graph.
    existing = Graph.query.filter_by(meta=backend.metadata, sha256=contents_hash).first()

    if existing:
        logger.info(f"Graph previously generated with id {existing.id}")
        return {"id": existing.id, "self": f"/{existing.category}/{existing.id}"}

    dest_folder = category.replace(" ", "_").lower()

    # Set up the storage directory.
    dest_path = f"{Config.get('storage', 'dir')}/{dest_folder}/{contents_hash}.json"
    os.makedirs(f"{Config.get('storage', 'dir')}/{dest_folder}", exist_ok=True)

    json.dump(backend.to_json(), open(dest_path, "w"))

    if graph_id:
        db_entry = Graph.query.filter_by(id=graph_id).first()
        # set the new hash.
        db_entry.file_path = f"{contents_hash}.json"
        db_entry.sha256 = contents_hash
        # NOTE: Old path is not deleted.

    else:
        db_entry = Graph(
            sha256=contents_hash,
            meta=backend.metadata,
            comment=request.form.get("comment", None),
            category=dest_folder,  # Categories use the lower name!
            file_path=f"{contents_hash}.json",
        )
        # Add new entry
        db.session.add(db_entry)

    db.session.commit()

    logger.info(f"Added graph to database with id={db_entry.id}")

    logger.info(f"Saved graph to {dest_path}")

    return {"id": db_entry.id, "self": f"/{dest_folder}/{db_entry.id}"}
Ejemplo n.º 9
0
def test_empty_graph(nx):
    backend = NetworkX(nodes=[], consolidate_edges=True)
    backend.graph()
    assert backend.is_empty()
Ejemplo n.º 10
0
 def _backend(*args, **kwargs) -> networkx.Graph:
     return NetworkX(*args, consolidate_edges=True,
                     **kwargs).graph()  # type: ignore