Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
608fb9f
Fix bulk call example in README.md
Jul 12, 2019
dfc1cd0
Update Darwin header
Jul 12, 2019
8a7e504
Merge pull request #1 from VultureProject/small_fixes
Raznak Jul 15, 2019
a0f6b87
Merge pull request #2 from VultureProject/darwin_async
Jul 15, 2019
d062018
Merge branch 'dev' into darwin_async
Jul 19, 2019
072be45
Handle no/darwin types better
Jul 19, 2019
880060d
Add filter codes
NS4nti Jul 22, 2019
c76f219
Add event id
NS4nti Jul 23, 2019
7b5e6f8
Merge pull request #3 from VultureProject/return-event-id
Jul 23, 2019
34be607
Fix PEP8 syntax + Improve Python descr function
Jul 24, 2019
81e7f1b
Merge branch 'darwin_async' into pep8_fixes
Jul 24, 2019
cadf168
Handle case with no certitude for back/both modes
Jul 24, 2019
b6ffc6c
Remove useless file
Jul 24, 2019
a6cac92
Merge pull request #4 from VultureProject/pep8_fixes
NS4nti Jul 25, 2019
2e9d453
Improve comments and version
Jul 25, 2019
1ee999b
Fix version number
Jul 25, 2019
31b30eb
Merge pull request #5 from VultureProject/improve_comments
NS4nti Jul 25, 2019
ad41829
Add tests
Jul 26, 2019
5ef892b
Add requirements
Jul 26, 2019
ee8240b
Add TCP support
Jul 26, 2019
2dad603
Add README
Jul 26, 2019
a30cec6
Set error message color to red
Jul 26, 2019
e4edda7
Fix & add host and port description in README
Jul 26, 2019
b35bce3
Handle response type
Jul 26, 2019
0bc02f2
Update README with response type
Jul 26, 2019
0224fe3
Update variation filter tests
Jul 26, 2019
9d6d7a0
Add filter code
NS4nti Jul 29, 2019
5547b60
Add debug mode
Jul 29, 2019
a09f66a
Improve logs
Jul 29, 2019
b00835a
Allow setting the debug mode individually
Jul 29, 2019
9ad8c78
Improve README: add debug mode & argument types
Jul 29, 2019
5d85252
Clean tests_descr.py, leaving only two examples
Jul 29, 2019
c37b8e7
Merge pull request #7 from VultureProject/add-tests
Raznak Jul 30, 2019
a27ddf2
Add missing socket_type when calling the DPC
Jul 31, 2019
868155e
Update darwinapi.py
NS4nti Jul 31, 2019
3ce88bb
Merge pull request #6 from VultureProject/add-filter-code
Jul 31, 2019
6b6b5e8
Merge pull request #8 from VultureProject/missing-tcp-type
NS4nti Jul 31, 2019
8342195
Fix "no" and "darwin" tests with bulk results
Aug 1, 2019
70fe48b
Merge pull request #9 from VultureProject/fix-darwin-and-no-tests
Raznak Aug 1, 2019
51fffc3
Add time performance values
Aug 1, 2019
789677e
Merge pull request #10 from VultureProject/add-time-performance
frikilax Aug 1, 2019
2fcef29
Close socket when an exception occurs
Aug 5, 2019
ac1e0f4
Merge pull request #11 from VultureProject/close-socket-exception
frikilax Aug 5, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ darwin_api.call(
Same than point **3**, but the data has to be given in a list to make it... bulky. Hm...

```python
darwin_api.call(
darwin_api.bulk_call(
[
["example.com"],
["1jd1d0w9dsaj10245dsaf.tk"],
Expand Down
10 changes: 10 additions & 0 deletions darwin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
#!/usr/bin/env python

"""__init__.py: Import classes used in the Darwin Python package"""

__author__ = "gcatto"
__version__ = "1.0"
__date__ = "20/02/19"
__license__ = "GPLv3"
__copyright__ = "Copyright (c) 2019 Advens. All rights reserved."

from .darwinapi import DarwinApi

from .darwinexceptions import (
Expand Down
137 changes: 62 additions & 75 deletions darwin/darwinapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
"""darwin.py: Provide an API which allows the user to call Darwin filters from Python code"""

__author__ = "gcatto"
__version__ = "1.2"
__version__ = "1.0"
__date__ = "22/01/19"
__license__ = "GPLv3"
__copyright__ = "Copyright (c) 2018 Advens. All rights reserved."
__copyright__ = "Copyright (c) 2019 Advens. All rights reserved."


# "pip" imports
import ctypes
import json
import socket
import time
import uuid

# local imports
from .darwinprotocol import DarwinPacket
Expand Down Expand Up @@ -48,7 +49,8 @@ class DarwinApi:
Return a filter code from a given filter name. This is case insensitive

low_level_call(self, **kwargs)
Perform an API call to Darwin, and return the results
Perform an API call to Darwin, and return the results or the event ID, depending on wheter the call is
asynchronous or not

call(self,
arguments,
Expand Down Expand Up @@ -80,6 +82,10 @@ class DarwinApi:
"reputation": 0x72657075,
"session": 0x73657373,
"useragent": 0x75736572,
"logs": 0x4C4F4753,
"anomaly": 0x414D4C59,
"tanomaly": 0x544D4C59,
"end": 0x454E4453,
}

DEFAULT_TIMEOUT = 10
Expand Down Expand Up @@ -154,7 +160,7 @@ def __init__(self, **kwargs):

try:
self.socket.connect(darwin_socket_path)
except ConnectionError as error:
except socket.error as error:
raise DarwinConnectionError(str(error))

else:
Expand All @@ -179,7 +185,7 @@ def __init__(self, **kwargs):

try:
self.socket.connect((darwin_socket_host, darwin_socket_port))
except ConnectionError as error:
except socket.error as error:
raise DarwinConnectionError(str(error))

def low_level_call(self, **kwargs):
Expand All @@ -204,8 +210,9 @@ def low_level_call(self, **kwargs):

Returns
-------
dict
the Darwin results. Currently, the dictionary only contains them, stored in a "certitude_list" key
dict/str
if the call is synchronous, the Darwin results are returned as a dictionary, stored in a "certitude_list"
key. If the call is asynchronous, the event ID is returned
"""

if self.verbose:
Expand All @@ -214,15 +221,22 @@ def low_level_call(self, **kwargs):
darwin_header = kwargs.get("header", None)
darwin_data = kwargs.get("data", None)
darwin_body = json.dumps(darwin_data)
darwin_certitude = -1

if darwin_header is None:
darwin_header_descr = kwargs.get("header_descr", None)

if darwin_header_descr is None:
raise DarwinInvalidArgumentError("DarwinApi:: low_level_call:: No header nor description header given")

darwin_header = DarwinPacket(**darwin_header_descr, verbose=self.verbose)
event_id = uuid.uuid4().hex

if self.verbose:
print("DarwinApi:: low_level_call:: UUID computed: {event_id} ".format(
event_id=event_id,
))

darwin_header_descr["event_id"] = event_id
darwin_header = DarwinPacket(verbose=self.verbose, **darwin_header_descr)

try:
darwin_packet_len = ctypes.sizeof(DarwinPacket) + ctypes.sizeof(ctypes.c_uint) * (len(darwin_data) - 1)
Expand All @@ -239,11 +253,14 @@ def low_level_call(self, **kwargs):

if self.verbose:
print("DarwinApi:: low_level_call:: Body size in the Darwin header set to {body_size}".format(
body_size=darwin_header.body_size,
body_size=darwin_header.body_size,
))

print("DarwinApi:: low_level_call:: Sending header to Darwin...")
print("DarwinApi:: low_level_call:: Header description: " + str(darwin_header.get_python_descr()))

print("DarwinApi:: low_level_call:: Header description: {header_descr}".format(
header_descr=darwin_header.get_python_descr()
))

self.socket.sendall(darwin_header)

Expand All @@ -264,7 +281,6 @@ def low_level_call(self, **kwargs):
if self.verbose:
print("DarwinApi:: low_level_call:: Receiving response from Darwin...")


try:
bytes_received = 0
raw_response = b''
Expand Down Expand Up @@ -302,6 +318,8 @@ def low_level_call(self, **kwargs):
"certitude_list": certitude_list
}

return event_id

except Exception as error:
print("DarwinApi:: low_level_call:: Something wrong happened while calling the Darwin filter")
raise error
Expand Down Expand Up @@ -337,22 +355,36 @@ def call(self,

Returns
-------
int
the Darwin result
int/None/str
if the call is synchronous, the Darwin result is returned. If no result are available, None is returned. If
the call is asynchronous, the event ID is returned
"""

results = self.bulk_call([arguments],
packet_type=packet_type,
response_type=response_type,
filter_code=filter_code,
**kwargs)

return result["certitude_list"][0]
if response_type == "back" or response_type == "both":
try:
return results["certitude_list"][0]
except IndexError:
if self.verbose:
print("DarwinApi:: call:: No certitude returned")

return None

else:
return results

def close(self):
"""
"""

print("DarwinApi:: low_level_call:: Closing socket")
if self.verbose:
print("DarwinApi:: close:: Closing socket")

self.socket.close()

def bulk_call(self,
Expand Down Expand Up @@ -381,7 +413,7 @@ def bulk_call(self,
associated to it

kwargs :
other keyword arguments can be given. This function uses darwin.DarwinApi.low_level_call" internally. For a
other keyword arguments can be given. This function uses darwin.DarwinApi.low_level_call internally. For a
more advanced use, please refer to the darwin.DarwinApi.low_level_call method documentation

Returns
Expand All @@ -397,61 +429,16 @@ def bulk_call(self,
raise DarwinInvalidArgumentError("DarwinApi:: call:: The filter code provided "
"(\"{filter_code}\") does not exist. "
"Accepted values are: {accepted_values}".format(
filter_code=filter_code,
accepted_values=", ".join(self.FILTER_CODE_MAP.keys()),
))

return self.low_level_call(header_descr={
"packet_type": packet_type,
"response_type": response_type,
"filter_code": filter_code,
},
data=data,
**kwargs)


if __name__ == "__main__":
print("__main__:: {file_name} has been called directly. Demo:".format(file_name=__file__), )

print("\n***\n")
# parameters needed for the demo
# body: what the Darwin filter will take as an input

body = "GET /helloworld.html HTTP/1.1 accept: application/xml authorization: "\
"Basic WXVxb3N1YXI6dTR4UEI4NDc2Mzll referer: https://mysuperwebsite.com/helloworld.html "\
"host: livemysuperwebsite.mysuperwebsite.org"

# socket_path: the Darwin filter socket path
socket_path = "/var/sockets/darwin/injection_1.sock"
# response_type:
# > "no": no response from Darwin
# > "back": Darwin responds directly to the caller
# > "darwin": Darwin sends the response to the next filter
# > "both": Darwin responds back to the caller, and sends the response to the next filter
response_type = "back"
# filter_code: the unique ID of the Darwin filter
filter_code = DarwinApi.get_filter_code("injection")

print("__main__:: Asking the injection filter whether this request is malicious or not:")
print(body)

print("\n***\n")
print("__main__:: Calling DarwinApi...")

darwin_api = DarwinApi(socket_path=socket_path,
socket_type="unix", )

# you call also call the Darwin API with the "raw call" function (low_level_call), which is called by call:
# darwin_response = darwin_api.low_level_call(header_descr={
# "response_type": response_type,
# "filter_code": filter_code,
# },
# body=body, )

darwin_api.close()

print("\n***\n")
print("__main__:: Response received from the Darwin filter:")
print("__main__:: {darwin_response}".format(darwin_response=darwin_response, ))
print("\n***\n")
print("__main__:: End of demo!")
filter_code=filter_code,
accepted_values=", ".join(self.FILTER_CODE_MAP.keys()),
))

return self.low_level_call(
header_descr={
"packet_type": packet_type,
"response_type": response_type,
"filter_code": filter_code,
},
data=data,
**kwargs
)
5 changes: 2 additions & 3 deletions darwin/darwinexceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
"""exceptions.py: List different exceptions that can be raised/used in the Darwin Python Library"""

__author__ = "gcatto"
__version__ = "1.2"
__version__ = "1.0"
__date__ = "22/01/19"
__license__ = "GPLv3"
__copyright__ = "Copyright (c) 2018 Advens. All rights reserved."
__copyright__ = "Copyright (c) 2019 Advens. All rights reserved."


class DarwinInvalidArgumentError(ValueError):
Expand Down Expand Up @@ -34,7 +34,6 @@ class DarwinConnectionError(ValueError):
pass



class DarwinTimeoutError(ValueError):
"""
A class used to raise an exception when the darwinapi.DarwinApi object waited too much time for a reply from
Expand Down
Loading