Stealth Cell Tower

Published: Sun 30 October 2016



Rogue Cellular Infrastructure Disguised as Office Printer

Stealth Cell Tower is an antagonistic GSM base station in the form of an innocuous office printer. It brings the covert design practice of disguising cellular infrastructure as other things - like trees and lamp-posts - indoors, while mimicking technology used by police and intelligence agencies to surveil mobile phone users.

Stealth Cell Tower

Masquerading as a regular cellular service provider, Stealth Cell Tower surreptitiously catches phones and sends them SMSs written to appear they are from someone that knows the recipient. It does this without needing to know any phone numbers.

Stealth Cell Tower
SMS exchange with Stealth Cell Tower

With each response to these messages, a transcript is printed revealing the captured message sent, alongside the victim’s unique IMSI number and other identifying information. Every now and again the printer also randomly calls phones in the environment and on answering, Stevie Wonder’s 1984 classic hit I Just Called To Say I Love You is heard.

Stealth Cell Tower
Printed output, complete with identifying IMSI number from SIM card Stealth Cell Tower
View of interior with BladeRF SDR board (top right) and R-Pi 3 (bottom left) interfacing with printer mainboard Stealth Cell Tower
View of interior (right side) with automobile USB device charger converting 21-22v supply from printer to 5v, powering BladeRF and R-Pi 3. Stealth Cell Tower
View from printer cartridge bay, modified to host 2 omnidirectional antennae (TX and RX) fed by SMA cable to BladeRF.

Conceptual background

Stealth Cell Tower is a continuation of my research into the uncanny design practice of disguising cell towers as other things (like trees, bricks, church spires) - a topic I wrote about in 2014 in an article called Stealth Infrastructure.

Here, Stealth Cell Tower situates this same outdoor practice indoors, where an HP printer is perhaps the most innocuous of flora.

Stealth Cell Tower
Cell Tower badly disguised as a tree from the Coniferus family Stealth Cell Tower
Cell Tower badly disguised as a palm tree (photo taken by the artist in Marrakech) Stealth Cell Tower
Cell Tower badly disguised as a lamp post, and placed uncharacteristically near an actual lamp-post, for no discernable reason Stealth Cell Tower
Cell Tower very badly disguised as pendulous bricks

Stealth Cell Tower is also a continuation of my studies into the surveillance of mobile phones by police, government intelligence agencies and the military using what have come to be known as IMSI Catchers. The most famous tool within the spy’s inventory is Stingray.

Stingray IMSI Catcher
Stingray mobile surveillance hardware as presented in Harris’ original patent application.

In 2013 it was discovered the NSA was found to be spying on the German Bundestag, via the US embassy next door. Danja Vasiliev and I sought to emulate the methods used by the NSA as part of an intervention at Transmediale, where we successfully hooked over 740 mobile phones without knowing their phone number, then proceeding to send them SMSs of a paranoid and sardonic nature. We called our project PRISM: Tower. See also Border Bumping for an earlier (2012) investigation of cellular infrastructure by Oliver.

Hardware

Stealth Cell Tower is a Hewlett Packard Laserjet 1320 printer modified to contain and power components required implement a GSM 900 Base Station.

These components comprise:

  • BladeRF x40
  • Raspberry Pi 3
  • 2x short GSM omnidirectional antennae with magnetic base
  • 2x SMA cable
  • Cigarette-lighter-to-USB-charger circuit (converting 12-24v to 5v)
  • 1x USB Micro cable (cut and soldered to output of USB charger)
  • 1x USB A cable (cut and soldered to printer mainboard)

The HP Laserjet 1320 was chosen not only for its surprisingly unmentionable appearance but also because it had (after much trial and error) the minimal unused interior volumes required to host the components. No cables, other than the one standard power-cord, are externally visible. More so, care has been taken to ensure the printer functions normally when connected via USB cable to the standard socket in the rear.

The Raspberry Pi 3 was chosen after failed attempts to acheive stable YateBTS performance on the Intel Edison (tiny - would’ve saved space!), Beaglebone Black and even an I-MX6 Marsboard. Unlike the antiquated OpenBTS, YateBTS really seems to need those extra cores, otherwise ignoring accelerators like NEON on the Cortex A8/9 platforms.

Code

Stealth Cell Tower is built atop the free and open source API YateBTS, the NiB core script nib.js of which was modified to drive the SMS conversation. welcome.js was modified to automatically respond to calls by playing Stevie Wonder’s 1984 classic hit I Just Called_To Say I Love You from a GSM encoding of an MP3 owned by the artist.

The BTS is run on init, from /etc/rc.local by a script that also filters for log output from exchanges, formats a PDF from the resulting text file and sends it to the printer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/bin/bash

readonly FH=/home/pi/yate.log
rm -f $FH
# Start the BTS, log to $FH and background
yate 2>&1 -l $FH &
sleep 1
echo "Starting up..."
last=" "

while true;
    do
        # Poll every 10 seconds
        sleep 10
        # Check log for new sniffed 'call route' entries and do some subbing
        cur=$(cat $FH | grep -A 16 "Sniffed\ 'call.route'" | sed -e "s/param\['//" \
        -e "s/'\]//" -e 's/thread.*//' -e 's/time\=[0-9].*//' \
        -e 's/\ data=(.*//' -e 's/\ retval=.*//' \
        -e 's/\ tmsi.*//' -e 's/ybts/Stealth\ Cell\ Tower/' \
        -e 's/Sniffed/Monitored\ =/' -e '/^\s*$/d' \
        -e 's/^\s*//' | tail -n 13)
        if [ "$cur" != "$last" ]; then
            if [ ${#cur} -gt 1 ]; then 
                echo "New SMS events detected"
                # Test to see if an IMSI is in the string. If not, look it up and put it in
                if [[ $cur != *imsi* ]]; then
                    caller=$(echo "$cur" | grep "caller" | awk '{ print $3 }' | sed "s/'//g" \
                    | tr -cd '[:print:]')
                    imsi=$(cat /usr/local/etc/yate/tmsidata.conf | grep "$caller" \
                    | cut -d '=' -f 1)
                    cur=$(echo "$cur" | sed -e "s/\ called\ .*/imsi\ =\ '$imsi'/" )
                fi
                # Make it all uppercase
                event=$(echo -e \\n"$cur" | tr 'a-z' 'A-Z')
                echo "printing file..."
                echo "$event" > printme
                # Format a postscript file with enscript
                enscript -r --header='SMS EVENT RECORD|%W|%* UTC' -i2cm --margins=10:10:30:10 \
                -o printme.ps -f Courier@15/12 printme
                # Convert to PDF
                ps2pdfwr printme.ps printme.pdf
                # Send it to the print queue for immediate processing
                lp -U pi -o a4 -q 100 -d hp_LaserJet_1320_2 printme.pdf 
            fi
            last=$cur
        fi
done

This script will randomly pick and call an msisdn registered to the BTS:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/bin/bash

readonly HOST=127.0.0.1
readonly PORT=5038
readonly DATA=/usr/local/share/yate/sounds/stevie.au
readonly TMSI=/usr/local/etc/yate/tmsidata.conf
readonly CC=49 #MSISDN prefix, matching that of definition in yate conf.

callone () {
  # Play "I Just Called To Say I Love You" by Stevie Wonder, on pickup 
  echo "call wave/play/$DATA $mt" | netcat -i 1 -q 1 $HOST $PORT
  # Or, setup channel and route to IAX/SIP
  # echo "call 'iax/iax:$PORT@11.22.33.44/$PORT' $mt" | netcat -q 1 $HOST $PORT
}

callall() {
  for mt in ${UES[@]} #override $mt
    do
      echo "calling $mt"
      callone
  done
}

while true;
  do

    tmsilen=$(wc -l $TMSI | awk '{ print $1 }')
    ues=($(cat $TMSI | grep -A $tmsilen ues | sed 's/\[ues\]//' | cut -d ',' -f 3))
    if [ ! -z $ues ]; then
      ueslen=${#ues}
      RANGE=$ueslen
      select=$RANDOM
      let "select%=$RANGE"
      mt=${ues[$select]} 
      callone
    fi
    sleep 30
done

YateBTS’s Network in a Box provides a high-level Javascript interface, the core script of which is nib.js. It was modified in several locations to provide for the SMS conversation. An example follows:

    function onSMS(msg)
    {
        Engine.debug(Engine.DebugInfo,"onSMS");

        var imsi = msg.imsi;
        var tmsi = msg.tmsi;

        var responses = [
            "No probs if you're busy. I'll track you down later.",
            "Don't remember me? How could I forget you?",
            "Hehe, you've probably never noticed - I've been here all along",
            "All good. I'm in the corner - come over when you're ready",
            "I'm printing the details for you now. Waiting over here for you",
            "Give me a call if you like and we can sort this out!",
            "I left you something on the printer ;-)"
        ];

        var randResp = responses[Math.random(0, responses.length)];

        if (msg.caller=="" || msg.called=="" || (imsi=="" && tmsi=="")) {
            // Protocol error, unspecified
            msg.error = "111";
            return false;
        }

        if (tmsi!="" && imsi=="") {
            imsi = getSubscriberIMSI(null,tmsi);
            msg.imsi = imsi;
        }
        if (imsi=="" || registered_subscribers[imsi]==undefined) {
            // Unidentified subscriber
            msg.error = "28";
            return false;
        }

        // user must be registered
        var msisdn = getRegUserMsisdn(imsi);
        if (msisdn==false) {
            // Unidentified subscriber
            msg.error = "28";
            return false;
        }

        var dest = msg["sms.called"];

        if (dest==nib_smsc_number) {
            message(randResp,imsi,msisdn,3);    
            return true;
        }

        // check if short number was used
        dest = isShortNumber(dest);
        var dest_imsi = getSubscriberIMSI(dest);

        if (dest_imsi==false) {
            msg.error = "1"; // Unassigned (unallocated) number
            return false;
        }

        var next_try = Date.now()/1000; 
        var sms = {"imsi":imsi, "msisdn":msisdn, "smsc":msg.called, "dest":dest, "dest_imsi":dest_imsi, "next_try":next_try, "tries":sms_attempts, "msg":msg.text };

        pendingSMSs.push(sms);
        return true;
    }

The complete tree of scripts and configuration files for implementing Stealth Cell Tower is here, as a tar.gz archive (sha256sum a6d2546150f46756bfb7affa8dc82390240f5ba92d2cd03e9f7cfd4b6522cc3b). To use it on an existing install of YateBTS, just:

    cd /
    tar xvzf yatebts_r-pi3_conf-scripts.tar.gz

Precompiled binaries

While compiling Yate and YateBTS on the R-Pi 3 isn’t heinously difficult, it is tedious. For this latter reason I’m providing the source and compiled binaries for the R-Pi 3, running atop kernel 4.4.11-v7 on a Debian 8 system. You can download the entire tree here (sha256sum eaabeb72eb5bf3e62cbfedb43dbc623437b40728b25555d88c9e8f06ca31d090).

Press

Affiliated