-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathdeploy_base64.py
More file actions
206 lines (165 loc) · 8.58 KB
/
Copy pathdeploy_base64.py
File metadata and controls
206 lines (165 loc) · 8.58 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
import socket
import time
import base64
import argparse
from pathlib import Path
# Auto-detect firmware directory relative to this script
SCRIPT_DIR = Path(__file__).parent.absolute()
FIRMWARE_DIR = SCRIPT_DIR / "orbic_fw_c"
FIRMWARE_FILE = "orbic_app"
BOOT_SCRIPT_FILE = "dagshell_boot.sh"
FILESYSTEM_PATH = FIRMWARE_DIR / FIRMWARE_FILE
BOOT_SCRIPT_PATH = SCRIPT_DIR / BOOT_SCRIPT_FILE
# PKI files (Generated by gen_pki.py in DER format)
SSL_CERT_PATH = FIRMWARE_DIR / "server.der"
SSL_ROOT_PATH = FIRMWARE_DIR / "root.der"
SSL_KEY_PATH = FIRMWARE_DIR / "server.key.der"
# Persistent locations on device
REMOTE_FILE_B64 = "/data/orbic_app.b64"
REMOTE_FILE = "/data/orbic_app"
REMOTE_BOOT_SCRIPT = "/data/dagshell_boot.sh"
REMOTE_SSL_CERT = "/data/server.der"
REMOTE_SSL_ROOT = "/data/root.der"
REMOTE_SSL_KEY = "/data/server.key.der"
def send_cmd(sock, cmd, wait=0.2):
sock.sendall(cmd.encode() + b"\n")
time.sleep(wait)
def read_response(sock):
try:
sock.settimeout(2)
return sock.recv(16384).decode('utf-8', errors='ignore')
except:
return ""
def setup_autostart(sock):
"""
Sets up persistent autostart by hijacking the USB composition script.
Target: /data/usb/boot_hsusb_composition
This file is executed by /etc/init.d/usb on boot for MDM9207.
"""
print("Setting up persistence (USB Hijack)...")
# 1. Clean up old attempts (optional but good practice)
send_cmd(sock, "sed -i '/dagshell_boot.sh/d' /data/dnsmasq.conf", wait=0.5)
# 2. Transfer boot script (Fixed Shebang: /bin/sh)
print(f"Transferring {BOOT_SCRIPT_FILE}...")
with open(BOOT_SCRIPT_PATH, "r") as f:
boot_script_content = f.read()
# Ensure correct shebang on device
send_cmd(sock, f"echo '#!/bin/sh' > {REMOTE_BOOT_SCRIPT}")
for line in boot_script_content.splitlines():
if line.startswith("#!"): continue
safe_line = line.replace("'", "'\\''")
send_cmd(sock, f"echo '{safe_line}' >> {REMOTE_BOOT_SCRIPT}", wait=0.05)
send_cmd(sock, f"chmod +x {REMOTE_BOOT_SCRIPT}")
# 3. Hijack USB Composition
WRAPPER_PATH = "/data/usb/boot_hsusb_composition"
ORIGINAL_SCRIPT = "/sbin/usb/compositions/PRJ_SLT779_9025"
print("Hijacking USB composition script...")
# Create wrapper that runs our script THEN configures USB
# We write directly to the persistent location (overwriting symlink/file)
# Using 'sh' explicitly to bypass execution restrictions
# Remove existing first (to break symlink if present)
send_cmd(sock, f"rm {WRAPPER_PATH}")
send_cmd(sock, f"echo '#!/bin/sh' > {WRAPPER_PATH}")
send_cmd(sock, f"echo '# DagShell Wrapper' >> {WRAPPER_PATH}")
send_cmd(sock, f"echo 'sh {REMOTE_BOOT_SCRIPT} &' >> {WRAPPER_PATH}")
send_cmd(sock, f"echo '# Chainload original' >> {WRAPPER_PATH}")
send_cmd(sock, f"echo '{ORIGINAL_SCRIPT} \"$@\"' >> {WRAPPER_PATH}")
send_cmd(sock, f"chmod +x {WRAPPER_PATH}")
print("Persistence configured! (USB Hook applied)")
def deploy(target_ip, target_port):
print(f"Deploying DagShell firmware...")
# Check if boot script exists locally
if not BOOT_SCRIPT_PATH.exists():
print(f"ERROR: {BOOT_SCRIPT_FILE} not found!")
return
# 1. Read and Encode Firmware
print(f"Reading {FILESYSTEM_PATH}...")
try:
with open(FILESYSTEM_PATH, "rb") as f:
data = f.read()
except FileNotFoundError:
print("Error: compiled firmware not found. Run build.ps1 first!")
return
b64_data = base64.b64encode(data).decode('utf-8')
print(f"Encoded size: {len(b64_data)} bytes")
chunks = [b64_data[i:i+1000] for i in range(0, len(b64_data), 1000)]
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(10)
s.connect((target_ip, target_port))
print("Connected.")
# Kill old process
send_cmd(s, "pkill -f orbic_app")
time.sleep(1)
# Send chunks
print("Sending firmware chunks...")
send_cmd(s, f"echo -n '' > {REMOTE_FILE_B64}") # Clear file
for i, chunk in enumerate(chunks):
if i % 50 == 0: print(f" {i}/{len(chunks)}", end="\r")
send_cmd(s, f"echo -n '{chunk}' >> {REMOTE_FILE_B64}", wait=0.02)
print("")
print("Decoding & Installing...")
send_cmd(s, f"base64 -d {REMOTE_FILE_B64} > {REMOTE_FILE}", wait=2)
send_cmd(s, f"chmod +x {REMOTE_FILE}")
# Deploy PKI Files (DER format directly)
if SSL_CERT_PATH.exists() and SSL_KEY_PATH.exists():
print("Deploying PKI files (DER format)...")
# Helper to deploy binary file
def deploy_bin(local_path, remote_path):
with open(local_path, "rb") as f:
data = f.read()
b64_data = base64.b64encode(data).decode('utf-8')
print(f" Transferring {local_path.name}...")
send_cmd(s, f"echo -n '' > {remote_path}.b64")
# Chunk size 1000
for i in range(0, len(b64_data), 1000):
send_cmd(s, f"echo -n '{b64_data[i:i+1000]}' >> {remote_path}.b64", wait=0.02)
send_cmd(s, f"base64 -d {remote_path}.b64 > {remote_path}", wait=0.5)
send_cmd(s, f"rm {remote_path}.b64")
deploy_bin(SSL_CERT_PATH, REMOTE_SSL_CERT)
deploy_bin(SSL_KEY_PATH, REMOTE_SSL_KEY)
if SSL_ROOT_PATH.exists():
deploy_bin(SSL_ROOT_PATH, REMOTE_SSL_ROOT)
send_cmd(s, f"chmod 600 {REMOTE_SSL_KEY}") # Protect private key
print(" PKI files deployed to /data/")
else:
print(" WARNING: PKI files not found (run gen_pki.py)")
# Setup autostart with the shell script
setup_autostart(s)
print("\n------------------------------------------------")
print("Deployment Complete!")
print(f"1. Firmware at: {REMOTE_FILE}")
print(f"2. Boot script at: {REMOTE_BOOT_SCRIPT}")
print(f"3. SSL certs at: {REMOTE_SSL_CERT}, {REMOTE_SSL_KEY}")
print("4. Autostart hooked in /etc/init.d/misc-daemon")
print("------------------------------------------------")
print("Opening firewall port 8443...")
send_cmd(s, "iptables -I INPUT -p tcp --dport 8443 -j ACCEPT", wait=0.5)
# Disable Orbic captive portal (stops redirect to 192.168.1.1)
print("Disabling captive portal...")
send_cmd(s, "iptables -t nat -F PREROUTING", wait=0.3) # Flush redirect rules
send_cmd(s, "echo 'nameserver 8.8.8.8' > /etc/resolv.conf", wait=0.3)
send_cmd(s, "echo 'nameserver 1.1.1.1' >> /etc/resolv.conf", wait=0.3)
# Configure dnsmasq to forward DNS (CRITICAL - clients use 192.168.1.1 as DNS)
send_cmd(s, "echo 'server=8.8.8.8' > /data/dnsmasq.conf", wait=0.3)
send_cmd(s, "echo 'server=1.1.1.1' >> /data/dnsmasq.conf", wait=0.3)
send_cmd(s, "killall -HUP dnsmasq 2>/dev/null", wait=0.5)
# Enable internet passthrough for connected WiFi clients
# Note: Hotspot is on bridge0, cellular is on rmnet_data0
print("Enabling internet passthrough (NAT)...")
send_cmd(s, "echo 1 > /proc/sys/net/ipv4/ip_forward", wait=0.3)
send_cmd(s, "iptables -t nat -A POSTROUTING -o rmnet_data0 -j MASQUERADE", wait=0.3)
send_cmd(s, "iptables -A FORWARD -i bridge0 -o rmnet_data0 -j ACCEPT", wait=0.3)
send_cmd(s, "iptables -A FORWARD -i rmnet_data0 -o bridge0 -m state --state RELATED,ESTABLISHED -j ACCEPT", wait=0.3)
print("Restarting orbic_app...")
send_cmd(s, "pkill -f orbic_app", wait=1)
send_cmd(s, f"{REMOTE_FILE} &", wait=1)
print("Done! Access https://192.168.1.1:8443")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Deploy DagShell firmware to Orbic device via base64")
parser.add_argument("--target-ip", default="192.168.1.1", help="Orbic device IP (default: 192.168.1.1)")
parser.add_argument("--target-port", type=int, default=24, help="Orbic shell port (default: 24)")
args = parser.parse_args()
deploy(args.target_ip, args.target_port)