Building a Portable GSM BTS Using BladeRF, Raspberry Pi and YateBTS - The Definitive Guide

I have been working on this project for a few months now and I think it is finally ready to share. This is a complete, step-by-step guide to building a portable GSM base transceiver station (BTS) using commodity hardware. The total cost is under $500 and everything fits in a backpack.

Legal notice: Operating a GSM BTS without authorization is illegal in most jurisdictions. This guide is intended for security researchers working in shielded RF environments or with explicit authorization from their local telecommunications authority. In many countries, you can apply for an experimental radio license that covers this type of research. Do not operate this equipment in the open without proper licensing.

What You Need

Hardware:

  • BladeRF 2.0 micro xA4 (or original BladeRF x40) - the SDR transceiver
  • Raspberry Pi 3 Model B (or newer) - runs YateBTS
  • GSM 900 MHz antenna (50 ohm, SMA connector) - I use a simple quarter-wave whip
  • SMA male to SMA male cable (short, 15cm)
  • 5V 3A power supply for the Pi
  • USB 3.0 cable (BladeRF to Pi)
  • MicroSD card (32GB, Class 10 minimum)
  • Optional: RF shielded enclosure for legal indoor testing

Software:

  • Raspbian (Debian-based, 32-bit works fine)
  • YateBTS (open-source GSM BTS implementation)
  • BladeRF host libraries and firmware
  • GNU Radio (for spectrum monitoring, not strictly required)

Total cost: approximately $400-500 depending on where you source the BladeRF.

Step 1: Prepare the Raspberry Pi

Start with a fresh Raspbian image. I recommend the Lite version since we do not need a desktop environment.

# Update everything first
sudo apt-get update && sudo apt-get upgrade -y

# Install build dependencies
sudo apt-get install -y build-essential cmake libusb-1.0-0-dev \
  pkg-config git autoconf libtool libgsm1-dev

# Install BladeRF host libraries
git clone https://github.com/Nuand/bladeRF.git
cd bladeRF/host
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j4
sudo make install
sudo ldconfig

Verify the BladeRF is detected:

bladeRF-cli -p

You should see your device listed with its serial number. If not, check the USB connection and make sure you are using a USB 3.0 port (the blue one).

Step 2: Flash the BladeRF FPGA

The BladeRF needs the correct FPGA image loaded for GSM operation. Download the appropriate image from the Nuand FPGA repository:

# For BladeRF 2.0 micro xA4
bladeRF-cli -l /path/to/hostedxA4-latest.rbf

# Verify
bladeRF-cli -e "version"

The FPGA image is loaded into volatile memory by default, so you need to reload it after each power cycle. To autoload, use the bladeRF-cli -L (capital L) command to write it to flash.

Step 3: Install YateBTS

YateBTS is the software that turns your SDR into a functioning GSM base station. It implements the GSM air interface (Um) and connects to the Yate telephony engine for call routing.

# Install Yate first
svn checkout http://voip.null.ro/svn/yate/trunk yate
cd yate
./autogen.sh
./configure --prefix=/usr/local
make -j4
sudo make install
sudo ldconfig

# Now install YateBTS
svn checkout http://voip.null.ro/svn/yatebts/trunk yatebts
cd yatebts
./autogen.sh
./configure --prefix=/usr/local
make -j4
sudo make install

Step 4: Configure YateBTS

The configuration happens in two files. First, the radio parameters:

# /usr/local/etc/yate/ybts.conf

[ybts]
Radio.Band=900
Radio.C0=975
Identity.MCC=001
Identity.MNC=01
Identity.ShortName=TestBTS
Radio.PowerManager.MaxAttenDB=35
Radio.PowerManager.MinAttenDB=35

A few notes on these settings:

  • Radio.Band=900 sets GSM 900 MHz. You can also use 1800 for DCS.
  • Radio.C0=975 is the ARFCN (Absolute Radio Frequency Channel Number). ARFCN 975 maps to 925.0 MHz downlink / 880.0 MHz uplink. Choose an ARFCN that does not conflict with commercial operators in your area.
  • Identity.MCC=001 and Identity.MNC=01 are the test network identifiers. MCC 001 is reserved for testing by the ITU.
  • Power attenuation is set to 35 dB to minimize the range. For a shielded environment, you can lower this.

Second, configure the network interface:

# /usr/local/etc/yate/subscribers.conf

[general]
expires=3600

[security]
auth.call=false
auth.sms=false

Setting auth to false means any phone that connects will be accepted without authentication. This is intentional for a test network - real GSM networks use Ki/IMSI authentication via the HLR.

Step 5: Start the BTS

# Start Yate with BTS support
sudo yate -s -vvv -l /var/log/yate.log

# In another terminal, check the logs
tail -f /var/log/yate.log | grep -i "bts\|radio\|gsm"

If everything is configured correctly, you will see messages about the transceiver starting up and synchronizing. The BladeRF LED should change from blinking to solid, indicating that it is transmitting.

Step 6: Connect a Phone

Put a test SIM (or no SIM, using emergency call mode) in a GSM-capable phone. Go to network settings and do a manual network scan. You should see "TestBTS" (or whatever you set in Identity.ShortName) appear in the list. Select it.

Once connected, the phone will receive a temporary TMSI from your BTS. You can verify the connection in the Yate logs:

grep "TMSI" /var/log/yate.log

Making Calls

With two phones connected to your BTS, you can make calls between them. YateBTS includes a basic numbering plan. By default, each phone gets an extension number based on its IMSI. You can configure static number assignments in the subscriber database.

SMS

SMS between connected phones works out of the box. The messages are routed internally by Yate's message engine. Be aware that SMS messages on your test network are not encrypted (A5/0 cipher) unless you configure A5/1 or A5/3.

Security Observations

Building this setup taught me several things about GSM security:

  1. No mutual authentication. The phone authenticates to the network, but the network does not authenticate to the phone. This is why IMSI catchers work - a phone has no way to verify that it is connecting to a legitimate tower.

  2. Encryption is optional. The BTS decides whether to enable encryption, and many test configurations (including our default) use A5/0 (no encryption). Even A5/1, the most common production cipher, has been broken since 2009.

  3. IMSI exposure. When a phone first connects to a new BTS, it must send its IMSI in the clear. This happens before any encryption is negotiated. This is the fundamental vulnerability that IMSI catchers exploit.

  4. Downgrade attacks. A rogue BTS can force connected phones to use A5/0 (no encryption) even if the phone supports A5/1 or A5/3. The phone has no mechanism to refuse.

These are not new observations, but building a working BTS makes them tangible. Reading about IMSI exposure in a paper is one thing. Watching your own phone send its IMSI to a Raspberry Pi in your living room is another.

Troubleshooting

BladeRF not detected: Check USB cable (must be USB 3.0 capable), try a different port, verify with lsusb.

No signal on phone scan: Verify the ARFCN is correct for your band, check antenna connection, increase transmit power (lower the attenuation value).

Yate crashes on startup: Usually a configuration syntax error. Check /var/log/yate.log for the specific error message.

Phone connects then immediately disconnects: Often a timing issue. Try setting Radio.PowerManager.MinAttenDB to a lower value.

sc
strcpy
SDR & Radio Security Researcher
Radio tinkerer and SDR enthusiast. Explores wireless protocols at the physical layer using BladeRF, HackRF, and RTL-SDR hardware. Focused on GSM/cellular security research, IoT radio analysis, and GNU Radio development. All work is receive-only or conducted in authorized test environments.