Jump to content

[WIP] Python wigleAgent


dustbyter
 Share

Recommended Posts

Hi All,

I've finally had some time to pick up some development for the pineapple again. Starting working on a Wigle agent that will be set up as a command line infusion/module which the rest of the modules can use also.

Right now, I have it able to search for a location based on a mac address, or to pull back some information about all networks that are found when searching by an SSID.

Looking for ideas on what else you would like to see implemented.

If your interested in trying it out, I have started to run it on my MKV. When developing it on my PC, the results are returned pretty quickly, on the MKV, it takes some time. Not sure where the bottleneck is at this point, but will work on it in the future. Have not tried it on a NANO, as i don't own one yet.

You will need to install some packages on the MKV to get this to work correctly. I don't have that list handy right now, but try to run the script and python will tell you what libraries it needs installed.

Looking for some feedback. Thanks!

Note:

Below is the code for the three files you will need to create. Place them in the same directory. Location on the pineapple doesn't matter.

To execute the script, the command line is (with sample output):

Example run (search by ssid):

python testWigleAgent.py -u <username> -p <password> -s <SSID> to search for info per SSID

==============================
[*] WIGLE: This user was validated
[*] WIGLE: Lat / Long and SSID have been retrived
BSSID: 00:13:10:F8:9B:70
ESSID: NavyPier
WEP: Y
Channel: 6
Latitude: 41.87978745
Longitude: -87.62429047

Example run (search by macid):

python testWigleAgent.py -u <username> -p <password> -m <MAC> to get the location for a specific BSSID

[*] WIGLE: This user was validated
[*] WIGLE: Lat / Long and SSID have been retrived
==============================
SSID: NavyPier
Latitude: 41.88973236
Longitude: -87.61649323

wigle_query.py

#!/usr/bin/env python
from uuid import getnode
#from Modules.Common import *
import sys
import re
import requests
import json
import helpers

#Inspired and stolen from Jamie Bull (author).. at http://code.activestate.com/recipes/578637-wigle-wifi-geolocation/


class WigleAgent():
      #These are the options we will set
    def __init__(self, username, password):
        self.agent(username, password)
        self.mac_address()
        # required options
        self.description = "simple WIGLE query"
        self.language = "python"

        # options we require user interaction for- format is {Option : [Value, Description]]}
        self.required_options = {"wigle_user" : ["offtest", "Set WIGLE User-Name"],
                                 "wigle_pass" : ["83128312", "Set WIGLE Password"],
                                 "mac" : ["00:22:55:DF:C8:01", "Set MAC Address"]}    

    def get_lat_lng_by_mac(self, mac_address):
        #Start with Credintial check
        try:
            self.response = send_user_check()
            response = self.check_cred_login()
            if response == 'false':
                print "[*] Unable to validate this user..."
        except:
            #Use this two let user know we had a true login..
            print helpers.color('[*] WIGLE: This user was validated', bold=False)
            pass
        
        
        if mac_address == None:
            mac_address = self.mac_address
        if '-' in mac_address:
           mac_address = mac_address.replace('-', ':')
               
        try:
            self.query_response = self.send_query_location_by_mac(mac_address)
            
            #Need to use Try statment since the "message" Key isnt always prsent when conducting query
            try:
                message = self.check_query_limit()
                if message == "too many queries":
                    print "[*]" + message
            except:
                #Use pass since we dont have an error...
                pass
            response = self.parse_response_mac()
        except IndexError:
            response = 'BSSID (MAC) location not known'
            return response
        print helpers.color('[*] WIGLE: Lat / Long and SSID have been retrived', bold=False)
        return response
      
    def get_lat_lng_by_ssid(self, ssid):
        #Start with Credintial check
        try:
            self.response = send_user_check()
            response = self.check_cred_login()
            if response == 'false':
                print "[*] Unable to validate this user..."
        except:
            #Use this two let user know we had a true login..
            print helpers.color('[*] WIGLE: This user was validated', bold=False)
            pass
               
        try:
            self.query_response = self.send_query_by_SSID(ssid)
            
            #Need to use Try statment since the "message" Key isnt always prsent when conducting query
            try:
                message = self.check_query_limit()
                if message == "too many queries":
                    print "[*]" + message
            except:
                #Use pass since we dont have an error...
                pass
            response = self.parse_response_search()
        except IndexError:
            response = 'ESSID (ESSID) location not known'
            return response
        print helpers.color('[*] WIGLE: Lat / Long and SSID have been retrived', bold=False)
        return response
  
    def agent(self, username, password):
        self.agent = requests.Session()
        self.agent.post('https://wigle.net/api/v1/jsonLogin',
                   data={'credential_0': username,
                         'credential_1': password,
                         'destination': '/https://wigle.net/'})
        
    def mac_address(self):
        mac = hex(getnode())
        mac_bytes = [mac[x:x+2] for x in xrange(0, len(mac), 2)]
        self.mac_address = ':'.join(mac_bytes[1:6])    
    
    def send_query_by_SSID(self, ssid):
        response = self.agent.post(url='https://wigle.net/api/v1/jsonSearch', data={'ssid': ssid,'Query': 'Query'})
        #Check for and handle JSON Errors, due to blank returns
        try: 
            #print "====>>>>"
            #print json.dumps( response.json(), indent=3 )
            #print "<<<<===="
            
            #return response.json()
            return response
        except ValueError:  # includes simplejson.decoder.JSONDecodeError
            print helpers.color('[*] WIGLE: Decoding JSON has failed', bold=False, warning=True)
            print helpers.color('[!] Exiting...', bold=True, warning=True)
            sys.exit()
            
    def send_query_location_by_mac(self, mac_address):
        response = self.agent.post(url='https://wigle.net/api/v1/jsonLocation', data={'netid': mac_address,'Query2': 'Query'})
        #Check for and handle JSON Errors, due to blank returns
        try: 
            return response.json()
        except ValueError:  # includes simplejson.decoder.JSONDecodeError
            print helpers.color('[*] WIGLE: Decoding JSON has failed', bold=False, warning=True)
            print helpers.color('[!] Exiting...', bold=True, warning=True)
            sys.exit()
    
    def send_user_check(self):
        response = self.agent.post()
        return response.json()
    
    # this method does not process the response. it returns the object to the caller
    def parse_response_search(self):
        #print json.dumps( self.query_response.json(), indent=3 )
        return self.query_response
    
    def parse_response_mac(self):
        #print "=================================================="
        #print self.query_response
        #print "=================================================="
        
        lat = self.get_lat()
        lng = self.get_lng()
        bssid = self.get_ssid()
        string = str(self.query_response)
        return {'lat':lat,'lng':lng, 'bssid':bssid, 'description':string}

    def get_lat(self):
        resp_lat = self.query_response['result'][0]['trilat']
        return float(resp_lat)
    
    def get_lng(self):
        resp_lng = self.query_response['result'][0]['trilong']
        return float(resp_lng)
    
    #Request the SSID name of the WIFI point
    def get_ssid(self):
        resp_ssid = self.query_response['result'][0]['ssid']
        return str(resp_ssid)
    
    #Check to see if we reached our limit of 100 querys
    def check_query_limit(self):
        resp_message = self.query_response['message']
        return str(resp_message)
    
    #Check User loign creds
    def check_cred_login(self):
        resp_message = self.query_response['success']
        return str(resp_message)

testWigleAgent.py

#!/usr/bin/env python
import os
import optparse
import urllib
import requests.packages.urllib3
import re
import urlparse
import wigle_query
import json

wa = None

def getLocationByMacID(macid):
    result =  wa.get_lat_lng_by_mac(macid)
    print "=============================="
    
    if ( isinstance(result, dict) ):
        print "SSID: " + result["bssid"]
        print "Latitude: " + str(result["lat"])
        print "Longitude: " + str(result["lng"])
    else:
        print result
    return

def getInformationBySSID(ssid):
    print "=============================="
    # result object needs to call .json() to get the actual dict object back
    result = wa.get_lat_lng_by_ssid(ssid)
    
    data = result.json()
    
    for key, value in data.iteritems():
        if key == "results":
            for entry in value:
                print "BSSID: " + entry["netid"]
                print "ESSID: " + entry["ssid"]
                print "WEP: " + entry["wep"]
                print "Channel: " + entry["channel"]
                print "Latitude: " + entry["trilat"]
                print "Longitude: " + entry["trilong"]
                #print "Lasttime: " + entry["lasttime"]
                print "\n"       
        
    return

def main():
    myusage = "usage: %prog -u <wigle username> -p <wigle_password> -n <macid>"
    #parser = optparse.OptionParser(usage=usage)
    parser = optparse.OptionParser(usage=myusage)
    parser.add_option("-u", dest="username", type="string", help="specify wigle username")
    parser.add_option("-p", dest="password", type="string", help="specify wigle password")
    parser.add_option("-s", dest="ssid", type="string",     help="specify network BSSID")
    parser.add_option("-m", dest="mac", type="string",      help="specify network ESSID")
    #parser.add_option('-a', dest='address', type='string', help='specify address in format address:state:zip')
    
    
    (options, args) = parser.parse_args()
    
    username = options.username
    password = options.password
    ssid = options.ssid
    macid = options.mac
    #address = options.address
    
    if username == None or password == None:
        print parser.usage
        exit(0)
    else:
        requests.packages.urllib3.disable_warnings()
        global wa
        wa = wigle_query.WigleAgent( username, password )
        if macid != None and ssid == None:
            getLocationByMacID(macid)
        elif ssid != None:
            getInformationBySSID(ssid)
        
if __name__ == '__main__':
    main()

helpers.py

#!/usr/bin/env python

import os, sys, types, string, textwrap

def color(string, status=True, warning=False, bold=True, blue=False):
    """
    Change text color for the linux terminal, defaults to green.
    Set "warning=True" for red.
    stolen from Veil :)
    """
    attr = []
    if status:
        # green
        attr.append('32')
    if warning:
        # red
        attr.append('31')
    if bold:
        attr.append('1')
    if blue:
        #blue
        attr.append('34')
    return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)

def formatLong(title, message, frontTab=True, spacing=16):
    """
    Print a long title:message with our standardized formatting.
    Wraps multiple lines into a nice paragraph format.
    """

    lines = textwrap.wrap(textwrap.dedent(message).strip(), width=50)
    returnString = ""

    i = 1
    if len(lines) > 0:
        if frontTab:
            returnString += "\t%s%s" % (('{0: <%s}'%spacing).format(title), lines[0])
        else:
            returnString += " %s%s" % (('{0: <%s}'%(spacing-1)).format(title), lines[0])
    while i < len(lines):
        if frontTab:
            returnString += "\n\t"+' '*spacing+lines[i]
        else:
            returnString += "\n"+' '*spacing+lines[i]
        i += 1
    return returnString
Edited by dustbyter
Link to comment
Share on other sites

Thats pretty cool.

So based on ssid/mac you find geo location.

​Few days ago i started messing around with wigle also but i went in different direction.

​Since there was no access points near me in wigle database online i made local database via wigle for android.

​Made php script that based on gps cordinates goes thru local wigle database and filters close ssids (50-100meters close).

​Was thinking of making pineapple change and spoof fake accesspoints based on location.

​Have option to spoof open only or protected networks as open etc.

​If anyone thinks this is good or wants it after i clean it up and test more i can release script on github :)

Link to comment
Share on other sites

Made a bit more progress on this script.

Now I can provide a street address and get back 100 networks that are listed near it. The output that is returned from the script is shown below. One could run the command-line module to get the results and then convert them to a format that they can post on Google Maps.

Gonna have to see what needs to be done to make this a command-line module.

Sample execution:

 
python testWigleAgent.py -u <username> -p <password> -a "1600 Pennsylvania:DC:20500"
==============================
[*] WIGLE: This user was validated
[*] WIGLE: Lat / Long and SSID have been retrived
BSSID: 00:0B:6C:BD:BD:BD
ESSID: null
WEP: ?
Channel: null
Latitude: 38.90174103
Longitude: -77.02464294
 
 
BSSID: 00:15:AF:17:ED:97
ESSID: GlobalSuiteWireless
WEP: N
Channel: 0
Latitude: 38.90188217
Longitude: -77.02464294
 
 
BSSID: 00:18:0A:81:EB:88
ESSID: DCPL_ MLK_Digital Commons_Staff
WEP: 2
Channel: 1
Latitude: 38.89808655
Longitude: -77.02464294
 
 
BSSID: 00:18:F8:18:84:1B
ESSID: tiger
WEP: Y
Channel: 11
Latitude: 38.89736938
Longitude: -77.02464294
 
 
... truncated result set ....
 
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...