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

New analyser : Google Vision API #297

Merged
merged 2 commits into from
Jul 14, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
30 changes: 30 additions & 0 deletions analyzers/GoogleVisionAPI/GoogleVisionAPI_WebDetection.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "GoogleVisionAPI_WebDetection",
"version": "1.0.0",
"author": "CERT-LaPoste",
"url": "https://github.com/TheHive-Project/Cortex-Analyzers",
"license": "AGPL-V3",
"description": "Find look alike image via Google Cloud Vision API using the Web_Detection service ",
"dataTypeList": ["file", "url"],
"command": "GoogleVisionAPI/GoogleVisionAPI_WebDetection.py",
"baseConfig": "GoogleVisionAPI",
"config": {
"service": "get"
},
"configurationItems": [
{
"name": "api_key",
"description": "API key for this service",
"type": "string",
"multi": false,
"required": true
},
{
"name": "max_Result",
"description": "Maximum number of url to fetch",
"type": "string",
"multi": false,
"required": false
}
]
}
80 changes: 80 additions & 0 deletions analyzers/GoogleVisionAPI/GoogleVisionAPI_WebDetection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/usr/bin/python3
#coding:utf-8

from cortexutils.analyzer import Analyzer
from requests import post
from json import dumps, loads
from base64 import b64encode

class GoogleAPI_Vision(Analyzer):

def __init__(self):
Analyzer.__init__(self)
self.api_endpoint = "https://vision.googleapis.com/v1/images:annotate"

def make_api_call(self, url: str, query: str, api_key: str, https_proxy: str, maxResults: int, datatype: str, file=None) -> dict:

header = {
"Content-Type" : "application/json"
}

data = {
"requests": [{
"image": {
"source": {
"imageUri": query
}
},
"features": [{
"type": "WEB_DETECTION",
"maxResults": maxResults
}]
}]
}

if datatype == "file":
try:
query = b64encode(open(file, "rb").read()).decode("utf-8")
except FileNotFoundError:
self.error("Error while reading provided file")
else:
del data["requests"][0]["image"]["source"]
data["requests"][0]["image"]["content"] = query

try:
api_answser = loads(post(url + "?key=" + api_key, data=dumps(data), headers=header, proxies=https_proxy).text)
except ValueError:
self.error("Cannot parse JSON answer from server")
else:
return api_answser

def get_artifacts(self, google_results: str) -> list:
return [ item["url"] for item in google_results['responses'][0]["webDetection"]["pagesWithMatchingImages"]]

def run(self):
query = self.getData()

if query is None:
self.error("You must provide a file or a valid url to this image")

api_key = self.getParam("config.api_key")
if api_key is None:
self.error("You need an API key for Google Vision API")

https_proxy = { "https" : self.getParam("config.proxy_https") }
maxResults = self.getParam("config.max_Result")
maxResults = maxResults if maxResults is not None else 100

answer = self.make_api_call(self.api_endpoint, query, api_key, https_proxy, maxResults, self.data_type, file=self.getParam("file"))
self.report({ 'api_full_report' : answer })

def summary(self, raw):

number_of_image_found = self.build_taxonomy("info", "GoogleVisionAPI", "pagesWithMatchingImages", str(len(raw["api_full_report"]["responses"][0]["webDetection"]["pagesWithMatchingImages"])))
number_of_look_alike = self.build_taxonomy("info", "GoogleVisionAPI", "visuallySimilarImages", str(len(raw["api_full_report"]["responses"][0]["webDetection"]["visuallySimilarImages"])))

return { "taxonomies" : [number_of_look_alike, number_of_image_found] }


if __name__ == "__main__":
GoogleAPI_Vision().run()
2 changes: 2 additions & 0 deletions analyzers/GoogleVisionAPI/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cortexutils
requests
72 changes: 72 additions & 0 deletions thehive-templates/GoogleVisionAPI_WebDetection_1_0_0/long.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!-- Success -->
<div class="panel panel-primary" ng-if="content.api_full_report.responses[0].webDetection.pagesWithMatchingImages.length > 0">
<div class="panel-heading">
Pages with matching images
</div>
<div class="panel-body">
<dl class="dl-horizontal" >
<strong>Number of pages found : </strong> {{ content.api_full_report.responses[0].webDetection.pagesWithMatchingImages.length }}
<dd>
<div ng-repeat="pages in content.api_full_report.responses[0].webDetection.pagesWithMatchingImages | limitTo:50">
<span class="wrap"><a ng-href="{{ pages.url }}" target="_blank">{{pages.pageTitle }}</a></span>
</div>
</dd>
</dl>
</div>
</div>

<div class="panel panel-primary" ng-if="content.api_full_report.responses[0].webDetection.visuallySimilarImages.length > 0">
<div class="panel-heading">
Visually Similar Images
</div>
<div class="panel-body">
<dl class="dl-horizontal" >
<strong>Number of similar image found : </strong> {{ content.api_full_report.responses[0].webDetection.visuallySimilarImages.length }}
<dd>
<div ng-repeat="similar in content.api_full_report.responses[0].webDetection.visuallySimilarImages | limitTo:50">
<span class="wrap"><a ng-href="{{ similar.url }}" target="_blank">{{similar.url }}</a></span>
</div>
</dd>
</dl>
</div>
</div>

<div class="panel panel-primary" ng-if="content.api_full_report.responses[0].webDetection.webEntities.length > 0">
<div class="panel-heading">
Web Entities
</div>
<div class="panel-body">
<dd>
<div ng-repeat="entities in content.api_full_report.responses[0].webDetection.webEntities | limitTo:50">
<span class="wrap" ng-if="entities.description.length >0"><strong>{{ entities.description }} : </strong>{{ entities.score }}</span>
</div>
</dd>
</div>
</div>

<!-- General error -->
<div class="panel panel-danger" ng-if="content.api_full_report.error">
<div class="panel-heading">
<strong>An error occured</strong>
</div>
<div class="panel-body">
<dl class="dl-horizontal">
<dt><i class="fa fa-warning"></i> {{ content.api_full_report.error.status }} :</dt>
<dd class="wrap">{{content.api_full_report.error.message}}</dd>
</dl>
</div>
</div>

<div class="panel panel-danger" ng-if="!content.success">
<div class="panel-heading">
<strong>An error occured</strong>
</div>
<div class="panel-body">
<dl class="dl-horizontal">
<dt><i class="fa fa-warning"></i> {{ content.errorMessage }} :</dt>
<dd class="wrap">{{content.input}}</dd>
</dl>
</div>
</div>


Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<span class="label" ng-repeat="t in content.taxonomies"
ng-class="{'info': 'label-info', 'safe': 'label-success',
'suspicious': 'label-warning',
'malicious':'label-danger'}[t.level]">
{{t.namespace}}:{{t.predicate}}={{t.value}}
</span>