发布于10月9日10月9日 本文记录一个适合纳入漏洞库的 WordPress 历史漏洞条目:CVE-2019-8942 与 CVE-2019-8943。问题集中在旧版本 WordPress 对图片附件元数据、附件文件名和存储路径处理不严谨,具备上传能力的低权限账户在特定版本和配置下,可能影响站点文件操作边界;若站点同时存在可执行上传目录、插件缺陷或权限配置不当,风险可能进一步扩大。本文只讨论授权渗透测试和修复验证,不提供破坏性利用载荷。验证目标是确认版本、权限条件、文件存储策略、日志记录和修复状态,而不是在生产站点写入脚本或删除文件。一、漏洞条目与影响范围漏洞编号:CVE-2019-8942、CVE-2019-8943。影响重点:WordPress 5.0.0 至 5.0.3 等历史版本,实际影响应结合发行版本、反向代理、PHP 版本和插件情况确认。必要条件:通常需要已认证账户,并且账户具备上传媒体或修改附件的能力;“未登录即可利用”不能作为默认结论。直接风险:附件路径被异常解析、文件操作越过预期目录边界,或者利用站点已有的可执行文件处理能力扩大影响。高风险组合:旧版 WordPress、上传目录允许 PHP 执行、Web 进程对站点目录具有写权限、存在弱权限账户或第三方媒体处理插件。漏洞库记录应把“受影响版本”和“实际可利用条件”分开填写。仅发现旧版本,不等于已经证明存在远程代码执行;仅发现具备上传权限,也不等于可以直接执行 PHP。二、具体场景与问题定位典型场景是:站点运行 WordPress 5.0.x,存在一个具备 upload_files 能力的普通账户。该账户可以上传图片,站点随后根据图片元数据生成附件文件名和缩略图路径。如果旧版本的路径规范化、文件名过滤或附件元数据更新流程存在缺陷,异常输入可能影响预期的上传目录边界。首先应从主机或容器内确认实际版本,而不是只依赖页面生成的版本标记。使用 WP-CLI 时建议以只读方式执行:cd /var/www/html wp core version wp core verify-checksums wp plugin list --status=active --format=table wp user list --fields=ID,user_login,roles,capabilities --format=table如果无法使用 WP-CLI,可以检查 wp-includes/version.php 中的 $wp_version,但要注意:代码目录可能经过人工修改,版本字符串也可能被缓存或隐藏,最终应以部署包校验和、软件仓库记录或镜像标签交叉确认。权限边界需要单独核实。重点检查低权限账户是否拥有 upload_files,以及是否存在可修改附件标题、描述、文件名或媒体元数据的接口。不要使用管理员账户直接完成验证,否则会掩盖漏洞所需的最低权限条件。三、技术分析:为什么上传目录配置决定风险等级WordPress 通常将媒体存储在 wp-content/uploads/YYYY/MM。正常情况下,目录内应只存放图片、文档和其他业务允许的静态文件,不能让 PHP、PHAR 或其他服务器端脚本被 Web 服务器解释执行。因此,同一个路径处理缺陷在不同环境中的后果可能不同:上传目录禁止脚本执行:通常降低为文件覆盖、文件删除或敏感文件写入风险,但仍可能造成内容篡改和持久化。上传目录允许 PHP 执行:如果攻击者能够让服务器接收并保存可执行脚本,风险会从文件操作问题升级为远程代码执行。PHP-FPM、Apache、Nginx 对路径规范化处理不一致:编码后的点号、反斜杠、重复斜杠和路径解码顺序可能造成规则绕过,应在实际链路中验证。Web 进程对整个站点目录拥有写权限:即使没有直接执行条件,也可能覆盖插件、主题或配置文件,形成后续影响。在授权测试中,应记录以下边界信息:Web 根目录真实路径、上传目录真实路径、PHP 执行范围、Web 进程账户、容器挂载点、是否存在对象存储,以及上传文件是否经过独立的内容类型检测。四、授权验证步骤1. 先做无破坏性版本确认将目标版本与 WordPress 官方安全版本进行比对。如果站点属于生产环境,不应为了验证而降级或修改核心文件。建议在隔离的预发布环境使用同版本镜像复现,再把复现结论映射回生产环境。2. 检查上传目录是否可执行在服务器上检查 Nginx、Apache 和 PHP-FPM 配置。以下命令只读取配置和文件类型,不会创建文件:nginx -T 2>/dev/null | grep -nE 'wp-content/uploads|fastcgi_pass|location' apachectl -S 2>/dev/null find /var/www/html/wp-content/uploads -type f \\( -iname '*.php' -o -iname '*.phtml' -o -iname '*.phar' \\) -printf '%p %u:%g %m\\n' 2>/dev/null namei -l /var/www/html/wp-content/uploads发现上传目录已有 PHP 文件时,不要直接执行或访问这些文件。先记录路径、文件所有者、权限、哈希和创建时间,再由站点负责人确认是否为业务文件。若文件来源不明,应按照事件响应流程隔离取证。3. 检查 Web 进程写权限ps -eo user,pid,cmd | grep -E '[p]hp-fpm|[a]pache2|[h]ttpd|[n]ginx' stat -c '%A %U:%G %n' /var/www/html /var/www/html/wp-content /var/www/html/wp-content/uploads find /var/www/html -xdev -type d -writable -printf '%m %u:%g %p\\n' 2>/dev/null理想状态是 Web 进程只能写入必要的缓存、上传或临时目录,核心文件、插件和主题目录由发布用户管理,不能由 PHP-FPM 运行账户任意修改。容器环境还要检查宿主机目录是否以读写方式挂载。4. 检查访问日志和应用日志不要通过构造删除文件、覆盖核心文件或写入脚本来证明漏洞。可以使用已有日志确认是否出现过异常路径和上传行为:zgrep -hEi 'wp-admin/(async-upload|upload\\.php)|wp-json|\\.\\./|%2e%2e|%252e|wp-content/uploads' /var/log/nginx/access.log* 2>/dev/null | tail -n 200 grep -RniE 'upload_files|wp_handle_upload|_wp_attached_file|metadata' /var/log/php* /var/log/apache2 2>/dev/null | tail -n 100 find /var/www/html/wp-content/uploads -type f -printf '%TY-%Tm-%Td %TH:%TM:%TS %s %u:%g %p\\n' 2>/dev/null | sort | tail -n 100日志中需要关联时间、账户、源 IP、User-Agent、请求方法、HTTP 状态码和对应的附件 ID。仅凭出现 ../ 字符串不能直接判定漏洞成立,因为安全设备、扫描器和正常编码请求也可能产生类似记录。五、修复配置示例第一优先级是升级 WordPress 核心到仍受支持的安全版本,并同步升级主题、插件和 PHP 运行时。升级前应备份数据库、上传目录和当前配置,在预发布环境验证媒体上传、缩略图生成、对象存储同步等功能。Nginx 站点可在确认现有路由规则不会冲突的前提下,禁止上传目录中的脚本解释:location ~* ^/wp-content/uploads/.*\\.(php|phtml|pht|phar|php[0-9]*)$ { deny all; return 403; }Apache 2.4 可在上传目录放置最小化的访问控制规则,具体以站点是否使用 AllowOverride 为准:<FilesMatch 漏洞成因、验证条件与修复闭环示意
10月9日10月9日 这个洞排查时建议别只看“有没有上传可疑 php”,关键点在于附件的 _wp_attached_file 元数据是否被改成了带路径穿越/异常目录的值。CVE-2019-8942/8943 这条链通常需要已登录且具备媒体相关能力的账号,所以授权验证和留痕要一起看。 1)先确认是否存在可利用条件 WordPress 版本:重点看 5.0.1 之前的 5.x,以及未打补丁的 4.x 分支。 是否允许低权限用户上传媒体,比如 author、contributor 被额外赋予了 upload_files。 是否存在可编辑附件元数据的历史操作。 # 查看版本 wp core version # 查看具备上传能力的用户角色 wp role list wp cap list author | grep upload_files wp cap list contributor | grep upload_files 2)数据库侧重点查 _wp_attached_file 正常情况下该字段一般类似: 2024/01/example.jpg 如果出现 ../、绝对路径、非 uploads 子目录、异常扩展名,就需要重点确认。 SELECT p.ID, p.post_author, p.post_date, p.post_modified, pm.meta_value AS attached_file FROM wp_posts p JOIN wp_postmeta pm ON p.ID = pm.post_id WHERE p.post_type = 'attachment' AND pm.meta_key = '_wp_attached_file' AND ( pm.meta_value LIKE '%../%' OR pm.meta_value LIKE '/%' OR pm.meta_value LIKE '%..\\%' OR pm.meta_value REGEXP '\\.(php|phtml|phar|shtml)$' ) ORDER BY p.post_modified DESC; 如果站点表前缀不是 wp_,记得替换成实际前缀。 3)结合 Web 日志确认是否有授权利用痕迹 重点看已登录用户访问 async-upload.php、admin-ajax.php、附件编辑页面、图片裁剪相关请求。尤其是短时间内上传图片后马上出现裁剪、编辑附件、访问异常文件的行为。 # Nginx / Apache 访问日志中筛选典型入口 grep -E "async-upload\.php|admin-ajax\.php|post\.php|upload\.php" access.log* # 查路径穿越特征 grep -Ei "\.\./|%2e%2e|%252e%252e|_wp_attached_file|crop|image-editor" access.log* # 查 uploads 目录下被访问的脚本 grep -Ei "/wp-content/uploads/.*\.(php|phtml|phar|shtml)" access.log* 如果日志里能看到 Cookie: wordpress_logged_in_* 对应的请求,建议进一步关联登录日志或应用日志,确认是哪个用户触发的。 4)文件系统排查不要只扫 php 有些利用会先落图片,再通过裁剪/路径处理生成目标文件。建议按修改时间和扩展名一起看。 # 最近 30 天 uploads 下新增/修改的可疑脚本 find wp-content/uploads -type f -mtime -30 \ \( -name "*.php" -o -name "*.phtml" -o -name "*.phar" -o -name "*.shtml" \) \ -ls # 查包含 PHP 代码但扩展名不是 php 的文件 grep -RIl --include="*" -E "<\?php|eval\s*\(|base64_decode\s*\(" wp-content/uploads 2>/dev/null # 查看最近被修改的附件文件 find wp-content/uploads -type f -mtime -7 -printf "%TY-%Tm-%Td %TH:%TM %p\n" | sort 5)修复建议 升级 WordPress 核心到当前稳定版本,至少确保已包含 2019 年相关补丁。 回收不必要的 upload_files 能力,尤其不要给 contributor 自定义加上传权限。 禁止 uploads 目录执行脚本,这是兜底措施,强烈建议做。 Nginx 示例: location ~* ^/wp-content/uploads/.*\.(php|phtml|phar|shtml)$ { deny all; } Apache 示例: <Directory "/var/www/html/wp-content/uploads"> <FilesMatch "\.(php|phtml|phar|shtml)$"> Require all denied </FilesMatch> </Directory> 如果没有目录级权限,也可以在 wp-content/uploads/.htaccess 放: <FilesMatch "\.(php|phtml|phar|shtml)$"> Require all denied </FilesMatch> 6)处置时别忘了清理异常元数据 如果确认 _wp_attached_file 被污染,不建议直接批量替换,先导出留证,再按附件实际路径修正。 # 导出可疑记录 mysqldump -u root -p wordpress wp_posts wp_postmeta \ --where="1=1" > wordpress_before_fix.sql 最后建议把相关低权限账号密码重置一遍,并检查最近新增管理员、插件文件和主题文件。这个漏洞入口是授权用户,但后续如果落了 webshell,就不能只按“低权限误操作”处理了。
10月9日10月9日 补充一个排查点:只查 _wp_attached_file 当前值可能会漏掉“已经被改回去”的情况,建议把附件主表、上传用户、附件元数据一起关联看,重点看路径和时间线是否对得上。 -- 找 _wp_attached_file 中明显异常的路径 SELECT p.ID, p.post_date, p.post_author, u.user_login, p.post_title, pm.meta_value AS attached_file FROM wp_posts p JOIN wp_postmeta pm ON p.ID = pm.post_id LEFT JOIN wp_users u ON p.post_author = u.ID WHERE p.post_type = 'attachment' AND pm.meta_key = '_wp_attached_file' AND ( pm.meta_value LIKE '%../%' OR pm.meta_value LIKE '/%' OR pm.meta_value LIKE '%\\%' OR pm.meta_value LIKE '%.php%' OR pm.meta_value REGEXP '(^|/)\\.' ) ORDER BY p.post_date DESC; 另外建议一起查 _wp_attachment_metadata,有些异常会体现在缩略图、sizes 里的 file 字段,而不一定只在主路径里。 SELECT p.ID, p.post_date, u.user_login, pm.meta_value FROM wp_posts p JOIN wp_postmeta pm ON p.ID = pm.post_id LEFT JOIN wp_users u ON p.post_author = u.ID WHERE p.post_type = 'attachment' AND pm.meta_key = '_wp_attachment_metadata' AND ( pm.meta_value LIKE '%../%' OR pm.meta_value LIKE '%/tmp/%' OR pm.meta_value LIKE '%.php%' OR pm.meta_value LIKE '%s:4:"file"%' ) ORDER BY p.post_date DESC LIMIT 100; 日志侧可以按附件编辑相关入口回溯,不只看上传接口。常见需要关注: /wp-admin/async-upload.php:媒体上传; /wp-admin/post.php:附件编辑、更新; /wp-admin/admin-ajax.php:媒体相关 AJAX 操作; 同一登录用户在短时间内是否有多次修改附件、裁剪图片、编辑图片操作。 # Nginx/Apache 日志里按后台媒体相关入口粗筛 grep -E "wp-admin/(async-upload.php|post.php|admin-ajax.php)" access.log* \ | grep -Ei "attachment|upload|media|image|crop|edit" # 如果日志里带 Cookie 或用户名映射,也可以按可疑时间段进一步缩小 grep "2024-01-15:1[0-2]:" access.log* | grep "wp-admin" 如果站点有审计插件或反向代理日志,建议重点确认三类信息:账号、源 IP、附件 ID。附件 ID 可以和数据库里的 wp_posts.ID 对上,这样比单纯看文件名可靠。 修复时我一般按这个顺序处理: 先备份数据库和 wp-content/uploads; 升级 WordPress 核心到受修复版本,插件主题也一起更新; 收回非必要角色的 upload_files、edit_posts 等能力; 清理异常附件元数据; 重新生成缩略图; 强制可疑账号改密、清理会话。 权限收敛可以直接用 WP-CLI 看一下有没有被额外加过能力: wp cap list contributor wp cap list author # 如果 contributor 不应该上传媒体 wp cap remove contributor upload_files # 视业务情况检查 author 是否真的需要上传 wp cap remove author upload_files 清理元数据不要直接批量替换所有记录,容易误伤历史媒体。建议先导出命中结果,人工确认后再改。改完可以用: wp media regenerate --yes 最后别忘了检查 uploads 目录里是否存在不该有的可执行文件。即使这条链核心在附件路径元数据,落地后经常会伴随其它上传点或插件问题。 find wp-content/uploads -type f \( -name "*.php" -o -name "*.phtml" -o -name "*.phar" -o -name "*.shtml" \) -ls 如果是 Nginx,建议明确禁止 uploads 下脚本执行,作为兜底: location ~* ^/wp-content/uploads/.*\.(php|phtml|phar|shtml)$ { deny all; } Apache 可以在 wp-content/uploads/.htaccess 里加: <FilesMatch "\.(php|phtml|phar|shtml)$"> Require all denied </FilesMatch> 这样即便后续又出现媒体上传类问题,也能降低直接 WebShell 执行的风险。
创建帐户或登录后发表意见