Skip to content

Instantly share code, notes, and snippets.

@darkoperator
Created March 8, 2025 20:25
Show Gist options
  • Save darkoperator/606b68db569c2d030699e8548c119471 to your computer and use it in GitHub Desktop.
Save darkoperator/606b68db569c2d030699e8548c119471 to your computer and use it in GitHub Desktop.
WordPress Plugin Version and Vuln Check Functions
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