diff --git a/flowsint-enrichers/src/flowsint_enrichers/ip/to_fraudscore.py b/flowsint-enrichers/src/flowsint_enrichers/ip/to_fraudscore.py index ff31eb7a..3ceb7014 100644 --- a/flowsint-enrichers/src/flowsint_enrichers/ip/to_fraudscore.py +++ b/flowsint-enrichers/src/flowsint_enrichers/ip/to_fraudscore.py @@ -74,11 +74,16 @@ class IpToFraudScore(Enricher): self.ip_risk_mapping = [] api_username = self.get_secret("SCAMLYTICS_USERNAME", os.getenv("SCAMLYTICS_USERNAME")) - api_key = self.get_secret("SCAMLYTICS_API_KEY", os.getenv("SCAMLYTICS_API_KEY")) + api_key = self.get_secret("SCAMLYTICS_API_KEY", os.getenv("SCAMLYTICS_API_KEY")) + # Scamalytics assigns each account a numbered API node (api11, api12, + # ...); a hardcoded host 404s for every account that is not on it. + api_host = self.get_secret( + "SCAMLYTICS_API_HOST", os.getenv("SCAMLYTICS_API_HOST", "api12") + ) for ip in data: try: - api_request = requests.get(f'https://api12.scamalytics.com/v3/{api_username}/?key={api_key}&ip={ip.address}', timeout=30) + api_request = requests.get(f'https://{api_host}.scamalytics.com/v3/{api_username}/?key={api_key}&ip={ip.address}', timeout=30) if api_request.status_code != 200: Logger.error( diff --git a/flowsint-enrichers/src/tools/dockertool.py b/flowsint-enrichers/src/tools/dockertool.py index bf906668..94077da8 100644 --- a/flowsint-enrichers/src/tools/dockertool.py +++ b/flowsint-enrichers/src/tools/dockertool.py @@ -46,7 +46,7 @@ class DockerTool(Tool): except ImageNotFound: return False - def launch(self, command: str, volumes: dict = None, timeout: int = 30, environment: dict = None): + def launch(self, command, volumes: dict = None, timeout: int = 30, environment: dict = None, entrypoint=None): self.install() # Merge default environment with custom environment env = {"TERM": "dumb"} # Set terminal type to avoid TTY issues @@ -54,8 +54,7 @@ class DockerTool(Tool): env.update(environment) try: - result = self.client.containers.run( - self.image, + run_kwargs = dict( command=command, remove=True, stdout=True, @@ -67,6 +66,11 @@ class DockerTool(Tool): stdin_open=False, # Ensure stdin is not open environment=env, ) + # Some tools only accept a single target on stdin, which needs a + # shell in front of the image's default entrypoint. + if entrypoint is not None: + run_kwargs["entrypoint"] = entrypoint + result = self.client.containers.run(self.image, **run_kwargs) return result.decode() except ImageNotFound: raise RuntimeError(f"Image {self.image} not found. Did you run install()?") diff --git a/flowsint-enrichers/src/tools/network/dnsx.py b/flowsint-enrichers/src/tools/network/dnsx.py index 57d88b30..cfa140ce 100644 --- a/flowsint-enrichers/src/tools/network/dnsx.py +++ b/flowsint-enrichers/src/tools/network/dnsx.py @@ -1,4 +1,5 @@ import json +import shlex from typing import List from ..dockertool import DockerTool @@ -109,14 +110,20 @@ class DnsxTool(DockerTool): flags.append("-aaaa") flags += ["-json", "-silent"] - command = f"-d {domain} {' '.join(flags)}" + # dnsx >= 1.2 treats `-d` as "bruteforce this domain" and refuses to + # run without a `-w` wordlist, so a plain `-d example.com` exits with + # "missing wordlist(w) flag required with domain(d) input" and the + # enricher silently returns nothing. Feeding the single target on + # stdin is the supported invocation. + inner = f"dnsx {' '.join(flags)}" + command = ["-c", f"echo {shlex.quote(domain)} | {inner}"] env = {} if api_key: env["PDCP_API_KEY"] = api_key try: - result = super().launch(command, environment=env) + result = super().launch(command, environment=env, entrypoint="sh") except Exception as e: raise RuntimeError( f"Error running dnsx: {str(e)}. Output: {getattr(e, 'output', 'No output')}"