/pager-sec

Hacking hospital pagers, then building an encrypted solution.

Primary LanguagePythonGNU General Public License v3.0GPL-3.0

pager-sec

Timeline

🏁 This independent research project was started on Jan. 27, 2021, under the guidance of Dr. Tyler Bletsch at Duke University.

🚧 Per guidance from Duke University’s Office of Counsel, the interception and decoding steps of this project were suspended on March 26, 2021.

✅ This project was finished on April 21, 2021.

🏆 This project was awarded 2nd place on April 26, 2021, in the 2021 Duke Electrical & Computer Engineering Independent Study Poster Session.

Table of Contents

  1. Motivation
  2. Materials
  3. Part 1: Hacking Pagers
    1. Finding Frequencies
    2. Interception
    3. Alternative: Generating Data
    4. Processing
  4. Part 2: Fixing Pagers
  5. Conclusion
  6. Poster
  7. Additional Readings

Motivation

Though largely replaced by smartphones today, pagers remain extremely common in niche fields, such as hospitals, where pagers are favored for their low cost, long battery life, wide range and reliable connectivity—crucial in a setting where many walls are shielded to block X-ray radiation. An estimated 80% of all U.S. clinicians still carry pagers, not to mention the nurses, paramedics and other health-care personnel who also rely on pagers.

However, most pagers lack even the most basic security. Most data is transmitted unencrypted despite carrying, in many cases, protected health information (PHI)—including patient names, medical histories and test results, all in real time. This poses significant risk to patient confidentiality, especially when the pages contain information about patient locations or stigmatized illnesses. It may even violate the HIPAA Security Rule. Still, it remains common practice in many hospitals.

In this project, I illustrate this dangerous yet neglected security flaw by:

  1. Demonstrating the ease of intercepting and decoding pages; then
  2. Building a simple proof of concept for pager security.

Materials

This project uses the following hardware:

  • SDR with antenna, to intercept pages. I use the DVB-T+DAB+FM SDR, a USB 2.0 dongle that is available for cheap ($15–25) online.
    • My SDR is based on the Realtek RTL2832U chipset and the Rafael Micro R820T tuner.
    • My SDR supports frequencies from 24 MHz to 1.766 GHz. You can check your SDR’s range based on its tuner on the rtl-sdr wiki.
  • Arduino Nano, to build the proof of concept. This and other Arduino models are available online.
    • My Arduino uses the ATmega328P microcontroller.

This project uses the following software stack:

  • Ncat 7.80, a networking utility for reading and writing data across networks.
  • Gqrx 2.14.4, an open-source SDR receiver on Linux.
    • Dependencies: gnuradio, gr-osmosdr, portaudio, qt5-qtbase, qt5-qtsvg, volk (and their dependencies)
  • SoX 14.4.2, a cross-platform tool for audio processing.
    • Dependencies: flac, lame, libiconv, libid3tag, libmad, libmagic, libogg, libopus, libpng, libsndfile, libvorbis, opusfile, twolame, wavpack, zlib (and their dependencies)
  • multimon-ng 1.1.8, a digital decoder on Linux.
    • It is one of the few decoders that support FLEX and POCSAG, two common paging protocols.
  • PyCryptodome 3.9.9, a cryptography library for Python.
  • Crypto 0.2.0, a cryptography library for Arduino.
  • I am running macOS Big Sur 11.1 on my machine. All Linux software were installed on macOS through MacPorts.

Part 1: Hacking Pagers

Finding Frequencies

Most U.S. pagers use either FLEX or POCSAG as their paging protocols. You can identify a pager frequency’s protocol by its characteristic sounds and waterfall shape, which can be found in its Signal Identification Guide entry. The wiki entries also contain each protocol’s usual frequency ranges.

All frequencies were tested from Durham, N.C., United States. Only 929.577 MHz could be positively identified, as the interception and decoding of pages were suspended afterward. The other frequencies are only suspected to follow the FLEX protocol, based on their sound and waterfalls.

  • 929.142 MHz: ??? (FLEX)
  • 929.577 MHz: Hospital services in North and South Carolina (FLEX)
  • 931.161 MHz: ??? (FLEX)

I used the FLEX frequency 929.577 MHz. Fortunately, the frequency had relatively busy traffic, with roughly about 50 pages a minute.

Interception

To intercept and decode pages, open Gqrx and tune it to the chosen frequency, adjusting the gain and squelch settings as needed. Then click "UDP" to stream the audio over UDP to a remote host.

Listen to the UDP data (port 7355), resample the raw audio from 48 kHz to 22.05 kHz, then try to decode it using several common paging protocols. This command is adapted from that in the Gqrx docs. Protocols can be added or removed using the -a flag in multimon-ng, and you can display the timestamp for each message with the --timestamp flag.

ncat -lu 7355 \
| sox -t raw -esigned-integer -b16 -r 48000 - -esigned-integer -b16 -r 22050 -t raw - \
| multimon-ng -t raw -a POCSAG512 -a POCSAG1200 -a POCSAG2400 -a FLEX -

From what I’ve observed, the messages seem to fall into one of several formats:

  1. For binary pages, a series of nine 8-digit hexadecimal numbers.
  2. For tone/numeric pages, a number or an extension to call.
  3. For alphanumeric pages,
    1. A short message that appears manually typed.
    2. A long message with a structured header (From/Subject fields), often followed by a confidentiality notice.
    3. An automated alert.
    4. A long series of base-64 characters, terminating in four (or fewer) A’s.

For each decoded FLEX message, multimon-ng prints a lot of associated metadata. I deciphered its syntax using the ARIB Standard for FLEX and the relevant source code. Here is a typical (but not real) message that you might see:

FLEX|3200/4|08.103.C|0004783821|LS|5|ALN|3.0.K|PT IN 413 DOE, JANE 37F DILAUDID 0.5MG 1HR AGO STILL C/O PAIN, INCREASE DOSE?
  1. Protocol name: FLEX
  2. Transmission mode
    1. Speed (1600/3200/6400): 3,200 bits per second
    2. FSK level (2/4): 4-level
  3. Frame information
    1. Cycle number (0 to 14): 8
    2. Frame number (0 to 127): 103
    3. Phase (A for 1,600 bps, A/C for 3,200 bps, A/B/C/D for 6,400 bps): C
  4. Capcode, left-padded with zeroes: 478-3821
  5. Address type
    1. Long/short (L/S): Long
    2. Group/single (G/S): Single
  6. Page enum (2 for tone, 3 for numeric, 5 for alphanumeric, 6 for binary): Alphanumeric
  7. Page type (TON for tone, NUM for numeric, ALN for alphanumeric, BIN for binary): Alphanumeric
  8. (Only for alphanumeric) Message fragment information
    1. Fragment indicator (3 for first fragment, 0,1,2,4,… for next fragments): First fragment
    2. Message continued flag (0 if end of message, 1 if more to follow): End of message
    3. Fragment flag (K if only 1 fragment, F if more to follow, C if last fragment): First and only fragment of message
  9. Message: Patient Jane Doe in Rm. 413, a 37-year-old female, was given 0.5 mg of Dilaudid (hydromorphone) 1 hour ago, yet she is still complaining of pain. Should we increase her dose?

Alternative: Generating Data

If you wish not to intercept real pages, you can also auto-generate artificial data. The script generate.py follows the multimon-ng output format above to generate fake pages.

Processing

Longer messages are often fragmented and transmitted over several pages. This is not an issue for practical use—each pager receives only those pages intended for it—but, because I see all pages on a frequency, these fragments can arrive interrupted by other messages. I can reassemble these fragments by concatenating the pages according to their frame information and message fragment information.

Redirect the output to collect.py to reassemble the message fragments in real time.

ncat -lu 7355 \
| sox -t raw -esigned-integer -b16 -r 48000 - -esigned-integer -b16 -r 22050 -t raw - \
| multimon-ng -t raw -a POCSAG512 -a POCSAG1200 -a POCSAG2400 -a FLEX - \
| ./collect.py

Part 2: Fixing Pagers

Cryptographically, pagers are limited by the following:

  • Small memory, which may make computationally or resource-intensive protocols (e.g., RSA) infeasible.
    • RSA implementations for the Arduino do exist, but they are far too weak for practical use—one proof of concept uses 8-bit keys, while the National Institute of Standards and Technology recommends at least 2,048-bit keys.
  • One-way communication, which make many common encryption protocols (e.g., Diffie–Hellman) impossible.
    • This does mean one-way pagers cannot be used for location-tracking—as pager advocates like to tout—but that is a trivially small benefit in exchange for total lack of data privacy.

To show even limited hardware can support encryption, I modeled pagers with an Arduino Nano, which is the smallest Arduino available and has even less memory than pagers. It has only 32 KB of flash memory and 2 KB of SRAM, compared to the Motorola Advisor pager, which has 8×32 KB of SRAM.

I also used ChaCha20–Poly1305, a lightweight symmetric-key protocol for authenticated encryption with additional data (AEAD). The stream cipher ChaCha, with 20 rounds of encryption, is as secure as the more popular AES while offering better performance. The message authentication code (MAC) protocol Poly1305 allows verifying the integrity of a message—i.e., it detects when the contents of a message have been changed. The implementation details are as follows:

  • Each pager is assigned a unique, randomly generated pre-shared key (PSK), which is also known to the central paging system. In this way, if the PSK is somehow compromised, only communications to that one pager are compromised.
  • The frame information of a message is used as the “additional data” (AD), which is unencrypted and used for authentication only. By checking that the frame information, incremented with every message, is as expected, I can prevent replay attacks, where an attacker simply records and replays an encrypted message.
  • This implementation uses 256-bit keys, 96-bit initialization vectors (IVs) and 128-bit authentication tags.
  • Due to memory constraints, this implementation is limited to 300-byte messages and 32-byte ADs.

This proof of concept does not require any changes in hardware, since modifying or replacing pagers can be costly for hospitals. Instead, it is designed to be only a software upgrade.

I simulated the paging system with the Python script encrypt.py, which encrypts a message with a hardcoded PSK. And I simulated the pager with the Arduino script Decrypt.ino.

Conclusion

Pagers used by hospitals are easy to attack. With cheap hardware and free software, anyone can intercept pages to access sensitive data.

Pagers are also easy to defend. Even limited hardware can support authenticated encryption for one-way communication. After all the decades in which hospitals have been using pagers, there is little excuse for this huge lapse in security.

Poster

Additional Readings