├── LICENSE ├── README.md ├── esp8266_packet_counter ├── esp8266_packet_counter.ino └── esp8266_packet_counter_1mb.bin ├── packetGraph.py ├── requirements.txt └── screenshot.jpg /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 David Schütz 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 | # Packet Graph 2 | 3 | Displays the WiFi traffic around you in a nice terminal graph. 4 | 5 | ![Screenshot of PacketGraph](https://raw.githubusercontent.com/spacehuhn/packetGraph/master/screenshot.jpg) 6 | 7 | ## Usage 8 | 9 | To scan the traffic you can either use a standard WiFi interface or an ESP8266! 10 | 11 | **WiFi interface (e.g. USB dongle)** 12 | 13 | Start monitor mode on your WiFi card: `airmon-ng start ` 14 | Example: `airmon-ng start wlan0` 15 | 16 | Make sure your card supports monitor mode! 17 | 18 | **ESP8266** 19 | 20 | Flash the esp8266_packet_counter onto your ESP8266. You can either use the Arduino sketch or the .bin file. 21 | Then just plug the ESP8266 in over USB. 22 | 23 | **Start the program** 24 | `python3 packetGraph.py` 25 | -------------------------------------------------------------------------------- /esp8266_packet_counter/esp8266_packet_counter.ino: -------------------------------------------------------------------------------- 1 | #include 2 | extern "C" { 3 | #include "user_interface.h" 4 | } 5 | 6 | //===== Run-Time variables =====// 7 | int ch = 1; 8 | unsigned long prevTime = 0; 9 | unsigned long pkts = 0; 10 | 11 | void sniffer(uint8_t *buf, uint16_t len) { 12 | pkts++; 13 | } 14 | 15 | //===== SETUP =====// 16 | void setup() { 17 | /* start Serial */ 18 | Serial.begin(115200); 19 | 20 | /* setup wifi */ 21 | wifi_set_opmode(STATION_MODE); 22 | wifi_set_promiscuous_rx_cb(sniffer); 23 | wifi_set_channel(ch); 24 | wifi_promiscuous_enable(1); 25 | } 26 | 27 | //===== LOOP =====// 28 | void loop() { 29 | unsigned long curTime = millis(); 30 | 31 | //every second 32 | if(curTime - prevTime >= 1000){ 33 | prevTime = curTime; 34 | Serial.println((String)pkts); 35 | pkts = 0; 36 | } 37 | 38 | if(Serial.available()){ 39 | ch = Serial.readString().toInt(); 40 | if(ch < 1 || ch > 14) ch = 1; 41 | wifi_set_channel(ch); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /esp8266_packet_counter/esp8266_packet_counter_1mb.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacehuhn/packetGraph/be58b7f41e344c141ffacdbe6ff5d347bc95d426/esp8266_packet_counter/esp8266_packet_counter_1mb.bin -------------------------------------------------------------------------------- /packetGraph.py: -------------------------------------------------------------------------------- 1 | import random, time 2 | import os 3 | 4 | # VISUALIZER VARIABLES 5 | scr_height = 15 6 | scr_widht = 80 7 | allPackets = [] 8 | # IFACE SNIFFER VARIABLES 9 | ifacePackets = 0 10 | ifaceChannel = "" 11 | monitor_iface = "" 12 | stoppingIface = False 13 | sniffStarted = False 14 | sniffError = False 15 | # ESP VARTIABLES 16 | serialport = "" 17 | boardRate = 0 18 | ser = "" 19 | espChannel = 1 20 | espStarted = False 21 | stoppingEsp = False 22 | 23 | def get_multiplicator(): 24 | largestInt = 0 25 | multiplicator = 1 26 | for num in allPackets: 27 | if num > largestInt: 28 | largestInt = num 29 | if largestInt > scr_height: 30 | multiplicator = scr_height / largestInt 31 | return multiplicator 32 | 33 | def addNumber(number): 34 | global allPackets 35 | if len(allPackets) >= scr_widht: 36 | allPackets.pop(0) 37 | allPackets.append(number) 38 | return allPackets 39 | 40 | def visualize(): 41 | global allPackets 42 | global monitor_iface 43 | multiplicator = get_multiplicator() 44 | print(chr(27) + "[2J") 45 | graph = header(True) + "\n" + 80 * "-" + "\n" 46 | for index in reversed(range(1, scr_height + 1)): 47 | line = "" 48 | for num in allPackets: 49 | num *= multiplicator 50 | if num >= index: 51 | line = line + "#" 52 | else: 53 | line = line + " " 54 | graph = graph + line + "\n" 55 | graph += 80 * "-" + "\n" 56 | if sniffStarted: 57 | graph += str(allPackets[-1]) + " packets/sec - interface: " + \ 58 | str(monitor_iface) + " - channel: " + str(ifaceChannel) + "\n" 59 | elif espStarted: 60 | global ser 61 | graph += str(allPackets[-1]) + " packets/sec - connection: " + \ 62 | str(ser.name) + " - channel: " + str(espChannel) + "\n" 63 | print(graph) 64 | 65 | def showESP(): 66 | try: 67 | import serial 68 | except ImportError: 69 | print("\n[!] Package 'Pyserial' not found... Make sure to install the requirements with 'pip3 install -r requirements.txt'.") 70 | exit() 71 | canBreak = False 72 | global serialport 73 | global boardRate 74 | global ser 75 | global allPackets 76 | global espStarted 77 | global espChannel 78 | print("\n[+] Connecting to device...") 79 | while not canBreak: 80 | try: 81 | ser = serial.Serial(serialport, boardRate) 82 | canBreak = True 83 | except KeyboardInterrupt: 84 | print("\n[+] Exiting...") 85 | exit() 86 | except: 87 | print("[!] Serial connection failed... Retrying...") 88 | time.sleep(2) 89 | continue 90 | print("[+] Serial connected. Name: " + ser.name) 91 | espStarted = True 92 | ser.write(espChannel.encode()) 93 | try: 94 | while True: 95 | packet = ser.readline().decode("utf-8") 96 | packet = packet.replace("\r\n", "") 97 | try: 98 | packet = int(packet) 99 | except: 100 | print("[!] Recived corrupted serial input... Exiting...") 101 | exit() 102 | allPackets = addNumber(packet) 103 | visualize() 104 | except KeyboardInterrupt: 105 | print("\n[+] Exiting...") 106 | exit() 107 | except: 108 | print("\n[!] Serial disconnected... Exiting...") 109 | exit() 110 | 111 | def ifaceCounter(pckt): 112 | global ifacePackets 113 | ifacePackets += 1 114 | 115 | def ifaceSniffer(): 116 | import sys, logging 117 | logging.getLogger("scapy.runtime").setLevel(logging.ERROR) 118 | global sniffError 119 | try: 120 | from scapy.all import sniff 121 | except ImportError: 122 | print("\n[!] Package 'Scapy' not found... Make sure to install the requirements with 'pip3 install -r requirements.txt'.") 123 | sniffError = True 124 | sys.exit() 125 | global stoppingIface 126 | global monitor_iface 127 | global sniffStarted 128 | while True: 129 | if not stoppingIface: 130 | try: 131 | sniffStarted = True 132 | sniff(iface=monitor_iface, prn=ifaceCounter) 133 | except: 134 | sniffError = True 135 | sys.exit() 136 | else: 137 | sys.exit() 138 | 139 | def showIface(): 140 | import time, threading 141 | global allPackets 142 | global stoppingIface 143 | global ifacePackets 144 | global sniffStarted 145 | global sniffError 146 | snifferthread = threading.Thread(target=ifaceSniffer) 147 | snifferthread.daemon = True 148 | snifferthread.start() 149 | curTs = int(round(time.time() * 1000)) 150 | prevTs = int(round(time.time() * 1000)) 151 | printedLoading = False 152 | while True: 153 | try: 154 | if sniffStarted: 155 | if sniffError: 156 | print("[!] Something went wrong with the wireless interface. Exiting...") 157 | stoppingIface = True 158 | exit() 159 | curTs = int(round(time.time() * 1000)) 160 | if curTs - prevTs > 1000: 161 | prevTs = curTs 162 | allPackets = addNumber(ifacePackets) 163 | ifacePackets = 0 164 | visualize() 165 | else: 166 | if not printedLoading: 167 | print("\n[+] Starting WiFi Interface traffic visualizer...") 168 | printedLoading = True 169 | if sniffError: 170 | stoppingIface = True 171 | exit() 172 | except KeyboardInterrupt: 173 | print("\n[+] Exiting...") 174 | stoppingIface = True 175 | exit() 176 | 177 | 178 | def showDemo(): 179 | while True: 180 | number = random.randint(1, 500) 181 | allPackets = addNumber(number) 182 | visualize() 183 | time.sleep(0.1) 184 | 185 | def header(toReturn=False): 186 | header = """ 187 | __ __ ______ __ 188 | ____ ____ ______/ /_____ / /_/ ____/________ _____ / /_ 189 | / __ \/ __ `/ ___/ //_/ _ \/ __/ / __/ ___/ __ `/ __ \/ __ \\ 190 | / /_/ / /_/ / /__/ ,< / __/ /_/ /_/ / / / /_/ / /_/ / / / / 191 | / .___/\__,_/\___/_/|_|\___/\__/\____/_/ \__,_/ .___/_/ /_/ 192 | /_/ /_/ 193 | v1.0 by David Schütz (@xdavidhu) 194 | """ 195 | if toReturn: 196 | return header 197 | print(header) 198 | 199 | def menu(): 200 | print("\n\t[1] - Show traffic from ESP") 201 | print("\t[2] - Show traffic from wireless interface") 202 | print("\t[3] - Show traffic from random numbers\n") 203 | try: 204 | option = input("menu> ") 205 | except KeyboardInterrupt: 206 | print("\n[+] Exiting...") 207 | exit() 208 | if option == "1": 209 | global serialport 210 | print("\n[!] Make sure that you flashed your ESP with @Spacehuhn's code!\n\thttps://github.com/spacehuhn") 211 | try: 212 | print("\n[?] Please select a serial port (default '/dev/ttyUSB0')\n") 213 | serialportInput = input("serial-port> ") 214 | if serialportInput == "": 215 | serialport = "/dev/ttyUSB0" 216 | else: 217 | serialport = serialportInput 218 | print("[+] Serial port => '" + str(serialport) + "'") 219 | except KeyboardInterrupt: 220 | print("\n[+] Exiting...") 221 | exit() 222 | try: 223 | global boardRate 224 | canBreak = False 225 | while not canBreak: 226 | print("\n[?] Please select a baudrate (default '115200')\n") 227 | boardRateInput = input("baudrate> ") 228 | if boardRateInput == "": 229 | boardRate = 115200 230 | canBreak = True 231 | else: 232 | try: 233 | boardRate = int(boardRateInput) 234 | except KeyboardInterrupt: 235 | print("\n[+] Exiting...") 236 | exit() 237 | except Exception as e: 238 | print("\n[!] Please enter a number!") 239 | continue 240 | canBreak = True 241 | print("[+] Baudrate => '" + str(boardRate) + "'") 242 | except KeyboardInterrupt: 243 | print("\n[+] Exiting...") 244 | exit() 245 | try: 246 | global espChannel 247 | canBreak = False 248 | while not canBreak: 249 | print("\n[?] Please select which channel to use:\n") 250 | espChannelInput = input("channel> ") 251 | if espChannelInput == "": 252 | print("\n[!] Please enter a number!") 253 | continue 254 | else: 255 | try: 256 | espChannel = int(espChannelInput) 257 | espChannel = str(espChannelInput) 258 | except KeyboardInterrupt: 259 | print("\n[+] Exiting...") 260 | exit() 261 | except Exception as e: 262 | print("\n[!] Please enter a number!") 263 | continue 264 | canBreak = True 265 | print("[+] Channel => '" + str(espChannel) + "'") 266 | except KeyboardInterrupt: 267 | print("\n[+] Exiting...") 268 | exit() 269 | time.sleep(0.5) 270 | showESP() 271 | elif option == "2": 272 | global monitor_iface 273 | global ifaceChannel 274 | try: 275 | print("\n[?] Please enter the name of your WiFi interface (in monitor mode):\n") 276 | monitor_iface = input("interface> ") 277 | print("[+] Monitor interface => '" + str(monitor_iface) + "'") 278 | except KeyboardInterrupt: 279 | print("\n[+] Exiting...") 280 | exit() 281 | try: 282 | print("\n[?] Please select which channel to use:\n") 283 | ifaceChannel = input("channel> ") 284 | print("[+] Channel => '" + str(ifaceChannel) + "'") 285 | except KeyboardInterrupt: 286 | print("\n[+] Exiting...") 287 | exit() 288 | print("\n[+] Setting channel to " + str(ifaceChannel) + "...") 289 | os.system("iwconfig " + monitor_iface + " channel " + str(ifaceChannel)) 290 | time.sleep(0.5) 291 | showIface() 292 | elif option == "3": 293 | print("[+] Starting Demo visualizer...") 294 | time.sleep(0.5) 295 | showDemo() 296 | else: 297 | print("[!] Please choose a number from the list.") 298 | menu() 299 | header() 300 | menu() 301 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | scapy 2 | pyserial 3 | -------------------------------------------------------------------------------- /screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spacehuhn/packetGraph/be58b7f41e344c141ffacdbe6ff5d347bc95d426/screenshot.jpg --------------------------------------------------------------------------------