-
Notifications
You must be signed in to change notification settings - Fork 161
217 lines (179 loc) · 10.2 KB
/
Repository And Package Scan on Virus Total.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
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
}