Server.Enrichment.Virustotal.FileScan

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