Page MenuHomeSealhub

No OneTemporary

Authored By
Unknown
Size
15 KB
Referenced Files
None
Subscribers
None
diff --git a/android/code/index.ts b/android/code/index.ts
index 4226475..9304684 100644
--- a/android/code/index.ts
+++ b/android/code/index.ts
@@ -1,477 +1,481 @@
import child_process from "child_process";
import { Server } from "socket.io";
import { exit } from "process";
import fs from "node:fs/promises";
import { summerize_har } from "har-analyzer/analyzer";
import { AnalysisResponse, AnalysisResult } from "./types";
async function spawnPromise(
program: string,
args: string[]
): Promise<{ output: string; code: number }> {
return new Promise((resolve, _reject) => {
let output = "";
const process = child_process.spawn(program, args);
process.stdout.on("data", (data) => {
output += data;
});
process.stderr.on("data", (data) => {
output += data;
});
process.on("close", (code) => {
resolve({ output, code });
});
process.on("error", (err) => {
console.log("Process has errored", err);
resolve({ output, code: 1 });
});
});
}
let io = new Server();
async function send_private_data() {
let adid = (await spawnPromise("bash", ["/conf/get_adid.sh"])).output;
let gps_coords = (await spawnPromise("bash", ["/conf/get_location.sh"]))
.output;
let gps_coords_split = gps_coords.trim().split(",");
io.emit("private_info", {
adid,
latitude: gps_coords_split[0],
longitude: gps_coords_split[1],
});
}
async function send_ports_scan() {
function state_to_confidence(state) {
if (state === "open") return 3;
if (state === "filtered") return 2;
if (state === "closed") return 1;
console.error("unexpected nmap port state:", state);
return 0;
}
// [{"proto": "tcp", "port": "2221", "state": "open", "name": "ftp"}, ...]
let out = (await spawnPromise("bash", ["/conf/nmap_scan.sh"])).output;
let ports_info = JSON.parse(out);
let ports = new Map();
for (let row of ports_info) {
let prev = ports.get(row.port);
if (
!prev ||
state_to_confidence(row.state) > state_to_confidence(prev.state)
) {
prev = row;
ports.set(row.port, prev);
}
}
let ret = [];
for (let [port, port_row] of ports.entries()) {
ret.push({ port: port, state: port_row.state, name: port_row.name });
}
io.emit("ports_scan", ret);
}
async function send_open_ports() {
let ports = (
await spawnPromise("bash", ["/conf/get_ports.sh"])
).output.trim();
if (ports !== "") {
io.emit("open_ports", ports.split(" "));
} else {
io.emit("open_ports", []);
}
}
async function send_installed_apps() {
let out = await spawnPromise("bash", ["/conf/get_installed_apps.sh"]);
if (out.code != 0) {
send_notification(
io,
false,
"Listing installed apps with frida",
out.output
);
}
try {
io.emit("installed_apps", JSON.parse(out.output));
} catch {}
}
function send_notification(socket, is_ok, context, message) {
socket.emit("notification", {
is_ok,
context,
message,
});
}
let analyzer_running = false;
-let uuids_to_analyze = [];
+type ANALYSE_REQ = {uuid: string, app_id?: string};
+let uuids_to_analyze: ANALYSE_REQ[] = [];
let analysis_results: Record<string, AnalysisResult> = {};
async function analyze() {
// CORRECTNESS: Because the UUIDs are removed from the `uuids_to_analyze` array by index,
// it's important that only one instance of this function runs at any given moment
if (analyzer_running) {
return;
}
analyzer_running = true;
try {
while (uuids_to_analyze.length !== 0) {
- let uuid = uuids_to_analyze[0];
+ let uuid = uuids_to_analyze[0].uuid;
console.info("Running uuid: " + uuid);
const cmd = await spawnPromise("bash", ["/conf/analyze.sh", uuid]);
console.info("Finished running uuid with: ", cmd);
const har_route = `/shared_buffer/app/${uuid}/har`;
if (cmd.code !== 0) {
console.error("Analysis error:", cmd.output);
analysis_results[uuid] = {
status: "analysis_failed",
error: "Failed to analyze the app",
error_code:
cmd.code == 2 ? "signature_check_failed" : "other",
};
} else {
let har = await fs.readFile(har_route, {
encoding: "utf8",
});
const adid = await fs.readFile(
`/shared_buffer/app/${uuid}/adid`,
{
encoding: "utf8",
}
);
const requested_adid = parseInt(
await fs.readFile(
`/shared_buffer/app/${uuid}/requested_adid`,
{ encoding: "utf8" }
)
);
const adid_perm_required = parseInt(
await fs.readFile(
`/shared_buffer/app/${uuid}/adid_perm_required`,
{ encoding: "utf-8" }
)
) == 0 ? false : true;
const screenshot = await fs.readFile(
`/shared_buffer/app/${uuid}/screenshot`,
{ encoding: "utf8" }
);
const fallback = parseInt(await fs.readFile(
`/shared_buffer/app/${uuid}/fallback`,
{ encoding: "utf8" }
)) == 1;
analysis_results[uuid] = {
status: "ok",
screenshot,
requested_adid,
adid_perm_required,
fallback,
summary: await summerize_har(new Blob([har]), [
[adid, "adid"],
]),
};
}
// delete the har file immediatelly
await fs.rm(har_route, { force: true, recursive: true });
// Delete the uuid
uuids_to_analyze = uuids_to_analyze.slice(1);
// Create a timer to delete the results
setTimeout(
async () => {
console.log("cleaning up uuid:", uuid);
analysis_results[uuid] = undefined;
await fs.rm(`/shared_buffer/app/${uuid}`, {
force: true,
recursive: true,
});
},
// 10 min timer
1000 * 60 * 10
);
}
} catch (e) {
console.error("Analyzing apk failed: ", e);
}
analyzer_running = false;
}
let gps_setting_in_progress = false;
//maybe check output of child processes and send errors in some way
io.on("connection", (socket) => {
send_notification(socket, true, "Server started", "");
socket.onAny((ev, ...args) => {
console.log("server got: ", ev, ...args);
});
let screenshots_in_flight = 0;
let last_screen_id = 0;
socket.on("screenshot", async (id) => {
last_screen_id = id;
if (screenshots_in_flight > 1) return;
screenshots_in_flight++;
try {
let screenshot = await spawnPromise("bash", [
"/conf/screenshot.sh",
]);
let image_data_base64 = screenshot.output;
socket.emit("screenshot_data", {
data: image_data_base64,
resp_id: last_screen_id,
});
} catch (err) {
console.error(
"Failed to get the screenshot. The emulator probably died",
err
);
return;
}
screenshots_in_flight--;
});
let priv_data_requests_in_flight = 0;
socket.on("private_info_req", async () => {
if (priv_data_requests_in_flight > 3) return;
priv_data_requests_in_flight++;
await send_private_data();
priv_data_requests_in_flight--;
});
let port_requests_in_flight = 0;
socket.on("open_ports_req", async () => {
if (port_requests_in_flight > 3) return;
port_requests_in_flight++;
await send_open_ports();
port_requests_in_flight--;
});
let installed_apps_requests_in_flight = 0;
socket.on("installed_apps_req", async () => {
if (installed_apps_requests_in_flight > 3) return;
installed_apps_requests_in_flight++;
await send_installed_apps();
installed_apps_requests_in_flight--;
});
let scan_ports_requests_in_flight = 0;
socket.on("ports_scan_req", async () => {
if (scan_ports_requests_in_flight > 0) {
send_notification(
socket,
false,
"A scan is already in progress...",
""
);
return;
}
scan_ports_requests_in_flight++;
await send_ports_scan();
scan_ports_requests_in_flight--;
send_notification(socket, true, "Nmap scan finished...", "");
});
socket.on("start_frida_app", async (app_id) => {
await spawnPromise("bash", ["/conf/start_frida_app.sh", app_id]);
send_notification(
socket,
true,
"Frida intercepting stopped",
"the traffic of " + app_id + " is no longer being intercepted"
);
});
socket.on("shallow_reset", async () => {
send_notification(socket, true, "Shallow reset is in progress", "");
await spawnPromise("bash", ["/conf/restart_mitmproxy.sh"]);
send_notification(socket, true, "Shallow reset is finished", "");
});
socket.on("full_reset", async () => {
console.log("Exiting for a reaset....");
exit(0);
});
socket.on("reset_adid", async () => {
await spawnPromise("bash", ["/conf/reset_adid.sh"]);
await send_private_data();
});
socket.on("back", async () => {
if (gps_setting_in_progress) {
send_notification(
socket,
false,
"Interactions not allowed when setting gps coordinates",
""
);
return;
}
await spawnPromise("bash", ["/conf/back.sh"]);
});
socket.on("recent", async () => {
if (gps_setting_in_progress) {
send_notification(
socket,
false,
"Interactions not allowed when setting gps coordinates",
""
);
return;
}
await spawnPromise("bash", ["/conf/recent.sh"]);
});
socket.on("home", async () => {
if (gps_setting_in_progress) {
send_notification(
socket,
false,
"Interactions not allowed when setting gps coordinates",
""
);
return;
}
await spawnPromise("bash", ["/conf/home.sh"]);
});
socket.on("install", async () => {
const res = await spawnPromise("bash", ["/conf/install.sh"]);
send_notification(
socket,
res.code === 0,
"Installing the application",
res.output
);
});
// https://ihateregex.io/expr/uuid/
// The \b seams to be redundant
const uuid_regex =
/^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/;
- socket.on("analyze", async (uuid) => {
- // this is not a user controlled input,
- // but just in case this changes later
- if (uuid_regex.exec(uuid) !== null) {
- uuids_to_analyze.push(uuid);
- analyze();
- }
+
+ socket.on("analyze", async (param: ANALYSE_REQ) => {
+ uuids_to_analyze.push(param);
+ analyze();
});
socket.on(
"analysis_status",
- async (uuid, callback: (resp: AnalysisResponse) => void) => {
+ async (uuid: string, callback: (resp: AnalysisResponse) => void) => {
// We need to validate the uuid, so the users don't start
// doing anything dumb (injecting commands)
if (uuid_regex.exec(uuid) === null) {
callback({ status: "invalid_uuid" });
return;
}
- let idx = uuids_to_analyze.indexOf(uuid);
+ let idx = uuids_to_analyze.findIndex((e) => e.uuid == uuid);
if (idx != -1) {
callback({ status: "waiting", queue_position: idx });
return;
}
if (analysis_results[uuid] === undefined) {
callback({ status: "job_not_found" });
return;
}
callback(analysis_results[uuid]);
}
);
+ socket.on(
+ "queue_status",
+ async (callback: (resp: ANALYSE_REQ[]) => void) => {
+ callback(uuids_to_analyze)
+ }
+ )
// drag handles both drag and click
socket.on("motionevent", async (data) => {
if (gps_setting_in_progress) {
send_notification(
socket,
false,
"Interactions not allowed when setting gps coordinates",
""
);
return;
}
await spawnPromise("bash", [
"/conf/motionevent.sh",
data.motionType,
data.x + "",
data.y + "",
]);
});
// drag handles both drag and click
socket.on("drag", async (data) => {
if (gps_setting_in_progress) {
send_notification(
socket,
false,
"Interactions not allowed when setting gps coordinates",
""
);
return;
}
await spawnPromise("bash", [
"/conf/drag.sh",
data.startX + "",
data.startY + "",
data.endX + "",
data.endY + "",
data.dragTime + "",
]);
});
socket.on("key", async (data) => {
if (gps_setting_in_progress) {
send_notification(
socket,
false,
"Interactions not allowed when setting gps coordinates",
""
);
return;
}
await spawnPromise("bash", ["/conf/press_key.sh", data.key]);
});
socket.on("setcoord", async (data) => {
if (gps_setting_in_progress) {
send_notification(
socket,
false,
"Interactions not allowed when setting gps coordinates",
""
);
return;
}
gps_setting_in_progress = true;
const res = await spawnPromise("bash", [
"/conf/set_geo_full.sh",
data.lon + "",
data.lat + "",
]);
send_notification(
socket,
res.code === 0,
"Setting the moch location",
res.output
);
gps_setting_in_progress = false;
await send_private_data();
});
});
io.listen(3000);
console.log("listening on port 3000");
diff --git a/http_server/code/index.ts b/http_server/code/index.ts
index 219c970..461ca20 100644
--- a/http_server/code/index.ts
+++ b/http_server/code/index.ts
@@ -1,85 +1,91 @@
// This is always on the first line, to avoid the majority of git conflicts
import "./webui"
import express from "express";
import { writeFile } from "node:fs/promises";
import { execSync } from "node:child_process";
import fileUpload from "express-fileupload";
const analysis_app = express();
analysis_app.use(express.urlencoded({ extended: false }));
analysis_app.use(express.text({ limit: "500mb" }));
analysis_app.use(fileUpload());
import { randomUUID } from "node:crypto";
import { back } from "./shared"
analysis_app.post("/analyze_apk", async function (req, res) {
try {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send("No files were uploaded.");
}
let uuid = randomUUID();
let dir = `/shared_buffer/app/${uuid}`;
execSync(`mkdir -p ${dir}`);
if (Array.isArray(req.files.app)) {
for (const [idx, file] of req.files.app.entries()) {
// SAFETY: The only user controlled input is the file names, and the file contents
// We replace the file names with indexes here
await file.mv(`${dir}/${idx}.apk`);
}
} else {
await req.files.app.mv(`${dir}/0.apk`);
}
- back.emit("analyze", uuid);
+ back.emit("analyze", {uuid: uuid});
res.status(200).send(uuid);
} catch (e) {
console.log(e);
res.status(500);
}
});
analysis_app.post("/analyze_app_id", async function (req, res) {
console.log(req.body);
let app_id = Object.keys(req.body)[0];
// allows for versions with org.example.app@100.2.3
let re = /^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+){1,}(?:@(?:[0-9]+\.?)+)?$/;
if (typeof app_id != "string" || !re.test(app_id)) {
return res.status(400).send("Invalid request");
}
let uuid = randomUUID();
let dir = `/shared_buffer/app/${uuid}`;
execSync(`mkdir -p ${dir}`);
await writeFile(`${dir}/app_name`, app_id);
- back.emit("analyze", uuid);
+ back.emit("analyze", {uuid: uuid, app_id: app_id});
res.status(200).send(uuid);
});
analysis_app.post("/analysis_status", async function (req, res) {
console.log(req.body);
let uuid = Object.keys(req.body)[0];
if (typeof uuid != "string") {
return res.status(400).send("Invalid request");
}
// SAFETY: the UUID is verified / parsed in the backend
back.emit("analysis_status", uuid, (response: any) => {
return res.status(200).send(JSON.stringify(response));
});
});
+analysis_app.get("/queue_status", async function (_req, res) {
+ back.emit("queue_status", (response: any) => {
+ return res.status(200).send(JSON.stringify(response));
+ })
+})
+
analysis_app.listen(8081, () =>
console.log("Analysis API listening on port 8081")
);

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 9, 13:35 (16 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1182188
Default Alt Text
(15 KB)

Event Timeline