Searching VirusTotal.com with PowerShell

While reading the following article on Didier Steven’s blog, http://blog.didierstevens.com/2012/10/01/searching-for-that-adobe-cert/, I’ve noticed a screenshot where VirusTotal detection results are reported. He also mentioned that we can actually search virustotal and points to his page http://blog.didierstevens.com/2012/05/21/searching-with-virustotal/ where he says:

Did you know that you can search VirusTotal? You don’t have to submit a file, but you can search for the report of a file has been submitted before. You use a cryptographic hash (MD5, SHA1, SHA256) to identify the file.

If I go to this page https://www.virustotal.com/#search and submit for example the SHA1 of the C:\Windows\SysWOW64\ntoskrnl.exe of my Windows 7 x64 SP1 (en-US) computer

I’ve got the following results:

With the following sample code, I can get the same returned as a powershell object:

$checksum = "4988e05aaae2fa035b8199295be7d4cf5527e4cb"            
$res = (Invoke-WebRequest -Uri 'https://www.virustotal.com/search/' -Method Post -Body "query=$checksum")                        
$page = Invoke-WebRequest -Method GET -Uri $res.BaseResponse.ResponseUri.OriginalString                        
$obj = New-Object -TypeName PSObject                        
    ($page.AllElements | ? { ($_.TagName -eq 'TBODY') -and ($_.outerHTML -match "$checksum") }).OuterText -split "`n" |  % {                        
    $obj | Add-Member -MemberType NoteProperty -Name ($_ -split ":")[0] -Value (-join($_ -split ":" )[1..($_ -split ":" ).count])                        
}                        
$obj

Cool, isn’t it ? Wait, there’s more. There are more detailed tabs.

We can access these tabs this way:

$page.AllElements.FindById('antivirus-results').outerHTML            
$page.AllElements.FindById('behavioural-info').outerHTML            
$page.AllElements.FindById('additional-info').outerHTML

Here’s the function that parses 2 of the 3 tabs. Parsing behavioural-info is a hassle..

# Requires -Version 3.0


Function Test-VTresults  {
    [CmdletBinding()]
    param(
    [Parameter(Mandatory,ValueFromPipeline)]
    [string[]]$CheckSum
    )
Begin {
    $URI = 'https://www.virustotal.com/search/'
}
Process {
    if ($CheckSum) {
        $CheckSum | ForEach-Object -Process {
            Write-Verbose -Message "Dealing with $_"
            $res = (Invoke-WebRequest -Uri $URI -Method Post -Body "query=$_")            
            $page = Invoke-WebRequest -Method GET -Uri $res.BaseResponse.ResponseUri.OriginalString            

            # Main tab
            $obj = New-Object -TypeName PSObject            
            ($page.AllElements | Where-Object {
                ($_.TagName -eq 'TBODY') -and ($_.outertext -match 'Detection\sratio') }
            ).OuterText -split "`n" |  ForEach-Object -Process {
                $obj | Add-Member -MemberType NoteProperty -Name ($_ -split ":")[0] -Value (-join($_ -split ":" )[1..($_ -split ":" ).count])            
            }

            # Analysis tab
            $count = 0
            $analysisar = @()
            $AVName = $DetectionDate = $DetectionRate = $null
            ([regex]'<TD(>|(\sclass=text\-red>))(?<ID>.*)</TD>').Matches(
            $page.AllElements.FindById('antivirus-results').outerHTML) | ForEach-Object -Process { 
                $count++
                switch ((@($_.Groups))[-1]) {
                    {$_ -match '\d{8}'} { $DetectionDate = $_ ; break}
                    {$_ -match '^\-$'}{ $DetectionRate = '-' ; break }
                    {$_ -match '.*'} { 
                        if ($count -eq 1) {
                            $AVName = $_ 
                        } else {
                            $DetectionRate = $_
                        }
                        ; break            }
                }
                if ($count -eq 3) {
                    $count = 0
                    $analysisar += New-Object -TypeName PSObject -Property @{
                        Update = $DetectionDate
                        Result = $DetectionRate
                        Antivirus = $AVName
                    }
                }
            }
            # Add the analysis results array as a single property
            $obj | Add-Member -MemberType NoteProperty -Name Analysis -Value $analysisar

            if ($page.AllElements.FindById('additional-info')) {
                $locations = $string = $null
                # Identify indexes where the H5 tag is located
                $locations = ([regex]'<H5>').Matches($page.AllElements.FindById('additional-info').outerHTML).Index
                if ($locations) {
                    
                    $additionalinfoar = @()
                    # Last item and content,...</LI> is missing at the end of each line for easy parsing 😦
                    # $string = $page.AllElements.FindById('additional-info').outerHTML.Substring($locations[-1])
                    
                    for ($i = 0 ; $i -le ($locations.Count-2) ; $i++) {

                        # Define the string between two H5 tags
                        $string = $page.AllElements.FindById('additional-info').outerHTML.Substring($locations[$i],($locations[$i+1]-$locations[$i]))

                        # Split this new string
                        switch -Regex ($string) {
                            # Case 1
                            '<H5>(?<Tool>.*)</H5>(?<text>.*)</TD></TR>' { 
                                $additionalinfoar += New-Object -TypeName PSObject -Property @{
                                    Item = ([regex]'<H5>(?<Item>.*)</H5>(?<Content>.*)</TD></TR>').Matches($string).Groups[1].Value
                                    Content = (([regex]'<H5>(?<Item>.*)</H5>(?<Content>.*)</TD></TR>').Matches($string).Groups[2].Value -split '<BR>') | Out-String
                                }
                            }
                            # Case 2
                            '<H5>(?<Tool>.*)</H5><PRE\sstyle=\"MAX\-WIDTH:\s\d{3}px\">(?<text>.*)' {
                                $additionalinfoar += New-Object -TypeName PSObject -Property @{
                                    Item = ([regex]'<H5>(?<Item>.*)</H5><PRE\sstyle=\"MAX\-WIDTH:\s\d{3}px\">(?<Content>.*)').Matches($string).Groups[1].Value
                                    Content = -join (
                                    $string[
                                    ([regex]'<H5>(?<Tool>.*)</H5><PRE\sstyle=\"MAX\-WIDTH:\s\d{3}px\">').Matches($string).Length..
                                    (([regex]'</PRE></TD></TR>').Matches($string).Index-1)
                                    ])
                                }
                            }
                        }
                    }
                    $obj | Add-Member -MemberType NoteProperty -Name 'additional-info' -Value $additionalinfoar 
                }
            }
            # Output 
            $obj
        }
    }
}
End {}

<#
     
.SYNOPSIS   
    Search virustotal.com for checksum and parse the returned HTML page for relevant information.
    
.DESCRIPTION 
    Submit an array of checksum MD5, SHA1, SHA256 and get the info from the main tab, analysis results and additional info.
 
.PARAMETER Checksum
    Array of checksum strings that can either be a MD5, SHA1 or SHA256
      
.NOTES   
    Name: Test-VTresults
    Author: Emin Atac
    DateCreated: 17/01/2013
      
.LINK   
    https://p0w3rsh3ll.wordpress.com
      
.EXAMPLE
    Test-VTresults 4988e05aaae2fa035b8199295be7d4cf5527e4cb
    Search virustotal.com for the SHA1 checksum of C:\Windows\SysWOW64\ntoskrnl.exe of a Windows 7 x64 SP1 (en-us) computer
 
.EXAMPLE
    a6c80ce949469cc86f6c22355f4d3bb8773fc634 | Test-VTresults
    Search virustotal.com for the SHA1 checksum of eicar.com
 
#>
}

Now, let’s see how to use the above function πŸ™‚

I’ve seen the recent post about EICAR being generated by powershell on this page: http://www.obscuresecurity.blogspot.fr/2013/01/New-Eicar.html
(also published on http://poshcode.org/3874).
Let’s have some fun with it, here’s my one-liner with a different approach πŸ˜› :

[System.Text.Encoding]::UTF8.GetString(@(            
('8853793380376465809152928090885352408094415567674155'-split "(?<=\G.{2})",26)+            
'125'+            
('36697367658245838465786865826845657884738673828583458469838445707376693336724372421310'-split "(?<=\G.{2})",43))            
).Trim()|Out-File E:\eicar.txt -Force -Encoding ASCII

If I use the Get-Checksum I’ve already presented on this page, I can do

Get-CheckSum -FilePath E:\eicar.txt | Test-VTresults

'fe71aa78dc9288e9997482380c4f270495ca7631',            
'91e764c72619b2e469bded5c21e2a6826aadad62' | Test-VTresults -Verbose |            
Select -ExpandProperty Analysis

'91e764c72619b2e469bded5c21e2a6826aadad62' |             
Test-VTresults -Verbose |             
Select -ExpandProperty 'additional-info' |            
Select -ExpandProperty Content

Did I already say that Powershell rocks! 😎

Advertisements

3 thoughts on “Searching VirusTotal.com with PowerShell

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s