Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Device identifier module #900

Merged
merged 7 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
9 changes: 9 additions & 0 deletions artemis/binds.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ class TaskType(str, Enum):
# {URL: just a HTTP URL. Must have content attached to make further operations faster}
URL = "url"

# {device: having an ip, port, ssl, and a device type, e.g. Device.FORTIOS}
Matie26 marked this conversation as resolved.
Show resolved Hide resolved
DEVICE = "device"


class Service(str, Enum):
# Each of the services can have the SSL flag enabled - therefore HTTP covers both HTTP and HTTPS.
Expand Down Expand Up @@ -58,6 +61,12 @@ def _missing_(cls, value: object) -> WebApplication:
return WebApplication.UNKNOWN


class Device(str, Enum):
UNKNOWN = "unknown"

FORTIOS = "fortios"


class TaskStatus(str, Enum):
OK = "OK"
ERROR = "ERROR"
Expand Down
2 changes: 2 additions & 0 deletions artemis/http_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class HTTPResponse:
encoding: str
is_redirect: bool
url: str
headers: Dict[str, str]

def json(self) -> Any:
return json.loads(self.content)
Expand Down Expand Up @@ -79,6 +80,7 @@ def _internal_request() -> HTTPResponse:
encoding=response.encoding if response.encoding else "utf-8",
is_redirect=bool(response.history),
url=response.url,
headers=response.headers,
)

return throttle_request(_internal_request) # type: ignore
Expand Down
53 changes: 53 additions & 0 deletions artemis/modules/device_identifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from karton.core import Task

from artemis import http_requests
from artemis.binds import Device, Service, TaskStatus, TaskType
from artemis.module_base import ArtemisBase
from artemis.task_utils import get_target_host, get_target_url


class DeviceIdentifier(ArtemisBase):
"""
Tries to identify the device (FortiOS, ...) and produces a SERVICE task with proper type (e.g. Device.FORTIOS)
Matie26 marked this conversation as resolved.
Show resolved Hide resolved
"""

identity = "device_identifier"

filters = [
{"type": TaskType.SERVICE.value, "service": Service.HTTP.value},
kazet marked this conversation as resolved.
Show resolved Hide resolved
]

@staticmethod
def _identify(url: str) -> Device:
response = http_requests.get(url, allow_redirects=True)
if "xxxxxxxx-xxxxx" in response.headers.get("Server", "") and "/remote/login" in response.url:
return Device.FORTIOS

return Device.UNKNOWN

def _process(self, current_task: Task, url: str, host: str, port: int) -> None:
device = self._identify(url)

new_task = Task(
{
"type": TaskType.DEVICE,
"device": device,
},
payload={"host": host, "port": int(port), "ssl": current_task.get_payload("ssl")},
)
self.add_task(current_task, new_task)

self.db.save_task_result(task=current_task, status=TaskStatus.OK, data=device)

def run(self, current_task: Task) -> None:
url = get_target_url(current_task)
host = get_target_host(current_task)
port = current_task.get_payload("port")

self.log.info(f"device identifier scanning {url}")

self._process(current_task, url, host, port)


if __name__ == "__main__":
DeviceIdentifier().loop()
11 changes: 11 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,17 @@ services:
restart: always
volumes: ["./docker/karton.ini:/etc/karton/karton.ini", "${DOCKER_COMPOSE_ADDITIONAL_SHARED_DIRECTORY:-./shared}:/shared/"]

karton-device_identifier:
build:
context: .
dockerfile: docker/Dockerfile
command: "python3 -m artemis.modules.device_identifier"
depends_on: [karton-system]
env_file: .env
restart: always
volumes: ["./docker/karton.ini:/etc/karton/karton.ini", "${DOCKER_COMPOSE_ADDITIONAL_SHARED_DIRECTORY:-./shared}:/shared/"]


volumes:
data-nuclei-templates:
data-nuclei-config:
Expand Down
Loading