├── .gitignore ├── LICENSE.md ├── README.md ├── network_meta_info.txt └── probespy.sh /.gitignore: -------------------------------------------------------------------------------- 1 | location.db 2 | network_meta_info.txt 3 | meta.lst 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 stumblebot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Probespy 2 | Probespy is a dumb and dirty tool for analyzing directed and broadcast probe request data sent by wifi client devices. 3 | 4 | Usage: bash probespy.sh -c -d 5 | bash probespy.sh -c -d -l <"lat,lng"> -r 6 | bash probespy.sh -c -d -l <"lat,lng"> -r -f 7 | Options: 8 | -c: The directory to read pcap files from 9 | -f: Report output format 10 | Options: html or txt 11 | -d: The directory to write the current report to 12 | -l: The location to bound our SSID search to 13 | -r: The distance to search from the coordinate 14 | designated by -l 15 | -h: Display this help 16 | -------------------------------------------------------------------------------- /network_meta_info.txt: -------------------------------------------------------------------------------- 1 | Air Canada: Airline wifi. Traveller. Air Canada Customer. 2 | Apple Store: Retail wifi. Apple Customer. 3 | ATL Free Wi-Fi: Airport wifi. Traveller. Visited ATL Airport, GA, USA. 4 | att-wifi: ISP Shared wifi. Potential AT&T Customer. 5 | attwifi: ISP Shared wifi. Potential AT&T Customer. 6 | Belle Tire Free wiFi: Retail Wifi. Belle Tire Customer. 7 | BestBuy: Retail wifi. BestBuy Customer. 8 | BlackHatUSA2017: BlackHat Briefings 2017 attendee. Visited Las Vegas, NV, USA. 9 | Boingo Hotspot: Airport wifi. Traveller. 10 | BostonMkt_Guest: Restaraunt wifi. Boston Market Customer. 11 | C21 Guest: Century 21 Customer. 12 | CARite-Public: Retail wifi. CARite Customer. 13 | City of Minneapolis Public WiFi: Visited Minneapolis, MN, USA. 14 | CMU: University wifi. Visited Carnegie Mellon University, PA, USA. 15 | CMU-GUEST: University wifi. Visited Carnegie Mellon University, PA, USA. 16 | CMU-SECURE: University wifi. Visited Carnegie Mellon University, PA, USA. 17 | Comfort_Suites: Hotel wifi. Traveller. Comfort Inn and Suites Customer. 18 | CountryInnAndSuites: Hotel wifi. Traveller. Country Inn and Suites Customer. 19 | Courtyard_GUEST: Hotel wifi. Traveller. Courtyard Customer. 20 | DefCon: Defcon attendee. Visited Las Vegas, NV, USA. 21 | DefCon-Open: Defcon attendee. Visited Las Vegas, NV, USA. RENEGADE. 22 | DeltaSkyClub: Airport wifi. Traveller. Delta Airlines Customer. 23 | - DEN Airport Free WiFi: Airport wifi. Traveller. Visited DEN Airport, CO, USA. 24 | Detroit Airport Wi-Fi: Airport wifi. Traveller. Visited DTW Airport, MI, USA. 25 | Devonport City Wifi: Visited Devonport, Tasmania, Austrialia. 26 | FairField Inn_GUEST: Hotel wifi. Traveller. FairField Inn Customer. 27 | _Free_MDW_Wi-Fi: Traveller. Visited MDW Airport, IL, USA. 28 | _Free_ORD_Wi-Fi: Traveller. Visited ORD Airport, IL, USA. 29 | ...GAP_FREE: Retail wifi. GAP Customer. 30 | gogoinflight: Traveller. Airplane wifi. 31 | GSP-Public-WiFi: Airport wifi. Traveller. Visited GSP Airport, SC, USA. 32 | Guest T-Mobile: ISP Shared wifi. Potential T-Mobile Customer. 33 | Helsinki Airport Free Wi-Fi: Traveller. Visited Helsinki Airport, Finland. 34 | HFHS.Guest: Hospital wifi. 35 | hhonors: Hotel wifi. Traveller. Hilton Customer. 36 | hhonors_guest: Hotel wifi. Traveller. Hilton Customer. 37 | hhonors-public: Hotel wifi. Traveller. Hilton Customer. 38 | HI Express: Hotel wifi. Traveller. Holiday Inn Customer. 39 | HI Express Rocklin: Hotel wifi. Traveller. Holiday Inn Customer. Visited Rocklin, CA, USA. 40 | HI Express Shreveport Park Plaza: Hotel wifi. Traveller. Holiday Inn Customer. Visited Shreveport, LA, USA. 41 | Hyatt_GUEST: Hotel wifi. Traveller. Hyatt Customer. 42 | Hyatt Guest Room: Hotel wifi. Traveller. Hyatt Customer. 43 | hyatt: Hotel wifi. Traveller. Hyatt Customer. 44 | @Hyatt_WiFi: Hotel wifi. Traveller. Hyatt Customer. 45 | Ihopmanager: Restaraunt wifi. 46 | KFC FREE WIFI: Restaraunt wifi. KFC Customer. 47 | kroger: Grocery wifi. Kroger Customer. 48 | Kroger Guest: Grocery wifi. Kroger Customer. 49 | KrogerWiFi: Grocery wifi. Kroger Customer. 50 | _LAX Free WiFi: Airport wifi. Traveller. Visited LAX Airport, CA, USA. 51 | Loews_Guest: Loews Customer. 52 | Marriott_Guest: Hotel wifi. Traveller. FairField Inn Customer. 53 | McCarran_WiFi: Airport wifi. Traveler. Visited LAS Airport, NV, USA. 54 | McDonalds Free WiFi: Restaraunt wifi. McDonalds customer. 55 | MGMResorts-WiFi: Hotel wifi. MGM resorts customer. 56 | MicroCenterGuest: Retail wifi: MicroCenter Customer. 57 | Oddfellows Cafe + Bar: Restaraunt wifi. Visited Seattle, WA, USA. 58 | Olgas Guest: Restaraunt wifi. Olgas Diner Customer. 59 | Olgas Guest WiFi: Restaraunt wifi. Olgas Diner Customer. 60 | Origins Wi-Fi: Retail wifi. Origins Customer. 61 | Otopeni Airport: Airport wifi. Traveller. Visited Otopeni Airport, Romania. 62 | PANERA: Restaraunt wifi. Panera Bread Customer 63 | Park Plaza County Hall: Hotel wifi. Visited London, United Kingdom. 64 | PartyCity_Guest: Retail wifi. PartyCity Customer. 65 | Penn Station: Restaraunt wifi. Penn Station Sandwiches Customer. 66 | Qdoba_Guest: Restaraunt wifi. Qdoba Customer. 67 | Quality Inn and Suites: Hotel wifi. Traveller. Quality Inn Customer. 68 | Renaissance_GUEST: Hotel wifi. Traveller. Renaissance Customer. 69 | ResidenceInn_GUEST: Hotel wifi. Traveller. FairField Inn Customer. 70 | Roeper Student and Guest: Edu wifi. 71 | Schiphol_Airport_WiFi: Airport wifi. Traveller. Visited Amsterdam, Netherlands. 72 | SEATAC-FREE-WIFI: Airport wifi. Traveller. Visited SEATAC Airport, WA, USA. 73 | Sheraton-Guestrooms: Hotel wifi. Traveller. Sheraton Customer. 74 | Sheraton-Meeting Room: Hotel wifi. Traveler. Sheraton Customer. 75 | SouthwestWiFi: Airline wifi. Traveller. Southwest Customer. 76 | Target Guest Wi-Fi: Retail wifi. Target Customer. 77 | Toronto Pearson Wi-Fi: Airport wifi. Traveller. Visited 78 | United_Wi-Fi: Airline wifi. Traveller. United Airlines customer. 79 | WestinGuestrooms: Hotel wifi. Traveller. Westin Customer. 80 | WholeFoodsMarket: Grocery wifi. Whole Foods Customer. 81 | WIFI_BEN_GURION_AIRPORT: Airport wifi. Traveller. Visited Ben Gurion Airport, Israel. 82 | #WiFi@Changi: Airport wifi. Traveller. Visited Changi Airport, Shanghai, China. 83 | www.hotel-litz.de: Hotel wifi. Traveller. Hotel Litz Customer. Visited Langenargen, Germany. 84 | xfinitywifi: ISP Shared wifi. Potential Xfinity Customer. 85 | YOW Free Wi-Fi: Airport wifi. Traveller. Visited YOW Airport, Ottawa, CA. 86 | Five Guys: Restaraunt wifi. Five Guys Customer. 87 | FlyDulles: Airport wifi. Traveller. Visited IAD Airport, Washington DC, USA. 88 | VenetianPalazzoWifi: Hotel wifi. Traveller. Visited Venetian Palazzo Hotel, Las Vegas, NV, USA. 89 | McCarran WiFi: Airport wifi. Traveller. Visited Las Vegas, NV, USA. 90 | united_club: Airline wifi. Traveller. United airlines customer. 91 | Copthorne Lobby Wireless: Hotel wifi. Traveller. Copthorne Hotels Customer. 92 | flyCOS: Airport wifi. Traveller. Visited Colorado Springs, CO, USA. 93 | -------------------------------------------------------------------------------- /probespy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #TODO 4 | 5 | #PRIORITY 6 | #Local database lookup via wigle export 7 | # figure out what is going on with the elongated lat/lng values 8 | 9 | #BACK BURNER 10 | #Centralized report file 11 | #re-integrate direct capture from probespy 12 | #update report display format 13 | #active attacks?? 14 | # beacon honeypotting 15 | #Change maps lookups to use openstreetmaps instead of google 16 | #cluster search 17 | #turn on/off location lookup 18 | #sort a given run by profile mac address or SSID 19 | #wigle billing status check 20 | 21 | #set the internal field separator to newlines only 22 | IFS=$'\n' 23 | 24 | #Initialize variables from probespy.conf 25 | #check if probespy.conf is present 26 | if [[ -z "$(ls probespy.conf 2>/dev/null)" ]]; 27 | then 28 | echo probespy.conf could not be found. Please create probespy.conf, in the current directory 29 | echo and add a WIGLE API key in the following format. 30 | echo 31 | echo WIGLE_API_KEY=\'AID0d903714c7d78b11a222c77b956d4200:e6c1b74909bdba1f331776e5b96c696f\' 32 | else 33 | echo -n found probespy.conf 34 | #source conf file 35 | . probespy.conf 36 | if [[ -z "$(echo $WIGLE_API_KEY)" ]] 37 | then 38 | echo 39 | echo No WIGLE API key present. Please add a key to probespy.conf in the following format 40 | echo 41 | echo WIGLE_API_KEY=\'AID0d903714c7d78b11a222c77b956d4200:e6c1b74909bdba1f331776e5b96c696f\' 42 | else 43 | echo ...WIGLE API key loaded 44 | fi 45 | fi 46 | 47 | userLocation='' 48 | 49 | usage() { 50 | echo "Usage: bash probespy.sh -c -d " 1>&2 51 | echo " bash probespy.sh -c -d -l <\"lat,lng\"> -r " 1>&2 52 | echo " bash probespy.sh -c -d -l <\"lat,lng\"> -r -f " 1>&2 53 | # echo " bash probespy.sh -c -i " 1>&2 54 | echo "Options:" 1>&2 55 | echo "-c: The directory to read pcap files from" 1>&2 56 | # echo "-i: The network interface to capture packets on" 1>&2 57 | echo "-f: Report output format" 1>&2 58 | echo " Options: html or txt" 1>&2 59 | echo "-d: The directory to write the current report to" 1>&2 60 | echo "-l: The location to bound our SSID search to" 1>&2 61 | echo "-r: The distance to search from the coordinate" 1>&2 62 | echo " designated by -l" 1>&2 63 | echo "-h: Display this help" 1>&2 64 | exit 1 65 | } 66 | 67 | #Defining script arguments 68 | while getopts :i:c:f:d:l:r:g:h option; 69 | do 70 | case $option in 71 | i) 72 | networkInterface=$OPTARG 73 | ;; 74 | c) 75 | captureDir=$OPTARG 76 | ;; 77 | f) 78 | reportFormat=$OPTARG 79 | ;; 80 | d) 81 | reportDir=$OPTARG 82 | ;; 83 | l) 84 | userLocation=$OPTARG 85 | ;; 86 | r) 87 | searchRange=$OPTARG 88 | ;; 89 | g) 90 | clusterSearch=$OPTARG 91 | ;; 92 | h) 93 | usage 94 | ;; 95 | \?) 96 | echo "Invalid option: $OPTARG" 1>&2 97 | ;; 98 | :) 99 | echo "option -$OPTARG needs an argument" 100 | exit 101 | ;; 102 | esac 103 | done 104 | 105 | #Check for valid capture directory 106 | if [ -z "$captureDir" ]; then 107 | echo "ERROR: supply a directory to read pcaps from" 108 | echo "" 109 | usage 110 | fi 111 | 112 | #Check for valid report directory 113 | if [ -z "$reportDir" ]; then 114 | echo "ERROR: supply a directory to write report results" 115 | echo "" 116 | usage 117 | fi 118 | 119 | #Check for valid report format 120 | if [ -z $reportFormat ] 121 | then 122 | echo Report format was not set, Defaulting to TXT 123 | echo Report will be printed to stdout 124 | elif [ $reportFormat == html ] 125 | then 126 | echo Report format set to HTML 127 | echo Report will be written to $reportDir 128 | elif [ $reportFormat == txt ] 129 | then 130 | echo Report format set to TXT 131 | echo Report will be printed to stdout 132 | else 133 | echo Reporting format $reportFormat is not recognized 134 | echo Please define a valid reporting format 135 | echo ------------------------------------------------ 136 | usage 137 | exit 138 | fi 139 | 140 | #Check for valid user location 141 | if [ -z $userLocation ] 142 | then 143 | echo No location has been set to search within 144 | userLocation='NOLOC' 145 | else 146 | echo -n Location has been set as: $userLocation 147 | fi 148 | 149 | echo \ with a range of $searchRange miles 150 | echo ------------------------------------------------ 151 | 152 | #INITIALIZE MORE VARIABLES 153 | dataDir=$(echo $reportDir/data/) 154 | htmlDir=$(echo $reportDir/html/) 155 | 156 | 157 | ############################################################################### 158 | #INTERFACE CAPTURE JUNK 159 | # This code is not in use right now, but may be helpful if/when I re-implement 160 | # capturing probe requests from within probespy 161 | ############################################################################### 162 | #clear pcaps from the ringbuffer directory 163 | #rm ringbuffer/* 164 | 165 | #TEMP DEV SHIT 166 | #copy other pcaps in here because sometimes we dont have awesome sampling 167 | #cp ~/a/directory/*.cap ringbuffer/ 168 | 169 | #start capturing data from the wireless adapter to the ringbuffer 170 | #tshark -i $networkInterface -f 'subtype probereq ' -w ringbuffer/probes -b duration:60 -b files:5 2> /dev/null & 171 | #alternate with no ringbuffer 172 | #tshark -i $networkInterface -f 'subtype probereq ' -w ringbuffer/probes 2> /dev/null & 173 | 174 | #wait for tshark to write something to the ringbuffer dir before continuing 175 | : ' 176 | echo -n "Initializing tshark" 177 | while [ -z $(ls ringbuffer/) ] 178 | do 179 | echo -n . 180 | sleep 1 181 | done 182 | echo 183 | 184 | #wait for a probe request before continuing 185 | echo -n "Waiting for probe requests" 186 | while [[ -z $probes ]] 187 | do 188 | probes=$(for files in $( ls ringbuffer/);do sudo tshark -r ringbuffer/$files 2> /dev/null | grep "Probe Request, SN=";done) 189 | echo -n . 190 | sleep 1 191 | done 192 | echo 193 | 194 | 195 | # perform the rest of these actions until the user cancels the script 196 | while [ 1 -eq 1 ] 197 | do 198 | #' 199 | #END OF INTERFACE CAPTURE JUNK 200 | ############################################################################### 201 | 202 | ############################################################################### 203 | #CREATE REPORTING DIRECTORIES 204 | ############################################################################### 205 | report_directory (){ 206 | mkdir -p $dataDir 207 | mkdir -p $htmlDir 208 | } 209 | 210 | 211 | ############################################################################### 212 | #PCAP PROCESSING FUNCTION 213 | ############################################################################### 214 | pcap_processing () { 215 | 216 | #clear profile data from previous runs 217 | rm -f $dataDir/*.mac 218 | rm -f $dataDir/*.compressed 219 | 220 | #do some actions for each pcap in the current captureDir 221 | for i in $( ls $captureDir/ | grep .cap ); 222 | do 223 | echo 'Processing '$i 224 | #for each pcap, output only the data we want, the source MAC and SSID 225 | for j in $( tshark -r $captureDir/$i -Y 'wlan.fc.type_subtype == 0x0004' -Nn 2> /dev/null | egrep -v 'SSID=Broadcast$|\[Malformed Packet\]$' | cut -d '.' -f 2- | cut -d ' ' -f 2,12- | sed 's/ SSID=/,SSID=/g' | egrep -v "\\\001|\\\002|\\\003|\\\004|\\\005|\\\006|\\\016|\\\017|\\\020|\\\021|\\\022|\\\023|\\\024|\\\025|\\\026|\\\027|\\\030|\\\031|\\\032|\\\033|\\\034|\\\035|\\\036|\\\037|\\\277|\\\357" | sort -u ) 226 | do 227 | echo $j >> $dataDir/$i.compressed 228 | #also create a file for each source mac from each capture file 229 | touch $dataDir/$(echo $j | cut -d , -f 1).mac 230 | done 231 | done 232 | 233 | echo Compressing results 234 | #Create a sorted, deduped file of all data 235 | cat $dataDir/*.compressed | sort -u > $dataDir/all.compressed 236 | } 237 | 238 | ############################################################################### 239 | #MASTER GEOLOCATION FUNCTION 240 | ############################################################################### 241 | geolocation () { 242 | #create the file location.db if it does not already exist 243 | #if [ -z $(ls $dataDir/location.db) ]; 244 | #then 245 | #seems like maybe I don't actually need to check if this file exists 246 | touch $dataDir/location.db 247 | #fi 248 | 249 | echo -------------------------------Begin SSID Lookup--------------------------------- 250 | 251 | #run a wigle query for all SSIDs listed in all.compressed 252 | #we need to pass some arguments to the other function in order for it to work 253 | cat $dataDir/all.compressed | cut -d = -f 2- | sort -u | parallel --no-notice -j 10 ssidGeolocation {} $dataDir $userLocation $WIGLE_API_KEY $searchRange 254 | 255 | echo ------------------------------SSID Lookup Complete------------------------------- 256 | 257 | #remove duplicates and sort 258 | echo Trimming the database 259 | sort -u -o $dataDir/location.db $dataDir/location.db 260 | } 261 | 262 | ############################################################################### 263 | #SSID GEOLOCATION FUNCTION 264 | # Runs a the geolocation search via wigle and handles some other location 265 | # meta-info gathering tasks at this time. 266 | ############################################################################### 267 | ssidGeolocation () { 268 | #re-instantiate variables (required for parallelization) 269 | i=$(echo $1) 270 | dataDir=$(echo $2) 271 | userLocation=$(echo $3) 272 | WIGLE_API_KEY=$(echo $4) 273 | searchRange=$(echo $5) 274 | 275 | #sanitize control chars from bash because... I don't have a better way to fix the bug now 276 | sanSSID=$(echo $i | sed -e 's/\*/\\*/g' \ 277 | -e 's/\[/\\[/g' \ 278 | -e 's/\]/\\]/g' \ 279 | -e 's/\&/\\&/g' ) 280 | if [ -z "$(grep -i "\"ssid\"\:\"$sanSSID\"" $dataDir/location.db)" ] 281 | then 282 | #entry is new 283 | echo -n $i 284 | 285 | #urlencode spaces with sed because curl bitches at you otherwise 286 | urlencodeSSID=$(echo $i | sed -e 's/ /%20/g' -e 's/\&/%26/g') 287 | 288 | #run query for the current SSID by wigle 289 | #at this time, since we haven't determined better criteria, only 290 | # keep entries that return one network 291 | if [ $userLocation == 'NOLOC' ] 292 | then 293 | wigle=$(curl --connect-timeout 30 -s -u $WIGLE_API_KEY "https://api.wigle.net/api/v2/network/search?latrange1=&latrange2=&longrange1=&longrange2=&variance=0.010&lastupdt=&netid=&ssid=$urlencodeSSID&ssidlike=&Query=Query&resultsPerPage=2" | grep "\"resultCount\"\:1\," ) 294 | else 295 | #this isn't the RIGHT way to calc these distances, but it's pretty close most of the time 296 | # and I don't care that much about precision at the moment 297 | 298 | latRange=$(echo $searchRange/69.2 | bc -l) 299 | lngRange=$(echo $searchRange/69.2 | bc -l) 300 | 301 | lat=$(echo $userLocation | cut -d , -f 1) 302 | lng=$(echo $userLocation | cut -d , -f 2) 303 | latlow=$(echo "$lat-$latRange" | bc) 304 | lathigh=$(echo "$lat+$latRange" | bc) 305 | lnglow=$(echo "$lng-$lngRange" | bc) 306 | lnghigh=$(echo "$lng+$lngRange" | bc) 307 | 308 | #lat/lng is not placed dynamicaly at this time, so these location settings 309 | # will only work in the north american lat/lng quadrant 310 | wigle=$(curl --connect-timeout 30 -s -u $WIGLE_API_KEY "https://api.wigle.net/api/v2/network/search?latrange1=$latlow&latrange2=$lathigh&longrange1=$lnglow&longrange2=$lnghigh&variance=0.010&lastupdt=&netid=&ssid=$urlencodeSSID&ssidlike=&Query=Query&resultsPerPage=2" | grep "\"resultCount\"\:1\," ) 311 | fi 312 | 313 | if [ -z "$wigle" ] 314 | then 315 | echo "\"trilat\":NULL,\"trilong\":NULL,\"ssid\":\"$i\",\"wep\":\"\"" >> $dataDir/location.db 316 | echo "" 317 | else 318 | gkey=$(echo "AIzaSyCPMj_9PkQKstTkTNv9RH5gwY40WmJP8N4") 319 | trilat=$(echo $wigle | jq .results[].trilat ) 320 | trilong=$(echo $wigle | jq .results[].trilong ) 321 | 322 | #add headers and junk for the location.db (re-evaluate if this is still needed pls) 323 | displaytrilat=$(echo $trilat | sed -e 's/^/\"trilat\":/g') 324 | displaytrilong=$(echo $trilong | sed -e 's/^/\"trilong\":/g') 325 | 326 | #bits and pieces that we need from the wigle results 327 | coordinates=$( echo $trilat,$trilong ) 328 | ssid=$(echo $wigle | jq .results[].ssid | sed -e 's/^/\"ssid\":/g') 329 | encryption=$(echo $wigle | jq .results[].encryption) 330 | 331 | #if the coordinates from wigle return 0,0, as they sometimes do, fix them by 332 | # marking the locations as unlocated and avoid running the meta-info lookup 333 | # because there's no point 334 | if [ $coordinates = '0,0' ] 335 | then 336 | displaytrilat=$(echo "\"trilat\":NULL") 337 | displaytrilong=$(echo "\"trilong\":NULL") 338 | address=$(echo "NULL") 339 | addressType=$(echo "NULL") 340 | encryption=$(echo "NULL") 341 | else 342 | #Otherwise, try to find out how the location has been identified by google 343 | #stored json from google's geocoding API 344 | geocode=$(curl -s https://maps.googleapis.com/maps/api/geocode/json?latlng=$coordinates) 345 | #google's placeid is required to get more meta information about the location 346 | placeid=$(echo $geocode | jq .results[].place_id | head -n1 | sed 's/\"//g') 347 | #identify what type of address this is 348 | addressType=$(curl -s "https://maps.googleapis.com/maps/api/place/details/json?placeid=$placeid&key=$gkey" | jq .result.types[]) 349 | address=$(echo $geocode | jq .results[].formatted_address | head -n1) 350 | fi 351 | 352 | echo $displaytrilat,$displaytrilong,$ssid,$encryption,$address,$addressType >> $dataDir/location.db 353 | echo " :LOCATED" 354 | fi 355 | fi 356 | } 357 | #function needs to be exported so parallel can interact with it 358 | export -f ssidGeolocation 359 | 360 | ############################################################################### 361 | #DEVICE PROFILING FUNCTION 362 | # place SSID probes from each source MAC in its own file 363 | # ensure that only unique entries are in each file 364 | ############################################################################### 365 | profile_gen () { 366 | for i in $(cat $dataDir/all.compressed ) 367 | do 368 | echo $(echo $i | cut -d , -f 2) >> $dataDir/$(echo $i | cut -d , -f 1).mac 369 | done 370 | 371 | for i in $(ls $dataDir/*.mac) 372 | do 373 | sort -u -o $i $i 374 | done 375 | } 376 | 377 | ############################################################################### 378 | #TXT REPORT GENERATION FUNCTION 379 | ############################################################################### 380 | txt_gen () { 381 | for i in $(ls $dataDir/*.mac); 382 | do 383 | for e in $(cat $i); 384 | do 385 | mac=$(echo $i | rev | cut -d \/ -f 1 | rev | cut -d . -f 1) 386 | ssid=$(echo $e | cut -d = -f 2) 387 | 388 | extended=$(grep "$ssid" $dataDir/location.db) 389 | if [ -z $(echo $extended | grep "\"trilat\"\:NULL\,\"trilong\"\:NULL\,") ] 390 | then 391 | #network has lat/lng 392 | ext=$(echo $extended | cut -d , -f 1,2,4-) 393 | else 394 | #network has no lat/lng 395 | #check for behavior data 396 | behavior=$(grep "^$ssid:" network_meta_info.txt) 397 | if [[ -z $behavior ]] 398 | then 399 | #no information is known about this network 400 | ext=$(echo NO_DATA) 401 | else 402 | #a beavioral profile has been determined for this network 403 | ext=$(echo $behavior | cut -d : -f 2-) 404 | fi 405 | fi 406 | 407 | echo $mac:$ssid:$ext; 408 | done; 409 | done 410 | } 411 | 412 | ############################################################################### 413 | #HTML REPORT GENERATION FUNCTION 414 | ############################################################################### 415 | html_gen () { 416 | #clear old html files 417 | rm -f $htmlDir/*.html 418 | 419 | echo ------------------------------Generating Profiles-------------------------------- 420 | #generate a default display.html so there's always something 421 | #for the active page to refresh to 422 | #this is decommissioned for now 423 | #echo "

BEAR WITH US

TECHNICAL DIFFICULTIES

" > html/display.html 424 | 425 | #perform these actions on each .mac profile 426 | for i in $( ls $dataDir/*.mac) 427 | do 428 | echo -n . 429 | #woo variables because we reuse them all the time 430 | mac=$(echo $i | sed 's/.*\///g' | cut -d . -f 1) 431 | manufacturer=$(grep -i $(echo $mac | cut -d : -f -3 | sed 's/://g' ) /usr/share/ieee-data/oui.txt | cut -d ' ' -f 3) 432 | #apply the following actions only on .mac profiles with more than one SSID 433 | #I'm disabling this temporarily for now. I may make it a flagged option? 434 | # if [ "$(cat $i | wc -l)" -gt 1 ] 435 | # then 436 | #Download google maps image for this location 437 | #for each SSID in this .mac profile 438 | for j in $(cat $i | cut -d = -f 2-) 439 | do 440 | #create a variable for all this shit 441 | #because we're going to be using it a LOT 442 | data=$(grep ":\"$j\"," $dataDir/location.db | grep -v "\"trilat\":NULL,\"trilong\":NULL,") 443 | ssid=$(echo $data | cut -d , -f 3 | sed -e 's/\"ssid\":"//g' -e 's/\"$//g') 444 | #display the current lat,lng 445 | latlng=$(echo $data | cut -d , -f 1-2 | sed -e 's/"trilat"://g' -e 's/"trilong"://g') 446 | #if the current SSID does not have google maps photo 447 | if ls $htmlDir/$ssid.png 1> /dev/null 2>&1 448 | then 449 | #do nothing, file exists 450 | : 451 | else 452 | #if the file does not exst, see if we have 453 | #coordinates for it, don't download anything if we 454 | #don't. DUH 455 | if [[ $loc == *"\"trilat\":NULL,\"trilong\":NULL,"* ]] 456 | then 457 | : 458 | else 459 | wget -q https://maps.googleapis.com/maps/api/staticmap?markers=color:red%7Clabel:$ssid%7C$latlng\&zoom=13\&size=400x400\&maptype=roadmap -O $htmlDir/$ssid.png 460 | fi 461 | fi 462 | done 463 | 464 | #generate html page 465 | #for each SSID in this .mac profile 466 | for n in $(cat $i | cut -d = -f 2-) 467 | do 468 | if [ -z "$manufacturer" ] 469 | then 470 | manufacturer=$(echo UNKNOWN) 471 | fi 472 | 473 | #if an image exists for this network, add it to the html 474 | if [ -z "$(ls $htmlDir/*.png 2>/dev/null | grep "\/$n.png")" ] 475 | then 476 | : 477 | else 478 | #if we haven't created an html file for this 479 | # profile yet, add the boilerplate header 480 | if [ -z "$(grep $mac $htmlDir/*html 2>/dev/null)" ] 481 | then 482 | uniqueNets=$(cat $i | wc -l) 483 | echo -n "

Device ID $mac, manufacturer:$manufacturer

Looking for $uniqueNets network(s):::Located network count: LOCATED_NETS_STRING_HERE

" >> $htmlDir/$mac.html 484 | fi 485 | #add the image to the profile 486 | address=$(grep \"$n\" $dataDir/location.db | cut -d , -f 5- | sed -e 's/\",\"/

/g' -e 's/,/

/' -e 's/\"$//g' -e 's/^\"//g') 487 | latlng=$(grep \"$n\" $dataDir/location.db | cut -d , -f 1-2 | sed -e 's/"trilat"://g' -e 's/"trilong"://g' ) 488 | encryption=$(grep \"$n\" $dataDir/location.db| cut -d , -f 4 | sed 's/\"//g') 489 | echo -n "

" >> $htmlDir/$mac.html 490 | #echo -n "" >> html/$mac.html 491 | fi 492 | done 493 | #end of 'one probe' profile generation loop 494 | # fi 495 | 496 | #now that the profile has been fully generated, replace placeholder 497 | # for number of located networks with the actual value 498 | if [ -z "$(grep $mac $htmlDir/*html 2>/dev/null )" ] 499 | then 500 | : 501 | else 502 | locatedNets=$(sed 's/\.png/.png\n/g' $htmlDir/$mac.html 2>/dev/null | wc -l) 503 | if [ $locatedNets -ne 0 ] 504 | then 505 | sed -i -e "s/LOCATED_NETS_STRING_HERE/$locatedNets/" $htmlDir/$mac.html 506 | fi 507 | 508 | echo "

Networks that have not been located

    " >> $htmlDir/$mac.html 509 | cat $i | cut -d = -f 2- | while read net 510 | do 511 | behavior=$(grep "^$net:" network_meta_info.txt) 512 | if [ -z "$behavior" ] 513 | then 514 | if [ -z "$(grep -v "\"trilat\":NULL,\"trilong\":NULL" $dataDir/location.db | grep ",\"ssid\":\"$net\"," )" ] 515 | then 516 | echo $net | sed 's/^/
  • /g' >> $htmlDir/$mac.html 517 | fi 518 | # echo $net | sed 's/^/
  • /g' >> $htmlDir/$mac.html 519 | else 520 | echo $behavior | sed -e 's/\(.*\):/\1<\/b>:/' -e 's/^/
  • /g' >> $htmlDir/$mac.html 521 | fi 522 | done 523 | 524 | if [ -z "$(grep "
  • " $htmlDir/$mac.html)" ] 525 | then 526 | sed -i -e 's/

    Networks that have not been located

      //g' $htmlDir/$mac.html 527 | fi 528 | 529 | echo "
    " >> $htmlDir/$mac.html 530 | fi 531 | 532 | echo -n . 533 | done 534 | echo '' 535 | echo -------------------------------Profiles Complete--------------------------------- 536 | } 537 | 538 | ############################################################################### 539 | #CALL FUNCTIONS TO DO THINGS! 540 | ############################################################################### 541 | report_directory 542 | pcap_processing 543 | geolocation 544 | profile_gen 545 | 546 | if [ -z $reportFormat ] 547 | then 548 | txt_gen 549 | elif [ $reportFormat == html ] 550 | then 551 | html_gen 552 | elif [ $reportFormat == txt ] 553 | then 554 | txt_gen 555 | fi 556 | 557 | ############################################################################### 558 | #CHILL FUNCTION 559 | ############################################################################### 560 | chill_out () { 561 | #just chill for a second. jesus 562 | echo -n Chill out. Take a beat 563 | for ani in $(seq 1 5) 564 | do 565 | sleep 1 566 | echo -n . 567 | done 568 | echo " Back to it" 569 | } 570 | 571 | #continue looping 572 | #done 573 | --------------------------------------------------------------------------------

SSID: $n

LAT,LNG: $latlng

Encryption: $encryption

$address

SSID: $n
COORDINATE: $latlng
ADDRESS: $address