Created
March 8, 2025 20:25
-
-
Save darkoperator/606b68db569c2d030699e8548c119471 to your computer and use it in GitHub Desktop.
WordPress Plugin Version and Vuln Check Functions
This file contains hidden or 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
function Get-WordPressPlugin { | |
<# | |
.SYNOPSIS | |
Extracts WordPress plugin names and versions from a given plugin directory. | |
.DESCRIPTION | |
This function scans a given WordPress plugin directory, detects installed plugins, | |
and extracts their names and versions from `readme.txt` or PHP files. | |
.PARAMETER PluginFolder | |
The path to the WordPress plugin directory containing multiple plugin subdirectories. | |
This parameter is mandatory. | |
.EXAMPLE | |
Get-WordPressPlugin -PluginFolder "C:\path\to\wordpress\wp-content\plugins" | |
This example scans all plugins inside the specified folder and returns an object | |
containing plugin names and versions. | |
.EXAMPLE | |
Get-WordPressPlugin -PluginFolder "C:\capture\htdocs\wordpress\wp-content\plugins" | Format-Table -AutoSize | |
This example outputs the results in a formatted table. | |
.OUTPUTS | |
[PSCustomObject] - Returns an object for each detected plugin with: | |
- Name (string) : Plugin name | |
- Version (string) : Installed plugin version | |
.NOTES | |
- This function requires read access to the plugin directory. | |
- It first checks `readme.txt` for plugin details and falls back to parsing PHP files. | |
- If no details are found, the plugin will be reported as "Unknown". | |
Author: carlos_perez[at]darkoperator.com | |
#> | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory = $true, Position = 0)] | |
[string]$PluginFolder | |
) | |
if (-Not (Test-Path $PluginFolder)) { | |
Write-Error "The specified folder does not exist." | |
return | |
} | |
$plugins = Get-ChildItem -Path $PluginFolder -Directory | |
foreach ($plugin in $plugins) { | |
$pluginName = $null | |
$pluginVersion = $null | |
# Check readme.txt for plugin details | |
$readmePath = Join-Path -Path $plugin.FullName -ChildPath "readme.txt" | |
if (Test-Path $readmePath) { | |
$readmeContent = Get-Content $readmePath | |
foreach ($line in $readmeContent) { | |
if ($line -match "^Plugin Name:\s*(.+)$") { | |
$pluginName = $matches[1].Trim() | |
} | |
if ($line -match "^Stable tag:\s*(.+)$") { | |
$pluginVersion = $matches[1].Trim() | |
} | |
} | |
} | |
# Check for main PHP file in the root of the plugin folder | |
if (-not $pluginName -or -not $pluginVersion) { | |
$phpFiles = Get-ChildItem -Path $plugin.FullName -Filter "*.php" | Where-Object { $_.PSIsContainer -eq $false } | |
foreach ($phpFile in $phpFiles) { | |
$phpContent = Get-Content $phpFile.FullName -Raw | |
if ($phpContent -match "/\*[\s\S]*?Plugin Name:\s*(.+?)[\r\n]") { | |
$pluginName = $matches[1].Trim() | |
} | |
if ($phpContent -match "/\*[\s\S]*?Version:\s*(.+?)[\r\n]") { | |
$pluginVersion = $matches[1].Trim() | |
} | |
# Stop checking after finding the first valid header | |
if ($pluginName -and $pluginVersion) { | |
break | |
} | |
} | |
} | |
# If plugin name isn't found, use the folder name | |
if (-not $pluginName) { | |
$pluginName = $plugin.Name | |
} | |
# Ensure a result is returned | |
[PSCustomObject]@{ | |
Name = $pluginName ?? "Unknown" | |
Version = $pluginVersion ?? "Not found" | |
} | |
} | |
} | |
function Invoke-WordPressPluginVulnCheck { | |
<# | |
.SYNOPSIS | |
Checks WordPress plugins for known vulnerabilities using the WPVulnerability API. | |
.DESCRIPTION | |
This function scans a given WordPress plugin directory, extracts plugin names and versions, | |
and checks for known vulnerabilities using the WPVulnerability API. It returns structured | |
PowerShell objects with vulnerability information. | |
.PARAMETER PluginFolderPath | |
The path to the WordPress plugin directory containing multiple plugin subdirectories. | |
This parameter is mandatory. | |
.EXAMPLE | |
Invoke-WordPressPluginVulnCheck -PluginFolderPath "C:\path\to\wordpress\wp-content\plugins" | |
This example scans all plugins inside the specified folder and checks for vulnerabilities. | |
.EXAMPLE | |
Get-ChildItem "C:\path\to\wordpress\wp-content\plugins" | Invoke-WordPressPluginVulnCheck | |
This example allows the function to accept pipeline input to process multiple plugin paths. | |
.OUTPUTS | |
[PSCustomObject] - Returns an object for each plugin with the following properties: | |
- Name (string) : Plugin name | |
- InstalledVersion (string) : The installed plugin version | |
- IsVulnerable (boolean) : Indicates whether the plugin is vulnerable | |
- Vulnerabilities (array) : List of vulnerabilities (if any), containing: | |
- CVE (string) : CVE identifier (if available) | |
- CVE_Link (string) : URL to CVE details | |
- Severity (float) : CVSS score indicating severity (the constant liar :P ) | |
- SeverityType (string) : Classification (e.g., Critical, High, Medium, Low) | |
- Description (string) : Brief description of the vulnerability | |
.NOTES | |
- This function requires an active internet connection to query the WPVulnerability API. | |
- It processes plugin subdirectories and extracts the version from PHP files. | |
- If no vulnerabilities are found, "IsVulnerable" is False, and "Vulnerabilities" will be empty. | |
Author: carlos_perez[at]darkoperator.com | |
.LINK | |
WPVulnerability API: https://www.wpvulnerability.net/ | |
#> | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] | |
[Alias('FullName', 'Path')] | |
[string]$PluginFolderPath | |
) | |
# Function to extract plugin name and version from PHP files | |
function Get-PluginInfo { | |
param ( | |
[string]$PluginFile | |
) | |
$content = Get-Content -Path $PluginFile -Raw | |
$pluginInfo = @{} | |
if ($content -match "Plugin Name:\s*(.+)") { | |
$pluginInfo["Name"] = $matches[1].Trim() | |
} | |
if ($content -match "Version:\s*([\d\.]+)") { | |
$pluginInfo["Version"] = $matches[1].Trim() | |
} | |
return $pluginInfo | |
} | |
# Function to check vulnerability status | |
function Check-PluginVulnerability { | |
param ( | |
[string]$PluginSlug, | |
[string]$InstalledVersion | |
) | |
$apiUrl = "https://www.wpvulnerability.net/plugin/$PluginSlug/" | |
$response = Invoke-RestMethod -Uri $apiUrl -Method Get -ErrorAction SilentlyContinue | |
$resultObject = [PSCustomObject]@{ | |
PluginSlug = $PluginSlug | |
InstalledVersion = $InstalledVersion | |
IsVulnerable = $false | |
Vulnerabilities = @() | |
} | |
if ($response -and $response.error -eq 0) { | |
$vulnerabilities = $response.data.vulnerability | |
foreach ($vuln in $vulnerabilities) { | |
$maxVersion = $vuln.operator.max_version | |
$maxOperator = $vuln.operator.max_operator # 'le' (<=) means up to this version | |
if ($maxOperator -eq "le" -and [version]$InstalledVersion -le [version]$maxVersion) { | |
$resultObject.IsVulnerable = $true | |
$vulnDetails = [PSCustomObject]@{ | |
CVE = $vuln.source[0].id | |
CVE_Link = $vuln.source[0].link | |
Severity = $vuln.impact.cvss.score | |
SeverityType = $vuln.impact.cvss.severity | |
Description = $vuln.source[0].description | |
} | |
$resultObject.Vulnerabilities += $vulnDetails | |
} | |
} | |
} | |
return $resultObject | |
} | |
# Process all plugins in the given folder | |
$pluginFolders = Get-ChildItem -Path $PluginFolderPath -Directory | |
foreach ($folder in $pluginFolders) { | |
$phpFiles = Get-ChildItem -Path $folder.FullName -Filter "*.php" | |
foreach ($file in $phpFiles) { | |
$pluginInfo = Get-PluginInfo -PluginFile $file.FullName | |
if ($pluginInfo.Name -and $pluginInfo.Version) { | |
$pluginSlug = ($folder.Name -replace "\s", "-").ToLower() | |
$vulnerabilityData = Check-PluginVulnerability -PluginSlug $pluginSlug -InstalledVersion $pluginInfo.Version | |
[PSCustomObject]@{ | |
Name = $pluginInfo.Name | |
InstalledVersion = $pluginInfo.Version | |
IsVulnerable = $vulnerabilityData.IsVulnerable | |
Vulnerabilities = $vulnerabilityData.Vulnerabilities | |
} | |
break # Stop after finding the main plugin file | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment