Skip to content

feat: add USB cable deployer (deploy_usb.py) + cert/firewall fixes#7

Open
simeononsecurity wants to merge 7 commits into
dagnazty:mainfrom
simeononsecurity:usb-installer
Open

feat: add USB cable deployer (deploy_usb.py) + cert/firewall fixes#7
simeononsecurity wants to merge 7 commits into
dagnazty:mainfrom
simeononsecurity:usb-installer

Conversation

@simeononsecurity

@simeononsecurity simeononsecurity commented Jun 30, 2026

Copy link
Copy Markdown

Branch: usb-installermain
Closes: #6 #5


Summary

Adds deploy_usb.py — a one-command USB cable installer for the Orbic RCL400 that works on completely fresh devices without requiring prior root access, WiFi connectivity, or Rayhunter pre-installation. The installer mirrors Rayhunter's orbic-usb approach and is fully compatible with devices that already have Rayhunter installed.


Key Changes

New: deploy_usb.py v2.0 — rootshell-based install flow

  • 8-step deployment pipeline: detect → mode-switch → ADB → push files → install rootshell → install DagShell → reboot → verify
  • Root gain via SUID rootshell: On fresh devices (ADB shell is uid=2000, not root), uses AT+SYSCMD to install a SUID root binary at /bin/rootshell with just 3 commands (cp, chown, chmod 4755). All subsequent privileged operations use adb shell /bin/rootshell -c "command".
  • Rayhunter compatibility: If Rayhunter is already installed, /bin/rootshell already exists — detected automatically, AT+SYSCMD step skipped entirely.
  • Boot-activated firewall: iptables rules are applied by dagshell_boot.sh on boot (from init context with full capabilities) rather than via rootshell (which lacks CAP_NET_ADMIN).
  • Device reboot after install: Ensures boot hook activates cleanly, firewall rules apply, and orbic_app starts from init cgroup (survives ADB disconnect).

New: orbic_fw_c/rootshell + rootshell.S

  • 408-byte ARM ELF binary, pure assembly, zero libc dependencies
  • setgroups([3003, 3004])setgid(0)setuid(0)execve("/bin/sh", argv, envp)
  • Preserves -c "command" arguments for scripted use
  • Prebuilt binary included; source in rootshell.S

New: .github/workflows/build-rootshell.yml

  • GitHub Actions workflow that cross-compiles rootshell from rootshell.S on every release
  • Uses binutils-arm-linux-gnueabi from Ubuntu repos (no custom toolchain needed)
  • Verifies ELF properties (ARM, statically linked)
  • Attaches binary as release artifact

Fixed: orbic_fw_c/gen_pki.py

  • Server certificate validity: 365 days → 3650 days (10 years)
  • Root CA validity: also extended to 3650 days
  • Fixed datetime.utcnow() deprecation warnings

Fixed: dagshell_boot.sh

  • orbic_app launched with </dev/null & to prevent fd 0 bug (server_fd==0 exit check)
  • All iptables/NAT rules applied from boot context (init cgroup, full capabilities)

Improved: AT+SYSCMD reliability

  • Health check probe before bulk AT commands
  • USB stabilization delay after mode switch/reboot
  • ATDeviceLost exception for stale USB handles (errno 19)
  • Graceful fallback: AT+SYSCMD → root ADB shell → rootshell path

Install Flow Diagram

Fresh Device (uid=2000)          Rayhunter Device (rootshell exists)
─────────────────────            ──────────────────────────────────
1. USB mode switch               1. USB mode switch
2. ADB push files to /tmp        2. ADB push files to /tmp
3. AT+SYSCMD install rootshell   3. Skip (rootshell already at /bin/)
4. rootshell -c (all ops)        4. rootshell -c (all ops)
5. Reboot → boot hook            5. Reboot → boot hook
6. Verify via ADB                6. Verify via ADB

Files Changed

File Change
deploy_usb.py Rewritten — rootshell-based install flow, 8-step pipeline
orbic_fw_c/rootshell New — prebuilt SUID root ARM binary (408 bytes)
orbic_fw_c/rootshell.S New — ARM assembly source for rootshell
orbic_fw_c/rootshell.c New — C reference implementation (not used in build)
.github/workflows/build-rootshell.yml New — CI cross-compile on release
dagshell_boot.sh Fixed — fd 0 bug, iptables from init context
orbic_fw_c/gen_pki.py Fixed — 10-year cert validity, utcnow() deprecation
docs/deploy_usb_feature.md Updated — rootshell details, compatibility matrix
docs/pr_description.md New — this document

Testing

  • ✅ Fresh Orbic RCL400 (never rooted, ADB uid=2000) — full pipeline success
  • ✅ Rayhunter-first device (rootshell pre-installed) — skips AT+SYSCMD, installs via rootshell
  • ✅ Post-reboot verification: orbic_app running, port 8443 listening, TLS handshake confirmed
  • ✅ Boot persistence survives power cycle
  • ✅ 10-year SSL certificates verified

deploy_usb.py (new):
- One-command installer via USB cable — no WiFi required
- Mirrors Rayhunter orbic-usb method: USB vendor ctrl request to switch
  device from RNDIS (0xf626) to ADB mode (0xf601)
- AT+SYSCMD path (root via atfwd_daemon) with ADB shell fallback
- Pushes firmware, boot script, and TLS certs to device
- Configures iptables: ACCEPT 8443 (DagShell) + 8080, MASQUERADE NAT
- Boot persistence via /data/usb/boot_hsusb_composition hook
- Persistent daemon launch: uses init-context nc shell (port 24) to
  escape Android ADB cgroup — survives ADB disconnect
- Post-deploy verification: process/port/TLS checks, no WiFi needed
- --verify-only flag for checking existing installs

dagshell_boot.sh:
- Add iptables ACCEPT rule for port 8080 alongside 8443

orbic_fw_c/gen_pki.py:
- Fix leaf cert validity: 365 days → 3650 days (10 years)
- Fix deprecated datetime.utcnow() → datetime.now(timezone.utc)

docs/deploy_usb_feature.md (new):
- Full feature description, rationale, and quick-start guide
Catch usb.core.NoBackendError at import time by probing for a working
backend with usb.core.find(). Without libusb installed (e.g. on macOS
before 'brew install libusb') the script crashed with a traceback at
step 2. Now degrades gracefully to ADB-only mode with a clear
install hint.
- requirements.txt: add pyusb (optional) with libusb + adb install notes
- README.md: add USB deploy dependencies to Requirements section and
  new 'Option C: USB Cable Deploy' deployment walkthrough
@simeononsecurity simeononsecurity marked this pull request as draft June 30, 2026 01:10
…lback

Fixes the 'Operation timed out' / 'No such device' wall of errors seen on
the first run right after a USB mode switch + reboot — the device accepted
the serial-interface claim but atfwd_daemon was not ready yet.

- Add USB_STABILIZE_SEC settle pause after a reboot before touching AT
- Add at_health_check(): probe AT interface with a no-op until responsive
- at_syscmd_raw now raises ATDeviceLost on errno 19 (device dropped) so we
  stop retrying every command against a dead handle
- Extract install_via_at() and install_via_adb_shell() helpers
- Step 7 now: stabilize -> health-check -> AT install (primary), with
  automatic fallback to the ADB shell path if the interface is unresponsive
  or drops mid-install
- ADB fallback gained its own readiness wait + echo health check
rootshell: 408-byte ARM asm ELF, SUID root escalation (mirrors Rayhunter)
dagshell_boot.sh: start orbic_app with </dev/null to avoid fd 0 socket bug
- deploy_usb.py v2.0: 8-step pipeline with rootshell SUID root gain
  - AT+SYSCMD installs rootshell (3 cmds: cp, chown, chmod 4755)
  - All privileged ops via 'adb shell /bin/rootshell -c'
  - Rayhunter compatible (detects existing rootshell, skips AT step)
  - Device reboot after install (boot script applies iptables)
- .github/workflows/build-rootshell.yml: cross-compile on release
- docs/deploy_usb_feature.md: rootshell details + compatibility matrix
@simeononsecurity simeononsecurity marked this pull request as ready for review June 30, 2026 01:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant