Improved bootstrapper script #72
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Repository And Package Scan on Virus Total | |
on: | |
workflow_dispatch: | |
release: # to trigger on releases | |
pull_request: | |
types: | |
- closed # When a pull request is closed. Merging also results in closing the pull request. | |
jobs: | |
run-script: | |
name: Run VirusTotal Analysis | |
runs-on: windows-latest | |
steps: | |
# Step to check out the repository | |
- uses: actions/checkout@v4 | |
# Step to create ZIP of the repository | |
- name: Create a zip file of the entire repository | |
shell: pwsh | |
run: | | |
Compress-Archive -Path '*' -DestinationPath 'Harden-Windows-Security-Repository.zip' | |
Write-Host "Repository ZIP created." | |
# Step to fetch the latest release and download attached files to a separate folder | |
- name: Fetch Latest Release Files | |
id: get_release_files | |
shell: pwsh | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # GitHub API access token | |
run: | | |
$null = New-Item -Path './release_assets' -ItemType Directory # Create folder for release assets | |
# Get latest release information from GitHub API | |
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/${{ github.repository }}/releases/latest" -Headers @{Authorization = "token $env:GITHUB_TOKEN"} -UseBasicParsing | |
# Download assets if they exist | |
if ($release.assets.Count -gt 0) { | |
foreach ($asset in $release.assets) { | |
$assetUrl = $asset.browser_download_url | |
$assetName = $asset.name | |
# Download each asset into the release_assets folder | |
Invoke-WebRequest -Uri $assetUrl -OutFile "./release_assets/$assetName" | |
Write-Host "Downloaded: $assetName" | |
} | |
} else { | |
Write-Host "No assets found in the latest release." | |
} | |
- name: Run VirusTotal Script | |
env: | |
VTAPIsecret: ${{ secrets.VTNEWAPI }} # VirusTotal API key | |
shell: pwsh | |
run: | | |
$ErrorActionPreference = 'Stop' | |
# Function to upload file to VirusTotal | |
function Invoke-VTFileUpload { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory = $true)][System.String]$FilePath, | |
[Parameter(Mandatory = $true)][System.String]$ApiKey | |
) | |
[System.IO.FileInfo]$FileToUpload = Get-Item -Path $FilePath | |
# Check if file size is greater than 20MB (20 * 1024 * 1024 bytes) | |
if ($FileToUpload.Length -gt (20 * 1024 * 1024)) { | |
Write-Host 'File is larger than 20MB. Using big file upload URL.' -ForegroundColor Cyan | |
# https://docs.virustotal.com/reference/files-upload-url | |
[System.Collections.Hashtable]$BigFileUploadHeaders = @{} | |
$BigFileUploadHeaders.Add('accept', 'application/json') | |
$BigFileUploadHeaders.Add('x-apikey', $ApiKey) | |
$BigFileUploadResponse = Invoke-WebRequest -Uri 'https://www.virustotal.com/api/v3/files/upload_url' -Method GET -Headers $BigFileUploadHeaders | |
$BigFileUploadResponseJSON = $BigFileUploadResponse.Content | ConvertFrom-Json | |
[System.String]$UploadUrl = $BigFileUploadResponseJSON.data | |
} | |
else { | |
[System.String]$UploadUrl = 'https://www.virustotal.com/api/v3/files' | |
} | |
# Upload the file to VirusTotal | |
try { | |
Write-Host "Uploading file to VirusTotal: $FilePath" -ForegroundColor Yellow | |
# cURL handles multipart uploads nicely | |
$Response = curl --request POST ` | |
--url $UploadUrl ` | |
--header 'accept: application/json' ` | |
--header 'content-type: multipart/form-data' ` | |
--header "x-apikey: $ApiKey" ` | |
--form file="@$FilePath" | |
$Json = $Response | ConvertFrom-Json | |
Write-Host 'Upload completed.' -ForegroundColor Yellow | |
# Return the analysis ID and URL | |
return [PSCustomObject]@{ | |
ID = $Json.data.id | |
URL = $Json.data.links.self | |
} | |
} | |
catch { | |
Write-Host "Error uploading file: $_" -ForegroundColor Red | |
exit 1 | |
} | |
} | |
# Function to get the VirusTotal scan report | |
function Get-VirusTotalReport { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory = $true)][System.String]$FilePath, | |
[Parameter(Mandatory = $true)][System.String]$ApiKey, | |
[Parameter(Mandatory = $false)][System.String]$Comments | |
) | |
# Set headers for the report request | |
[System.Collections.Hashtable]$Headers = @{} | |
$Headers.Add('accept', 'application/json') | |
$Headers.Add('x-apikey', $ApiKey) | |
# Upload the file to virus total | |
$AnalysisData = Invoke-VTFileUpload -filePath $FilePath -apiKey $ApiKey | |
# Fetch the report from VirusTotal | |
do { | |
$Response = Invoke-WebRequest -Uri $AnalysisData.URL -Method Get -Headers $Headers | |
$JsonResponse = $Response.Content | ConvertFrom-Json | |
if ($JsonResponse.data.attributes.status -eq 'queued') { | |
Write-Host "Status: $($JsonResponse.data.attributes.status). Waiting 10 more seconds..." -ForegroundColor Blue | |
Start-Sleep -Seconds 10 | |
} | |
} | |
until ($JsonResponse.data.attributes.status -eq 'completed') | |
Write-Host "Status is now: $($JsonResponse.data.attributes.status)" -ForegroundColor Blue | |
[System.String]$FileURLOnVirusTotal = "https://www.virustotal.com/gui/file/$($JsonResponse.meta.file_info.sha256)" | |
# Display detailed report | |
Write-Host -Object "Results URL: $FileURLOnVirusTotal" -ForegroundColor Magenta | |
[System.Int32]$Undetected = $JsonResponse.data.attributes.stats.undetected | |
[System.Int32]$Suspicious = $JsonResponse.data.attributes.stats.suspicious | |
[System.Int32]$Malicious = $JsonResponse.data.attributes.stats.malicious | |
Write-Host -Object "Undetected Result: $Undetected" -ForegroundColor Green | |
Write-Host -Object "Suspicious Result: $Suspicious" -ForegroundColor Yellow | |
Write-Host -Object "Malicious Result: $Malicious" -ForegroundColor Red | |
# $JsonResponse.meta.file_info | Format-List * | |
# $JsonResponse.data.attributes | Format-List * | |
# $JsonResponse.data.attributes.stats | Format-List * | |
# $JsonResponse.data.attributes.status | Format-List * | |
# $JsonResponse.data.attributes.results | Format-List * | |
# $JsonResponse.data.attributes.results.Microsoft | Format-List * | |
# Only add the comment if it was provided by parameter | |
if (![string]::IsNullOrWhiteSpace($Comments)) { | |
# If comments or votes exist, we see error which can be safely ignored | |
try { | |
# Add comment to the file | |
[System.String]$CommentsSubmitURL = "https://www.virustotal.com/api/v3/files/$($JsonResponse.meta.file_info.sha256)/comments" | |
[System.Collections.Hashtable]$CommentsSubmitHeaders = @{} | |
$CommentsSubmitHeaders.Add('accept', 'application/json') | |
$CommentsSubmitHeaders.Add('x-apikey', $ApiKey) | |
$CommentsSubmitHeaders.Add('content-type', 'application/json') | |
$CommentsSubmitResponse = Invoke-WebRequest -Uri $CommentsSubmitURL -Method POST -Headers $CommentsSubmitHeaders -ContentType 'application/json' -Body "{`"data`":{`"type`":`"comment`",`"attributes`":{`"text`":`"$Comments`"}}}" | |
if ($CommentsSubmitResponse.StatusCode -ne '200') { | |
Write-Host "Error submitting comment. Status Code: $($CommentsSubmitResponse.StatusCode)`n Error: $($CommentsSubmitResponse.Content)" -ForegroundColor Red | |
} | |
} | |
catch { | |
Write-Host "Error submitting comment: $_" -ForegroundColor Red | |
} | |
} | |
try { | |
# Add 'harmless' verdict/vote to the file | |
[System.String]$VoteURL = "https://www.virustotal.com/api/v3/files/$($JsonResponse.meta.file_info.sha256)/votes" | |
[System.Collections.Hashtable]$VoteHeaders = @{} | |
$VoteHeaders.Add('accept', 'application/json') | |
$VoteHeaders.Add('x-apikey', $ApiKey) | |
$VoteHeaders.Add('content-type', 'application/json') | |
$VoteResponse = Invoke-WebRequest -Uri $VoteURL -Method POST -Headers $VoteHeaders -ContentType 'application/json' -Body '{"data":{"type":"vote","attributes":{"verdict":"harmless"}}}' | |
if ($VoteResponse.StatusCode -ne '200') { | |
Write-Host "Error submitting vote. Status Code: $($VoteResponse.StatusCode)`n Error: $($VoteResponse.Content)" -ForegroundColor Red | |
} | |
} | |
catch { | |
Write-Host "Error submitting vote: $_" -ForegroundColor Red | |
} | |
} | |
# VirusTotal API Key | |
$VTApi = $env:VTAPIsecret | |
# Submit the ZIP of the repository to VirusTotal | |
$RepoZip = '.\Harden-Windows-Security-Repository.zip' | |
Get-VirusTotalReport -FilePath $RepoZip -ApiKey $VTApi -Comments "Harden Windows Security GitHub Repository Upload at $(Get-Date -Format 'yyyy-MM-dd_HH-mm-ss'). #HotCakeX #Security #Windows #SpyNetGirl" | |
# Submit each release file in the release_assets folder | |
$ReleaseFiles = Get-ChildItem -Path '.\release_assets' -File -Force | |
foreach ($File in $ReleaseFiles) { | |
# Submit each file to VirusTotal - Not using comments because they might already exist there | |
Get-VirusTotalReport -FilePath $File.FullName -ApiKey $VTApi | |
} |