From f4475ea45d26ed9346a2f511462bd3f35a7d5c00 Mon Sep 17 00:00:00 2001 From: Isak Van Der Walt Date: Mon, 9 Sep 2024 16:43:19 +0200 Subject: [PATCH 1/6] [fix] Add check for empty file. --- agent/src/android/filesystem.ts | 3 +++ agent/src/ios/filesystem.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/agent/src/android/filesystem.ts b/agent/src/android/filesystem.ts index aaf0eaf..7338b0f 100644 --- a/agent/src/android/filesystem.ts +++ b/agent/src/android/filesystem.ts @@ -1,4 +1,5 @@ import * as fs from "fs"; +import { Buffer } from "buffer"; import { hexStringToBytes } from "../lib/helpers.js"; import { IAndroidFilesystem } from "./lib/interfaces.js"; import { @@ -79,6 +80,8 @@ export const pwd = (): Promise => { // heavy lifting is done in frida-fs here. export const readFile = (path: string): Buffer => { + if (fs.statSync(path).size == 0) + return Buffer.alloc(0); return fs.readFileSync(path); }; diff --git a/agent/src/ios/filesystem.ts b/agent/src/ios/filesystem.ts index cf10b07..6451223 100644 --- a/agent/src/ios/filesystem.ts +++ b/agent/src/ios/filesystem.ts @@ -1,4 +1,5 @@ import * as fs from "fs"; +import { Buffer } from "buffer"; import { hexStringToBytes } from "../lib/helpers.js"; import { getNSFileManager } from "./lib/helpers.js"; import { @@ -88,6 +89,8 @@ export const pwd = (): string => { // heavy lifting is done in frida-fs here. export const readFile = (path: string): Buffer => { + if (fs.statSync(path).size == 0) + return Buffer.alloc(0); return fs.readFileSync(path); }; From b683997b728532c9005ac2419321f4fb1a3202f8 Mon Sep 17 00:00:00 2001 From: Isak Van Der Walt Date: Mon, 9 Sep 2024 16:58:17 +0200 Subject: [PATCH 2/6] [fix] Support for "../", file autocomplete adds quotes. --- objection/commands/filemanager.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/objection/commands/filemanager.py b/objection/commands/filemanager.py index 89f9956..69956a0 100644 --- a/objection/commands/filemanager.py +++ b/objection/commands/filemanager.py @@ -44,7 +44,9 @@ def cd(args: list) -> None: return # moving one directory back - if path == '..': + device_path_separator = device_state.platform.path_separator + + if path == '..' or path == '..'+device_path_separator: split_path = os.path.split(current_dir) @@ -66,6 +68,10 @@ def cd(args: list) -> None: # assume the path does not exist by default does_exist = False + # normalise path to remove '../' + if '..'+device_path_separator in path: + path = os.path.normpath(path).replace('\\', device_path_separator) + # check for existence based on the runtime if device_state.platform == Ios: does_exist = _path_exists_ios(path) @@ -89,7 +95,13 @@ def cd(args: list) -> None: # see if its legit. else: - proposed_path = device_state.platform.path_separator.join([current_dir, path]) + proposed_path = device_path_separator.join([current_dir, path]) + + # normalise path to remove '../' + if '..'+device_path_separator in proposed_path: + proposed_path = os.path.normpath(proposed_path).replace('\\', device_path_separator) + if proposed_path == '//': + return # assume the proposed_path does not exist by default does_exist = False @@ -785,7 +797,10 @@ def list_folders_in_current_fm_directory() -> dict: file_name, file_type = entry if file_type == 'directory': - resp[file_name] = file_name + if ' ' in file_name: + resp[f"'{file_name}'"] = file_name + else: + resp[file_name] = file_name return resp @@ -816,6 +831,9 @@ def list_files_in_current_fm_directory() -> dict: file_name, file_type = entry if file_type == 'file': - resp[file_name] = file_name + if ' ' in file_name: + resp[f"'{file_name}'"] = file_name + else: + resp[file_name] = file_name return resp From a85a0681f1e53aab21b210f791b80c96840a9490 Mon Sep 17 00:00:00 2001 From: Isak Van Der Walt Date: Mon, 9 Sep 2024 19:24:48 +0200 Subject: [PATCH 3/6] (fix) Webserver changes revert. Added "recursive" directory listing. --- agent/src/android/filesystem.ts | 4 +-- agent/src/generic/http.ts | 59 +++++++++++++++++++++++++-------- agent/src/ios/filesystem.ts | 4 +-- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/agent/src/android/filesystem.ts b/agent/src/android/filesystem.ts index 7338b0f..40c78e1 100644 --- a/agent/src/android/filesystem.ts +++ b/agent/src/android/filesystem.ts @@ -1,4 +1,4 @@ -import * as fs from "fs"; +import * as fs from "frida-fs"; import { Buffer } from "buffer"; import { hexStringToBytes } from "../lib/helpers.js"; import { IAndroidFilesystem } from "./lib/interfaces.js"; @@ -79,7 +79,7 @@ export const pwd = (): Promise => { }; // heavy lifting is done in frida-fs here. -export const readFile = (path: string): Buffer => { +export const readFile = (path: string): string | Buffer => { if (fs.statSync(path).size == 0) return Buffer.alloc(0); return fs.readFileSync(path); diff --git a/agent/src/generic/http.ts b/agent/src/generic/http.ts index 8bc7ff4..9ffd595 100644 --- a/agent/src/generic/http.ts +++ b/agent/src/generic/http.ts @@ -1,4 +1,4 @@ -import * as fs from "fs"; +import * as fs from "frida-fs"; import * as httpLib from "http"; import * as url from "url"; import { colors as c } from "../lib/color.js"; @@ -11,7 +11,7 @@ const log = (m: string): void => { c.log(`[http server] ${m}`); }; -const dirListingHTML = (p: string): string => { +const dirListingHTML = (pwd: string, path: string): string => { let h = ` @@ -22,8 +22,15 @@ const dirListingHTML = (p: string): string => { `; h = h.replace(`{file_listing}`, () => { - return fs.readdirSync(p).map((f) => { - return `${f}`; + return fs.list(pwd + path).map((f) => { + // Add a slash at the end if it is a directory. + var fname = f.name + (f.type == 4 ? '/' : ''); + + if (path !== '/') { + return `${fname}`; + } else { + return `${fname}`; + } }).join("
"); }); @@ -49,16 +56,40 @@ export const start = (pwd: string, port: number = 9000): void => { log(`${c.redBright('Missing URL or request method.')}`); return; } - - const parsedUrl = new URL(req.url); - if (parsedUrl.pathname === "/") { - res.end(dirListingHTML(pwd)); - return; - } + try { + const parsedUrl = url.parse(req.url); + const fileLocation = pwd + decodeURIComponent(parsedUrl.path); + + if (fs.statSync(fileLocation).isDirectory()) { + res.end(dirListingHTML(pwd, decodeURIComponent(parsedUrl.path))); + return; + } - res.setHeader("Content-type", "application/octet-stream"); - res.end(fs.readFileSync(pwd + parsedUrl.pathname)); + res.setHeader("Content-type", "application/octet-stream"); + + // Check that we are not reading an empty file + if (fs.statSync(fileLocation).size !== 0) { + const file = fs.readFileSync(fileLocation); + res.write(file, 'utf-8') + } + res.end(); + + } catch (error) { + if (error instanceof Error && error.message == "No such file or directory") { + res.statusCode = 404; + res.end("File not found") + } else { + if (error instanceof Error) { + log(c.redBright(`${error.stack}`)); + } else { + log(c.redBright(`${error}`)); + } + + res.statusCode = 500; + res.end("Internal Server Error") + } + } }); httpServer.listen(port); @@ -75,12 +106,12 @@ export const stop = (): void => { httpServer.close() .once("close", () => { log(c.blackBright(`Server closed.`)); - // httpServer = undefined; + httpServer = undefined; }); }; export const status = (): void => { - if (httpServer.listening) { + if (httpServer && httpServer.listening) { log(`Server is running on port ` + `${c.greenBright(listenPort.toString())} serving ${c.greenBright(servePath)}`); return; diff --git a/agent/src/ios/filesystem.ts b/agent/src/ios/filesystem.ts index 6451223..deaf562 100644 --- a/agent/src/ios/filesystem.ts +++ b/agent/src/ios/filesystem.ts @@ -1,4 +1,4 @@ -import * as fs from "fs"; +import * as fs from "frida-fs"; import { Buffer } from "buffer"; import { hexStringToBytes } from "../lib/helpers.js"; import { getNSFileManager } from "./lib/helpers.js"; @@ -88,7 +88,7 @@ export const pwd = (): string => { }; // heavy lifting is done in frida-fs here. -export const readFile = (path: string): Buffer => { +export const readFile = (path: string): string | Buffer => { if (fs.statSync(path).size == 0) return Buffer.alloc(0); return fs.readFileSync(path); From 77bc2fac156c9baece9f4799ca66b37814ed82a0 Mon Sep 17 00:00:00 2001 From: Isak Van Der Walt Date: Mon, 9 Sep 2024 19:37:14 +0200 Subject: [PATCH 4/6] (fix) Android --uid flag fix. Fix frida-fs types. --- agent/src/ios/binary.ts | 3 +++ agent/src/rpc/ios.ts | 2 +- objection/utils/agent.py | 5 ++++- requirements.txt | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/agent/src/ios/binary.ts b/agent/src/ios/binary.ts index 4939754..7a0fd8f 100644 --- a/agent/src/ios/binary.ts +++ b/agent/src/ios/binary.ts @@ -31,6 +31,9 @@ export const info = (): IBinaryModuleDictionary => { const imports: Set = new Set(a.enumerateImports().map((i) => i.name)); const fb = iosfilesystem.readFile(a.path); + if (typeof(fb) == 'string') { + return; + } try { const exe = macho.parse(fb); diff --git a/agent/src/rpc/ios.ts b/agent/src/rpc/ios.ts index 47a8eb8..9e7836e 100644 --- a/agent/src/rpc/ios.ts +++ b/agent/src/rpc/ios.ts @@ -40,7 +40,7 @@ export const ios = { // ios filesystem iosFileCwd: (): string => iosfilesystem.pwd(), iosFileDelete: (path: string): boolean => iosfilesystem.deleteFile(path), - iosFileDownload: (path: string): Buffer => iosfilesystem.readFile(path), + iosFileDownload: (path: string): string | Buffer => iosfilesystem.readFile(path), iosFileExists: (path: string): boolean => iosfilesystem.exists(path), iosFileLs: (path: string): IIosFileSystem => iosfilesystem.ls(path), iosFilePathIsFile: (path: string): boolean => iosfilesystem.pathIsFile(path), diff --git a/objection/utils/agent.py b/objection/utils/agent.py index cf2a4ed..64ecc7b 100644 --- a/objection/utils/agent.py +++ b/objection/utils/agent.py @@ -216,6 +216,8 @@ def set_target_pid(self): elif self.config.spawn: if self.config.uid is not None: + if self.device.query_system_parameters()['os']['id'] != 'android': + raise Exception('--uid flag can only be used on Android.') self.pid = self.device.spawn(self.config.name, uid=int(self.config.uid)) else: self.pid = self.device.spawn(self.config.name) @@ -245,9 +247,10 @@ def attach(self): raise Exception('A PID needs to be set before attach()') if self.config.uid is None: + debug_print(f'Attaching to PID: {self.pid}') self.session = self.device.attach(self.pid) else: - self.session = self.device.attach(self.pid, uid=self.config.uid) + self.session = self.device.attach(self.pid) self.session.on('detached', self.handlers.session_on_detached) diff --git a/requirements.txt b/requirements.txt index 1f678cf..2b309d3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ requests Flask>=3.0.0 Pygments>=2.0.0 litecli>=1.3.0 +setuptools>=70.0.0 From b38cec4c1b904cef2902698ff8640e4848ef4b11 Mon Sep 17 00:00:00 2001 From: Isak Van Der Walt Date: Tue, 10 Sep 2024 14:17:51 +0200 Subject: [PATCH 5/6] (fix) enumerateKeychain not returning updated value. --- agent/src/ios/keychain.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/agent/src/ios/keychain.ts b/agent/src/ios/keychain.ts index d408696..e3d797f 100644 --- a/agent/src/ios/keychain.ts +++ b/agent/src/ios/keychain.ts @@ -111,9 +111,7 @@ const enumerateKeychain = (): IKeychainData[] => { }); const keyChainData: IKeychainData[] = []; - keyChainData.concat(...itemClassResults).filter((n) => n !== undefined); - - return keyChainData; + return keyChainData.concat(...itemClassResults).filter((n) => n !== undefined); }; // print raw entries using some Frida magic From 789e9a8c3c52bcfa9958f46f234263b14e4c030e Mon Sep 17 00:00:00 2001 From: Isak Van Der Walt Date: Sun, 13 Oct 2024 15:12:20 +0200 Subject: [PATCH 6/6] (fix) show correct path dirListing. --- agent/src/generic/http.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/agent/src/generic/http.ts b/agent/src/generic/http.ts index 9ffd595..ad56d4f 100644 --- a/agent/src/generic/http.ts +++ b/agent/src/generic/http.ts @@ -15,20 +15,22 @@ const dirListingHTML = (pwd: string, path: string): string => { let h = ` -

Index Of /

+

Index Of ${path}

{file_listing} `; h = h.replace(`{file_listing}`, () => { - return fs.list(pwd + path).map((f) => { + return fs.list(pwd + decodeURIComponent(path)).map((f) => { + if (f.name === '.') return; + // Add a slash at the end if it is a directory. var fname = f.name + (f.type == 4 ? '/' : ''); if (path !== '/') { return `${fname}`; - } else { + } else if (fname !== '../') { return `${fname}`; } }).join("
"); @@ -62,7 +64,7 @@ export const start = (pwd: string, port: number = 9000): void => { const fileLocation = pwd + decodeURIComponent(parsedUrl.path); if (fs.statSync(fileLocation).isDirectory()) { - res.end(dirListingHTML(pwd, decodeURIComponent(parsedUrl.path))); + res.end(dirListingHTML(pwd, parsedUrl.path)); return; }