-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathstart_proxy.py
More file actions
175 lines (153 loc) · 5.87 KB
/
start_proxy.py
File metadata and controls
175 lines (153 loc) · 5.87 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
#!/usr/bin/env python3
"""
Bosch Smart Camera — mitmproxy Helper
======================================
Starts a mitmproxy instance pre-configured for capturing Bosch Smart Camera
app traffic. Useful for:
- Discovering new API endpoints
- Capturing local camera Digest auth credentials
- Investigating motion detection rule changes
- Debugging app ↔ cloud communication
Requirements:
pip3 install mitmproxy
Usage:
python3 start_proxy.py # auto-detect IP, port 8890
python3 start_proxy.py --port 9090 # custom port
python3 start_proxy.py --dump # save flows to file for later analysis
Flags applied automatically:
--ignore-hosts Apple domains bypassed (certificate pinning blocks iOS traffic otherwise)
--ssl-insecure Accept self-signed certs (Bosch cameras use NXP-BUID self-signed certs)
Then configure your phone's WiFi proxy to point to this Mac.
See README.md section "Capturing App Traffic with mitmproxy" for full setup.
"""
import argparse
import os
import socket
import subprocess
import sys
import time
from datetime import datetime
def get_local_ip() -> str:
"""Get the Mac's local IP address on the active network interface."""
try:
result = subprocess.run(
["ipconfig", "getifaddr", "en0"],
capture_output=True, text=True, timeout=5,
)
ip = result.stdout.strip()
if ip:
return ip
except Exception:
pass
# Fallback: connect to external host to find local IP
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ip = s.getsockname()[0]
s.close()
return ip
except Exception:
return "127.0.0.1"
def check_mitmproxy() -> bool:
"""Check if mitmproxy is installed."""
try:
result = subprocess.run(
["mitmdump", "--version"],
capture_output=True, text=True, timeout=5,
)
return result.returncode == 0
except FileNotFoundError:
return False
def main():
parser = argparse.ArgumentParser(
description="Start mitmproxy for Bosch Smart Camera app traffic capture"
)
parser.add_argument(
"--port", type=int, default=8890,
help="Proxy listen port (default: 8890)"
)
parser.add_argument(
"--dump", action="store_true",
help="Save captured flows to a timestamped file for later analysis"
)
parser.add_argument(
"--filter", type=str, default="",
help="Filter expression (e.g. '~d boschsecurity.com' for Bosch traffic only)"
)
args = parser.parse_args()
if not check_mitmproxy():
print(" mitmproxy is not installed.")
print(" Install it with: pip3 install mitmproxy")
sys.exit(1)
local_ip = get_local_ip()
port = args.port
# Dump file location — save to parent captures/ folder (not inside the git repo)
script_dir = os.path.dirname(os.path.abspath(__file__))
dump_dir = os.path.join(script_dir, "..", "captures")
os.makedirs(dump_dir, exist_ok=True)
timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S")
dump_file = os.path.join(dump_dir, f"bosch_flows_{timestamp}.mitm")
print()
print("=" * 64)
print(" Bosch Smart Camera — mitmproxy Capture")
print("=" * 64)
print()
print(f" Proxy address: {local_ip}:{port}")
if args.dump:
print(f" Saving flows: {dump_file}")
print()
print(" Phone Setup (iOS / Android):")
print(" ─────────────────────────────────────────────────────")
print(f" 1. WiFi → your network → Proxy → Manual")
print(f" Server: {local_ip} Port: {port}")
print(f" 2. Open http://mitm.it on the phone browser")
print(f" → download + install the CA certificate")
print(f" 3. iOS: Settings → General → About → Certificate Trust")
print(f" → enable mitmproxy cert")
print(f" 4. Force-close the Bosch Smart Camera app")
print(f" 5. Reopen the app — traffic appears below")
print()
print(" What to look for:")
print(" ─────────────────────────────────────────────────────")
print(" • Motion detection changes:")
print(" PUT /v11/video_inputs/{id}/motion")
print(" PUT /v11/video_inputs/{id}/rules/{ruleId}")
print(" • Local camera credentials:")
print(" Watch for Digest auth headers to camera LAN IPs")
print(" • Bearer token (in Authorization header):")
print(" Copy to bosch_config.json if needed")
print()
print(" Press Ctrl+C to stop the proxy.")
print("=" * 64)
print()
# Build mitmdump command
cmd = [
"mitmdump",
"--listen-host", local_ip,
"--listen-port", str(port),
"--set", "console_eventlog_verbosity=info",
"--showhost",
# Apple domains use certificate pinning — bypass them
"--ignore-hosts",
r"(apple\.com|icloud\.com|mzstatic\.com|apple-dns\.net|cdn-apple\.com|push\.apple\.com|itunes\.com)",
# Bosch cameras use self-signed NXP-BUID certs
"--ssl-insecure",
]
if args.dump:
cmd.extend(["--save-stream-file", dump_file])
if args.filter:
cmd.extend(["--flow-filter", args.filter])
try:
subprocess.run(cmd)
except KeyboardInterrupt:
print()
print()
if args.dump and os.path.exists(dump_file):
size = os.path.getsize(dump_file) / 1024
print(f" Flows saved to: {dump_file} ({size:.0f} KB)")
print(f" View later: mitmproxy --rfile \"{dump_file}\"")
print()
print(" Don't forget to remove the proxy from your phone's WiFi settings!")
print()
if __name__ == "__main__":
main()