diff --git a/pyproject.toml b/pyproject.toml index df082b9..dcfaa4d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "polyswarm" -version = "3.19.0" +version = "3.20.0" description = "CLI for using the PolySwarm Customer APIs" readme = "README.md" authors = [{ name = "PolySwarm Developers", email = "info@polyswarm.io" }] @@ -22,7 +22,7 @@ classifiers = [ ] dependencies = [ - "polyswarm_api>=3.20.0", + "polyswarm_api>=3.21.0", "click>=7.1", "colorama>=0.4.6", "click-log>=0.4.0", @@ -51,7 +51,7 @@ include-package-data = true where = ["src"] [tool.bumpversion] -current_version = "3.19.0" +current_version = "3.20.0" commit = true tag = false sign_tags = true diff --git a/src/polyswarm/__init__.py b/src/polyswarm/__init__.py index 786602c..c170b8d 100644 --- a/src/polyswarm/__init__.py +++ b/src/polyswarm/__init__.py @@ -1 +1 @@ -__version__ = '3.19.0' +__version__ = '3.20.0' diff --git a/src/polyswarm/client/sandbox.py b/src/polyswarm/client/sandbox.py index 79075ca..3c69c4e 100644 --- a/src/polyswarm/client/sandbox.py +++ b/src/polyswarm/client/sandbox.py @@ -32,6 +32,35 @@ def submit(ctx, provider_slug, artifact_id, vm_slug, internet_disabled): output.sandbox_task(tasks) +@sandbox.command('hash', short_help='Submit by hash (sha256/sha1/md5) to be sandboxed.') +@click.argument('provider_slug', type=click.STRING) +@click.argument('hash_value', nargs=-1, required=True) +@click.option('-r', '--hash-file', help='File of hashes, one per line.', type=click.File('r')) +@click.option('--hash-type', help='Hash type [default:autodetect, sha256|sha1|md5].', default=None) +@click.option('--vm_slug', 'vm_slug', type=click.STRING) +@click.option('--internet-disabled', 'internet_disabled', type=click.BOOL, is_flag=True, default=False) +@click.pass_context +def hash_(ctx, provider_slug, hash_value, hash_file, hash_type, vm_slug, internet_disabled): + """ + Submit a sample to the sandbox by hash. Resolves the hash to its latest + known artifact instance and sandboxes that instance. + """ + api = ctx.obj['api'] + output = ctx.obj['output'] + hashes = utils.parse_hashes(hash_value, hash_file=hash_file) + + instance_ids = [] + for h in hashes: + instance = next(iter(api.search_hashes([h], hash_type=hash_type)), None) + if instance is None: + raise click.ClickException(f'No artifact instances found for hash {h}') + instance_ids.append(instance.id) + + for task in api.sandbox_instances( + instance_ids, provider_slug=provider_slug, vm_slug=vm_slug, network_enabled=not internet_disabled): + output.sandbox_task(task) + + @sandbox.command('file', short_help='Submit a local file to be sandboxed.') @click.argument('provider', type=click.STRING) @click.argument('path', type=click.Path(exists=True), required=True) diff --git a/src/polyswarm/formatters/hashes.py b/src/polyswarm/formatters/hashes.py index 3cfbeef..b40a572 100644 --- a/src/polyswarm/formatters/hashes.py +++ b/src/polyswarm/formatters/hashes.py @@ -45,6 +45,18 @@ def _to_json(result): def artifact_instance(self, result, timeout=False): click.echo(result.sha1, file=self.out) + def historical_result(self, result): + if result.sha1: + click.echo(result.sha1, file=self.out) + else: + logger.warning('Could not render historical result as sha1, value is %s', result.sha1) + + def live_result(self, result): + if result.sha1: + click.echo(result.sha1, file=self.out) + else: + logger.warning('Could not render live result as sha1, value is %s', result.sha1) + def metadata(self, result): if result.sha1: click.echo(result.sha1, file=self.out) @@ -62,6 +74,18 @@ def _to_json(result): def artifact_instance(self, result, timeout=False): click.echo(result.md5, file=self.out) + def historical_result(self, result): + if result.md5: + click.echo(result.md5, file=self.out) + else: + logger.warning('Could not render historical result as md5, value is %s', result.md5) + + def live_result(self, result): + if result.md5: + click.echo(result.md5, file=self.out) + else: + logger.warning('Could not render live result as md5, value is %s', result.md5) + def metadata(self, result): if result.md5: click.echo(result.md5, file=self.out) diff --git a/src/polyswarm/formatters/text.py b/src/polyswarm/formatters/text.py index 9c682f1..bf07719 100644 --- a/src/polyswarm/formatters/text.py +++ b/src/polyswarm/formatters/text.py @@ -174,6 +174,10 @@ def historical_result(self, result, write=True): output.append(self._blue(f'Instance Id: {result.instance_id}')) output.append(self._white(f'Created at: {result.created}')) output.append(self._white(f'SHA256: {result.sha256}')) + if result.sha1: + output.append(self._white(f'SHA1: {result.sha1}')) + if result.md5: + output.append(self._white(f'MD5: {result.md5}')) output.append(self._white(f'Rule: {result.rule_name}')) if result.malware_family: output.append(self._red(f'Malware Family: {result.malware_family}')) @@ -201,6 +205,10 @@ def live_result(self, result, write=True): output.append(self._blue(f'Instance Id: {result.instance_id}')) output.append(self._white(f'Created at: {result.created}')) output.append(self._white(f'SHA256: {result.sha256}')) + if result.sha1: + output.append(self._white(f'SHA1: {result.sha1}')) + if result.md5: + output.append(self._white(f'MD5: {result.md5}')) output.append(self._white(f'Rule: {result.rule_name}')) if result.malware_family: output.append(self._red(f'Malware Family: {result.malware_family}'))