typescript-virtual-container 1.1.4 → 1.1.6
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.
- package/CHANGELOG.md +42 -0
- package/HONEYPOT.md +358 -0
- package/README.md +471 -16
- package/dist/Honeypot/index.d.ts +132 -0
- package/dist/Honeypot/index.d.ts.map +1 -0
- package/dist/Honeypot/index.js +289 -0
- package/dist/SSHMimic/index.d.ts +2 -1
- package/dist/SSHMimic/index.d.ts.map +1 -1
- package/dist/SSHMimic/index.js +12 -1
- package/dist/SSHMimic/sftp.d.ts +3 -1
- package/dist/SSHMimic/sftp.d.ts.map +1 -1
- package/dist/SSHMimic/sftp.js +20 -1
- package/dist/VirtualFileSystem/index.d.ts +2 -1
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +8 -1
- package/dist/VirtualShell/index.d.ts +2 -1
- package/dist/VirtualShell/index.d.ts.map +1 -1
- package/dist/VirtualShell/index.js +6 -1
- package/dist/VirtualUserManager/index.d.ts +2 -1
- package/dist/VirtualUserManager/index.d.ts.map +1 -1
- package/dist/VirtualUserManager/index.js +19 -1
- package/dist/honeypot.d.ts +132 -0
- package/dist/honeypot.d.ts.map +1 -0
- package/dist/honeypot.js +289 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/examples/README.md +210 -0
- package/examples/honeypot-audit.ts +180 -0
- package/examples/honeypot-export.ts +253 -0
- package/examples/honeypot-quickstart.ts +110 -0
- package/package.json +1 -1
- package/src/Honeypot/index.ts +422 -0
- package/src/SSHMimic/index.ts +13 -1
- package/src/SSHMimic/sftp.ts +21 -1
- package/src/VirtualFileSystem/index.ts +8 -1
- package/src/VirtualShell/index.ts +6 -1
- package/src/VirtualUserManager/index.ts +21 -3
- package/src/index.ts +6 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honeypot tracking and auditing module for virtual shell events.
|
|
3
|
+
*
|
|
4
|
+
* Attaches listeners to VirtualShell, VirtualFileSystem, VirtualUserManager,
|
|
5
|
+
* SshMimic, and SftpMimic instances to log all activity for security auditing,
|
|
6
|
+
* anomaly detection, and forensic analysis.
|
|
7
|
+
*
|
|
8
|
+
* @module honeypot
|
|
9
|
+
*/
|
|
10
|
+
import type { SshMimic } from "../SSHMimic";
|
|
11
|
+
import type { SftpMimic } from "../SSHMimic/sftp";
|
|
12
|
+
import type VirtualFileSystem from "../VirtualFileSystem";
|
|
13
|
+
import type { VirtualShell } from "../VirtualShell";
|
|
14
|
+
import type { VirtualUserManager } from "../VirtualUserManager";
|
|
15
|
+
/**
|
|
16
|
+
* Audit log entry recorded for each event.
|
|
17
|
+
*/
|
|
18
|
+
export interface AuditLogEntry {
|
|
19
|
+
timestamp: string;
|
|
20
|
+
type: string;
|
|
21
|
+
source: string;
|
|
22
|
+
details: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Statistics tracker for honeypot activity.
|
|
26
|
+
*/
|
|
27
|
+
export interface HoneyPotStats {
|
|
28
|
+
authAttempts: number;
|
|
29
|
+
authSuccesses: number;
|
|
30
|
+
authFailures: number;
|
|
31
|
+
commands: number;
|
|
32
|
+
fileWrites: number;
|
|
33
|
+
fileReads: number;
|
|
34
|
+
sessionStarts: number;
|
|
35
|
+
sessionEnds: number;
|
|
36
|
+
userCreated: number;
|
|
37
|
+
userDeleted: number;
|
|
38
|
+
clientConnects: number;
|
|
39
|
+
clientDisconnects: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* HoneyPot audit and event tracking utility.
|
|
43
|
+
*
|
|
44
|
+
* Singleton-like helper that attaches listeners to virtual shell components
|
|
45
|
+
* and maintains an audit log of all activity.
|
|
46
|
+
*/
|
|
47
|
+
export declare class HoneyPot {
|
|
48
|
+
private auditLog;
|
|
49
|
+
private stats;
|
|
50
|
+
private maxLogSize;
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new HoneyPot instance.
|
|
53
|
+
*
|
|
54
|
+
* @param maxLogSize Maximum audit log entries to retain (default: 10000).
|
|
55
|
+
*/
|
|
56
|
+
constructor(maxLogSize?: number);
|
|
57
|
+
/**
|
|
58
|
+
* Attaches honeypot listeners to all provided event emitters.
|
|
59
|
+
*
|
|
60
|
+
* @param shell VirtualShell instance.
|
|
61
|
+
* @param vfs VirtualFileSystem instance.
|
|
62
|
+
* @param users VirtualUserManager instance.
|
|
63
|
+
* @param ssh SshMimic instance (optional).
|
|
64
|
+
* @param sftp SftpMimic instance (optional).
|
|
65
|
+
*/
|
|
66
|
+
attach(shell: VirtualShell, vfs: VirtualFileSystem, users: VirtualUserManager, ssh?: SshMimic, sftp?: SftpMimic): void;
|
|
67
|
+
/**
|
|
68
|
+
* Attaches to VirtualShell events.
|
|
69
|
+
*/
|
|
70
|
+
private attachVirtualShell;
|
|
71
|
+
/**
|
|
72
|
+
* Attaches to VirtualFileSystem events.
|
|
73
|
+
*/
|
|
74
|
+
private attachVirtualFileSystem;
|
|
75
|
+
/**
|
|
76
|
+
* Attaches to VirtualUserManager events.
|
|
77
|
+
*/
|
|
78
|
+
private attachVirtualUserManager;
|
|
79
|
+
/**
|
|
80
|
+
* Attaches to SshMimic events.
|
|
81
|
+
*/
|
|
82
|
+
private attachSshMimic;
|
|
83
|
+
/**
|
|
84
|
+
* Attaches to SftpMimic events.
|
|
85
|
+
*/
|
|
86
|
+
private attachSftpMimic;
|
|
87
|
+
/**
|
|
88
|
+
* Records an audit log entry.
|
|
89
|
+
*
|
|
90
|
+
* @param source Event source (e.g., "SshMimic", "VirtualFileSystem").
|
|
91
|
+
* @param type Event type.
|
|
92
|
+
* @param details Event-specific data.
|
|
93
|
+
*/
|
|
94
|
+
private log;
|
|
95
|
+
/**
|
|
96
|
+
* Returns audit log entries matching optional filters.
|
|
97
|
+
*
|
|
98
|
+
* @param type Optional event type filter.
|
|
99
|
+
* @param source Optional source filter.
|
|
100
|
+
* @returns Filtered audit log entries.
|
|
101
|
+
*/
|
|
102
|
+
getAuditLog(type?: string, source?: string): AuditLogEntry[];
|
|
103
|
+
/**
|
|
104
|
+
* Returns current activity statistics.
|
|
105
|
+
*
|
|
106
|
+
* @returns Snapshot of honeypot stats.
|
|
107
|
+
*/
|
|
108
|
+
getStats(): Readonly<HoneyPotStats>;
|
|
109
|
+
/**
|
|
110
|
+
* Clears audit log and resets statistics.
|
|
111
|
+
*/
|
|
112
|
+
reset(): void;
|
|
113
|
+
/**
|
|
114
|
+
* Returns recent log entries in reverse chronological order.
|
|
115
|
+
*
|
|
116
|
+
* @param limit Number of recent entries to return (default: 100).
|
|
117
|
+
* @returns Recent audit log entries.
|
|
118
|
+
*/
|
|
119
|
+
getRecent(limit?: number): AuditLogEntry[];
|
|
120
|
+
/**
|
|
121
|
+
* Detects potential security issues based on activity patterns.
|
|
122
|
+
*
|
|
123
|
+
* @returns Array of anomalies detected.
|
|
124
|
+
*/
|
|
125
|
+
detectAnomalies(): Array<{
|
|
126
|
+
type: string;
|
|
127
|
+
severity: "low" | "medium" | "high";
|
|
128
|
+
message: string;
|
|
129
|
+
}>;
|
|
130
|
+
}
|
|
131
|
+
export default HoneyPot;
|
|
132
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Honeypot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,iBAAiB,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,qBAAa,QAAQ;IACpB,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,KAAK,CAaX;IAEF,OAAO,CAAC,UAAU,CAAS;IAE3B;;;;OAIG;gBACS,UAAU,GAAE,MAAc;IAItC;;;;;;;;OAQG;IACI,MAAM,CACZ,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,kBAAkB,EACzB,GAAG,CAAC,EAAE,QAAQ,EACd,IAAI,CAAC,EAAE,SAAS,GACd,IAAI;IAYP;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAmB1B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAoB/B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAkChC;;OAEG;IACH,OAAO,CAAC,cAAc;IAyCtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAyCvB;;;;;;OAMG;IACH,OAAO,CAAC,GAAG;IAuBX;;;;;;OAMG;IACI,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE;IAOnE;;;;OAIG;IACI,QAAQ,IAAI,QAAQ,CAAC,aAAa,CAAC;IAI1C;;OAEG;IACI,KAAK,IAAI,IAAI;IAkBpB;;;;;OAKG;IACI,SAAS,CAAC,KAAK,GAAE,MAAY,GAAG,aAAa,EAAE;IAItD;;;;OAIG;IACI,eAAe,IAAI,KAAK,CAAC;QAC/B,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;QACpC,OAAO,EAAE,MAAM,CAAC;KAChB,CAAC;CAkDF;AAED,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honeypot tracking and auditing module for virtual shell events.
|
|
3
|
+
*
|
|
4
|
+
* Attaches listeners to VirtualShell, VirtualFileSystem, VirtualUserManager,
|
|
5
|
+
* SshMimic, and SftpMimic instances to log all activity for security auditing,
|
|
6
|
+
* anomaly detection, and forensic analysis.
|
|
7
|
+
*
|
|
8
|
+
* @module honeypot
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* HoneyPot audit and event tracking utility.
|
|
12
|
+
*
|
|
13
|
+
* Singleton-like helper that attaches listeners to virtual shell components
|
|
14
|
+
* and maintains an audit log of all activity.
|
|
15
|
+
*/
|
|
16
|
+
export class HoneyPot {
|
|
17
|
+
auditLog = [];
|
|
18
|
+
stats = {
|
|
19
|
+
authAttempts: 0,
|
|
20
|
+
authSuccesses: 0,
|
|
21
|
+
authFailures: 0,
|
|
22
|
+
commands: 0,
|
|
23
|
+
fileWrites: 0,
|
|
24
|
+
fileReads: 0,
|
|
25
|
+
sessionStarts: 0,
|
|
26
|
+
sessionEnds: 0,
|
|
27
|
+
userCreated: 0,
|
|
28
|
+
userDeleted: 0,
|
|
29
|
+
clientConnects: 0,
|
|
30
|
+
clientDisconnects: 0,
|
|
31
|
+
};
|
|
32
|
+
maxLogSize;
|
|
33
|
+
/**
|
|
34
|
+
* Creates a new HoneyPot instance.
|
|
35
|
+
*
|
|
36
|
+
* @param maxLogSize Maximum audit log entries to retain (default: 10000).
|
|
37
|
+
*/
|
|
38
|
+
constructor(maxLogSize = 10000) {
|
|
39
|
+
this.maxLogSize = maxLogSize;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Attaches honeypot listeners to all provided event emitters.
|
|
43
|
+
*
|
|
44
|
+
* @param shell VirtualShell instance.
|
|
45
|
+
* @param vfs VirtualFileSystem instance.
|
|
46
|
+
* @param users VirtualUserManager instance.
|
|
47
|
+
* @param ssh SshMimic instance (optional).
|
|
48
|
+
* @param sftp SftpMimic instance (optional).
|
|
49
|
+
*/
|
|
50
|
+
attach(shell, vfs, users, ssh, sftp) {
|
|
51
|
+
this.attachVirtualShell(shell);
|
|
52
|
+
this.attachVirtualFileSystem(vfs);
|
|
53
|
+
this.attachVirtualUserManager(users);
|
|
54
|
+
if (ssh) {
|
|
55
|
+
this.attachSshMimic(ssh);
|
|
56
|
+
}
|
|
57
|
+
if (sftp) {
|
|
58
|
+
this.attachSftpMimic(sftp);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Attaches to VirtualShell events.
|
|
63
|
+
*/
|
|
64
|
+
attachVirtualShell(shell) {
|
|
65
|
+
shell.on("initialized", () => {
|
|
66
|
+
this.log("VirtualShell", "initialized", {});
|
|
67
|
+
});
|
|
68
|
+
shell.on("command", (data) => {
|
|
69
|
+
this.stats.commands++;
|
|
70
|
+
this.log("VirtualShell", "command", data);
|
|
71
|
+
});
|
|
72
|
+
shell.on("session:start", (data) => {
|
|
73
|
+
this.stats.sessionStarts++;
|
|
74
|
+
this.log("VirtualShell", "session:start", data);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Attaches to VirtualFileSystem events.
|
|
79
|
+
*/
|
|
80
|
+
attachVirtualFileSystem(vfs) {
|
|
81
|
+
vfs.on("file:read", (data) => {
|
|
82
|
+
this.stats.fileReads++;
|
|
83
|
+
this.log("VirtualFileSystem", "file:read", data);
|
|
84
|
+
});
|
|
85
|
+
vfs.on("file:write", (data) => {
|
|
86
|
+
this.stats.fileWrites++;
|
|
87
|
+
this.log("VirtualFileSystem", "file:write", data);
|
|
88
|
+
});
|
|
89
|
+
vfs.on("dir:create", (data) => {
|
|
90
|
+
this.log("VirtualFileSystem", "dir:create", data);
|
|
91
|
+
});
|
|
92
|
+
vfs.on("mirror:flush", () => {
|
|
93
|
+
this.log("VirtualFileSystem", "mirror:flush", {});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Attaches to VirtualUserManager events.
|
|
98
|
+
*/
|
|
99
|
+
attachVirtualUserManager(users) {
|
|
100
|
+
users.on("initialized", () => {
|
|
101
|
+
this.log("VirtualUserManager", "initialized", {});
|
|
102
|
+
});
|
|
103
|
+
users.on("user:add", (data) => {
|
|
104
|
+
this.stats.userCreated++;
|
|
105
|
+
this.log("VirtualUserManager", "user:add", data);
|
|
106
|
+
});
|
|
107
|
+
users.on("user:delete", (data) => {
|
|
108
|
+
this.stats.userDeleted++;
|
|
109
|
+
this.log("VirtualUserManager", "user:delete", data);
|
|
110
|
+
});
|
|
111
|
+
users.on("session:register", (data) => {
|
|
112
|
+
this.log("VirtualUserManager", "session:register", data);
|
|
113
|
+
});
|
|
114
|
+
users.on("session:unregister", (data) => {
|
|
115
|
+
this.stats.sessionEnds++;
|
|
116
|
+
this.log("VirtualUserManager", "session:unregister", data);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Attaches to SshMimic events.
|
|
121
|
+
*/
|
|
122
|
+
attachSshMimic(ssh) {
|
|
123
|
+
ssh.on("start", (data) => {
|
|
124
|
+
this.log("SshMimic", "start", data);
|
|
125
|
+
});
|
|
126
|
+
ssh.on("stop", () => {
|
|
127
|
+
this.log("SshMimic", "stop", {});
|
|
128
|
+
});
|
|
129
|
+
ssh.on("auth:success", (data) => {
|
|
130
|
+
this.stats.authAttempts++;
|
|
131
|
+
this.stats.authSuccesses++;
|
|
132
|
+
this.log("SshMimic", "auth:success", data);
|
|
133
|
+
});
|
|
134
|
+
ssh.on("auth:failure", (data) => {
|
|
135
|
+
this.stats.authAttempts++;
|
|
136
|
+
this.stats.authFailures++;
|
|
137
|
+
this.log("SshMimic", "auth:failure", data);
|
|
138
|
+
});
|
|
139
|
+
ssh.on("client:connect", () => {
|
|
140
|
+
this.stats.clientConnects++;
|
|
141
|
+
this.log("SshMimic", "client:connect", {});
|
|
142
|
+
});
|
|
143
|
+
ssh.on("client:disconnect", (data) => {
|
|
144
|
+
this.stats.clientDisconnects++;
|
|
145
|
+
this.log("SshMimic", "client:disconnect", data);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Attaches to SftpMimic events.
|
|
150
|
+
*/
|
|
151
|
+
attachSftpMimic(sftp) {
|
|
152
|
+
sftp.on("start", (data) => {
|
|
153
|
+
this.log("SftpMimic", "start", data);
|
|
154
|
+
});
|
|
155
|
+
sftp.on("stop", () => {
|
|
156
|
+
this.log("SftpMimic", "stop", {});
|
|
157
|
+
});
|
|
158
|
+
sftp.on("auth:success", (data) => {
|
|
159
|
+
this.stats.authAttempts++;
|
|
160
|
+
this.stats.authSuccesses++;
|
|
161
|
+
this.log("SftpMimic", "auth:success", data);
|
|
162
|
+
});
|
|
163
|
+
sftp.on("auth:failure", (data) => {
|
|
164
|
+
this.stats.authAttempts++;
|
|
165
|
+
this.stats.authFailures++;
|
|
166
|
+
this.log("SftpMimic", "auth:failure", data);
|
|
167
|
+
});
|
|
168
|
+
sftp.on("client:connect", () => {
|
|
169
|
+
this.stats.clientConnects++;
|
|
170
|
+
this.log("SftpMimic", "client:connect", {});
|
|
171
|
+
});
|
|
172
|
+
sftp.on("client:disconnect", (data) => {
|
|
173
|
+
this.stats.clientDisconnects++;
|
|
174
|
+
this.log("SftpMimic", "client:disconnect", data);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Records an audit log entry.
|
|
179
|
+
*
|
|
180
|
+
* @param source Event source (e.g., "SshMimic", "VirtualFileSystem").
|
|
181
|
+
* @param type Event type.
|
|
182
|
+
* @param details Event-specific data.
|
|
183
|
+
*/
|
|
184
|
+
log(source, type, details) {
|
|
185
|
+
const entry = {
|
|
186
|
+
timestamp: new Date().toISOString(),
|
|
187
|
+
type,
|
|
188
|
+
source,
|
|
189
|
+
details,
|
|
190
|
+
};
|
|
191
|
+
this.auditLog.push(entry);
|
|
192
|
+
// Trim log if exceeds max size
|
|
193
|
+
if (this.auditLog.length > this.maxLogSize) {
|
|
194
|
+
this.auditLog = this.auditLog.slice(-this.maxLogSize);
|
|
195
|
+
}
|
|
196
|
+
// Console output for real-time monitoring
|
|
197
|
+
console.log(`[AUDIT] ${entry.timestamp} | ${source} | ${type}`, details);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Returns audit log entries matching optional filters.
|
|
201
|
+
*
|
|
202
|
+
* @param type Optional event type filter.
|
|
203
|
+
* @param source Optional source filter.
|
|
204
|
+
* @returns Filtered audit log entries.
|
|
205
|
+
*/
|
|
206
|
+
getAuditLog(type, source) {
|
|
207
|
+
return this.auditLog.filter((entry) => (!type || entry.type === type) && (!source || entry.source === source));
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Returns current activity statistics.
|
|
211
|
+
*
|
|
212
|
+
* @returns Snapshot of honeypot stats.
|
|
213
|
+
*/
|
|
214
|
+
getStats() {
|
|
215
|
+
return Object.freeze({ ...this.stats });
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Clears audit log and resets statistics.
|
|
219
|
+
*/
|
|
220
|
+
reset() {
|
|
221
|
+
this.auditLog = [];
|
|
222
|
+
this.stats = {
|
|
223
|
+
authAttempts: 0,
|
|
224
|
+
authSuccesses: 0,
|
|
225
|
+
authFailures: 0,
|
|
226
|
+
commands: 0,
|
|
227
|
+
fileWrites: 0,
|
|
228
|
+
fileReads: 0,
|
|
229
|
+
sessionStarts: 0,
|
|
230
|
+
sessionEnds: 0,
|
|
231
|
+
userCreated: 0,
|
|
232
|
+
userDeleted: 0,
|
|
233
|
+
clientConnects: 0,
|
|
234
|
+
clientDisconnects: 0,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Returns recent log entries in reverse chronological order.
|
|
239
|
+
*
|
|
240
|
+
* @param limit Number of recent entries to return (default: 100).
|
|
241
|
+
* @returns Recent audit log entries.
|
|
242
|
+
*/
|
|
243
|
+
getRecent(limit = 100) {
|
|
244
|
+
return this.auditLog.slice(Math.max(0, this.auditLog.length - limit));
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Detects potential security issues based on activity patterns.
|
|
248
|
+
*
|
|
249
|
+
* @returns Array of anomalies detected.
|
|
250
|
+
*/
|
|
251
|
+
detectAnomalies() {
|
|
252
|
+
const anomalies = [];
|
|
253
|
+
// High auth failure rate
|
|
254
|
+
if (this.stats.authAttempts > 0 &&
|
|
255
|
+
this.stats.authFailures / this.stats.authAttempts > 0.5) {
|
|
256
|
+
anomalies.push({
|
|
257
|
+
type: "high_auth_failure_rate",
|
|
258
|
+
severity: "medium",
|
|
259
|
+
message: `Auth failure rate: ${((this.stats.authFailures / this.stats.authAttempts) * 100).toFixed(1)}%`,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
// Excessive auth failures in short time
|
|
263
|
+
if (this.stats.authFailures > 10) {
|
|
264
|
+
anomalies.push({
|
|
265
|
+
type: "excessive_auth_failures",
|
|
266
|
+
severity: "high",
|
|
267
|
+
message: `${this.stats.authFailures} authentication failures detected`,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
// Unusual command execution volume
|
|
271
|
+
if (this.stats.commands > 1000) {
|
|
272
|
+
anomalies.push({
|
|
273
|
+
type: "high_command_volume",
|
|
274
|
+
severity: "low",
|
|
275
|
+
message: `${this.stats.commands} commands executed`,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
// Unusual file write volume
|
|
279
|
+
if (this.stats.fileWrites > 500) {
|
|
280
|
+
anomalies.push({
|
|
281
|
+
type: "high_write_volume",
|
|
282
|
+
severity: "medium",
|
|
283
|
+
message: `${this.stats.fileWrites} file write operations`,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
return anomalies;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
export default HoneyPot;
|
package/dist/SSHMimic/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
1
2
|
import { Server as SshServer } from "ssh2";
|
|
2
3
|
import { VirtualShell } from "../VirtualShell";
|
|
3
4
|
/**
|
|
@@ -7,7 +8,7 @@ import { VirtualShell } from "../VirtualShell";
|
|
|
7
8
|
* Create an instance, call {@link SshMimic.start}, and stop it with
|
|
8
9
|
* {@link SshMimic.stop} when your process exits.
|
|
9
10
|
*/
|
|
10
|
-
declare class SshMimic {
|
|
11
|
+
declare class SshMimic extends EventEmitter {
|
|
11
12
|
port: number;
|
|
12
13
|
server: SshServer | null;
|
|
13
14
|
private shell;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAI/C;;;;;;GAMG;AACH,cAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAI/C;;;;;;GAMG;AACH,cAAM,QAAS,SAAQ,YAAY;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,aAAa,CAAS;IAE9B;;;;;;OAMG;gBACS,EACX,IAAI,EACJ,QAA0B,EAC1B,KAAkC,GAClC,EAAE;QACF,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,YAAY,CAAC;KACrB;IAQD;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAwHrC;;OAEG;IACI,IAAI,IAAI,IAAI;CAQnB;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
package/dist/SSHMimic/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
1
2
|
import { Server as SshServer } from "ssh2";
|
|
2
3
|
import { VirtualShell } from "../VirtualShell";
|
|
3
4
|
import { runExec } from "./exec";
|
|
@@ -9,7 +10,7 @@ import { loadOrCreateHostKey } from "./hostKey";
|
|
|
9
10
|
* Create an instance, call {@link SshMimic.start}, and stop it with
|
|
10
11
|
* {@link SshMimic.stop} when your process exits.
|
|
11
12
|
*/
|
|
12
|
-
class SshMimic {
|
|
13
|
+
class SshMimic extends EventEmitter {
|
|
13
14
|
port;
|
|
14
15
|
server;
|
|
15
16
|
shell;
|
|
@@ -22,6 +23,7 @@ class SshMimic {
|
|
|
22
23
|
* @param shell Optional preconfigured virtual shell instance to reuse.
|
|
23
24
|
*/
|
|
24
25
|
constructor({ port, hostname = "typescript-vm", shell = new VirtualShell(hostname), }) {
|
|
26
|
+
super();
|
|
25
27
|
this.port = port;
|
|
26
28
|
this.shellHostname = hostname;
|
|
27
29
|
this.server = null;
|
|
@@ -44,17 +46,23 @@ class SshMimic {
|
|
|
44
46
|
let authUser = "root";
|
|
45
47
|
let remoteAddress = "unknown";
|
|
46
48
|
let sessionId = null;
|
|
49
|
+
this.emit("client:connect");
|
|
47
50
|
client.on("authentication", (ctx) => {
|
|
48
51
|
shell;
|
|
49
52
|
if (ctx.method === "password") {
|
|
50
53
|
const candidateUser = ctx.username || "root";
|
|
51
54
|
remoteAddress = ctx.ip ?? remoteAddress;
|
|
52
55
|
if (!shell.users.verifyPassword(candidateUser, ctx.password ?? "")) {
|
|
56
|
+
this.emit("auth:failure", {
|
|
57
|
+
username: candidateUser,
|
|
58
|
+
remoteAddress,
|
|
59
|
+
});
|
|
53
60
|
ctx.reject();
|
|
54
61
|
return;
|
|
55
62
|
}
|
|
56
63
|
authUser = candidateUser;
|
|
57
64
|
sessionId = shell.users.registerSession(authUser, remoteAddress).id;
|
|
65
|
+
this.emit("auth:success", { username: authUser, remoteAddress });
|
|
58
66
|
const homePath = `/home/${authUser}`;
|
|
59
67
|
if (!shell.vfs.exists(homePath)) {
|
|
60
68
|
shell.vfs.mkdir(homePath, 0o755);
|
|
@@ -68,6 +76,7 @@ class SshMimic {
|
|
|
68
76
|
});
|
|
69
77
|
client.on("close", () => {
|
|
70
78
|
shell.users.unregisterSession(sessionId);
|
|
79
|
+
this.emit("client:disconnect", { user: authUser });
|
|
71
80
|
sessionId = null;
|
|
72
81
|
});
|
|
73
82
|
client.on("ready", () => {
|
|
@@ -100,6 +109,7 @@ class SshMimic {
|
|
|
100
109
|
this.server?.once("error", (err) => reject(err));
|
|
101
110
|
this.server?.listen(this.port, "0.0.0.0", () => {
|
|
102
111
|
console.log(`SSH Mimic listening on port ${this.port}`);
|
|
112
|
+
this.emit("start", { port: this.port });
|
|
103
113
|
resolve(this.port);
|
|
104
114
|
});
|
|
105
115
|
});
|
|
@@ -111,6 +121,7 @@ class SshMimic {
|
|
|
111
121
|
if (this.server) {
|
|
112
122
|
this.server.close(() => {
|
|
113
123
|
console.log("SSH Mimic stopped");
|
|
124
|
+
this.emit("stop");
|
|
114
125
|
});
|
|
115
126
|
}
|
|
116
127
|
}
|
package/dist/SSHMimic/sftp.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** biome-ignore-all lint/style/useNamingConvention: const as enum */
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
1
3
|
import { Server as SshServer } from "ssh2";
|
|
2
4
|
import type VirtualFileSystem from "../VirtualFileSystem";
|
|
3
5
|
import { VirtualShell } from "../VirtualShell";
|
|
@@ -9,7 +11,7 @@ export interface SftpMimicOptions {
|
|
|
9
11
|
vfs?: VirtualFileSystem;
|
|
10
12
|
users?: VirtualUserManager;
|
|
11
13
|
}
|
|
12
|
-
export declare class SftpMimic {
|
|
14
|
+
export declare class SftpMimic extends EventEmitter {
|
|
13
15
|
port: number;
|
|
14
16
|
server: SshServer | null;
|
|
15
17
|
private readonly hostname;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sftp.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/sftp.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sftp.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/sftp.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,KAAK,iBAAiB,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AA2HhE,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,GAAG,CAAC,EAAE,iBAAiB,CAAC;IACxB,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC3B;AAED,qBAAa,SAAU,SAAQ,YAAY;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;IAC5C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAC3C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,OAAO,CAAiC;gBAEpC,EACX,IAAI,EACJ,QAA0B,EAC1B,KAAK,EACL,GAAG,EACH,KAAK,GACL,EAAE,gBAAgB;IAuBnB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,QAAQ;IAIH,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAwJ9B,IAAI,IAAI,IAAI;IASnB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAiB1B;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,kBAAkB;CA6a1B"}
|
package/dist/SSHMimic/sftp.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** biome-ignore-all lint/style/useNamingConvention: const as enum */
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
import { Server as SshServer } from "ssh2";
|
|
4
5
|
import { VirtualShell } from "../VirtualShell";
|
|
@@ -22,7 +23,7 @@ const OPEN_MODE = {
|
|
|
22
23
|
TRUNC: 0x00000010,
|
|
23
24
|
EXCL: 0x00000020,
|
|
24
25
|
};
|
|
25
|
-
export class SftpMimic {
|
|
26
|
+
export class SftpMimic extends EventEmitter {
|
|
26
27
|
port;
|
|
27
28
|
server;
|
|
28
29
|
hostname;
|
|
@@ -32,6 +33,7 @@ export class SftpMimic {
|
|
|
32
33
|
nextHandleId = 0;
|
|
33
34
|
handles = new Map();
|
|
34
35
|
constructor({ port, hostname = "typescript-vm", shell, vfs, users, }) {
|
|
36
|
+
super();
|
|
35
37
|
this.port = port;
|
|
36
38
|
this.server = null;
|
|
37
39
|
this.hostname = hostname;
|
|
@@ -80,6 +82,7 @@ export class SftpMimic {
|
|
|
80
82
|
let authUser = "root";
|
|
81
83
|
let sessionId = null;
|
|
82
84
|
let remoteAddress = "unknown";
|
|
85
|
+
this.emit("client:connect");
|
|
83
86
|
// Add error handling for the client
|
|
84
87
|
client.on("error", (error) => {
|
|
85
88
|
console.error(`[SFTP] Client error:`, error);
|
|
@@ -104,10 +107,15 @@ export class SftpMimic {
|
|
|
104
107
|
console.log(`[SFTP] Auth attempt: user=${candidateUser}, method=${ctx.method}, ip=${remoteAddress}`);
|
|
105
108
|
if (ctx.method === "password") {
|
|
106
109
|
if (!this.getUsers().verifyPassword(candidateUser, ctx.password ?? "")) {
|
|
110
|
+
this.emit("auth:failure", {
|
|
111
|
+
username: candidateUser,
|
|
112
|
+
remoteAddress,
|
|
113
|
+
});
|
|
107
114
|
ctx.reject(allowedAuthMethods);
|
|
108
115
|
return;
|
|
109
116
|
}
|
|
110
117
|
acceptSession(candidateUser);
|
|
118
|
+
this.emit("auth:success", { username: authUser, remoteAddress });
|
|
111
119
|
ctx.accept();
|
|
112
120
|
return;
|
|
113
121
|
}
|
|
@@ -116,10 +124,18 @@ export class SftpMimic {
|
|
|
116
124
|
keyboardCtx.prompt([{ prompt: "Password: ", echo: false }], (answers) => {
|
|
117
125
|
const password = answers[0] ?? "";
|
|
118
126
|
if (!this.getUsers().verifyPassword(candidateUser, password)) {
|
|
127
|
+
this.emit("auth:failure", {
|
|
128
|
+
username: candidateUser,
|
|
129
|
+
remoteAddress,
|
|
130
|
+
});
|
|
119
131
|
keyboardCtx.reject(allowedAuthMethods);
|
|
120
132
|
return;
|
|
121
133
|
}
|
|
122
134
|
acceptSession(candidateUser);
|
|
135
|
+
this.emit("auth:success", {
|
|
136
|
+
username: authUser,
|
|
137
|
+
remoteAddress,
|
|
138
|
+
});
|
|
123
139
|
keyboardCtx.accept();
|
|
124
140
|
});
|
|
125
141
|
return;
|
|
@@ -128,6 +144,7 @@ export class SftpMimic {
|
|
|
128
144
|
});
|
|
129
145
|
client.on("close", () => {
|
|
130
146
|
this.getUsers().unregisterSession(sessionId);
|
|
147
|
+
this.emit("client:disconnect", { user: authUser });
|
|
131
148
|
sessionId = null;
|
|
132
149
|
});
|
|
133
150
|
client.on("ready", () => {
|
|
@@ -152,6 +169,7 @@ export class SftpMimic {
|
|
|
152
169
|
? address.port
|
|
153
170
|
: this.port;
|
|
154
171
|
console.log(`SFTP Mimic listening on port ${actualPort}`);
|
|
172
|
+
this.emit("start", { port: actualPort });
|
|
155
173
|
resolve(actualPort);
|
|
156
174
|
});
|
|
157
175
|
});
|
|
@@ -160,6 +178,7 @@ export class SftpMimic {
|
|
|
160
178
|
if (this.server) {
|
|
161
179
|
this.server.close(() => {
|
|
162
180
|
console.log("SFTP Mimic stopped");
|
|
181
|
+
this.emit("stop");
|
|
163
182
|
});
|
|
164
183
|
}
|
|
165
184
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
1
2
|
import type { RemoveOptions, VfsNodeStats, WriteFileOptions } from "../types/vfs";
|
|
2
3
|
/**
|
|
3
4
|
* In-memory virtual filesystem with tar.gz mirror persistence.
|
|
@@ -6,7 +7,7 @@ import type { RemoveOptions, VfsNodeStats, WriteFileOptions } from "../types/vfs
|
|
|
6
7
|
* {@link VirtualFileSystem.restoreMirror} on startup and
|
|
7
8
|
* {@link VirtualFileSystem.flushMirror} to persist pending changes.
|
|
8
9
|
*/
|
|
9
|
-
declare class VirtualFileSystem {
|
|
10
|
+
declare class VirtualFileSystem extends EventEmitter {
|
|
10
11
|
private readonly mirrorRoot;
|
|
11
12
|
private ensureMirrorRoot;
|
|
12
13
|
private resolveFsPath;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/VirtualFileSystem/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/VirtualFileSystem/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,OAAO,KAAK,EACX,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,MAAM,cAAc,CAAC;AAGtB;;;;;;GAMG;AACH,cAAM,iBAAkB,SAAQ,YAAY;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,eAAe;IA4BvB;;;;OAIG;gBACS,OAAO,GAAE,MAAsB;IAK3C;;;;OAIG;IACU,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3C;;;;OAIG;IACU,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAKzC;;;;;OAKG;IACI,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,MAAc,GAAG,IAAI;IAY5D;;;;;;;;OAQG;IACI,SAAS,CACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,OAAO,GAAE,gBAAqB,GAC5B,IAAI;IAwBP;;;;;;;OAOG;IACI,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAc3C;;;;;OAKG;IACI,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAS1C;;;;;OAKG;IACI,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAQpD;;;;;OAKG;IACI,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY;IAqC7C;;;;;OAKG;IACI,IAAI,CAAC,OAAO,GAAE,MAAY,GAAG,MAAM,EAAE;IAS5C;;;;;OAKG;IACI,IAAI,CAAC,OAAO,GAAE,MAAY,GAAG,MAAM;IAW1C;;;;;;;;OAQG;IACI,aAAa,CAAC,UAAU,GAAE,MAAY,GAAG,MAAM;IAQtD;;;;OAIG;IACI,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAY7C;;;;OAIG;IACI,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAY/C;;;;;OAKG;IACI,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,IAAI;IA4BpE;;;;;OAKG;IACI,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;CAsBnD;AAED,eAAe,iBAAiB,CAAC"}
|