Setting up an GSM sniffer with LimeSDR mini on Fedora 30

All the data gathered during the creation of this blog post has been deleted, i do not feel like i have an adequate solution.

Intro

So for a while now i've had an idea where i can count the number of patrons in a pub i hold near and dear to my heart. The first round of ideas was to check for Bluetooth devices and filter on whatever seems like an phone.

I dropped that idea when i realized that phones generally do not have Bluetooth activated/visible. After that plan was scrapped i moved over to the next technology phones tend to have. Namely Wifi. So i bought myself a AWUS1900 from Alfa Network. The idea ended with me setting up a system for monitoring devices with Kismet and a metric server and more and let it run for a week in the locale of choice.

I ended up with way too much data. Apparently 500 000 devices had been broadcasting in that one week... For me its sounds impossible, but i don't know.. Further testing with Wifi was abruptly stopped when the dongle died :( So with my money refunded for the Wifi dongle i figured it would be way more fun testing something new instead of screwing around more with Wifi.

I ended up looking into SDRs! I was looking into LimeSDR and a HackRF and for some magical reason i opted for picking up the LimeSDR. The reason why is that specwise the LimeSDR is way better at basically everything, but unfortunately less supported by the community it seems.

Anyways now you know how i ended up here, lets look into how we can get all our things to play nice together as well as getting some tracking up and running.

picture of the setup

The perquisites

For this setup i need the following:

Note: I have not tried setting this up in a virtual machine.

Installation

LimeSDR Suite

A natural start is fixing with the LimeSDR system itself

Lime Suite is a collection of software supporting several hardware platforms including the LimeSDR, drivers for the LMS7002M transceiver RFIC, and other tools for developing with LMS7-based hardware. Installing the Lime Suite enables many SDR applications such as GQRX to work with supported hardware through the bundled SoapySDR support module.

sudo dnf install git cmake libsqlite3x-devel gcc-c++ \
    libusb-devel libi2c-devel SoapySDR-devel freeglut-devel

And the to make and install LimeSuite

cd /tmp/
git clone https://github.com/myriadrf/LimeSuite.git
cd LimeSuite
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install

If you wish for the LimeSDR to be available for all users and not just root:

Add the following file to /etc/udev/rules.d/64-limesuite.rules

SUBSYSTEM=="usb", ATTR{idVendor}=="04b4", ATTR{idProduct}=="8613", SYMLINK+="stream-%k", MODE="666"
SUBSYSTEM=="usb", ATTR{idVendor}=="04b4", ATTR{idProduct}=="00f1", SYMLINK+="stream-%k", MODE="666"
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="601f", SYMLINK+="stream-%k", MODE="666"
SUBSYSTEM=="usb", ATTR{idVendor}=="1d50", ATTR{idProduct}=="6108", SYMLINK+="stream-%k", MODE="666"

And to finish up reload the rules

udevadm control --reload-rules
udevadm trigger

When this is setup you should run a quick self test:
https://wiki.myriadrf.org/Testing_the_LimeSDR#Testing_the_LimeSDR_Mini
Basically just run LimeQuickTest --no-gui

GNU Radio Companion

For some reason an application with Radio Companion in the title seems reasonable to have

For GNU Radio things are easy peasy! Just install the one from the default repository <3

sudo dnf install gnuradio

After this install we would still not be able to use our LimeSDR Mini, we still need some add-ons to be able to interact with it.

GNU Radio Companion Add-ons

We are going to install two add-on first one is so that we can use LimeSDR as a source for GRC, and a add-on which implements the GSM support that we need. First packages is gr-limesdr add-on, the second one is the gr-gsm. NOTE: the gr-gsm version we need is the one from MyriadFM (the creators of the LimeSDR) which supports the Lime. The compatibility patch has unfortunately not been upstreamed yet. Check out the following issue for updates:
https://github.com/ptrkrysik/gr-gsm/issues/393

gr-limesdr

Installing packages

dnf install git cmake boost-devel swig

And compile and install what we need

cd /tmp/
git clone https://github.com/myriadrf/gr-limesdr
cd gr-limesdr
mkdir build
cd build
cmake ..
make -j 4
sudo make install

gr-gsm

Installing packages

dnf install git cmake libsqlite3x-devel gcc-c++ libtool \
                boost-devel swig libosmocore-devel cppunit-devel \
                gnuradio-devel gr-osmosdr octave fltk-devel SoapySDR-devel \
                wxGTK3-devel mingw64-wxWidgets3

And compile and install what we need

cd /tmp/
git clone https://gitlab.com/myriadrf/gr-gsm.git
cd gr-gsm
mkdir build
cd build
cmake ..
make -j 4
sudo make install

Adding it all together

GNU Radio ✅ LimeSDR software ✅ gr_gsm ✅ gr_limesdr ✅
Ready to go!

Sweet! Now we got all the packages we need. Just to verify we need to open GRC and look for the following blocks in the right hand pane:

GRC in action

So now we can use our SDR as a source and we got the modules needed to parse the GSM data going over the airwaves. Next up is actually finding some GSM traffic and fetch some frames!

When you installed the grgsm packet you also installed a couple of GRC programs which are quite useful. Unfortunately like with everything else we are going to need a tweak.. Even tough we downloaded and installed gr_gsm from MyriadRF we are still installing a version of the tools which is based on the upstream gr_gsm. That is, its using the wrong type of radio source! But not always... More on that later.

I must say, it felt like i knew what i was doing when i figured out how to fix the program 😎

Tweaking the GRC programs

So here is a image of the graph that makes the grgsm_livemon

grgsm_livemon original

It's not really all that much we need to change to make the program work again. Simply change the source block (and maybe the samplerate) The resulting graph from the change looks like this:

grgsm_livemon limesdr

If you are in a hurry you can take my version of the grc file from here:

grgsm_livemon_limesdr.grc (With GUI)
grgsm_livemon_limesdr_headless.grc (Without GUI)

So what is GSM?

The Global System for Mobile Communications (GSM) is a standard developed by the European Telecommunications Standards Institute (ETSI) to describe the protocols for second-generation (2G) digital cellular networks used by mobile devices such as mobile phones and tablets.

Basically its the way our phones talked to the network between the 1990s ans 2010ish. Its still used by quite a few phones as an fallback protocol for when 4G and 3G fails (or you are living in a rural area), fortunately more and more phones prohibit the usage of GSM due to weaknesses found in the protocol.

GSM has a couple of possible frequency bands which is in use where the two most popular om global basis must be the GSM900 and GSM1800 bands.

BandDevice -> TowerTower -> Device
GSM900890 - 915 MHz935 - 960 MHz
GSM18001710 - 1785 MHz1805 - 1880 MHz

We also got a bunch of variations like GSM-R, E-GSM

The full list can be found here: GMS_frequency_bands

Since i'm from Norway we are mainly using the GSM900 band for our phones and therefor this is the area i will look for devices.

Finding and capturing our frequencies

So i know i'm in Norway, next step now is finding the frequencies in my area. There is a couple of different ways to do this. Like using SDRAngel and just poke around the spectrum like so:

grgsm_livemon limesdr

Its quite fast since the LimeSDR can look at such an insane width at once. Normally you can't really see more than 2 MHz at once.

If you don't want to install tools like SDRAngel too you already got the tool grgsm_scanner installed. For some reason not explored it supports the Lime already...

It works as follows:

[n@mamluk hugo]$ grgsm_scanner --help
Usage: grgsm_scanner: [options]

Options:
  -h, --help            show this help message and exit
  -b BAND, --band=BAND  Specify the GSM band for the frequency. Available
                        bands are: GSM900, DCS1800, GSM850, PCS1900, GSM450,
                        GSM480, GSM-R
  -s SAMP_RATE, --samp-rate=SAMP_RATE
                        Set sample rate [default=2000000.0] - allowed values
                        even_number*0.2e6
  -p PPM, --ppm=PPM     Set frequency correction in ppm [default=0]
  -g GAIN, --gain=GAIN  Set gain [default=24.0]
  --args=ARGS           Set device arguments [default=]
  --speed=SPEED         Scan speed [default=4]. Value range 0-5.
  -v, --verbose         If set, verbose information output is printed: ccch
                        configuration, cell ARFCN's, neighbour ARFCN's
  -d, --debug           Print additional debug messages

And a sample of its output:


[n@mamluk hugo]$ grgsm_scanner -b GSM900

ARFCN:    2, Freq:  935.4M, CID: 55181, LAC:  3804, MCC: 242, MNC:   2, Pwr: -71
ARFCN:    5, Freq:  936.0M, CID:     0, LAC:  3804, MCC: 242, MNC:   2, Pwr: -87
ARFCN:    6, Freq:  936.2M, CID:  3839, LAC:  3804, MCC: 242, MNC:   2, Pwr: -81
ARFCN:   11, Freq:  937.2M, CID: 51133, LAC:  3804, MCC: 242, MNC:   2, Pwr: -46
ARFCN:   14, Freq:  937.8M, CID:     0, LAC:     0, MCC:   0, MNC:   0, Pwr: -89
ARFCN:   17, Freq:  938.4M, CID:  3991, LAC:  3804, MCC: 242, MNC:   2, Pwr: -81
ARFCN:   38, Freq:  942.6M, CID: 51132, LAC:  3804, MCC: 242, MNC:   2, Pwr: -66
ARFCN:   39, Freq:  942.8M, CID: 45011, LAC:  3804, MCC: 242, MNC:   2, Pwr: -79
ARFCN:   41, Freq:  943.2M, CID:     0, LAC:     0, MCC:   0, MNC:   0, Pwr: -85
ARFCN:   43, Freq:  943.6M, CID:     0, LAC:     0, MCC:   0, MNC:   0, Pwr: -83
ARFCN:   45, Freq:  944.0M, CID: 45271, LAC:  3804, MCC: 242, MNC:   2, Pwr: -72
ARFCN:   48, Freq:  944.6M, CID: 51132, LAC:  3804, MCC: 242, MNC:   2, Pwr: -73
ARFCN:   49, Freq:  944.8M, CID:  3332, LAC: 11901, MCC: 242, MNC:   1, Pwr: -82
ARFCN:   52, Freq:  945.4M, CID: 20275, LAC: 11901, MCC: 242, MNC:   1, Pwr: -83
ARFCN:   57, Freq:  946.4M, CID:  3244, LAC: 11901, MCC: 242, MNC:   1, Pwr: -73
ARFCN:   59, Freq:  946.8M, CID:  3332, LAC: 11901, MCC: 242, MNC:   1, Pwr: -71
ARFCN:   61, Freq:  947.2M, CID:  3333, LAC: 11901, MCC: 242, MNC:   1, Pwr: -80
ARFCN:   62, Freq:  947.4M, CID:  3052, LAC: 11901, MCC: 242, MNC:   1, Pwr: -87
ARFCN:   67, Freq:  948.4M, CID: 20087, LAC: 11901, MCC: 242, MNC:   1, Pwr: -73
ARFCN:   71, Freq:  949.2M, CID: 20088, LAC: 11901, MCC: 242, MNC:   1, Pwr: -82
ARFCN:   72, Freq:  949.4M, CID: 20033, LAC: 11901, MCC: 242, MNC:   1, Pwr: -72
ARFCN:  122, Freq:  959.4M, CID:  3243, LAC: 11901, MCC: 242, MNC:   1, Pwr: -51

We are getting quite a bit of information here right now, but out focus is the Freq and Pwr fields- Since this is just a simple demo i want to single out the one channel with the highest power, namely the one located at 937.2M. That is the same as 937.2MHz.

The last approach is using the GUI version of grgsm_livemon.

In the GUI we can see an graph of where there is signal. Simple adjust the Frequency slider until you can see a stream of data in your terminal of choice!

grgsm_livemon in action

What is happening in the background while grgsm_livemon is running is that its parsing the data stream from the gsm network, and slicing it up in UDP packets which it sends out on the localhost port 4729. This is the default ports, it can be quite easily changed to whatever is needed. For example when an master-agent setup has been created.

Parsing out data

I'm still generally new to the GSM protocols. I have been trying to find some neato data structure diagrams like the ones we have for the OSI stack, but nothing has really been available..

So instead of rolling my own decoder from scratch i've instead been looking two projects, one which everyone already has been using, and one which everyone who just wants to capture tracking data fast has been using.

First tool is no other than Wireshark. Which ships with a GSMTAP dissector that works perfectly out of the box. Just start Wireshark and make it listen to for example the Loopback device and you will see data immediately.

From where we could make our own tool maybe using something like PyShark and wrap the Wireshark packet engine. At this point in time i opted for using the tool created by Oros42 and petterreinholdtsen.

You can find it here: https://github.com/Oros42/IMSI-catcher
Its super easy to use, all you need to do is let grgsm_livemon run and start the simple_IMSI-cather.py script. What is does is parse all the different kinds of packets which livemon passes to it. From there it tries to parse our either the TMSI or IMSI values. It can from there save the data in a sqlite database for further aggregation of the data.

[n@mamluk IMSI-catcher]$ python simple_IMSI-catcher.py  --help
Usage: simple_IMSI-catcher.py: [options]

Options:
  -h, --help            show this help message and exit
  -a, --alltmsi         Show TMSI who haven't got IMSI (default  : false)
  -i IFACE, --iface=IFACE
                        Interface (default : lo)
  -m IMSI, --imsi=IMSI  IMSI to track (default : None, Example:
                        123456789101112 or "123 45 6789101112")
  -p PORT, --port=PORT  Port (default : 4729)
  -s, --sniff           sniff on interface instead of listening on port
                        (require root/suid access)
  -w SQLITE, --sqlite=SQLITE
                        Save observed IMSI values to specified SQLite file

TMSI? IMSI?

IMSI stands for International mobile subscriber identity and TMSI is Temporary Mobile Subscriber Identity
Basically the telecom operators out the same way as the operating system developers that having your device broadcast a unique identifier for all to see might infringe on some basic privacy (looking at you MAC addresses). The telco equivalent of an MAC address is the IMSI number. The IMSI identifies you as an customer of your telco, and as such does not change unless your telco forces it on you. An solution to this problem is that the local cellular network can assign a (actually two ) TMSI values which the devices can use instead of its IMSI number. The problem with this is that even tough a device man use the TMSI number it needs to expose its IMSI number wierdly often...

So this is what Oros42's tool does. It simply captures the IMSI, TMSI-1 and TMSI-2 numbers and stores them with an timestamp.

The result and conclusion


Nb IMSI ; TMSI-1     ; TMSI-2     ; IMSI              ; country      ; brand      ; operator              ; MCC  ; MNC   ; LAC    ; CellId
1       ;            ;            ; 242 14 0XXXXXXXX4 ; Norway       ; ICE        ; ICE Communication Norg; 242  ; 02    ; 3804   ; 51132 
2       ;            ;            ; 242 02 9XXXXXXXX5 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
3       ;            ;            ; 242 14 0XXXXXXXX9 ; Norway       ; ICE        ; ICE Communication Norg; 242  ; 02    ; 3804   ; 51133 
4       ; 0x6f0c93e9 ;            ; 240 08 0XXXXXXXX0 ; Sweden       ; Telenor    ; Telenor Sverige AB    ; 242  ; 02    ; 3804   ; 51133 
5       ;            ;            ; 242 23 2XXXXXXXX0 ; Norway       ; Lycamobile ; Lyca Mobile Ltd       ; 242  ; 02    ; 3804   ; 51133 
6       ;            ;            ; 242 05 9XXXXXXXX4 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
        ; 0x640cd8c7 ;            ; 242 05 9XXXXXXXX4 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
        ; 0xea401e6d ;            ; 242 05 9XXXXXXXX4 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
7       ; 0x220e09ea ; 0x740ca8d9 ; 242 05 9XXXXXXXX0 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
8       ; 0x53045cff ;            ; 242 05 9XXXXXXXX8 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
        ; 0xe340213d ;            ; 242 23 2XXXXXXXX0 ; Norway       ; Lycamobile ; Lyca Mobile Ltd       ; 242  ; 02    ; 3804   ; 51133 
9       ;            ;            ; 242 23 1XXXXXXXX1 ; Norway       ; Lycamobile ; Lyca Mobile Ltd       ; 242  ; 02    ; 3804   ; 51133 
10      ;            ;            ; 242 14 0XXXXXXXX4 ; Norway       ; ICE        ; ICE Communication Norg; 242  ; 02    ; 3804   ; 51133 
11      ;            ;            ; 242 05 9XXXXXXXX9 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
12      ; 0xed384335 ; 0x330dc238 ; 242 23 2XXXXXXXX5 ; Norway       ; Lycamobile ; Lyca Mobile Ltd       ; 242  ; 02    ; 3804   ; 51133 
13      ; 0xfc40db3d ; 0x26060b48 ; 242 05 0XXXXXXXX1 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
14      ; 0xfc40db3d ;            ; 242 02 9XXXXXXXX7 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
15      ;            ;            ; 724 10 0XXXXXXXX4 ; Brazil       ; Vivo       ; Vivo S.A.             ; 242  ; 02    ; 3804   ; 51133 
16      ;            ;            ; 242 23 2XXXXXXXX0 ; Norway       ; Lycamobile ; Lyca Mobile Ltd       ; 242  ; 02    ; 3804   ; 51133 
17      ;            ;            ; 242 02 9XXXXXXXX4 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
18      ;            ;            ; 242 23 2XXXXXXXX1 ; Norway       ; Lycamobile ; Lyca Mobile Ltd       ; 242  ; 02    ; 3804   ; 51133 
19      ; 0xf7409d7d ;            ; 242 05 9XXXXXXXX3 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
20      ;            ;            ; 242 23 1XXXXXXXX6 ; Norway       ; Lycamobile ; Lyca Mobile Ltd       ; 242  ; 02    ; 3804   ; 51133 
21      ; 0xef40e315 ;            ; 242 23 2XXXXXXXX7 ; Norway       ; Lycamobile ; Lyca Mobile Ltd       ; 242  ; 02    ; 3804   ; 51133 
22      ;            ;            ; 242 23 1XXXXXXXX0 ; Norway       ; Lycamobile ; Lyca Mobile Ltd       ; 242  ; 02    ; 3804   ; 51133 
23      ;            ;            ; 242 14 0XXXXXXXX8 ; Norway       ; ICE        ; ICE Communication Norg; 242  ; 02    ; 3804   ; 51133 
24      ;            ;            ; 242 05 9XXXXXXXX7 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
25      ;            ;            ; 242 05 0XXXXXXXX2 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
26      ;            ;            ; 242 05 9XXXXXXXX9 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
27      ;            ;            ; 232 03 1XXXXXXXX0 ; Austria      ; T-Mobile AT; T-Mobile Austria      ; 242  ; 02    ; 3804   ; 51133 
28      ;            ;            ; 242 02 9XXXXXXXX4 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
29      ;            ;            ; 242 05 9XXXXXXXX8 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
        ; 0xf438624d ;            ; 232 03 1XXXXXXXX0 ; Austria      ; T-Mobile AT; T-Mobile Austria      ; 242  ; 02    ; 3804   ; 51133 
        ; 0xd4407c25 ;            ; 232 03 1XXXXXXXX0 ; Austria      ; T-Mobile AT; T-Mobile Austria      ; 242  ; 02    ; 3804   ; 51133 
30      ;            ;            ; 242 02 6XXXXXXXX1 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
31      ;            ;            ; 242 05 9XXXXXXXX8 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
32      ;            ;            ; 242 02 9XXXXXXXX3 ; Norway       ; Telia      ; TeliaSonera Norge AS  ; 242  ; 02    ; 3804   ; 51133 
        ; 0x690d2ac4 ;            ; 242 23 2XXXXXXXX7 ; Norway       ; Lycamobile ; Lyca Mobile Ltd       ; 242  ; 02    ; 3804   ; 51133 
        ; 0xe1381f3d ;            ; 242 23 2XXXXXXXX1 ; Norway       ; Lycamobile ; Lyca Mobile Ltd       ; 242  ; 02    ; 3804   ; 51133 

As you can see its rather easily to capture IMSI data from clients. The script which is used can quite easily be extended to save more precise timestamps, jump between different channels, and actually anonymize the data! The capture shown here was over the span of half an hour in a central location in my city. While looking over these results it dawned on me one of the biggest problems with this kind of solution. How to i anonymize the data from everyone including me? I guess i can generate som key in RAM which changes with each boot of the device i run the software on, but i do not really know if that is enough. I own the device, and as such. How do i make a system does not allow me to find the original? For example some normal hashing would not suffice in my eyes. Since the search space is so small. Maybe some bcrypt shenanigans with a giant salt would be okay?

Whats next?

There is a couple things i want to look more into. What is possible to do with LTE networks?
How on earth can i do this while the "victim" remains anonymous?
How can i make the livemon app parse data from multiple channels at once? Normally an radio might be able to see one channel at the time, but the LimeSDR is absurd and just does its own thing.. The repository got a version of the script one devices per channel, but why use six devices when one can do the same job? :D

I'm lazy. Can this be scripted?

YES!

Since i've been running this setup on a machine i tend to reinstall every couple of weeks i ended up setting up a couple of Ansible scripts. It worked last time i ran it ¯\_(ツ)_/¯ I pinkyswear that i'll compress the filestructure to only what we need at some point

Fun fact: It's actually the first Ansible roles i've made. Ever.

You can grab it from over here: https://github.com/N0K0/limesdr_IMSI_fedora

Please fix it if it does not work ;D