mcpField
W
wordpress-plugin-hunt

wordpress-plugin-hunt

github.com/uphiago安全1.3k41 次安装8 周前更新
代码仓库

关于 wordpress-plugin-hunt

wordpress-plugin-hunt 是用于 WordPress 安全测试的技能,可识别已安装插件并将其版本与已知 CVE 对照。它通过多种检测方式和验证步骤辅助授权测试。

主要功能

  1. 01探测 REST API 命名空间
  2. 02检查 readme.txt 版本
  3. 03分析 HTML 和 JavaScript 指纹
  4. 04将版本与 CVE 对照
  5. 05用多种信号验证结果

适用场景

  1. 01识别已确认 WordPress 目标上的插件
  2. 02检查插件版本是否存在已知漏洞
  3. 03readme.txt 被拦截时寻找替代检测方式

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/uphiago/recon-skills --skill wordpress-plugin-hunt

安装后在 Claude Code 中输入/wordpress-plugin-hunt确认已加载。

详细介绍

WordPress 插件探测技能

通过探测 REST API 命名空间、检测 readme.txt 版本以及分析 HTML/JS 源码,发现已安装的 WordPress 插件。将发现的版本与已知 CVE 交叉比对,以便利用漏洞。WordPress 插件漏洞是最可靠的 RCE 攻击途径之一——已确认的 CVE 涉及 Elementor、Slider Revolution、ElementsKit、Gravity Forms、Jetpack、WooCommerce 和 LiteSpeed Cache。

适用场景

  • 已通过 wp-mass-recon 确认目标运行 WordPress。
  • 正在执行 deep-invade 第 3 阶段。
  • 需要 CORS/XMLRPC 以外的利用途径。
  • 目标是插件较多的 WordPress 网站(电子商务、页面构建器、表单)。

前提条件

  • terminal,并配备 curl、python3。
  • 已确认目标运行 WordPress(/wp-json/ 或 /wp-login.php 可访问)。
  • 若要利用 CVE:了解具体 CVE PoC(参阅 security-arsenal 技能)。

运行方法

# Quick plugin namespace scan (30+ plugins)
TARGET="example.com"
for ns in "revslider/v1" "elementskit/v1" "elementor/v1" "gf/v2" "wc/v3" \
  "jetpack/v4" "litespeed/v1" "yoast/v1" "acf/v3" "contact-form-7/v1" \
  "solidwp-mail/v1" "wpsl/v1" "redirection/v1" "rankmath/v1"; do
  code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 5 --connect-timeout 5 "https://$TARGET/wp-json/$ns")
  [[ "$code" != "404" ]] && echo "FOUND: /wp-json/$ns (HTTP $code)"
done

快速参考

最易利用的插件(美国中小企业目标——大规模侦察确认的 CVE)
插件存在漏洞的版本CVE影响出现频率
Slider Revolution< 6.6.20CVE-2024-2534通过文件上传实现 RCE~10%
ElementsKit< 2.9.4CVE-2023-6851SQLi~5%
ElementsKit< 2.9.4CVE-2023-6853文件上传(未认证)~5%
Gravity Forms< 2.8.2CVE-2024-6115PHP 对象注入 → 认证绕过~8%
Jetpack< 13.1CVE-2024-1782SSRF28%
Elementor< 3.24.0CVE-2024-xxxx信息泄露 → 认证绕过28%
LiteSpeed Cache< 6.5.0CVE-2024-50550权限提升~15%
WooCommerce不适用(API 暴露)不适用订单/客户数据42%
Yoast SEO不适用(站点地图枚举)不适用作者电子邮件泄露42%
检测方法
方法可发现内容可靠性
REST 命名空间探测插件是否存在及其数据高(前提是插件注册了 REST 路由)
readme.txt 版本精确版本号中(许多网站会屏蔽 readme.txt)
HTML 源码搜索插件 CSS/JS 句柄中
robots.txt插件生成的条目低(仅当插件添加条目时)
/wp-content/plugins/<slug>/目录列表或资源中

流程

步骤 1 — REST 命名空间暴力探测(40 多个插件)
TARGET="$1"
OUTDIR="$OUTDIR/plugins/$TARGET"
mkdir -p "$OUTDIR"

# Comprehensive plugin namespace list
declare -A PLUGIN_NAMESPACES
PLUGIN_NAMESPACES["revslider"]="revslider/v1/slides"
PLUGIN_NAMESPACES["elementskit"]="elementskit/v1/layouts"
PLUGIN_NAMESPACES["elementor"]="elementor/v1/globals"
PLUGIN_NAMESPACES["gravityforms"]="gf/v2/forms"
PLUGIN_NAMESPACES["woocommerce"]="wc/v3/products"
PLUGIN_NAMESPACES["jetpack"]="jetpack/v4/settings"
PLUGIN_NAMESPACES["litespeed"]="litespeed/v1/token"
PLUGIN_NAMESPACES["yoast"]="yoast/v1/indexing"
PLUGIN_NAMESPACES["acf"]="acf/v3/posts"
PLUGIN_NAMESPACES["contactform7"]="contact-form-7/v1/contact-forms"
PLUGIN_NAMESPACES["solidwp"]="solidwp-mail/v1/export"
PLUGIN_NAMESPACES["wpsl"]="wpsl/v1/locations"
PLUGIN_NAMESPACES["redirection"]="redirection/v1/redirect"
PLUGIN_NAMESPACES["rankmath"]="rankmath/v1/getHead"
PLUGIN_NAMESPACES["fusionbuilder"]="fusion-builder/v1/elements"
PLUGIN_NAMESPACES["visualcomposer"]="visualcomposer/v1/posts"
PLUGIN_NAMESPACES["ninjaforms"]="ninja-forms/v1/forms"
PLUGIN_NAMESPACES["wpforms"]="wpforms/v1/forms"
PLUGIN_NAMESPACES["mailchimp"]="mailchimp-for-woocommerce/v1"
PLUGIN_NAMESPACES["automatewoo"]="automatewoo/v1"
PLUGIN_NAMESPACES["give"]="give-api/v1/forms"
PLUGIN_NAMESPACES["buddypress"]="buddypress/v1/members"
PLUGIN_NAMESPACES["learndash"]="ldlms/v1/courses"
PLUGIN_NAMESPACES["restrictcontent"]="rcp/v1/memberships"
PLUGIN_NAMESPACES["eventscalendar"]="tribe/events/v1/events"
PLUGIN_NAMESPACES["woosubscriptions"]="wc/v1/subscriptions"
PLUGIN_NAMESPACES["woomemberships"]="wc/v1/memberships"
PLUGIN_NAMESPACES["wpml"]="wpml/v1/languages"
PLUGIN_NAMESPACES["polylang"]="pll/v1/languages"
PLUGIN_NAMESPACES["translatepress"]="trp/v1/languages"
PLUGIN_NAMESPACES["nextgen"]="nextgen-gallery/v1"
PLUGIN_NAMESPACES["envira"]="envira-gallery/v1"
PLUGIN_NAMESPACES["essentialgrid"]="essential-grid/v1/grids"
PLUGIN_NAMESPACES["thegrid"]="the-grid/v1/grids"
PLUGIN_NAMESPACES["masterslider"]="masterslider/v1/sliders"
PLUGIN_NAMESPACES["smartslider3"]="smart-slider-3/v1/sliders"
PLUGIN_NAMESPACES["metaslider"]="ml-slider/v1/slideshows"
PLUGIN_NAMESPACES["duplicator"]="duplicator/v1"
PLUGIN_NAMESPACES["updraft"]="updraftplus/v1"
PLUGIN_NAMESPACES["backupbuddy"]="backupbuddy/v1"
PLUGIN_NAMESPACES["aioseo"]="aioseo/v1/settings"
PLUGIN_NAMESPACES["seopress"]="seopress/v1/settings"

echo "[*] Probing ${#PLUGIN_NAMESPACES[@]} plugin namespaces on $TARGET..."
echo ""

for plugin in "${!PLUGIN_NAMESPACES[@]}"; do
  ns="${PLUGIN_NAMESPACES[$plugin]}"
  resp=$(curl -sk --max-time 5 --connect-timeout 5 -o /tmp/plugin_check_$$.tmp -w "%{http_code}" "https://$TARGET/wp-json/$ns" 2>/dev/null)

  if [[ "$resp" == "200" ]]; then
    size=$(wc -c < /tmp/plugin_check_$$.tmp)
    # Check if response is real plugin data, not SPA catch-all
    if grep -qiE 'id|slides|forms|products|settings|locations|name' /tmp/plugin_check_$$.tmp 2>/dev/null; then
      echo "[PLUGIN] $plugin — REST API active (${size} bytes)"
      cp /tmp/plugin_check_$$.tmp "$OUTDIR/${plugin}_rest.json"
    fi
  elif [[ "$resp" == "401" ]]; then
    echo "[PLUGIN] $plugin — requires auth (HTTP 401)"
  elif [[ "$resp" == "403" ]]; then
    echo "[PLUGIN] $plugin — access forbidden (HTTP 403)"
  fi
done

rm -f /tmp/plugin_check_$$.tmp
步骤 2 — 通过 readme.txt 检测版本
TARGET="$1"
OUTDIR="$OUTDIR/plugins/$TARGET"

# Common plugin slugs to check
SLUGS=(
  "elementor" "revslider" "js_composer" "wp-rocket" "wordfence"
  "woocommerce" "jetpack" "litespeed-cache" "yoast-seo" "advanced-custom-fields"
  "contact-form-7" "gravityforms" "ninja-forms" "wpforms-lite"
  "all-in-one-wp-migration" "updraftplus" "duplicator" "backupbuddy"
  "essential-grid" "smart-slider-3" "masterslider" "metaslider"
  "fusion-builder" "visualcomposer" "elementor-pro" "essential-addons-for-elementor-lite"
  "redux-framework" "buddypress" "learndash" "give"
  "the-events-calendar" "events-manager" "wpml-string-translation"
  "mailchimp-for-woocommerce" "automatewoo" "woocommerce-subscriptions"
  "woocommerce-memberships" "restrict-content-pro" "easy-digital-downloads"
  "rank-math-seo" "seo-by-rank-math" "all-in-one-seo-pack" "wp-seopress"
  "monsterinsights" "pixel-caffeine" "facebook-for-woocommerce"
  "popup-maker" "optinmonster" "mailpoet" "fluentform"
  "wp-fastest-cache" "w3-total-cache" "sg-cachepress" "autoptimize"
  "redirection" "better-wp-security" "sucuri-scanner" "wp-cerber"
  "solid-security" "solidwp-mail" "post-smtp" "wp-mail-smtp"
)

echo "[*] Checking readme.txt for ${#SLUGS[@]} plugins..."
echo ""

for slug in "${SLUGS[@]}"; do
  readme=$(curl -sk --max-time 5 --connect-timeout 5 "https://$TARGET/wp-content/plugins/$slug/readme.txt" 2>/dev/null)

  if [[ -n "$readme" ]]; then
    version=$(echo "$readme" | grep -i "stable tag:" | sed 's/.*: //' | tr -d '\r' | head -1)
    name=$(echo "$readme" | grep -i "=== .* ===" | head -1 | sed 's/=== //;s/ ===//')

    if [[ -n "$version" ]]; then
      echo "[VERSION] $slug: $version ($name)"

      # Check for known vulnerable versions
      case "$slug" in
        revslider)
          [[ "$version" < "6.6.20" ]] && echo "  [VULN] Slider Revolution < 6.6.20 — CVE-2024-2534 (RCE)" ;;
        elementskit|elementskit-lite)
          [[ "$version" < "2.9.4" ]] && echo "  [VULN] ElementsKit < 2.9.4 — CVE-2023-6851/6853 (RCE)" ;;
        litespeed-cache)
          [[ "$version" < "6.5.0" ]] && echo "  [VULN] LiteSpeed Cache < 6.5.0 — CVE-2024-50550 (priv esc)" ;;
        elementor|elementor-pro)
          [[ "$version" < "3.24.0" ]] && echo "  [VULN] Elementor < 3.24.0 — info disclosure / auth bypass" ;;
        gravityforms)
          [[ "$version" < "2.8.2" ]] && echo "  [VULN] Gravity Forms < 2.8.2 — CVE-2024-6115 (auth bypass)" ;;
        jetpack)
          [[ "$version" < "13.1" ]] && echo "  [VULN] Jetpack < 13.1 — CVE-2024-1782 (info disc)" ;;
      esac
    fi
  fi
done
步骤 3 — 检测 HTML/JS 源码中的插件
TARGET="$1"

echo "[*] Scanning HTML source for plugin fingerprints..."

PAGE=$(curl -sk --max-time 10 --connect-timeout 10 "https://$TARGET/" 2>/dev/null)

# CSS/JS handles
echo "$PAGE" | grep -Eo "(?:/wp-content/plugins/|/wp-content/themes/)[a-zA-Z0-9_-]+" | sort -u | while read -r path; do
  plugin=$(echo "$path" | grep -Eo 'plugins/\K[a-zA-Z0-9_-]+|themes/\K[a-zA-Z0-9_-]+')
  echo "  [SOURCE] $plugin (found in HTML)"
done

# Elementor specific
if echo "$PAGE" | grep -q "elementor-element\|data-elementor-id"; then
  echo "  [SOURCE] Elementor (page builder in use)"
fi

# WooCommerce specific
if echo "$PAGE" | grep -q "woocommerce\|wc-forward\|add_to_cart_button"; then
  echo "  [SOURCE] WooCommerce (e-commerce active)"
fi

# WP Rocket
if echo "$PAGE" | grep -q "wpr-minify\|rocket-lazyload"; then
  echo "  [SOURCE] WP Rocket (caching plugin)"
fi

# Cloudflare
if echo "$PAGE" | grep -q "cloudflare\|cf-browser-verification"; then
  echo "  [SOURCE] Cloudflare (CDN/WAF detected)"
fi
步骤 4 — CVE 利用快速参考

确认存在有漏洞的插件版本后:

TARGET="$1"

# Slider Revolution CVE-2024-2534 (RCE via file upload)
# Requires: revslider < 6.6.20
# Attack: POST to /wp-json/revslider/v1/upload with ZIP containing PHP
# See: security-arsenal skill for full PoC

# ElementsKit CVE-2023-6853 (RCE via file upload, unauthenticated)
# Requires: elementskit < 2.9.4
# Attack: POST to /wp-json/elementskit/v1/upload with specially crafted file
# See: security-arsenal skill for full PoC

# Gravity Forms CVE-2024-6115 (auth bypass)
# Requires: gravityforms < 2.8.2
# Attack: Unauthenticated access to form entries via REST API
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-json/gf/v2/forms" 2>/dev/null | python3 -m json.tool | head -20

# LiteSpeed Cache CVE-2024-50550 (privilege escalation)
# Requires: litespeed < 6.5.0
# Attack: Crawler token manipulation to gain admin access
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-json/litespeed/v1/token" 2>/dev/null

注意事项

  • REST 命名空间返回 200 ≠ 插件存在。 某些主题和安全插件会对所有 /wp-json/ 路径返回 200。请确认响应内容包含实际插件数据(含 id、name 或 slug 字段的 JSON)。
  • 许多主机会屏蔽 readme.txt。 WP Engine、Hostinger 和 Cloudflare 通常会在 CDN 层屏蔽 readme.txt。可改用 REST 命名空间探测或 HTML 源码搜索。
  • 自定义插件 slug。 高级插件可能使用自定义目录名称。gravityforms 也可能是 gravityforms-clientsite。请检查 HTML 源码中的 wp-content/plugins/ 路径,确认实际 slug。
  • SliderRev 的 v1 端点在 6.x 版本上可能返回 404。 Slider Revolution 更改了 REST 端点名称,但插件仍保持启用状态。请探测当前非 v1 路径,包括 /wp-json/sliderrevolution/sliders/。
  • 插件版本比较需要遵循语义化版本规则。 Bash 字符串比较(<)无法正确比较 10.x 和 2.x。复杂比较请使用 sort -V 或 python。
  • Elementor 返回 500 仅表示一条线索。 /wp-json/elementor/v1/favorites 只有在响应中包含堆栈跟踪、服务器路径或其他非公开细节时,才构成信息泄露。

托管服务提供商模式(P-23 — 对插件检测至关重要)

不同托管服务提供商对插件检测有不同的漏洞特征:

主机REST 用户readme.txtCORSXMLRPC最佳插件检测方法
GoDaddy通常暴露通常可访问经常反射通常开放readme.txt(最容易访问)
Cloudflare + WP Engine通常被阻止在 CDN 处被阻止可能可用被阻止搜索 HTML 源码 + REST 命名空间暴力枚举
Hostinger暴露可访问经常反射开放readme.txt + REST 命名空间
WP Engine(直接连接)被阻止(401)被阻止情况不一被阻止仅 HTML 源码
Bluehost暴露可访问经常反射开放所有方法均有效
SiteGround情况不一通常可访问情况不一情况不一REST 命名空间 + readme.txt

验证

  • 每个检测到的插件都必须至少通过 2 种检测方法确认(REST + readme,或 REST + HTML 源码)。
  • 每个 CVE 都必须与确切的版本号匹配,而不能仅确认插件存在。
  • 必须通过能证明影响的 PoC 验证 CVE 利用(而不只是检测版本)。
  • 对于需要身份验证的插件漏洞,必须记录凭据获取途径(CORS、暴力破解、开放注册)。

评论

支持 Markdown