Rayhunter
Rayhunter is a project for detecting IMSI catchers, also known as cell-site simulators or stingrays. It's designed to run on a cheap mobile hotspot called the Orbic RC400L, but thanks to community efforts can support some other devices as well.
It's also designed to be as easy to install and use as possible, regardless of you level of technical skills. This guide should provide you all you need to acquire a compatible device, install Rayhunter, and start catching IMSI catchers.
To learn more about the aim of the project, and about IMSI catchers in general, please check out our introductory blog post. Otherwise, check out the installation guide to get started.
LEGAL DISCLAIMER: Use this program at your own risk. We believe running this program does not currently violate any laws or regulations in the United States. However, we are not responsible for civil or criminal liability resulting from the use of this software. If you are located outside of the US please consult with an attorney in your country to help you assess the legal risks of running this program.
Good Hunting!
Installing Rayhunter
So, you've got one of the supported devices, and are ready to start catching IMSI catchers. You have two options for installing Rayhunter:
Installing from the latest release
Make sure you've got one of Rayhunter's supported devices. These instructions have only been tested on macOS and Ubuntu 24.04. If they fail, you will need to install Rayhunter from source.
-
Download the latest
rayhunter-vX.X.X.zip
from the Rayhunter releases page -
Decompress the
rayhunter-vX.X.X.zip
archive. Open the terminal and navigate to the folder. (Be sure to replace X.X.X with the correct version number!)unzip ~/Downloads/rayhunter-vX.X.X.zip cd ~/Downloads/rayhunter-vX.X.X
-
Turn on your device by holding the power button on the front.
- For the Orbic, connect the device using a USB-C cable.
- For TP-Link, connect to its network using either WiFi or USB Tethering.
-
Run the install script for your operating system:
./install orbic # or: ./install tplink
The device will restart multiple times over the next few minutes.
You will know it is done when you see terminal output that says
Testing rayhunter... done
-
Rayhunter should now be running! You can verify this by viewing Rayhunter's web UI. You should also see a green line flash along the top of top the display on the device.
Troubleshooting
- On macOS if you encounter an error that says "No Orbic device found," it may because you the "Allow accessories to connect" security setting set to "Ask for approval." You may need to temporarily change it to "Always" for the script to run. Make sure to change it back to a more secure setting when you're done.
Installing from the latest release (Windows)
- Install the Zadig WinUSB driver.
- Download the latest
release.zip
from the Rayhunter releases page. - Unzip
release.zip
. - Save the
install.ps1
file below in top of the folder that was unzipped from release.zip. - Run the install script by double clicking on
install.ps1
. A powershell window will launch. The device will restart multiple times over the next few minutes. You will know it is done when you see terminal output that sayschecking for rayhunter server...success!
- Rayhunter should now be running! You can verify this by following the instructions below to view the web UI. You should also see a green line flash along the top of top the display on the device.
install.ps1
$global:adb = "./platform-tools-latest-windows/platform-tools/adb.exe"
$global:serial = "./serial-windows-x86_64/serial.exe"
function _adb_push {
$proc = start-process -passthru -wait $global:adb -argumentlist "push", $args[0], $args[1]
if ($proc.exitcode -ne 0) {
write-host "push exited with exit code $($proc.exitcode)"
}
return $proc.exitcode
}
function _adb_shell {
$proc = start-process -passthru -wait $global:adb -argumentlist "shell", $args[0]
if ($proc.exitcode -ne 0) {
write-host "shell exited with exit code $($proc.exitcode)"
}
return $proc.exitcode
}
function _wait_for_adb_shell {
do {
start-sleep -seconds 1
} until ((_adb_shell "cat /etc/ver.conf") -eq 0)
}
function _wait_for_atfwd_daemon {
do {
start-sleep -seconds 1
} until ((_adb_shell "pgrep atfwd_daemon") -eq 0)
}
function force_debug_mode {
write-host "Using adb at $($global:adb)"
write-host "Forcing a switch into debug mode to enable ADB"
&$global:serial "--root" | Out-Host
write-host "adb enabled, waiting for reboot..." -nonewline
_wait_for_adb_shell
write-host " it's alive!"
write-host "waiting for atfwd_daemon to start ..." -nonewline
_wait_for_atfwd_daemon
write-host " done!"
}
function setup_rootshell {
_adb_push "rootshell" "/tmp"
write-host "cp..."
&$global:serial "AT+SYSCMD=cp /tmp/rootshell /bin/rootshell" | Out-Host
start-sleep -seconds 1
write-host "chown..."
&$global:serial "AT+SYSCMD=chown root /bin/rootshell" | Out-Host
start-sleep -seconds 1
write-host "chmod..."
&$global:serial "AT+SYSCMD=chmod 4755 /bin/rootshell" | Out-Host
start-sleep -seconds 1
_adb_shell '/bin/rootshell -c id'
write-host "we have root!"
}
function setup_rayhunter {
&$global:serial "AT+SYSCMD=mkdir -p /data/rayhunter" | Out-Host
_adb_push "config.toml.example" "/tmp/config.toml"
&$global:serial "AT+SYSCMD=mv /tmp/config.toml /data/rayhunter" | Out-Host
_adb_push "rayhunter-daemon-orbic/rayhunter-daemon" "/tmp/rayhunter-daemon"
&$global:serial "AT+SYSCMD=mv /tmp/rayhunter-daemon /data/rayhunter" | Out-Host
_adb_push "scripts/rayhunter_daemon" "/tmp/rayhunter_daemon"
&$global:serial "AT+SYSCMD=mv /tmp/rayhunter_daemon /etc/init.d/rayhunter_daemon" | Out-Host
_adb_push "scripts/misc-daemon" "/tmp/misc-daemon"
&$global:serial "AT+SYSCMD=mv /tmp/misc-daemon /etc/init.d/misc-daemon" | Out-Host
&$global:serial "AT+SYSCMD=chmod 755 /data/rayhunter/rayhunter-daemon" | Out-Host
&$global:serial "AT+SYSCMD=chmod 755 /etc/init.d/rayhunter_daemon" | Out-Host
&$global:serial "AT+SYSCMD=chmod 755 /etc/init.d/misc-daemon" | Out-Host
write-host "waiting for reboot..."
&$global:serial "AT+SYSCMD=shutdown -r -t 1 now" | Out-Host
do {
start-sleep -seconds 1
} until ((_adb_shell "true 2> /dev/null") -ne 0)
_wait_for_adb_shell
write-host "done!"
}
function test_rayhunter {
$URL = "http://localhost:8080"
$fproc = start-process $global:adb -argumentlist "forward", "tcp:8080", "tcp:8080" -wait -passthru
if ($fproc.exitcode -ne 0) {
write-host "adb forward tcp:8080 tcp:8080 failed with exit code $($proc.exitcode)"
return
}
write-host "checking for rayhunter server..." -nonewline
$seconds = 0
do {
$resp = invoke-webrequest -uri $URL
if ($resp.statuscode -eq 200) {
write-host "success!"
write-host "you can access rayhunter at $($URL)"
return
}
start-sleep 1
$seconds = $seconds + 1
} until ($seconds -eq 30)
write-host "timeout reached! failed to reach rayhunter url $($URL), something went wrong :("
}
function get_android_tools {
write-host "adb not found, downloading local copy"
invoke-webrequest "https://dl.google.com/android/repository/platform-tools-latest-windows.zip" -outfile ./platform-tools-latest-windows.zip
expand-archive -force -path "platform-tools-latest-windows.zip"
}
if (-not (test-path -path $global:serial)) {
write-error "can't find serial, aborting"
return
}
if (-not (test-path -path $global:adb)) {
get_android_tools
}
force_debug_mode
setup_rootshell
setup_rayhunter
test_rayhunter$global:adb = "./platform-tools-latest-windows/platform-tools/adb.exe"
$global:serial = ".\installer-windows-x86_64\installer.exe"
function _adb_push {
& $global:adb -d push @args
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) {
write-host "push exited with exit code $($exitCode)"
}
return $proc.exitcode
}
function _adb_shell {
& $global:adb -d shell @args
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) {
write-host "shell exited with exit code $($exitCode)"
}
return $proc.exitcode
}
function _wait_for_adb_shell {
do {
start-sleep -seconds 1
} until ((_adb_shell "uname -a") -eq 0)
}
function _wait_for_atfwd_daemon {
do {
start-sleep -seconds 1
} until ((_adb_shell "pgrep atfwd_daemon") -eq 0)
}
function force_debug_mode {
write-host "Using adb at $($global:adb)"
write-host "Forcing a switch into debug mode to enable ADB"
_serial "util" "serial" "--root" | Out-Host
write-host "adb enabled, waiting for reboot..." -nonewline
_wait_for_adb_shell
write-host " it's alive!"
write-host "waiting for atfwd_daemon to start ..." -nonewline
_wait_for_atfwd_daemon
write-host " done!"
}
function _serial {
param (
[Parameter(Mandatory = $false, ValueFromRemainingArguments = $true)]
[string[]]$Args
)
# Build the full argument list
$allArgs = @("util", "serial") + $Args
# Call the serial executable
& $global:serial @allArgs
}
function setup_rootshell {
_adb_push "rootshell" "/tmp"
write-host "cp..."
_serial "AT+SYSCMD=cp /tmp/rootshell /bin/rootshell" | Out-Host
start-sleep -seconds 1
write-host "chown..."
_serial "AT+SYSCMD=chown root /bin/rootshell" | Out-Host
start-sleep -seconds 1
write-host "chmod..."
_serial "AT+SYSCMD=chmod 4755 /bin/rootshell" | Out-Host
start-sleep -seconds 1
_adb_shell '/bin/rootshell -c id'
write-host "we have root!"
}
function setup_rayhunter {
_serial "AT+SYSCMD=mkdir -p /data/rayhunter" | Out-Host
_adb_push "config.toml.example" "/tmp/config.toml"
_serial "AT+SYSCMD=mv /tmp/config.toml /data/rayhunter" | Out-Host
_adb_push "rayhunter-daemon-orbic/rayhunter-daemon" "/tmp/rayhunter-daemon"
_serial "AT+SYSCMD=mv /tmp/rayhunter-daemon /data/rayhunter" | Out-Host
_adb_push "scripts/rayhunter_daemon" "/tmp/rayhunter_daemon"
_serial "AT+SYSCMD=mv /tmp/rayhunter_daemon /etc/init.d/rayhunter_daemon" | Out-Host
_adb_push "scripts/misc-daemon" "/tmp/misc-daemon"
_serial "AT+SYSCMD=mv /tmp/misc-daemon /etc/init.d/misc-daemon" | Out-Host
_serial "AT+SYSCMD=chmod 755 /data/rayhunter/rayhunter-daemon" | Out-Host
_serial "AT+SYSCMD=chmod 755 /etc/init.d/rayhunter_daemon" | Out-Host
_serial "AT+SYSCMD=chmod 755 /etc/init.d/misc-daemon" | Out-Host
write-host "waiting for reboot..."
_serial "AT+SYSCMD=shutdown -r -t 1 now" | Out-Host
do {
start-sleep -seconds 1
} until ((_adb_shell "true 2> /dev/null") -ne 0)
_wait_for_adb_shell
write-host "done!"
}
function test_rayhunter {
$URL = "http://localhost:8080"
& $global:adb -d shell forward tcp:8080 tcp:8080
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) {
write-host "adb forward tcp:8080 tcp:8080 failed with exit code $($proc.exitcode)"
return
}
write-host "checking for rayhunter server..." -nonewline
$seconds = 0
do {
$resp = invoke-webrequest -uri $URL
if ($resp.statuscode -eq 200) {
write-host "success!"
write-host "you can access rayhunter at $($URL)"
return
}
start-sleep 1
$seconds = $seconds + 1
} until ($seconds -eq 30)
write-host "timeout reached! failed to reach rayhunter url $($URL), something went wrong :("
}
function get_android_tools {
write-host "adb not found, downloading local copy"
invoke-webrequest "https://dl.google.com/android/repository/platform-tools-latest-windows.zip" -outfile ./platform-tools-latest-windows.zip
expand-archive -force -path "platform-tools-latest-windows.zip"
}
if (-not (test-path -path $global:serial)) {
write-error "can't find serial, aborting"
return
}
if (-not (test-path -path $global:adb)) {
get_android_tools
}
force_debug_mode
setup_rootshell
setup_rayhunter
test_rayhunter
Installing from source
Building Rayhunter from source, either for development or because the install script doesn't work on your system, involves a number of external dependencies. Unless you need to do this, we recommend you use our compiled builds.
- Install nodejs/npm, which is required to build Rayhunter's web UI
- Make sure to build the site with
cd bin/web && npm install && npm run build
before building Rayhunter. If you're working directly on the frontend,npm run dev
will allow you to test a local frontend with hot-reloading (usehttp://localhost:5173
instead ofhttp://localhost:8080
).
- Make sure to build the site with
- Install ADB on your computer using the instructions above, and make sure it's in your terminal's PATH
- Install
curl
on your computer to run the install scripts. It is not needed to build binaries.
Install Rust targets
Install Rust the usual way. Then,
- install the cross-compilation target for the device rayhunter will run on:
rustup target add armv7-unknown-linux-musleabihf
- install the statically compiled target for your host machine to build the binary installer
serial
.
# check which toolchain you have installed by default with
rustup show
# now install the correct variant for your host platform, one of:
rustup target add x86_64-unknown-linux-musl
rustup target add aarch64-unknown-linux-musl
rustup target add aarch64-apple-darwin
rustup target add x86_64-apple-darwin
rustup target add x86_64-pc-windows-gnu
Now you can root your device and install Rayhunter by running:
cargo build --bin rayhunter-daemon --target armv7-unknown-linux-musleabihf --release --no-default-features --features orbic
cargo build --bin rootshell --target armv7-unknown-linux-musleabihf --release
cargo run --bin installer orbic
If you're on Windows or can't run the install scripts
- Root your device on Windows using the instructions here: https://xdaforums.com/t/resetting-verizon-orbic-speed-rc400l-firmware-flash-kajeet.4334899/#post-87855183
- Build the web UI using
cd bin/web && npm install && npm run build
- Push the scripts in
scripts/
to/etc/init.d
on device and make a directory called/data/rayhunter
usingadb shell
(and sshell for your root shell if you followed the steps above) - You also need to copy
config.toml.example
to/data/rayhunter/config.toml
- Then run
./make.sh
, which will build the binary, push it over adb, and restart the device. Once it's restarted, Rayhunter should be running!
Updating Rayhunter
Great news: if you've successfully installed rayhunter, you already know how to update it! Our update process is identical to the installation process: simply repeat the steps for installing Rayhunter via a release or from source.
Uninstalling
Orbic
To uninstall Rayhunter, power on your Orbic device and connect to it via USB. Then, start a rootshell on it by running adb shell
, followed by rootshell
.
Once in a rootshell, run:
echo 3 > /usrdata/mode.cfg
rm -rf /data/rayhunter /etc/init.d/rayhunter-daemon /bin/rootshell.sh
reboot
Your device is now Rayhunter-free, and should no longer be in a rooted ADB-enabled mode.
TPLink
TODO
Using Rayhunter
Once installed, Rayhunter will run automatically whenever your device is running. You'll see a green line on top of the device's display to indicate that it's running and recording. The line will turn red once a potential IMSI catcher has been found, until the device is rebooted or a new recording is started through the web UI.
It also serves a web UI that provides some basic controls, such as being able to start/stop recordings, download captures, delete captures, and view heuristic analyses of captures.
You can access this UI in one of two ways:
-
Connect over wifi: Connect your phone/laptop to your device's wifi network and visit http://192.168.1.1:8080 (orbic) or http://192.168.0.1:8080 (tplink).
Click past your browser warning you about the connection not being secure, Rayhunter doesn't have HTTPS yet.
On the Orbic, you can find the wifi network password by going to the Orbic's menu > 2.4 GHz WIFI Info > Enter > find the 8-character password next to the lock 🔒 icon.
-
Connect over USB (orbic): Connect your device to your laptop via USB. Run
adb forward tcp:8080 tcp:8080
, then visit http://localhost:8080.- For this you will need to install the Android Debug Bridge (ADB) on your computer, you can copy the version that was downloaded inside the
releases/platform-tools/
folder to somewhere else in your path or you can install it manually. - You can find instructions for doing so on your platform here, (don't worry about instructions for installing it on a phone/device yet).
- On macOS, the easiest way to install ADB is with Homebrew: First install Homebrew, then run
brew install android-platform-tools
.
- For this you will need to install the Android Debug Bridge (ADB) on your computer, you can copy the version that was downloaded inside the
-
Connect over USB (tplink): Plug in the TP-Link and use USB tethering to establish a network connection. ADB support can be enabled on the device, but the installer won't do it for you.
Heuristics
TODO
How we analyze a capture
TODO
Supported devices
Rayhunter was built and tested primarily on the Orbic RC400L mobile hotspot, but the community has been working hard at adding support for other devices. Theoretically, if a device runs a Qualcomm modem and exposes a /dev/diag
interface, Rayhunter may work on it.
If you have a device in mind which you'd like Rayhunter to support, please open a discussion on our Github!
TP-Link M7350
The TP-Link M7350 is supported by Rayhunter as of 0.2.9. It supports many more frequency bands than Orbic and therefore works in Europe.
You can get it from:
- First check for used offers on Ebay or equivalent, sometimes it's much cheaper there.
- Geizhals price comparison
- Ebay
Installation & Usage
Follow the release installation guide. Substitute ./installer orbic
for ./installer tplink
in other documentation. The rayhunter UI will be available at http://192.168.0.1:8080.
Unlike on Orbic, the installer will not enable ADB. Instead, you can do this to obtain a root shell:
./installer util tplink-start-telnet
telnet 192.168.0.1
Display states
If your device has a color display, Rayhunter will show the same red/green/white line at the top of the display as it does on Orbic, each color meaning "warning"/"recording"/"paused" respectively. See Using Rayhunter.
If your device has a one-bit (black-and-white) display, Rayhunter will instead show an emoji to indicate status:
!
means "warning (potential IMSI catcher)":)
(smiling) means "recording":
(face with no mouth) means "paused"
Hardware versions
The TP-Link comes in many different hardware versions. Support for installation varies:
1.0-2.0
: Not tested, probably impossible to obtain anymore (even second-hand)3.0
,3.2
,5.0
,5.2
,7.0
,8.0
: Tested, no issues.9.0
: Recording might be broken, could be fixed if there is demand.
TP-Link versions newer than 3.0
have cyan packaging and a color display.
Version 3.0
has a one-bit display and white packaging.
You can find the exact hardware version of each device under the battery or
next to the barcode on the outer packaging, for example V3.0
or V5.2
.
When filing bug reports, particularly with the installer, please always specify the exact hardware version.
Other links
For more information on the device and instructions on how to install Rayhunter without an installer, see rayhunter-tplink-m7350
Orbic RC400L
The Orbic RC400L is an inexpensive LTE modem primarily designed for the US marked, and the original device for which Rayhunter is developed.
You can buy an Orbic using bezos bucks, or on eBay.
Please check whether the Orbic works in your country, and whether the Orbic RC400L supports the right frequency bands for your purpose before buying.
Supported Bands
Frequency | Band |
---|---|
5G (wideband,midband,nationwide) | n260/n261, n77, n2/5/48/66 |
4G | 2/4/5/12/13/48/66 |
Global & Roaming | n257/n78 |
Wifi 2.4Ghz | b/g/n |
Wifi 5Ghz | a/ac/ax |
Wifi 6 | 🮱 |
Support, Feedback, and Community
If you're using Rayhunter (or trying to), we'd love to hear from you! Check out one of the following forums for contacting the Rayhunter developers and community:
- If you've received a Rayhunter warning and would like to help us with our research, please send your Rayhunter data captures (QMDL and PCAP logs) to us at our Signal username ElectronicFrontierFoundation.90 with the following information: capture date, capture location, device, device model, and Rayhunter version. If you're unfamiliar with Signal, feel free to check out our Security Self Defense guide on it.
- If you're having issues installing or using Rayhunter, please open an issue on our Github repo.
- If you'd like to propose a feature, heuristic, or device for Rayhunter, start a discussion in our Github repo
- For anything else, join us in the
#rayhunter
or#rayhunter-developers
channel of EFF's Mattermost instance to chat!
Frequently Asked Questions
Do I need an active SIM card to use Rayhunter?
It Depends. Operation of Rayhunter does require the insertion of a SIM card into the device, but whether that SIM card has to be currently active for our tests to work is still under investigation. If you want to use the device as a hotspot in addition to a research device an active plan would of course be necessary, however we have not done enough testing yet to know whether an active subscription is required for detection. If you want to test the device with an inactive SIM card, we would certainly be interested in seeing any data you collect, and especially any runs that trigger an alert!
Help, Rayhunter's line is red! What should I do?
Unfortunately, the circumstances that might lead to a positive cell site simulator (CSS) signal are quite varied, so we don't have a universal recommendation for how to deal with the a positive signal. Depending on your circumstances and threat model, you may want to turn off your phone until you are out of the area (or put it on airplane mode) and tell your friends to do the same!
If you've received a Rayhunter warning and would like to help us with our research, please send your Rayhunter data captures (QMDL and PCAP logs) to us at our Signal username ElectronicFrontierFoundation.90 with the following information: capture date, capture location, device, device model, and Rayhunter version. If you're unfamiliar with Signal, feel free to check out our Security Self Defense guide on it.
Please note that this file may contain sensitive information such as your IMSI and the unique IDs of cell towers you were near which could be used to ascertain your location at the time.
Should I get a locked or unlocked orbic device? What is the difference?
If you want to use a non-Verizon SIM card you will probably need an unlocked device. But it's not clear how locked the locked devices are nor how to unlock them, we welcome any experimentation and information regarding the use of unlocked devices.