Code Monkey home page Code Monkey logo

imsi-catcher's Introduction

IMSI-catcher

This program shows you IMSI numbers, country, brand and operator of cellphones around you.

/!\ This program was made to understand how GSM network work. Not for bad hacking !

screenshot0

What you need

1 PC with Gnu/Linux. Tested with :

  • debian 10
  • Ubuntu 20.04/LinuxMint 20+
  • Kali 2020+

1 SDR receiver. Tested with :

Setup

git clone https://github.com/Oros42/IMSI-catcher.git
cd IMSI-catcher

or

wget https://github.com/Oros42/IMSI-catcher/archive/master.zip && unzip -q master.zip
cd IMSI-catcher-master
sudo apt install python3-numpy python3-scipy python3-scapy

Warning : don't use python 3.9 (ctypes bug)!

You have the choice with 2 types of gr-gsm's install : in your OS or with docker.

Install gr-gsm in your OS (recommended)

sudo apt-get install -y \
    cmake \
    autoconf \
    libtool \
    pkg-config \
    build-essential \
    python-docutils \
    libcppunit-dev \
    swig \
    doxygen \
    liblog4cpp5-dev \
    gnuradio-dev \
    gr-osmosdr \
    libosmocore-dev \
    liborc-0.4-dev \
    swig
gnuradio-config-info -v

if >= 3.8

git clone -b maint-3.8 https://github.com/velichkov/gr-gsm.git

else (3.7)

git clone https://git.osmocom.org/gr-gsm
cd gr-gsm
mkdir build
cd build
cmake ..
make -j 4
sudo make install
sudo ldconfig
echo 'export PYTHONPATH=/usr/local/lib/python3/dist-packages/:$PYTHONPATH' >> ~/.bashrc

Importlib vs Imp

Beginning with Python 3.1, Imp is replaced by importlib. Imp is deprecated in Python 3.11, with the new requirements met as follows.

apt install python3-pip
pip install importlib

Install gr-gsm with Docker

sudo xhost +local:docker
docker pull atomicpowerman/imsi-catcher
docker run -ti --net=host -e DISPLAY=$DISPLAY --privileged -v /dev/bus/usb:/dev/bus/usb  atomicpowerman/imsi-catcher bash

Run all grgsm_* in this docker.

Usage

We use grgsm_livemon to decode GSM signals and simple_IMSI-catcher.py to find IMSIs.

python3 simple_IMSI-catcher.py -h
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
  -t TXT, --txt=TXT     Save observed IMSI values to specified TXT file
  -z, --mysql           Save observed IMSI values to specified MYSQL DB (copy
                        .env.dist to .env and edit it)

Open 2 terminals.

In terminal 1

sudo python3 simple_IMSI-catcher.py -s

In terminal 2

grgsm_livemon

Now, change the frequency until it display, in terminal, something like that :

15 06 21 00 01 f0 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
25 06 21 00 05 f4 f8 68 03 26 23 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
49 06 1b 95 cc 02 f8 02 01 9c c8 03 1e 57 a5 01 79 00 00 1c 13 2b 2b

Wireshark

You can watch GSM packets with wireshark.

sudo apt install wireshark
sudo wireshark -k -Y '!icmp && gsmtap' -i lo

Find frequencies

grgsm_scanner
ARFCN:  974, Freq:  925.0M, CID:     2, LAC:   1337, MCC: 208, MNC:  20, Pwr: -41
ARFCN:  976, Freq:  925.4M, CID:  4242, LAC:   1007, MCC: 208, MNC:  20, Pwr: -45

Now, you can set the frequency for grgsm_livemon :

grgsm_livemon -f 925.4M

Or, for hackrf, fetch the kalibrate-hackrf tool like this:

sudo apt-get install automake autoconf libhackrf-dev
git clone https://github.com/scateu/kalibrate-hackrf
cd kalibrate-hackrf/
./bootstrap
./configure
make
sudo make install

Run

kal -s GSM900
kal: Scanning for GSM-900 base stations.
GSM-900:
	chan:   14 (937.8MHz + 10.449kHz)	power: 3327428.82
	chan:   15 (938.0MHz + 4.662kHz)	power: 3190712.41
...

Log data in mysql

Use db-example.sql to create your DB.

cp .env.dist .env
nano .env
# set your config
sudo apt install python-decouple python3-mysqldb
sudo python3 simple_IMSI-catcher.py -s --mysql

scan-and-livemon (no longer used)

Scan frequencies and listen the 1st found :
In terminal 1

python3 scan-and-livemon

In terminal 2

python3 simple_IMSI-catcher.py

Links

Setup of Gr-Gsm : https://osmocom.org/projects/gr-gsm/wiki/Installation and https://github.com/velichkov/gr-gsm
Frequency : http://www.worldtimezone.com/gsm.html and https://fr.wikipedia.org/wiki/Global_System_for_Mobile_Communications
Mobile Network Code : https://en.wikipedia.org/wiki/Mobile_Network_Code
Scapy : http://secdev.org/projects/scapy/doc/usage.html
IMSI : https://fr.wikipedia.org/wiki/IMSI
Realtek RTL2832U : https://osmocom.org/projects/sdr/wiki/rtl-sdr and http://doc.ubuntu-fr.org/rtl2832u and http://doc.ubuntu-fr.org/rtl-sdr

Donate

To support my work, a tipee would be nice ;-)
https://liberapay.com/Oros/

imsi-catcher's People

Contributors

0mazahacka0 avatar alt-glitch avatar anderstogern avatar dspinellis avatar jabreity avatar jonirinta-kahila avatar lapolis avatar nylecohen avatar oros42 avatar petterreinholdtsen avatar purwowd avatar puyoulu avatar thefinn93 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

imsi-catcher's Issues

Question | does it open a bts?

hey there @Oros42

quick question, does ur code / grgsm_livemon open a new BTS ? or just listing the air ?

Do phones /handset/device gets connected to our device for example USB DVB-T key (RTL2832U) or it just listing to the wireless signals (like wifi on an open network)

cheers

I can find my own MS.

Good evening.

I was doing a IMSI-CATCHER and i get it. It Works perfect, i found a loot of MS and they information, but i cant find a my own imsi number. I made a lot test, putting my phone into GMS and trying to conect to the same BTS and nothing.

I'm using next ones

RTL2832U donggle
E4000 donggle

Core i5 8gb Ram
Ubuntu 16-04

Error

Hola amigos buenos dias, al tratar de correr la orden sudo python simple_IMSI-catcher.py
me saca el siguiente error:

WARNING: No route found for IPv6 destination :: (no default route?)
Nb IMSI ; TMSI-1 ; TMSI-2 ; IMSI ; country ; brand ; operator ; MCC ; MNC ; LAC ; CellId
Traceback (most recent call last):
File "simple_IMSI-catcher.py", line 416, in
sniff(iface=options.iface, filter="port {} and not icmp and udp".format(options.port), prn=find_imsi, store=0)
File "/usr/lib/python2.7/dist-packages/scapy/sendrecv.py", line 586, in sniff
r = prn(p)
File "simple_IMSI-catcher.py", line 286, in find_imsi
find_cell(x)
File "simple_IMSI-catcher.py", line 273, in find_cell
operator=mcc_codes[mcc]['MNC'][mnc][1]
KeyError: '10'

Por favor, alguien me puede ayudar?
Gracias.

cant assign the network interface to the BPF handle

trying run simple_IMSI-catcher.py script on

OS X High Sierra 10.13.6 (17G65)
Python 2.7.16
scapy 2.4.2
scipy 1.2.1
numpy 1.16.2

sudo python simple_IMSI-catcher.py -s

Traceback (most recent call last):
  File "simple_IMSI-catcher.py", line 533, in <module>
    sniff(iface=options.iface, filter="port {} and not icmp and udp".format(options.port), prn=find_imsi_from_pkg, store=0)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scapy/sendrecv.py", line 836, in sniff
    *arg, **karg)] = iface
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scapy/arch/bpf/supersocket.py", line 72, in __init__
    raise Scapy_Exception("BIOCSETIF failed on %s" % self.iface)
scapy.error.Scapy_Exception: BIOCSETIF failed on lo

found this in src scapy/supersocket.py
https://github.com/secdev/scapy/blob/master/scapy/arch/bpf/supersocket.py#L68

sudo python immediate_assignment_catcher.py

gives the same result..

thks for your attention

option to search for specific one

Hi is it possible to continuously search for specific imsi?
i saw in the code an empty line for it, is it working?
Thanks.
Im trying to find my phone in the list.

GPS coordinates !!!

@Oros42 Do you think it would be useful for you to display GPS coordinates in a script from opencellid.org ??? And is it difficult to do this ???

Signal power

Hi,

Is it possible to add the signal power in dBM?

Thanks

socket.error: [Errno 98] Address already in use

hi

ubuntu 16.04 + hackrf [Firmware Version: 2017.02.1 (API:1.02)]

In 1st terminal run
sudo QT_X11_NO_MITSHM=1 grgsm_livemon --h

In 2st terminal run:
~/IMSI-catcher$ sudo python simple_IMSI-catcher.py

Nb IMSI ; TMSI-1 ; TMSI-2     ; IMSI   ; country  ; brand      ; operator ; MCC  ; MNC   ; LAC    ; CellId
Traceback (most recent call last):
  File "simple_IMSI-catcher.py", line 595, in <module>
    udpserver(port=options.port, prn=find_imsi)
  File "simple_IMSI-catcher.py", line 544, in udpserver
    sock.bind(server_address)
  File "/usr/lib/python2.7/socket.py", line 228, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 98] Address already in use

why tip " address already in use ",should I change imsi-catcher.py
"udpdata, address = sock.recvfrom(4096) " ?

thanks

IMSI-catcher for OsmocomBB ?

Hello :)
I am happy about your tool and it is working perfect, even if I do not have gr-gsm, but just regular airprobe.
My request would be to write just the same program for osmocombb.
If you have a Motorola phone you can test it.
My idea would be to run osmocoms command "./ccch_scan -a 871 -i 127.0.0.1"
and your tool will collect/extract all the IMSIs from ARFCN 871, in this example.
Are you up for it?

Best regards,
Alex

scan-and-livemon not working

Scan-and-livemon outputs "TypeError: an integer is required"

root@kali:~/IMSI-catcher# python scan-and-livemon
Locating potential GSM base station frequencies (this can take a few minutes).
Found 14 frequences
Traceback (most recent call last):
  File "scan-and-livemon", line 105, in <module>
    main()
  File "scan-and-livemon", line 85, in main
    freqs = select_freqs(list, numreceivers)
  File "scan-and-livemon", line 61, in select_freqs
    if 0 in sorted_list:
TypeError: an integer is required

No output by simple_IMSI-catcher.py

Dear
despite my efforts to find myself alone, a solution, I am compelled to parasitize here.
I'm using two terminals: Terminal 1 to find one frequency (by grgsm-scanner) and after select one of these; I'm using grgsm-livemon to send GSMTAP data format by UDP server. Terminal 2: to read UDP packet of terminal 1 by simpleIMSYCatcher.py .
Here an example:

Terminal 1:

VirtualBox:~$ grgsm_scanner -v -g 40
linux; GNU C++ version 7.3.0; Boost_106501; UHD_003.010.003.000-0-unknown

ARFCN: 980, Freq: 926.2M, CID: 0, LAC: 0, MCC: 0, MNC: 0, Pwr: -58
|---- Configuration: Unknown
|---- Cell ARFCNs:
|---- Neighbour Cells:

ARFCN: 79, Freq: 950.8M, CID: 7690, LAC: 30510, MCC: 208, MNC: 10, Pwr: -60
|---- Configuration: 1 CCCH, not combined
|---- Cell ARFCNs:
|---- Neighbour Cells:

VirtualBox:~$ grgsm_livemon -g 40 -f 926.2M --serverport=4729
Warning: failed to XInitThreads()
linux; GNU C++ version 7.3.0; Boost_106501; UHD_003.010.003.000-0-unknown

gr-osmosdr 0.1.4 (0.1.4) gnuradio 3.7.11
built-in source types: file osmosdr fcd rtl rtl_tcp uhd miri hackrf bladerf rfspace airspy airspyhf soapy redpitaya freesrp
Cannot connect to server socket err = Aucun fichier ou dossier de ce type
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
Detached kernel driver
Found Rafael Micro R820T tuner
Reattached kernel driver
Using device #0 Realtek RTL2838UHIDIR SN: 00000001
Detached kernel driver
Found Rafael Micro R820T tuner
[R82XX] PLL not locked!
Exact sample rate is: 2000000,052982 Hz
[R82XX] PLL not locked!
Allocating 15 zero-copy buffers
15 06 21 00 01 f0 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
25 06 21 00 05 f4 02 d9 01 9e 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
25 06 21 00 05 f4 e8 78 23 03 23 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
25 06 21 00 05 f4 f0 70 2e 13 23 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
31 06 1c 02 f8 02 01 a7 60 06 b9 00 00 80 01 47 2b 2b 2b 2b 2b 2b 2b
01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
15 06 21 00 01 f0 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
31 06 21 00 08 29 80 02 71 61 20 39 92 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
15 06 21 00 01 f0 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
15 06 21 00 01 f0 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
......

    • Terminal 2:
      VirtualBox:~/IMSI-catcher$ sudo ./simple_IMSI-catcher.py
      [sudo] Mot de passe de rolland :
      Nb IMSI ; TMSI-1 ; TMSI-2 ; IMSI ; country ; brand ; operator ; MCC ; MNC ; LAC ; CellId
      Traceback (most recent call last):
      File "./simple_IMSI-catcher.py", line 547, in
      udpserver(port=options.port, prn=find_imsi)
      File "./simple_IMSI-catcher.py", line 496, in udpserver
      sock.bind(server_address)
      File "/usr/lib/python2.7/socket.py", line 228, in meth
      return getattr(self._sock,name)(*args)
      socket.error: [Errno 98] Address already in use
      VirtualBox:~/IMSI-catcher$ sudo ./simple_IMSI-catcher.py -s
      Nb IMSI ; TMSI-1 ; TMSI-2 ; IMSI ; country ; brand ; operator ; MCC ; MNC ; LAC ; CellId

And I Have no output; May be I am wrong somewhere ?
WireShark work well.
Could you help me to find my mistake ?
Philippe,
Best regards

why not

Screenshot from 2019-03-31 13-56-48
Screenshot from 2019-03-31 14-01-04
Screenshot from 2019-03-31 14-01-37
Uploading Screenshot from 2019-03-31 14-01-51.png…

can you tell me how to solve this probiem?
not a conmputer majior
please

TypeError: ouput() takes at most 12 arguments (13 given)

Hi !

I am trying to use simple_IMSI-catcher.py but am facing the following problem. Seems output function is being passed more arguments than defined. But in the code I found output being passed 12 args only.

Pls help. I am using master branch of grgsm using hackrf for receiving.

thanks

merlin@den:~/work/gsm/IMSI-catcher$ sudo python simple_IMSI-catcher.py --sniff
Nb IMSI ; TMSI-1 ; TMSI-2 ; IMSI ; country ; brand ; operator ; MCC ; MNC ; LAC ; CellId
Traceback (most recent call last):
File "simple_IMSI-catcher.py", line 577, in
sniff(iface=options.iface, filter="port {} and not icmp and udp".format(options.port), prn=find_imsi_from_pkg, store=0)
File "/usr/local/lib/python2.7/dist-packages/scapy/sendrecv.py", line 620, in sniff
r = prn(p)
File "simple_IMSI-catcher.py", line 539, in find_imsi_from_pkg
find_imsi(udpdata)
File "simple_IMSI-catcher.py", line 470, in find_imsi
t.register_imsi(gsm.arfcn, imsi1, imsi2, tmsi1, tmsi2, p)
File "simple_IMSI-catcher.py", line 278, in register_imsi
self.pfields(str(n), self.str_tmsi(tmsi1), self.str_tmsi(tmsi2), imsi1, str(self.mcc), str(self.mnc), str(self.lac), str(self.cell), p)
File "simple_IMSI-catcher.py", line 214, in pfields
self.ouput_function(cpt, tmsi1, tmsi2, imsi, imsibrand, imsicountry, imsioperator, mcc, mnc, lac, cell, packet)
TypeError: ouput() takes at most 12 arguments (13 given)

simple_IMSI-catcher look like to work but not scan-and-livemon.

Hi Oros42,

I am french, but I try to write you in english for the other people followings your project.
Compliment for the job you have done, I am facing a strange issue, without apparently errors.

In the First terminale I start:

simple_IMSI-catcher.py look like to work but not scan-and-livemon.

so when I start "scan-and-livemon" th result I have look like to be empty, and stop quickly.

Locating potential GSM base station frequencies (this can take a few minutes).
linux; GNU C++ version 4.9.1; Boost_105500; UHD_003.007.003-0-unknown

I am using it on Raspberry Updated.
I have following all different test to install gr-gsm, the grgsm_scanner produce the same output.

Locating potential GSM base station frequencies (this can take a few minutes).
linux; GNU C++ version 4.9.1; Boost_105500; UHD_003.007.003-0-unknown

My USB DVB-T is configured right, when I do:

kal -s GSM900 ( To scan channel )

Found 1 device(s):
0: Generic RTL2832U OEM

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Exact sample rate is: 270833.002142 Hz
kal: Scanning for GSM-900 base stations.
GSM-900:
chan: 23 (939.6MHz + 24.800kHz) power: 27664.59
chan: 53 (945.6MHz + 25.843kHz) power: 99831.14

After I do:

kal -c 53
Found 1 device(s):
0: Generic RTL2832U OEM

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Exact sample rate is: 270833.002142 Hz
kal: Calculating clock frequency offset.
Using GSM-900 channel 53 (945.6MHz)
average [min, max] (range, stddev)

  • 28.251kHz [24167, 28987] (4821, 1024.137451)
    overruns: 0
    not found: 0
    average absolute error: -29.876 ppm

Where can I have a look for to resolve this issue.

Without errors, it's difficult to me to understand where I get wrong.

Thanks for support,

Regards,

Christian

Run without root privileges?

With the introduction of the gr-gsm change in ptrkrysik/gr-gsm#317 it is possible to set up a non-privileged UDP collector service to gather the GSM data, instead of using wireshark/scapy.

What about rewriting simple_IMSI-catcher.py to listen on the appropriate port? Something like this patch should do it:

diff --git a/simple_IMSI-catcher.py b/simple_IMSI-catcher.py
index 5e6c43e..ea133df 100644
--- a/simple_IMSI-catcher.py
+++ b/simple_IMSI-catcher.py
@@ -63,6 +63,8 @@ Realtek RTL2832U : http://doc.ubuntu-fr.org/rtl2832u and http://doc.ubuntu-fr.or
 from scapy.all import sniff
 import json
 from optparse import OptionParser
+import socket
+import sys
 
 imsis=[] # [IMSI,...]
 tmsis={} # {TMSI:IMSI,...}
@@ -400,6 +402,17 @@ def find_imsi(x):
 				imsi2=p[0x48:][:8]
 				show_imsi(imsi1, imsi2, tmsi1, tmsi2, p)
 
+def udpserver(port, prn):
+        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+        server_address = ('localhost', port)
+        #print >>sys.stderr, 'starting up on %s port %s' % server_address
+        sock.bind(server_address)
+        print >>sys.stderr, '\nwaiting to receive message'
+        while True:
+                data, address = sock.recvfrom(4096)
+                # Pad packages as a workaround for find_imsi()
+                # expecting raw packages, not just the UDP data.
+                prn('x' * (81 - 39) + data)
 
 if __name__ == '__main__':
 	parser = OptionParser(usage="%prog: [options]")
@@ -407,6 +420,7 @@ if __name__ == '__main__':
 	parser.add_option("-i", "--iface", dest="iface", default="lo", help="Interface (default : lo)")
 	parser.add_option("-m", "--imsi", dest="imsi", default="", type="string", help='IMSI to track (default : None, Example: 123456789101112 or "123 45 6789101112")')
 	parser.add_option("-p", "--port", dest="port", default="4729", type="int", help="Port (default : 4729)")
+	parser.add_option("-s", "--sniff", action="store_true", dest="sniff", help="sniff on interface instead of listening on port")
 	(options, args) = parser.parse_args()
 
 	show_all_tmsi=options.show_all_tmsi
@@ -435,4 +449,7 @@ if __name__ == '__main__':
 		mcc_codes = json.load(file)
 
 	print("{:7s} ; {:10s} ; {:10s} ; {:17s} ; {:12s} ; {:10s} ; {:21s} ; {:5s} ; {:4s} ; {:5s} ; {:6s}".format("Nb IMSI", "TMSI-1", "TMSI-2", "IMSI", "country", "brand", "operator", "MCC", "MNC", "LAC", "CellId"))
-	sniff(iface=options.iface, filter="port {} and not icmp and udp".format(options.port), prn=find_imsi, store=0)
+	if options.sniff:
+		sniff(iface=options.iface, filter="port {} and not icmp and udp".format(options.port), prn=find_imsi, store=0)
+	else:
+		udpserver(port=options.port, prn=find_imsi)

Segmentation fault

Hi Oros42

I am new to telephony and wanted to try your programs.
But, I have difficulties to run scan-and-livemon, gr-gsm and grgsm_livemon: I get segmentation fault each time.I am using RTL2832 from Nooelec.

And when I run python simple_imsi_catcher.py, even after 20 minutes I get nothing.
Should I buy a bigger antenna? Any recommendation about antenna ? Or what am I doing wrong?

And wireshark is empty too :(
wireshark -k -Y '!icmp && gsmtap' -i lo

I have Kali linux, and I blacklisted the driver like described in Kubon forum.
rtl_test works fine.
Here is the procedure I followed for making my RTL working:

Edit /etc/modprobe.d/raspi-blacklist.conf file and add the following lines
blacklist dvb_usb_rtl28xxu
blacklist dvb_usb_v2
blacklist rtl_2830
blacklist rtl_2832
blacklist r820t

sudo apt-get install git build-essential cmake libusb-1.0-0-dev
git clone git://git.osmocom.org/rtl-sdr.git
cd rtl-sdr
mkdir build
cd build
cmake ../ -DDETACH_KERNEL_DRIVER=ON -DINSTALL_UDEV_RULES=ON
make
sudo make install
sudo ldconfig

Here are outputs I have, in case it is useful for you, to help me solve the issue:
grgsm_livemon gr-osmosdr 0.1.4 (0.1.4) gnuradio 3.7.13.4 built-in source types: file osmosdr fcd rtl rtl_tcp uhd miri hackrf bladerf rfspace airspy airspyhf soapy redpitaya freesrp [INFO] [UHD] linux; GNU C++ version 8.2.0; Boost_106700; UHD_3.13.1.0-3 [INFO] Using format CF32. Segmentation fault

./scan-and-livemon Locating potential GSM base station frequencies (this can take a few minutes). Segmentation fault

grgsm_scanner Segmentation fault

python simple_IMSI-catcher.py --sniff Nb IMSI ; TMSI-1 ; TMSI-2 ; IMSI ; country ; brand ; operator ; MCC ; MNC ; LAC ; CellId

I tried with and without sniff, but the same.
I hope that you can help me to solve this.

By the way, is there a way to obtain imei too? I would like to just scan for a device/number in particular (mine), would it be possible? Or should I query from results (when I will get them)?

Thanks a lot in advance for your help and really congrats for your program!

IMSI Periodic

Hi, I only see IMSI once when i power up mobile in front of RTL-SDR dongle.
Why IMSI not shown periodically?.
Does mobile send it periodically?

Understanding how it works

Hello,

I made some reading, but I still not sure about some fundamentals:
I would please like to ask, please:
Does rtl-sdr device also transmit (for this catcher to work), or is it used only as a receiving ?
Can I use any rtl-sdr device for this project (I am not sure all rtl-sdr in market capable of transmit) ?

Thank you very much!

pybombs installation

"hi, I am new to Pybombs and im trying to make an msi catcher as a subsysytem for a bigger project on Ubuntu, however I'm running into problems installing Pybombs. I'm still learning python and I had problem installing python as well the I'm having problems with the recipes and I tried and alternative route to install it which as the one on your website and it seems to be the soapy files and i get this out put please help or point me in the right direction"

k9@k9-HP-Notebook:~$ sudo pybombs install gr-gsm
PyBOMBS - INFO - PyBOMBS Version 2.3.1
PyBOMBS.Packager.apt - INFO - Install python-apt to speed up apt processing.
PyBOMBS.install_manager - INFO - Phase 1: Creating install tree and installing binary packages:
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
The directory '/home/k9/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Install tree:
|
\- gr-gsm
   |
   \- gr-osmosdr
      |
      +- airspy
      |
      +- hackrf
      |
      \- soapysdr
PyBOMBS.install_manager - INFO - Phase 2: Recursively installing source packages to prefix:
PyBOMBS.install_manager - INFO - Installing package: soapysdr
PyBOMBS.Packager.apt - INFO - Install python-apt to speed up apt processing.
PyBOMBS.Packager.source - WARNING - Build dir already exists: /usr/local/src/soapysdr/build
Configuring: (100%) [=========================================================]
PyBOMBS.Packager.source - WARNING - Configuration failed. Re-trying with higher verbosity.
-- 
-- #############################################
-- ## Begin configuration for Python support...
-- #############################################
-- Enabling optional Python bindings if possible...
-- SWIG_FOUND: TRUE - 2.0.12
-- PYTHONINTERP_FOUND: TRUE - 2.7.12
-- PYTHON_EXECUTABLE: /usr/bin/python
-- PYTHON_INSTALL_DIR: ${prefix}/lib/python2.7/dist-packages
-- PYTHONLIBS_FOUND: TRUE - 2.7.12
-- PYTHON_INCLUDE_DIRS: /usr/include/python2.7
-- PYTHON_LIBRARIES: /usr/lib/x86_64-linux-gnu/libpython2.7.so
-- CMAKE_SWIG_FLAGS=-c++;-threads
-- 
-- #############################################
-- ## Begin configuration for Python3 support...
-- #############################################
-- Enabling optional Python3 bindings if possible...
-- SWIG_FOUND: TRUE - 2.0.12
-- Could NOT find Python3InterpDbg (missing:  PYTHON3_DBG_EXECUTABLE) 
-- PYTHON3INTERP_FOUND: TRUE
-- PYTHON3_EXECUTABLE: /usr/local/bin/python3
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/local/lib/python3.4/distutils/sysconfig.py", line 13, in <module>
    import re
  File "/usr/local/lib/python3.4/re.py", line 336, in <module>
    import copyreg
  File "/usr/local/lib/python2.7/dist-packages/copyreg/__init__.py", line 7, in <module>
    raise ImportError('This package should not be accessible on Python 3. '
ImportError: This package should not be accessible on Python 3. Either you are trying to run from the python-future src folder or your installation of python-future is corrupted.
-- PYTHON3_INSTALL_DIR: ${prefix}/
-- PYTHON3LIBS_FOUND: TRUE
-- PYTHON3_INCLUDE_DIRS: /usr/local/include/python3.4m
-- PYTHON3_LIBRARIES: /usr/local/lib/libpython3.4m.a
-- CMAKE_SWIG_FLAGS=-c++;-threads
CMake Error at python3/CMakeLists.txt:87 (install):
  install TARGETS given no LIBRARY DESTINATION for module target
  "_SoapySDR3".


CMake Error at python3/CMakeLists.txt:92 (install):
  install FILES given no DESTINATION!


-- 
-- ######################################################
-- ## SoapySDR enabled features
-- ######################################################
-- 
 * Library , runtime library v0.6.1-g285e72aa
 * Tests , library unit tests
 * Docs , doxygen documentation
 * Python , python bindings v2.7.12
 * Python3 , python3 bindings

-- ######################################################
-- ## SoapySDR disabled features
-- ######################################################
-- 

-- SoapySDR version: v0.6.1-g285e72aa
-- ABI/so version: v0.6
-- Install prefix: /usr/local
-- Configuring incomplete, errors occurred!
See also "/usr/local/src/soapysdr/build/CMakeFiles/CMakeOutput.log".
See also "/usr/local/src/soapysdr/build/CMakeFiles/CMakeError.log".
PyBOMBS.Packager.source - ERROR - Configuration failed after running at least twice.
PyBOMBS.Packager.source - ERROR - Problem occurred while building package soapysdr:
Configuration failed
PyBOMBS.install_manager - ERROR - Error installing package soapysdr. Aborting.

Do I need to buy a tuner too?

Hi,

Great software you have here!!
I want to use this software to find 850mhz cell numbers.
Do I need to buy a tuner to use with RTL2832U or its just plug this hardware and run your software on ubuntu?

This dongle based on RTL2832U is good to run IMSI Captcher?
https://goo.gl/KLcP6J

Very thanks in advance

Marcelo

No funciona simple_IMSI-catcher.py

Hola, hace unos días instalé #Ubuntu 16.04 LTS y con el todas las dependencias y herramientas que se necesitan para poder utilizar GNURadio junto con un stick de radio RTL-SDR.
Al momento de utilizar gr-gsm livemon me arroja un error en simple_IMSI-catcher.py:

root@Scott:/home/scott/IMSI-catcher# python simple_IMSI-catcher.py
Nb IMSI ; TMSI-1     ; TMSI-2     ; IMSI              ; country      ; brand      ; operator              ; MCC  ; MNC   ; LAC    ; CellId
Traceback (most recent call last):
  File "simple_IMSI-catcher.py", line 582, in <module>
    udpserver(port=options.port, prn=find_imsi)
  File "simple_IMSI-catcher.py", line 531, in udpserver
    sock.bind(server_address)
  File "/usr/lib/python2.7/socket.py", line 228, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 98] Address already in use


Y sucesivamente alrevés si ejecuto primero simple_IMSI-catcher.py y después gr-gsm livemon me arroja lo siguiente:

Executing: /usr/bin/python2 -u /home/scott/pybombs/src/gr-gsm/apps/grgsm_livemon.py
gr-osmosdr v0.1.4-98-gc653754d (0.1.5git) gnuradio 3.7.12git-295-ga0adcd33
built-in source types: file osmosdr fcd rtl rtl_tcp uhd hackrf bladerf rfspace airspy soapy redpitaya 
�[32;1m[INFO] [UHDlinux; GNU C++ version 5.4.0 20160609; Boost_105800; UHD_3.11.0.git-191-g1cd96dde] �[39;0m
Using device #0 Realtek RTL2838UHIDIR SN: 00000001
No supported tuner found
Enabled direct sampling mode, input 1
Exact sample rate is: 2000000.052982 Hz
Traceback (most recent call last):
  File "/home/scott/pybombs/src/gr-gsm/apps/grgsm_livemon.py", line 357, in <module>
    main()
  File "/home/scott/pybombs/src/gr-gsm/apps/grgsm_livemon.py", line 345, in main
    tb = top_block_cls(args=options.args, collector=options.collector, collectorport=options.collectorport, fc=options.fc, gain=options.gain, osr=options.osr, ppm=options.ppm, samp_rate=options.samp_rate, serverport=options.serverport, shiftoff=options.shiftoff)
  File "/home/scott/pybombs/src/gr-gsm/apps/grgsm_livemon.py", line 176, in __init__
    self.blocks_socket_pdu_0_0 = blocks.socket_pdu("UDP_SERVER", '127.0.0.1', serverport, 10000, False)
  File "/usr/local/lib/python2.7/dist-packages/gnuradio/blocks/blocks_swig5.py", line 419, in make
    return _blocks_swig5.socket_pdu_make(*args, **kwargs)
RuntimeError: bind: La dirección ya se está usando
>>> Done

Pero se ejecuta correctamente simple IMSI catcher:

root@Scott:/home/scott/IMSI-catcher# python simple_IMSI-catcher.py
Nb IMSI ; TMSI-1     ; TMSI-2     ; IMSI              ; country      ; brand      ; operator              ; MCC  ; MNC   ; LAC    ; CellId

He instalado Kali linux, Ubuntu GNURADIO enviroment live y ahora estoy usando Ubuntu y no me funciona correctamente, estoy llegando a pensar que es mi stick de radio el que no funciona porque ya he instalado correctamente todo y he puesto los blacklist del RTL como corresponde.
El stick de radio es un RTL2832U + FC0012 Mini DVB-T + DAB + + FM USB Digital TV Dongle-Negro, lo compré aquí : http://www.dx.com/es/p/rtl2832u-r820t-mini-dvb-t-dab-fm-usb-digital-tv-dongle-black-170541?tc=MXN&gclid=EAIaIQobChMIstLBwLXv1gIVQ0AbCh0sSwHGEAYYAiABEgIxifD_BwE#.WeGllHBrw8o

Agradecería mucho que me orientaran sobre éste problema, sin más un saludo.

imsi catcher.py wont run simultaneously with scan-and-livemon

I am unable to get IMSI-catcher.py to run simultaneously with scan-and-livemon.

I am on ubuntu and I have tried both installation methods you recommend.

"grgsm_livemon" works and shows output. I am using RTL-SDR

sudo grgsm_livemon
sudo: unable to resolve host dog1853
gr-osmosdr v0.1.4-98-gc653754d (0.1.5git) gnuradio 3.7.12git-295-ga0adcd33
built-in source types: file osmosdr fcd rtl rtl_tcp uhd hackrf bladerf rfspace airspy soapy redpitaya
[INFO] [UHDlinux; GNU C++ version 5.4.0 20160609; Boost_105800; UHD_3.11.0.git-740-g3a58a5f0]
Using device #0 Realtek RTL2838UHIDIR SN: 00000001
Found Rafael Micro R820T tuner
[R82XX] PLL not locked!
Exact sample rate is: 2000000.052982 Hz
[R82XX] PLL not locked!

`sudo python scan-and-livemon
[sudo] password for dog: 
Locating potential GSM base station frequencies (this can take a few minutes).
Traceback (most recent call last):
  File "scan-and-livemon", line 101, in <module>
    main()
  File "scan-and-livemon", line 78, in main
    list = find_gsm_bases()
  File "scan-and-livemon", line 25, in find_gsm_bases
    (options, args) = scanner.argument_parser().parse_args()
AttributeError: 'module' object has no attribute 'argument_parser'
``sudo python simple_IMSI-catcher.py
sudo: unable to resolve host dog1853
[sudo] password for dog: 
Nb IMSI ; TMSI-1     ; TMSI-2     ; IMSI              ; country      ; brand      ; operator              ; MCC  ; MNC   ; LAC    ; CellId

Why I can't find IMSI number for my own phone?

Hi,

I was using this project to find some IMSI numbers with USRP N210 on the kali , and I really get a lot ,but I can't find my own imsi number. I made my phone work on the GSM and tried to send sms or make some calls ,but I still can't find it .

Can you give me explanation of my mistakes?
Thanks!

Error on python scan-and-livemon

Hi guys i have a problem with the python scan-and-livemon when i send the command i receive the next messege 3 minutes or 4 next i send the command :

python scan-and-livemon
Locating potential GSM base station frequencies (this can take a few minutes).
Found 0 frequences
Traceback (most recent call last):
File "scan-and-livemon", line 103, in
main()
File "scan-and-livemon", line 83, in main
freqs = select_freqs(list, numreceivers)
File "scan-and-livemon", line 61, in select_freqs
s = sorted_list[0]
IndexError: list index out of range

IMSI not showing up

Hi,

What could be the reason why my own IMSI is not showing up for every tests I did ?
Thanks in advance

IMSI Catcher not showing imsi etc

Dear Community,
Can anybody please help me.
Install all software to run my program.
But it could not detect imsi and phone information.
Hope u know the problem
I could sniff only one thing.
If u help me personally I would also pay for help if it works great in the end like an professional one.
kindly
8ee8fcef3bc955045e9bf695f3e11b58

Not able to detect GSM packets in Ubuntu 14.04

I have installed all the necessary libraries. I am not getting any IMSI number using the code simple_IMSI-catcher.py. Running the rtl_test gives -

Found 1 device(s):
  0:  Realtek, RTL2838UHIDIR, SN: 00000001

Using device 0: Generic RTL2832U OEM
No supported tuner found
Enabled direct sampling mode, input 1
Supported gain values (1): 0.0 
Sampling at 2048000 S/s.

Info: This tool will continuously read from the device, and report if
samples get lost. If you observe no further output, everything is fine.

Reading samples in async mode...

Running grgsm_scanner gives,
linux; GNU C++ version 4.8.2; Boost_105400; UHD_003.005.005-0-unknown
and nothing else.

What can be done further?

About how it works TX RX

Hi,

Does this IMSI catcher works just receiving celular data from DVB-T? I mean DVB-T does not have to transmit data to cell phone in order to this cell phone register on the IMSI catcher as cell phones normaly does with regular cell towers?

???

Hello ... Is it possible to search the first 5 characters (python simple IMSI-catcher.by -m 25007**********) ???

AttributeError: 'module' object has no attribute 'QWidget' error

im on ubuntu 18.04
installed all the dependenci

ImportError: No module named PyQt4

to solve this , i had to install python-qt4 ( sudo apt install python-qt4)

but when u do install it.
u get another error.

Warning: failed to XInitThreads()
Traceback (most recent call last):
File "/usr/bin/grgsm_livemon", line 45, in
from gnuradio import qtgui
File "/usr/lib/python2.7/dist-packages/gnuradio/qtgui/init.py", line 37, in
from range import Range, RangeWidget
File "/usr/lib/python2.7/dist-packages/gnuradio/qtgui/range.py", line 67, in
class RangeWidget(QtWidgets.QWidget):
AttributeError: 'module' object has no attribute 'QWidget'

any idea

NOT AN ISSUE: SUGGESTION

Sir will it be nice to suggest me how to combine the info en IMSI with the find_cell so I can display the MCC/MNC/LCC info with the IMSI located, can you please ? Thanks in advance

Its Alivveeee!!!!

Thanks Oros42, FFY00 and other guys for all the help.

My IMSI Catcher is on line and imsi numbers are now popping up over here.

Is there a way to capture the cell numbers of those imsi codes?

Tabs or spaces? (python 3 related)

Hi. Python 3 is more picky than python 2 when it comes to indenting with space or tabs. And the code currently only work with python 2, partly because it mixes tabs and spaces. Do you have any opinion if tabs or spaces should be used? Personally I prefer spaces, for various reasons, but my preference is not very strong.

Can we pick tabs or spaces, document the preference and convert the code to use it? Switching to python 3 would make several charset encoding issues easier to solve, and I believe it is a good long term goal.

runtime error

X Error: BadDrawable (invalid Pixmap or Window parameter) 9
Major opcode: 62 (X_CopyArea)
Resource id: 0x2200012

I get this error when running grgsm_livemon and don't know how to fix it.

No o/p in hackrf

Hi, I am using hackrf sdr and upon firing simple_imsi_catcher.py - it gives nothing apart from the first line saying cell_id, country etc...

there is only wrong imsi numbers

  • When I use the condition: p[71:][:2]=='\x08\x29' and p[62:][:2]=='\x08\x29', I have get no any imsi numbers output, and I think I have set the correct frequency.
  • When I use a condition: p[71:][:2]=='\x08\x49' and p[62:][:2]=='\x08\x49', there are some numbers output on the screen, but they all do not belong to any devices I want to track. So what can I do with this catcher?

find_cell_id_.py is not working

Hi there @Oros42,

Your utility is so great! I've tried to run the extra tool 'find_cell_id.py', but I'm getting this error:

ubuntu@ubuntu:~/IMSI-catcher$ sudo python find_cell_id.py 
WARNING: No route found for IPv6 destination :: (no default route?)
MCC   ; MNC  ; LAC   ; CellId ; Country ; Brand ; Operator
Traceback (most recent call last):
  File "find_cell_id.py", line 88, in <module>
    sniff(iface=options.iface, filter="port {} and not icmp and udp".format(options.port), prn=find_cell, store=0)
  File "/usr/lib/python2.7/dist-packages/scapy/sendrecv.py", line 586, in sniff
    r = prn(p)
  File "find_cell_id.py", line 75, in find_cell
    operator=mcc_codes[mcc]['MNC'][mnc][1]
KeyError: '05'

Any idea? Thanks!

Need to pass options to gsgsm_scanner

On my Raspberry PI 3B+ (Stretch) the option --args rtl must be passed to grgsm_scanner else it crashes.

I'm trying to see where that option can be set for scan-and-livemon

i have got 'address already in use' error here

there is error message:
:~/hackrf/IMSI-catcher$ ./simple_IMSI-catcher.py Nb IMSI ; TMSI-1 ; TMSI-2 ; IMSI ; country ; brand ; operator ; MCC ; MNC ; LAC ; CellId
Traceback (most recent call last):
File "./simple_IMSI-catcher.py", line 547, in
udpserver(port=options.port, prn=find_imsi)
File "./simple_IMSI-catcher.py", line 496, in udpserver
sock.bind(server_address)
File "/usr/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 98] Address already in use

==================================================================
when i run simple_IMSI-catcher.py, i got this error message. can you help me ?please

Spyserver

How do I use the IMSI catcher with a SpyServer over the internet? I have one because it's accessible anywhere with sdr#. If I can use sdr# with it I can also use IMSI catcher, i just have to tell them how to connect. How do I do that?

Lots of IMSI-numbers from Bermuda and Guam, can this be correct?

Hi,

this is not an issue, but a question. The scripts runs fine and after ~24 hours I already saw 35000+ distinct IMSI numbers. What puzzles me is the high number of numbers from Bermuda and Guam. The other numbers seem to be plausible, but I doubt that there where 1060 SIM-cards from the Bermudas around here at my place in Germany. Can it be, that some providers simply use these rather exotic countries like Bermuda and Guam, albeit the SIM-cards are for the German market?

sqlite> select count(distinct imsi) as count, imsicountry from observations group by imsicountry order by count desc limit 66;
count       imsicountry
----------  -----------
33067       Germany    
1060        Bermuda    
751         Poland     
464         Guam (Unite
271         Romania    
244         China      
164         Turkey     
150         Spain      
137         France     
116         Austria    
91          Guernsey (U
90          Italy      
89          Czech Repub
84          Bulgaria   
54          India      
53          Hungary    
48          Russian Fed
46          Croatia    
45          Netherlands
44          Ukraine    
40          Slovakia   
32          Serbia     
31          Egypt      
31          United Arab
29          Belgium    
27          Taiwan     
25          Greece     
24          Australia  
24          Switzerland
22          Lithuania  
21          Latvia     
21          Sweden     
20          South Korea

socket.error: [Errno 98] Address already in use

Hi!

I'm trying to get the script running but after getting gr-gsm running, when starting the IMSI-catcher I get the following error:

root@kali:/IMSI-catcher# python simple_IMSI-catcher.py
Saving to SQLite database in imsi-catcher.sqlite
Nb IMSI ; TMSI-1 ; TMSI-2 ; IMSI ; country ; brand ; operator ; MCC ; MNC ; LAC ; CellId
Traceback (most recent call last):
File "simple_IMSI-catcher.py", line 534, in
udpserver(port=options.port, prn=find_imsi)
File "simple_IMSI-catcher.py", line 487, in udpserver
sock.bind(server_address)
File "/usr/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 98] Address already in use
root@kali:
/IMSI-catcher#

Does any one have an idea for me or know of this issue? Ive scoured muliple forums but can't seem to find something that works.

Thanks so much in advance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.