├── License.md
├── README.md
└── VirusTotal.psm1
/License.md:
--------------------------------------------------------------------------------
1 | #Microsoft Public License (Ms-PL)
2 |
3 | This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
4 |
5 | ##1. Definitions
6 |
7 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
8 |
9 | A "contribution" is the original software, or any additions or changes to the software.
10 |
11 | A "contributor" is any person that distributes its contribution under this license.
12 |
13 | "Licensed patents" are a contributor's patent claims that read directly on its contribution.
14 |
15 | ##2. Grant of Rights
16 |
17 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
18 |
19 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
20 |
21 | ##3. Conditions and Limitations
22 |
23 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
24 |
25 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
26 |
27 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
28 |
29 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
30 |
31 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | VirusTotalShell
2 | =============
3 |
4 | A fork of David B Heise's VirusTotal Powershell Module
5 | http://psvirustotal.codeplex.com/SourceControl/latest#VirusTotal.psm1
6 |
7 | ##Example Usage
8 | ```
9 | PS E:\hunt\data> Import-Module .\VirusTotal.psm1
10 | PS E:\hunt\data> Get-Command -Module VirusTotal
11 |
12 | CommandType Name ModuleName
13 | ----------- ---- ----------
14 | Function Get-VTApiKey VirusTotal
15 | Function Get-VTReport VirusTotal
16 | Function Invoke-VTRescan VirusTotal
17 | Function Invoke-VTScan VirusTotal
18 | Function New-VTComment VirusTotal
19 | Function Set-VTApiKey VirusTotal
20 |
21 | PS E:\hunt\data> Set-VTApiKey -VTApiKey yourVTAPIkeyhere
22 |
23 | PS E:\hunt\data> Get-Help Get-VTReport
24 |
25 | NAME
26 | Get-VTReport
27 |
28 | SYNTAX
29 | Get-VTReport [-VTApiKey ] [-hash ] []
30 |
31 | Get-VTReport [-VTApiKey ] [-file ] []
32 |
33 | Get-VTReport [-VTApiKey ] [-uri ] []
34 |
35 | Get-VTReport [-VTApiKey ] [-ip ] []
36 |
37 | Get-VTReport [-VTApiKey ] [-domain ] []
38 |
39 |
40 | ALIASES
41 | None
42 |
43 |
44 | REMARKS
45 | None
46 | ```
47 | You can combine this script with the output from something like https://github.com/davehull/Get-StakRank#get-stakrank or hashes from Autorunsc.exe and do useful things like:
48 | ```
49 | PS E:\hunt\data> $data = Import-Csv -Delimiter "`t" '.\FIN-Image Path-MD5.tsv'
50 | PS E:\hunt\data> $data | ? { $_.Count -lt 10 -and $_.MD5.length -gt 3 } | select -unique MD5 -ExpandProperty MD5 | % { Get-VTReport -hash $_ | select scan_date, positives, resource, verbose_msg, permalink; sleep 15 }
51 | ```
52 | This will return something like the following:
53 | ```
54 | scan_date :
55 | positives :
56 | resource : 06f12e6478246b0f7ef11f2a6735b876
57 | verbose_msg : The requested resource is not among the finished, queued or pending scans
58 | permalink :
59 |
60 | scan_date :
61 | positives :
62 | resource : 04113bb90f3c162ebd961a3065c15fe1
63 | verbose_msg : The requested resource is not among the finished, queued or pending scans
64 | permalink :
65 |
66 | scan_date : 2013-06-10 14:19:55
67 | positives : 0
68 | resource : bf68a382c43a5721eef03ff45faece4a
69 | verbose_msg : Scan finished, scan information embedded in this object
70 | permalink : https://www.virustotal.com/file/09eba33e313cf8f19c5a2d19ada286e9fdd09c6a99f6bf77b65fa55cc6061590/analysis/1370873995/
71 |
72 | scan_date : 2013-11-06 03:43:51
73 | positives : 0
74 | resource : 5534ed475c61188fffa4168f28a0d893
75 | verbose_msg : Scan finished, scan information embedded in this object
76 | permalink : https://www.virustotal.com/file/10d3f4a431f259164f8abeb158381db92cbb9c02fd56e70addeab9907eb92e91/analysis/1383709431/
77 |
78 | scan_date : 2014-01-03 21:47:59
79 | positives : 1
80 | resource : a283e768fa12ef33087f07b01f82d6dd
81 | verbose_msg : Scan finished, scan information embedded in this object
82 | permalink : https://www.virustotal.com/file/1d4d787047200fc7bcbfc03a496cafda8e49075d2fbf2ff7feab90a4fdea8f89/analysis/1388785679/
83 | ...
84 | ```
85 | And of course, you can pipe this out to a file by running it as follows:
86 | ```
87 | PS E:\hunt\data> $($data | ? { $_.Count -lt 10 -and $_.MD5.length -gt 3 } | select -unique MD5 -ExpandProperty MD5 | % { Get-VTReport -hash $_ | select scan_date, positives, resource, verbose_msg, permalink | ConvertTo-Csv -Delimiter "`t" -NoTypeInformation; sleep 15 } ) | Add-Content -Encoding Ascii vt-results.tsv
88 | ```
89 |
--------------------------------------------------------------------------------
/VirusTotal.psm1:
--------------------------------------------------------------------------------
1 | #Requires -Version 3
2 | <#
3 | .SYNOPSIS
4 | Virus Total Module
5 | .DESCRIPTION
6 | Powershell Module for interaction with Virus Total's API
7 | .NOTES
8 | File Name : VirusTotal.psm1
9 | Author : David B Heise
10 | .LINK
11 | https://psvirustotal.codeplex.com
12 | #>
13 | Add-Type -AssemblyName System.Security
14 |
15 | function Set-VTApiKey {
16 | [CmdletBinding()]
17 | Param([Parameter(Mandatory=$true)][ValidateNotNull()][String] $VTApiKey,
18 | [String] $vtFileLocation = $(Join-Path $env:APPDATA 'virustotal.bin'))
19 | $inBytes = [System.Text.Encoding]::Unicode.GetBytes($VTApiKey)
20 | $protected = [System.Security.Cryptography.ProtectedData]::Protect($inBytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
21 | [System.IO.File]::WriteAllBytes($vtfileLocation, $protected)
22 | }
23 |
24 | function Get-VTApiKey {
25 | [CmdletBinding()]
26 | Param([String] $vtFileLocation = $(Join-Path $env:APPDATA 'virustotal.bin'))
27 | if (Test-Path $vtfileLocation) {
28 | $protected = [System.IO.File]::ReadAllBytes($vtfileLocation)
29 | $rawKey = [System.Security.Cryptography.ProtectedData]::Unprotect($protected, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
30 | return [System.Text.Encoding]::Unicode.GetString($rawKey)
31 | } else {
32 | throw "Call Set-VTApiKey first!"
33 | }
34 | }
35 |
36 | function Get-VTReport {
37 | [CmdletBinding()]
38 | Param(
39 | [String] $VTApiKey = (Get-VTApiKey),
40 | [Parameter(ParameterSetName="hash", ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)][String] $hash,
41 | [Parameter(ParameterSetName="file", ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)][System.IO.FileInfo] $file,
42 | [Parameter(ParameterSetName="uri", ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)][Uri] $uri,
43 | [Parameter(ParameterSetName="ipaddress", ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)][String] $ip,
44 | [Parameter(ParameterSetName="domain", ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)][String] $domain
45 | )
46 | Begin {
47 | $fileUri = 'https://www.virustotal.com/vtapi/v2/file/report'
48 | $UriUri = 'https://www.virustotal.com/vtapi/v2/url/report'
49 | $IPUri = 'http://www.virustotal.com/vtapi/v2/ip-address/report'
50 | $DomainUri = 'http://www.virustotal.com/vtapi/v2/domain/report'
51 |
52 | function Get-Hash(
53 | [System.IO.FileInfo] $file = $(Throw 'Usage: Get-Hash [System.IO.FileInfo]'),
54 | [String] $hashType = 'sha256')
55 | {
56 | $stream = $null;
57 | [string] $result = $null;
58 | $hashAlgorithm = [System.Security.Cryptography.HashAlgorithm]::Create($hashType )
59 | $stream = $file.OpenRead();
60 | $hashByteArray = $hashAlgorithm.ComputeHash($stream);
61 | $stream.Close();
62 |
63 | trap
64 | {
65 | if ($null -ne $stream) { $stream.Close(); }
66 | break;
67 | }
68 |
69 | # Convert the hash to Hex
70 | $hashByteArray | ForEach-Object { $result += $_.ToString("X2") }
71 | return $result
72 | }
73 | }
74 | Process {
75 | [String] $h = $null
76 | [String] $u = $null
77 | [String] $method = $null
78 | $body = @{}
79 |
80 | switch ($PSCmdlet.ParameterSetName) {
81 | "file" {
82 | $h = Get-Hash -file $file
83 | Write-Verbose -Message ("FileHash:" + $h)
84 | $u = $fileUri
85 | $method = 'POST'
86 | $body = @{ resource = $h; apikey = $VTApiKey}
87 | }
88 | "hash" {
89 | $u = $fileUri
90 | $method = 'POST'
91 | $body = @{ resource = $hash; apikey = $VTApiKey}
92 | }
93 | "uri" {
94 | $u = $UriUri
95 | $method = 'POST'
96 | $body = @{ resource = $uri; apikey = $VTApiKey}
97 | }
98 | "ipaddress" {
99 | $u = $IPUri
100 | $method = 'GET'
101 | $body = @{ ip = $ip; apikey = $VTApiKey}
102 | }
103 | "domain" {
104 | $u = $DomainUri
105 | $method = 'GET'
106 | $body = @{ domain = $domain; apikey = $VTApiKey}}
107 | }
108 |
109 | return Invoke-RestMethod -Method $method -Uri $u -Body $body
110 | }
111 | }
112 |
113 | function Invoke-VTScan {
114 | [CmdletBinding()]
115 | Param(
116 | [String] $VTApiKey = (Get-VTApiKey),
117 | [Parameter(ParameterSetName="file", ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
118 | [System.IO.FileInfo] $file,
119 | [Parameter(ParameterSetName="uri", ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
120 | [Uri] $uri
121 | )
122 | Begin {
123 | $fileUri = 'https://www.virustotal.com/vtapi/v2/file/scan'
124 | $UriUri = 'https://www.virustotal.com/vtapi/v2/url/scan'
125 | [byte[]]$CRLF = 13, 10
126 |
127 | function Get-AsciiBytes([String] $str) {
128 | return [System.Text.Encoding]::ASCII.GetBytes($str)
129 | }
130 | }
131 | Process {
132 | [String] $h = $null
133 | [String] $u = $null
134 | [String] $method = $null
135 | $body = New-Object System.IO.MemoryStream
136 |
137 | switch ($PSCmdlet.ParameterSetName) {
138 | "file" {
139 | $u = $fileUri
140 | $method = 'POST'
141 | $boundary = [Guid]::NewGuid().ToString().Replace('-','')
142 | $ContentType = 'multipart/form-data; boundary=' + $boundary
143 | $b2 = Get-AsciiBytes ('--' + $boundary)
144 | $body.Write($b2, 0, $b2.Length)
145 | $body.Write($CRLF, 0, $CRLF.Length)
146 |
147 | $b = (Get-AsciiBytes ('Content-Disposition: form-data; name="apikey"'))
148 | $body.Write($b, 0, $b.Length)
149 |
150 | $body.Write($CRLF, 0, $CRLF.Length)
151 | $body.Write($CRLF, 0, $CRLF.Length)
152 |
153 | $b = (Get-AsciiBytes $VTApiKey)
154 | $body.Write($b, 0, $b.Length)
155 |
156 | $body.Write($CRLF, 0, $CRLF.Length)
157 | $body.Write($b2, 0, $b2.Length)
158 | $body.Write($CRLF, 0, $CRLF.Length)
159 |
160 | $b = (Get-AsciiBytes ('Content-Disposition: form-data; name="file"; filename="' + $file.Name + '";'))
161 | $body.Write($b, 0, $b.Length)
162 | $body.Write($CRLF, 0, $CRLF.Length)
163 | $b = (Get-AsciiBytes 'Content-Type:application/octet-stream')
164 | $body.Write($b, 0, $b.Length)
165 |
166 | $body.Write($CRLF, 0, $CRLF.Length)
167 | $body.Write($CRLF, 0, $CRLF.Length)
168 |
169 | $b = [System.IO.File]::ReadAllBytes($file.FullName)
170 | $body.Write($b, 0, $b.Length)
171 |
172 | $body.Write($CRLF, 0, $CRLF.Length)
173 | $body.Write($b2, 0, $b2.Length)
174 |
175 | $b = (Get-AsciiBytes '--')
176 | $body.Write($b, 0, $b.Length)
177 |
178 | $body.Write($CRLF, 0, $CRLF.Length)
179 |
180 |
181 | Invoke-RestMethod -Method $method -Uri $u -ContentType $ContentType -Body $body.ToArray()
182 | }
183 | "uri" {
184 | $h = $uri
185 | $u = $UriUri
186 | $method = 'POST'
187 | $body = @{ url = $uri; apikey = $VTApiKey}
188 | Invoke-RestMethod -Method $method -Uri $u -Body $body
189 | }
190 | }
191 | }
192 | }
193 |
194 | function New-VTComment {
195 | [CmdletBinding()]
196 | Param(
197 | [String] $VTApiKey = (Get-VTApiKey),
198 | [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)][String] $hash,
199 | [Parameter(Mandatory=$true)][ValidateNotNull()][String] $Comment
200 | )
201 |
202 | Process {
203 | $u = 'https://www.virustotal.com/vtapi/v2/comments/put'
204 | $method = 'POST'
205 | $body = @{ resource = $hash; apikey = $VTApiKey; comment = $Comment}
206 |
207 | return Invoke-RestMethod -Method $method -Uri $u -Body $body
208 | }
209 | }
210 |
211 | function Invoke-VTRescan {
212 | [CmdletBinding()]
213 | Param(
214 | [String] $VTApiKey = (Get-VTApiKey),
215 | [Parameter(Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)][String] $hash
216 | )
217 | Process {
218 | $u = 'https://www.virustotal.com/vtapi/v2/file/rescan'
219 | $method = 'POST'
220 | $body = @{ resource = $hash; apikey = $VTApiKey}
221 | return Invoke-RestMethod -Method $method -Uri $u -Body $body
222 | }
223 | }
224 |
--------------------------------------------------------------------------------