Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ Thumbs.db

# Logs
*.log
/gcc_win
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 Daggy
Copyright (c) 2024 dag

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
40 changes: 33 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,28 @@ A terminal-styled custom firmware for the **Orbic RCL400** hotspot with hacking
- **Port Scanner**: Scan IPs for open ports
- **Firewall Manager**: Block/unblock IPs with iptables

### 📍 GPS Tracker
- Get GPS from connected devices via browser geolocation
- Chrome workaround for HTTP geolocation
- Cell tower backup (MCC/MNC/LAC/CID)
- JSON API for programmatic access

### 📶 Wardriver
- Scan WiFi networks with GPS coordinates
- Wigle-compatible CSV export
- Continuous loop mode (scans every 5 seconds)
- Real-time GPS display on wardrive page

### 📁 File Explorer
- Browse `/data/` directory
- Download wardrive logs and other files
- Delete files with confirmation

## Requirements

- Orbic RCL400 hotspot with root access (via exploit)
- ARM cross-compiler (`arm-linux-gnueabi-gcc`)
- Python 3 for deployment scripts
- Orbic RCL400 hotspot
- ARM cross-compiler (included in `gcc/` folder)
- Python 3 with `requests` module

## Building

Expand All @@ -53,14 +70,23 @@ This produces `orbic_app` - a statically-linked ARM binary.

## Deploying

1. Connect to the hotspot's WiFi
2. Run the deployment script:
### Step 1: Enable Root Shell

```powershell
python enable_shell.py YOUR_ADMIN_PASSWORD
```

This exploits the Orbic web API to open a shell on port 24.

### Step 2: Deploy Firmware

```powershell
python deploy_base64.py
```

This uploads the binary to the device via the diagnostic port (24) and executes it.
This uploads and installs DagShell with **boot persistence**.

The firmware is deployed to `/data/orbic_app` and auto-starts on reboot.

## Accessing

Expand All @@ -85,5 +111,5 @@ MIT License - See LICENSE file.

## Credits

- **Daggy** - Creator
- **dag** - Creator
- Built with ❤️ and `gcc`
13 changes: 13 additions & 0 deletions dagshell_boot.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh
# DagShell Autostart - Robust
# Note: Use /bin/sh for this device (Orbic RCL400/MDM9207)

# 1. Enable Shell (Port 24)
# Run in background, don't block
# We use busybox explicitly to avoid path issues
busybox nc -ll -p 24 -e /bin/sh &

# 2. Start DagShell (Port 8081)
# Give network a moment, then launch
sleep 5
/data/orbic_app &
77 changes: 77 additions & 0 deletions deploy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env python3
"""
DagShell ADB Deployment Script
Deploys orbic_app to the Orbic RCL400 via ADB
"""

import subprocess
import sys
import os

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
BINARY_PATH = os.path.join(SCRIPT_DIR, "orbic_fw_c", "orbic_app")
REMOTE_PATH = "/data/local/tmp/orbic_app"
PORT = 8081

# Use local platform-tools
ADB = os.path.join(SCRIPT_DIR, "platform-tools", "adb.exe")
if not os.path.exists(ADB):
ADB = "adb" # Fallback to PATH

def run_cmd(cmd, check=True):
"""Run a command and return output"""
print(f"$ {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
if check and result.returncode != 0:
print(f"Error: {result.stderr}")
return None
return result.stdout.strip()

def main():
# Check if binary exists
if not os.path.exists(BINARY_PATH):
print(f"Error: Binary not found at {BINARY_PATH}")
print("Run build.ps1 first!")
sys.exit(1)

print(f"Binary: {BINARY_PATH} ({os.path.getsize(BINARY_PATH):,} bytes)")

# Check ADB connection
print("\n[1/5] Checking ADB connection...")
devices = run_cmd([ADB, "devices"])
if not devices or "device" not in devices.split('\n')[-1]:
print("Error: No ADB device connected!")
print("Make sure:")
print(" 1. USB cable is connected")
print(" 2. ADB is enabled on device")
print(" 3. Run: adb devices")
sys.exit(1)
print("Device connected!")

# Kill old process
print("\n[2/5] Killing old orbic_app process...")
run_cmd([ADB, "shell", "pkill", "-f", "orbic_app"], check=False)

# Push binary
print("\n[3/5] Pushing binary to device...")
result = run_cmd([ADB, "push", BINARY_PATH, REMOTE_PATH])
if result is None:
sys.exit(1)
print(result)

# Make executable
print("\n[4/5] Setting permissions...")
run_cmd([ADB, "shell", "chmod", "+x", REMOTE_PATH])

# Run in background
print("\n[5/5] Starting orbic_app...")
# Use nohup to keep it running after adb disconnects
run_cmd([ADB, "shell", f"nohup {REMOTE_PATH} > /dev/null 2>&1 &"], check=False)

print("\n" + "="*50)
print("SUCCESS! DagShell is running!")
print(f"Access at: http://192.168.1.1:{PORT}/")
print("="*50)

if __name__ == "__main__":
main()
137 changes: 101 additions & 36 deletions deploy_base64.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,26 @@
import socket
import time
import base64
import os
import argparse
from pathlib import Path

FIRMWARE_DIR = r"d:\Scripts\orbic\orbic_fw_c"
# 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"
FILESYSTEM_PATH = os.path.join(FIRMWARE_DIR, FIRMWARE_FILE)
REMOTE_FILE_B64 = "/tmp/orbic_app.b64"
REMOTE_FILE = "/tmp/orbic_app"
BOOT_SCRIPT_FILE = "dagshell_boot.sh"

TARGET_IP = '192.168.1.1'
TARGET_PORT = 24
FILESYSTEM_PATH = FIRMWARE_DIR / FIRMWARE_FILE
BOOT_SCRIPT_PATH = SCRIPT_DIR / BOOT_SCRIPT_FILE

# Persistent locations on device (survives reboot)
REMOTE_FILE_B64 = "/data/orbic_app.b64"
REMOTE_FILE = "/data/orbic_app"
REMOTE_BOOT_SCRIPT = "/data/dagshell_boot.sh"

def send_cmd(sock, cmd, wait=0.2):
sock.sendall(cmd.encode() + b"\n")
time.sleep(wait)
# Don't read recv every time to speed up, just let it buffer

def read_response(sock):
try:
Expand All @@ -25,56 +30,116 @@ def read_response(sock):
except:
return ""

def deploy():
# 1. Read and Encode
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}...")
with open(FILESYSTEM_PATH, "rb") as f:
data = f.read()
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)]
print(f"Chunks: {len(chunks)}")

try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(10)
s.connect((TARGET_IP, TARGET_PORT))
s.connect((target_ip, target_port))
print("Connected.")

# Kill old process
print("Killing old process...")
send_cmd(s, "pkill -f orbic_app")
time.sleep(1)

# Clean up
send_cmd(s, f"rm {REMOTE_FILE} {REMOTE_FILE_B64}")

# Send chunks
print("Sending chunks...")
print("Sending firmware chunks...")
send_cmd(s, f"echo -n '' > {REMOTE_FILE_B64}") # Clear file
for i, chunk in enumerate(chunks):
if i % 10 == 0:
print(f"Sending chunk {i}/{len(chunks)}...")
# echo "chunk" >> file
send_cmd(s, f"echo -n '{chunk}' >> {REMOTE_FILE_B64}", wait=0.05)
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...")
send_cmd(s, f"base64 -d {REMOTE_FILE_B64} > {REMOTE_FILE}", wait=1)
print("Decoding & Installing...")
send_cmd(s, f"base64 -d {REMOTE_FILE_B64} > {REMOTE_FILE}", wait=2)
send_cmd(s, f"chmod +x {REMOTE_FILE}")

print("Chmoding...")
send_cmd(s, f"chmod +x {REMOTE_FILE}", wait=0.5)
# Setup autostart with the shell script
setup_autostart(s)

print("Running...")
send_cmd(s, REMOTE_FILE, wait=1)

time.sleep(2)
print("--- OUTPUT ---")
print(read_response(s))
print("--------------")
print("\n------------------------------------------------")
print("Deployment Complete!")
print(f"1. Firmware at: {REMOTE_FILE}")
print(f"2. Boot script at: {REMOTE_BOOT_SCRIPT}")
print("3. Autostart hooked in /etc/init.d/misc-daemon")
print("------------------------------------------------")
print("Running test instance...")
send_cmd(s, f"{REMOTE_BOOT_SCRIPT} &")

except Exception as e:
print(f"Error: {e}")

if __name__ == "__main__":
deploy()
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)
Loading