Python Script to Map Cell Tower Locations from an Android Device Report in Cellebrite

Recently Ed Michael showed me that Cellebrite now parses cell tower locations from several models of Android phones. He said that this information has been useful a few times but manually finding and mapping the cell tower locations by hand has been a pain in the butt. I figured that it should be easy enough to automate and Anaximander was born.

Anaximander consists of two python 2.7 scripts. One you only need to run once to dump the cell tower location information into a SQLite database and the second script you run each time to generate a Google Earth KML file with all of the cell tower locations on it. As an added bonus, the KML file also respects the timestamps in the file so modern versions of Google Earth will have a time slider bar across the top to let you create animated movies or only view results between a specific start and end time.

Step one is to acquire the cell tower location. For this we go to and sign up for a free API. Once we get the API key (instantly) we can download the latest repository of cell phone towers.


Currently the tower data is around 2.2 GB and contained in a CSV file. Once that file downloads you can unzip it to a directory and run the script from Anaximander. The short and simple script creates a SQLite database named “cellTowers.sqlite” and inserts all of the records into that database. The process should take 3-4 minutes and the resulting database will be around 2.6 GB.

Once the database is populated, the next time you dump an Android device with Cellebrite and it extracts the cell towers from the phone, you’ll be ready to generate a map.

From The “Cell Towers” section of your Cellebrite results, export the results in “XML”. Place that xml file and the file in the same directory as your cellTowers.sqlite database and then run –t <YourCellebriteExport.xml> . The script will start parsing through the XML file to extract cell towers and query the SQLite database for the location of the tower. Due to the size of the database the queries can take a second or two each so the script can take a while to run if the report contains a large number of towers.


Ed was kind enough to provide two reports from different Android devices and both parsed with no issues. Once the script is finished it will let you know how many records it parsed and that it generated a KML file.


This is what the end results look like.


The script can be downloaded from:

This is the first version and there are several improvements to make but I wanted to get a working script out to the community to alleviate the need for examiners to map the towers one at a time. Special thanks again to Ed Michael for the idea for this (and one other) script as well as for providing test data to validate the script.

13 thoughts on “Python Script to Map Cell Tower Locations from an Android Device Report in Cellebrite

    • I don’t always have access to PA depending on where I’m at and what I’m working on but figuring out how to take some of my scripts and convert them to run directly from PA is on my todo list.

  1. Pingback: Week 35 – 2016 – This Week In 4n6

  2. Pingback: More Updates –

  3. I have been trying to use this script and I keep getting the below error. My python is not strong enough to figure out what is going on.. any ideas?

    Thanks for doing this!

    Error Message:
    Insps-Mac-Pro-2:TowerAnalysis InspBroad$ python -t Report-CellTowers.xml
    Traceback (most recent call last):
    File “”, line 28, in
    tree = ET.parse(tgtFile)
    File “/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/”, line 1182, in parse
    tree.parse(source, parser)
    File “/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/”, line 656, in parse
    File “/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/”, line 1642, in feed
    File “/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/”, line 1506, in _raiseerror
    raise err
    xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 244986, column 93
    Insps-Mac-Pro-2:TowerAnalysis InspBroad$

    • hmm, that might be a problem with the xml file from Cellebrite for some reason. The first thing I would do is check out the xml output in notepad++ to see if there is anything funky looking. I haven’t tried it on a mac but there shouldn’t be an issue with that as it uses core libraries.

  4. C:\Anaximander> -t Report.xml
    File “C:\Anaximander\”, line 19
    print parser.usage
    SyntaxError: Missing parentheses in call to ‘print’

    C:\Anaximander> -t Report.xml
    File “C:\Anaximander\”, line 19
    print parser.usage
    print parser.usage error

      • U:\ProgsMobileForensik\UFED\Sonstiges\map Celltower IDs\Anaximander-master\Anaximander-master> -t Bericht.xml
        [+] Inserting the following record (MCC: GSM, MNC: 262, LAC: 3, CID: 40539)
        [+] Cont: (Timestamp: None, Pack Type: 2017-02-02T13:16:52.000+01:00, Cell Tower Type: Google)
        [+] Inserting the following record (MCC: GSM, MNC: 262, LAC: 3, CID: 40539)
        [+] Cont: (Timestamp: None, Pack Type: 2017-02-02T13:16:50.000+01:00, Cell Tower Type: Google)
        [+] Inserting the following record (MCC: GSM, MNC: 262, LAC: 3, CID: 40539)
        Traceback (most recent call last):
        File “U:\ProgsMobileForensik\UFED\Sonstiges\map Celltower IDs\Anaximander-master\Anaximander-master\”, line 48, in
        print “[+] Cont: (Timestamp: %s, Pack Type: %s, Cell Tower Type: %s)” % (varTimestamp, varPackageType, varCellTowerType)
        File “C:\Python27\lib\encodings\”, line 12, in encode
        return codecs.charmap_encode(input,errors,encoding_map)
        UnicodeEncodeError: ‘charmap’ codec can’t encode character u’\u2013′ in position 92: character maps to

        U:\ProgsMobileForensik\UFED\Sonstiges\map Celltower IDs\Anaximander-master\Anaximander-master>

  5. Hi Matt,
    have you tried it with Cellebrite 6.0?
    Ive been trying to parse it but I get the wrong
    +] Inserting the following record (MCC: Gmail, MNC: None, LAC: None, CID:
    I guess the exported XML from 6.0 has a different format.
    Ive been editing the whole root[6][0][x][4][0].text schema but cant compare with the previous versions.

    • Found the problem…
      in Cellebrite 6 the XML will be exported in one single tag(child):

      so when calling eg. varCellTowerType = root[6][0][x][5][0].text the whole tag will be attributed to varCellTowerType .
      I will try to fiy it by breaking the tag down.

      • Just to sum up:
        Seems that one can export xml in other formats according to Cellebrite.
        When Exporting, I did choose the Mobile telephony Tab (go to) so that each one of the fields had one unique value in the Tag.
        This way the xml export works right.

  6. When I run the script, I’m getting the following error. I exported the xml from Cellebrite PA

    C:\Forensics\Anaximander> -t LGLS775_Stylo_2_170314_152011.xml
    Traceback (most recent call last):
    File “C:\Forensics\Anaximander\”, line 31, in
    for child in root[6][0]:
    File “C:\Python27\lib\xml\etree\”, line 266, in __getitem__
    return self._children[index]
    IndexError: list index out of range

Leave a Reply

Your email address will not be published. Required fields are marked *