Submit a file to Virustotal for analysis.
This artifact is based on the multipart/form-data example here:
https://docs.velociraptor.app/knowledge_base/tips/multiparts_uploads/
This artifact can be called from within another artifact (such as one looking for files) to enrich the data made available by that artifact.
Ex.
SELECT * from Artifact.Server.Enrichment.Virustotal.FileScan(FileToScan=$YOURFILE)
NOTE: The default time to wait for scan results is set to 60 seconds. In the future, this artifact will be optimized to poll for result status instead of using a static wait interval.
name: Server.Enrichment.Virustotal.FileScan
author: Wes Lambert -- @therealwlambert
description: |
Submit a file to Virustotal for analysis.
This artifact is based on the multipart/form-data example here:
https://docs.velociraptor.app/knowledge_base/tips/multiparts_uploads/
This artifact can be called from within another artifact (such as one looking for files) to enrich the data made available by that artifact.
Ex.
`SELECT * from Artifact.Server.Enrichment.Virustotal.FileScan(FileToScan=$YOURFILE)`
NOTE: The default time to wait for scan results is set to 60 seconds. In the future, this artifact will be optimized to poll for result status instead of using a static wait interval.
type: SERVER
parameters:
- name: FileToScan
type: string
description: The file to submit to Virustotal (this refers to the file's actual path on disk).
default:
- name: TimeToWait
type: int
description: Time to wait before attempting to pull results for the file submission.
default: 60
- name: VirustotalKey
type: string
description: API key for Virustotal. Leave blank here if using server metadata store.
default:
sources:
- queries:
- |
LET Creds = if(
condition=VirustotalKey,
then=VirustotalKey,
else=server_metadata().VirustotalKey)
- |
LET Url <= 'https://www.virustotal.com/api/v3/'
- |
LET Boundary <= "-----------------------------9051914041544843365972754266"
- |
LET File(Filename, ParameterName, Data) = format(
format='--%s\nContent-Disposition: form-data; name="%s"; filename="%v"\nContent-Type: text/plain\n\n%s\n',
args=[Boundary, ParameterName, Filename, Data])
- |
LET END = format(format="--%s--\n", args=Boundary)
- |
LET Submission = SELECT * FROM chain(
a={SELECT parse_json(data=Content).data.id AS SubmissionId FROM http_client(
method="POST",
url=Url + 'files',
headers=dict(`x-apikey`=Creds, `Content-Type`="multipart/form-data; boundary=" + Boundary),
data=File(Filename=path_split(path=FileToScan)[1], ParameterName="file", Data=read_file(filename=FileToScan)) + END)},
b={SELECT sleep(time=TimeToWait) FROM scope()}
)
- |
LET Analysis = SELECT parse_json(data=Content) AS Content FROM http_client(
method="GET",
url=Url + 'analyses/' + Submission.SubmissionId[0],
headers=dict(`x-apikey`=Creds))
- |
SELECT path_split(path=FileToScan)[1] AS Filename,
Content.data.attributes.stats AS Stats,
Content.data.attributes.results AS Results,
Content.meta.file_info AS _FileInfo,
Content AS _Data
FROM Analysis