Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F10361240
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
18 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/android/conf/docker-entrypoint.sh b/android/conf/docker-entrypoint.sh
index 3446143..645d2c2 100644
--- a/android/conf/docker-entrypoint.sh
+++ b/android/conf/docker-entrypoint.sh
@@ -1,10 +1,24 @@
bash /conf/start_culebra.sh &
npm i -C /code
bash /conf/wait_for_sd.sh
adb shell su root /tmp/frida-server &
+apt-get install iptables -y
-cd /frida-scripts && perl -i -0777p -e 's|CERT_PEM = .*?;|CERT_PEM = `'"$(cat /certificates/ca.pem | sed -z 's/\n/\\n/g')"'`;|gsm' config.js
+# configuring the pinning / unpinning scripts
+perl -i -0777p -e 's|CERT_PEM = .*?;|CERT_PEM = `'"$(cat /certificates/mitmproxy-ca-cert.pem | sed -z 's/\n/\\n/g')"'`;|gsm' /frida-scripts/config.js
+perl -i -0777p -e 's|const PROXY_SUPPORTS_SOCKS5 = false|const PROXY_SUPPORTS_SOCKS5 = true|gsm' /frida-scripts/config.js
+perl -i -0777p -e 's|const BLOCK_HTTP3 = true|const BLOCK_HTTP3 = true|gsm' /frida-scripts/config.js
+perl -i -0777p -e 's|const PROXY_PORT = 8000|const PROXY_PORT = 8000|gsm' /frida-scripts/config.js
+
+# configuring forwarding the proxy info to mitmproxy
adb reverse tcp:8000 tcp:8000
+# iptables -t nat -A OUTPUT -p tcp --dport 8000 -j DNAT --to-destination $(getent hosts mitmproxy | awk '{ print $1 }'):8000
+
+iptables -t nat -A OUTPUT -m addrtype --src-type LOCAL --dst-type LOCAL -p tcp --dport 8000 -j DNAT --to-destination $(getent hosts mitmproxy | awk '{ print $1 }'):1080
+iptables -t nat -A POSTROUTING -m addrtype --src-type LOCAL --dst-type UNICAST -j MASQUERADE
+
+# iptables -t nat -A POSTROUTING -p tcp -d mitmproxy --dport 8000 -j SNAT --to-source 127.0.0.1:8000
+
node /code/index.mjs
diff --git a/android/entrypoint.sh b/android/entrypoint.sh
index 8c4dd8e..ecb5f2e 100755
--- a/android/entrypoint.sh
+++ b/android/entrypoint.sh
@@ -1,31 +1,31 @@
#!/bin/bash
set -e
-node /proxy_cache_thing/dist/index.js &
-CACHE_PID=$!
+# node /proxy_cache_thing/dist/index.js &
+# CACHE_PID=$!
-/httptoolkit-server/bin/run start -c /certificates &
-HTTPTOOLKIT_SERVER_PID=$!
+# /httptoolkit-server/bin/run start -c /certificates &
+# HTTPTOOLKIT_SERVER_PID=$!
bash /conf/docker-entrypoint.sh &
ANDROID_PID=$!
function check_dead() {
- if ! ps -p $CACHE_PID > /dev/null; then
- echo "[ERROR] The proxy cache died, exiting...";
- exit 1;
- fi
- if ! ps -p $HTTPTOOLKIT_SERVER_PID > /dev/null; then
- echo "[ERROR] The httptoolkit_server died, exiting...";
- exit 1;
- fi
+ # if ! ps -p $CACHE_PID > /dev/null; then
+ # echo "[ERROR] The proxy cache died, exiting...";
+ # exit 1;
+ # fi
+ # if ! ps -p $HTTPTOOLKIT_SERVER_PID > /dev/null; then
+ # echo "[ERROR] The httptoolkit_server died, exiting...";
+ # exit 1;
+ # fi
if ! ps -p $ANDROID_PID > /dev/null; then
echo "[ERROR] The android emulator died, exiting...";
exit 1;
fi
}
# Exit on error
while true; do
check_dead;
sleep 1;
done
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 0b693af..f374de8 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -1,59 +1,67 @@
services:
android:
build:
context: ./android/
args:
PROXY_PORT: "45459"
SERVER_PORT: "45456"
LOOPBACK_PORT: "10000"
MONITORING_API_PORT: "10001"
container_name: httptoolkit_server
container_name: android
sysctls:
- net.ipv6.conf.all.disable_ipv6=1
+ - net.ipv4.conf.all.route_localnet=1
cap_add:
- NET_ADMIN
devices:
- /dev/kvm
networks:
- rent_gen_android
ports:
- 45456:45459 # This cannot change
- 45457:45459 # This cannot change
- 10001:10001 # api port
- 3000:3000 # android server port
- 3001:3001 # Notifications server
- 5556:5556 # emulator grpc port
volumes:
- $PWD/shared_buffer:/shared_buffer
- $PWD/android/conf:/conf
- $PWD/certificates:/certificates
- $PWD/android/code:/code
+ mitmproxy:
+ build: ./mitmproxy
+ networks:
+ - rent_gen_android
+ volumes:
+ - $PWD/certificates:/root/.mitmproxy
+ container_name: mitmproxy
httptoolkit_ui:
build:
context: ./httptoolkit_ui/
args:
# The ip / hostname using which,
# the browser can reach this docker session
DOCKER_HOST: "127.0.0.1"
container_name: httptoolkit_ui
networks:
- rent_gen_android
ports:
- 9080:9080
http_server:
build: ./http_server/
container_name: http_server
networks:
- rent_gen_android
volumes:
- $PWD/http_server/code:/code
- $PWD/shared_buffer:/shared_buffer
- $PWD/log:/log
ports:
- 8080:8080
networks:
rent_gen_android:
driver: bridge
diff --git a/http_server/code/index.html b/http_server/code/index.html
index 3ac14b2..2dd1c6c 100644
--- a/http_server/code/index.html
+++ b/http_server/code/index.html
@@ -1,146 +1,146 @@
<!doctype html>
<html lang="en">
<head style="height: 100vh">
<meta charset="UTF-8" />
<title>Rentgen android</title>
<script src="/htmx.js"></script>
<link rel="stylesheet" href="styles.css" />
<script src="/main.js" type="module"></script>
</head>
<body>
<div id="notifications"></div>
<div id="resp" style="display: none"></div>
<main>
<section class="screen-section">
<img
id="screen"
alt="android screen"
src=""
draggable="false"
class="screen"
style="flex-grow: 0"
tabindex="0"
/>
<div class="screen-buttons" style="flex-grow: 0">
<button class="screen-buttons-recent-apps">recent-apps</button>
<button class="screen-buttons-home">home</button>
<button class="screen-buttons-back">back</button>
</div>
<form
id="upload_form"
hx-post="/upload_apk"
enctype="multipart/form-data"
hx-target="#resp"
>
<label id="upload_input" for="app"
>Select file
<input
type="file"
id="app"
name="app"
accept=".apk"
required
multiple
/>
</label>
<button type="submit">Install the app</button>
</form>
</section>
<div class="tab-section">
<div class="tab">
<button
class="tablinks active"
onclick="main.open_tab(event, 'httptoolkit-tab')"
>
HttpToolkit UI
</button>
<button class="tablinks" onclick="main.open_tab(event, 'logs-tab')">
Logs
</button>
<button
class="tablinks"
onclick="main.open_tab(event, 'controls-tab')"
>
Device Controls
</button>
</div>
<div class="tabcontent" id="logs-tab">
<div id="logs">
<p id="clicks-log" class="log-section"></p>
<div id="traffic-log" class="log-section">
<div>
<button onClick="main.download_har()">Download HAR</button>
<button onClick="main.inspect_har()">Inspect HAR</button>
<div>
<h2>stats:</h2>
<p id="traffic-log-req-res-pairs">
Request + responce pairs: 0
</p>
<p id="traffic-log-waiting">
Waiting for the responce: 0
</p>
</div>
<div id="traffic-log-lines">
</div>
</div>
</div>
</div>
</div>
<div class="tabcontent active" id="httptoolkit-tab">
- <iframe
- id="httptoolkit-frame"
- style="flex-grow: 1"
- src="http://localhost:9080/"
- title="httptoolkit"
- ></iframe>
+ <!-- <iframe -->
+ <!-- id="httptoolkit-frame" -->
+ <!-- style="flex-grow: 1" -->
+ <!-- src="http://localhost:9080/" -->
+ <!-- title="httptoolkit" -->
+ <!-- ></iframe> -->
</div>
<div class="tabcontent" id="controls-tab">
<form id="set_coords" onsubmit="main.coords_handler(event)">
<label>
Latitude:
<input type="text" name="lat" />
</label>
<label>
Longitude:
<input type="text" name="lon" />
</label>
<button type="submit">Submit coords</button>
</form>
<button id="reset_adid_btn" onclick="main.reset_adid_handler(event)">
Reset ADID
</button>
<table>
<thead></thead>
<tbody>
<tr>
<td>ADID:</td>
<td id="adid_priv_info_table">UNKNOWN</td>
</tr>
<tr>
<td>Longitude:</td>
<td id="lon_priv_info_table">UNKNOWN</td>
</tr>
<tr>
<td>Latitude:</td>
<td id="lat_priv_info_table">UNKNOWN</td>
</tr>
</tbody>
</table>
<h2>Lanuch app</h2>
<form id="launch_app_form">
<select name="appid" id="app_id_select">
</select>
<button type="submit">Launch app</button>
</form>
<h2>Open ports</h2>
<p id="open-ports"></p>
</div>
</div>
</main>
</body>
</html>
diff --git a/http_server/code/src/main.ts b/http_server/code/src/main.ts
index c20b4c5..07e8a15 100644
--- a/http_server/code/src/main.ts
+++ b/http_server/code/src/main.ts
@@ -1,297 +1,297 @@
// make the export accessible from inline js
import * as main from "./main";
// for some reason doing the same with the window object doesn't work
(globalThis as any).main = main;
import {
backButton,
clicksLog,
homeButton,
socket,
screen,
adid_priv_info_table,
lat_priv_info_table,
lon_priv_info_table,
recentButton,
open_ports,
app_id_select,
launch_app_form,
} from "./shared";
import { start_notifications } from "./notifications";
import { start_traffic_log } from "./traffic_log";
export { download_har, inspect_har } from "./traffic_log";
export function reset_adid_handler(_: Event) {
socket.emit("reset_adid");
}
export function coords_handler(e: FormDataEvent) {
e.preventDefault();
const form_data = new FormData(e.target as HTMLFormElement);
socket.emit("setcoord", {
lon: Number.parseFloat(form_data.get("lon") as string),
lat: Number.parseFloat(form_data.get("lat") as string),
});
}
export function open_tab(evt: Event, tab_name: string) {
let i, tabcontent, tablinks;
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
if (tabcontent[i].id != tab_name) {
tabcontent[i].classList.remove("active");
} else {
tabcontent[i].classList.add("active");
}
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].classList.remove("active");
}
// Show the current tab, and add an "active" class to the button that opened the tab
(evt.currentTarget as HTMLElement).classList.add("active");
}
let lastTouch = new Date().getTime();
export const calculateElapsedTime = () => {
const currentTouch = new Date().getTime();
const elapsedTime = currentTouch - lastTouch;
const elapsedSec = Math.round(elapsedTime / 1000);
lastTouch = currentTouch;
return elapsedSec;
};
export const waitToLog = (clickInfoText: string) => {
const clickInfo = document.createElement("span");
const waitInfo = document.createElement("span");
waitInfo.textContent = `await wait(${calculateElapsedTime()});`;
clicksLog.appendChild(waitInfo);
clickInfo.textContent = clickInfoText;
clicksLog.appendChild(clickInfo);
};
export const registerClick = ({
path,
logText,
body,
}: {
path: string;
logText: string;
body?: any;
}) => {
waitToLog(logText);
socket.emit(path, body ? body : {});
};
homeButton.addEventListener("click", () =>
registerClick({ path: "home", logText: "await homeButton();" })
);
backButton.addEventListener("click", () =>
registerClick({ path: "back", logText: "await backButton();" })
);
recentButton.addEventListener("click", () =>
registerClick({ path: "recent", logText: "await recentButton();" })
);
socket.on("screenshot_data", (data) => {
try {
const blob = new Blob([data]);
screen.src = URL.createObjectURL(blob);
} catch (error) {
console.error("Error fetching image: ", error);
}
});
socket.on("private_info", (data) => {
console.log("private_info");
adid_priv_info_table.textContent = data.adid;
lat_priv_info_table.textContent = data.latitude;
lon_priv_info_table.textContent = data.longitude;
});
socket.on("open_ports", (data: string[]) => {
console.log("open_ports");
open_ports.textContent = data.toString();
});
async function installed_apps_loop() {
var before;
while (true) {
before = performance.now();
socket.emit("installed_apps_req");
while (performance.now() - before < 2000) await sleep(100);
}
}
socket.on("installed_apps", (data) => {
let all_ids = new Set();
let all_inserted_ids = new Set();
for (let app of data) {
all_ids.add(app.identifier);
}
// remove all the elements that are no longer in the set
for (const el of app_id_select.children) {
const opt = el as HTMLOptionElement;
if (!all_ids.has(opt.value)) opt.remove();
else all_inserted_ids.add(opt.value);
}
for (let app of data) {
if (all_inserted_ids.has(app.identifier))
continue;
let app_opt = document.createElement("option");
app_opt.value = app.identifier;
app_opt.innerText = app.name;
app_id_select.appendChild(app_opt);
}
});
(launch_app_form as HTMLFormElement).addEventListener("submit", (event) => {
event.preventDefault();
event.stopImmediatePropagation();
const form_data = new FormData(event.target as HTMLFormElement);
socket.emit("start_frida_app", form_data.get("appid"));
})
socket.emit("private_info_req");
socket.onAny((ev, ...args) => {
console.log("ev: ", ev, args);
});
async function displayImage() {
socket.emit("screenshot");
}
let isDragging = false;
const screenSize = [320, 640];
export function calcMousePos(event: MouseEvent) {
let rect = screen.getBoundingClientRect();
let x = ((event.clientX - rect.left) / rect.width) * screenSize[0];
let y = ((event.clientY - rect.top) / rect.height) * screenSize[1];
x = Math.min(Math.max(x, 0), screenSize[0]);
y = Math.min(Math.max(y, 0), screenSize[1]);
return { x, y };
}
screen.addEventListener(
"mousemove",
(event) => {
if (!isDragging) return;
let pos = calcMousePos(event);
if (isDragging) {
registerClick({
path: "motionevent",
logText: `await motionevent({motionType: "MOVE", x:${pos.x},y:${pos.y}}});`,
body: {
motionType: "MOVE",
x: pos.x,
y: pos.y,
},
});
}
},
false
);
export const handleDraggStart = (event: MouseEvent) => {
isDragging = true;
let pos = calcMousePos(event);
registerClick({
path: "motionevent",
logText: `await motionevent({motionType: "DOWN", x:${pos.x},y:${pos.y}}});`,
body: {
motionType: "DOWN",
x: pos.x,
y: pos.y,
},
});
};
screen.addEventListener("mousedown", handleDraggStart);
document.addEventListener("mouseup", (e) => {
if (!isDragging) return;
isDragging = false;
let pos = calcMousePos(e);
registerClick({
path: "motionevent",
logText: `await motionevent({motionType: "MOVE", x:${pos.x},y:${pos.y}}});`,
body: {
motionType: "MOVE",
x: pos.x,
y: pos.y,
},
});
registerClick({
path: "motionevent",
logText: `await motionevent({motionType: "UP", x:${pos.x},y:${pos.y}}});`,
body: {
motionType: "UP",
x: pos.x,
y: pos.y,
},
});
});
window.addEventListener("keydown", (event) => {
let key = event.key;
if (key === "Space") key = " ";
else if (key !== "Enter" && key !== "Backspace" && key.length !== 1) return;
console.log(event.key, key);
if (screen.matches(":hover")) {
registerClick({
path: "key",
logText: `await key(${event.key});`,
body: { key },
});
}
});
export async function sleep(time: number) {
return new Promise((resolve) => setTimeout(resolve, time));
}
async function screenshot_loop() {
var before;
while (true) {
before = performance.now();
await displayImage();
// TODO: Make this dynamic again
while (performance.now() - before < 100) await sleep(50);
}
}
async function open_ports_loop() {
var before;
while (true) {
before = performance.now();
socket.emit("open_ports_req");
while (performance.now() - before < 2000) await sleep(100);
}
}
installed_apps_loop();
open_ports_loop();
screenshot_loop();
start_notifications();
-start_traffic_log();
+// start_traffic_log();
diff --git a/mitmproxy/Dockerfile b/mitmproxy/Dockerfile
new file mode 100644
index 0000000..0fe6425
--- /dev/null
+++ b/mitmproxy/Dockerfile
@@ -0,0 +1,8 @@
+FROM mitmproxy/mitmproxy
+
+USER root
+WORKDIR /root
+
+# CMD bash -c 'echo hello from mitmproxy && mitmdump -w /root/.mitmproxy/dump --set mode="socks5@0.0.0.0:1080"'
+cmd sleep 1000000000
+#--set mode="regular@0.0.0.0:8000"
diff --git a/pre_android/Dockerfile b/pre_android/Dockerfile
index b3c5238..9363c80 100644
--- a/pre_android/Dockerfile
+++ b/pre_android/Dockerfile
@@ -1,10 +1,10 @@
FROM runmymind/docker-android-sdk:ubuntu-standalone-20230511
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/android-sdk-linux/cmdline-tools/latest/bin:/opt/android-sdk-linux/cmdline-tools/tools/bin:/opt/android-sdk-linux/tools/bin:/opt/android-sdk-linux/build-tools/32.0.0:/opt/android-sdk-linux/platform-tools:/opt/android-sdk-linux/emulator:/opt/android-sdk-linux/bin
RUN sdkmanager --channel=2 "system-images;android-35;google_apis;x86_64" \
&& echo no | avdmanager create avd -n virtual_dev -b google_apis/x86_64 -k "system-images;android-35;google_apis;x86_64" \
- && apt-get update && apt-get install -y iproute2 iputils-ping npm git libxml2-utils telnet bc aapt python3 python3-pip \
+ && apt-get update && apt-get install -y iptables iproute2 iputils-ping npm git libxml2-utils telnet bc aapt python3 python3-pip \
&& pip install frida-tools && git clone https://github.com/httptoolkit/frida-interception-and-unpinning /frida-scripts
CMD bash /preconf/docker-entrypoint.sh
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 8, 12:12 (17 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1034565
Default Alt Text
(18 KB)
Attached To
Mode
R134 rentgen-android
Attached
Detach File
Event Timeline
Log In to Comment