$cat = absint($_GET['cat']);
$rows = $wpdb->get_results(
    $wpdb->prepare("SELECT * FROM {$wpdb->terms} WHERE term_id = %d", $cat)
);

分类页地址后面加 ?cat=1 UNION SELECT user_login,user_pass FROM wp_users,页面直接把管理员哈希打了出来,连表前缀都不用猜。这类现象通常不是突然出现的,往前翻半天日志能看到苗头。

追下去是这么回事:主题模板把 $_GET 的值拼进 SQL 字符串,没有走 $wpdb->prepare 的占位符。数字参数没做 intval,字符串参数没转义,UNION 就顺着拼进去了。

「wpdb prepare 缺失」排查到最后往往是很小的一处差异,前面那些复杂猜测可以先放一放。监控和日志的时间要对上,时区不一致会多绕很大一圈。

临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。

一次只改一处,改完立刻验证,几个改动叠在一起,出问题就说不清是谁导致的。

处理上按这个顺序:先把所有拼接点找出来,主题目录搜 $_GET 和 $wpdb->query;数字参数统一 absint,字符串参数一律用 prepare 的 %s;用同样的 payload 回归一次,确认页面只返回空结果。

确认没问题再收工,再请求同样的 UNION 地址,页面空白,错误日志里没有 SQL 语法报错。

作者 9823189