930 likes | 984 Views
Scripting Wifi Security Software Sharkfest 10 Mike Kershaw / Dragorn Aruba Networks / Kismet SHARK FEST ‘10 Stanford University June 14-17, 2010. Where We're Going. Why we'd script stuff Scripting Kismet Writing new tools Scripting LORCON Real world tools. What's the point?.
E N D
Scripting Wifi Security Software Sharkfest 10 Mike Kershaw / Dragorn Aruba Networks / Kismet SHARKFEST‘10 Stanford University June 14-17, 2010
Where We're Going Why we'd script stuff Scripting Kismet Writing new tools Scripting LORCON Real world tools
What's the point? Automation Alternate interfaces Logging Dynamic alerts Extremely fast prototype and tool development Real world securitytools (Boring, but useful) (Exciting and scary!)
Talking to Kismet Kismet is pretty easy to script But no-one seems to Actually 2 programs – kismet_server and kismet_client Talks over standard TCP And it's even a human-readable protocol, similar to IMAP
Where are you? Kismet listens to port 2501 by default Talk to it with netcat Or telnet Or any other TCP socket tools
Kismet says “Hi there” Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. *KISMET: 0.0.0 1275891833 DRD1812 tuntap 1000 *PROTOCOLS: KISMET,ERROR,ACK,PROTOCOLS,CAPABILITY,TERMINATE,TIME,PACKET,STATUS,PLUGIN,SOURCE,ALERT,BTSCANDEV,D15D4DEV,WEPKEY,STRING,GPS,BSSID,SSID,CLIENT,BSSIDSRC,CLISRC,NETTAG,CLITAG,REMOVE,CHANNEL,SPECTRUM,INFO,BATTERY,CRITFAIL *TIME: 1276050955 *TIME: 1276050956 *TIME: 1276050957
Kismet sentences Consist of a *sentence type followed by space-delimited fields Fields which contain free-form text are buffered with \001 bytes *FOO f1 f2 f3 \001f4 with spaces\001 f5
Commands Commands are !ID command parameters The ID may be incremented or repeating Kismet will include the ID in responses Useful for figuring out if a queued command completed
Assumptions about you Kismet assumes some sentences MUST be handled by the client. *KISMET, *TIME, *ERROR, *ACK, *PROTOCOLS, *CAPABILITY, *TERMINATE This doesn't mean you have to do something smart Just that you have to not fail
Umpteenth normal form Kismet protocols are vaguely like a normalized database When unknown numbers of dynamic records reference the same data, they are a separate sentence F.E. networks are stored as BSSID (primary data) and SSID (multiple SSID records indexed by BSSID)
What can you do Protocol fields are listed using the CAPABILITY command Different versions of Kismet may support different fields, your client can examine this Clients are expected to handle missing fields gracefully
Getting data Similar to SQL, ALL fields or only SPECIFIC fields can be requested Fields may be requested in any order (and will be returned in that order) Enabled via the ENABLE command Client is responsible for handling de-mux of multiple protocol requests – Kismet will only listen to the last req
Initial burst Kismet tracks things all the time Clients are only connected sometimes Non-realtime tracking records are sent in a burst when a sentence is enabled F.E. Enabling BSSID will cause Kismet to send all existing BSSID records Some protocols don't maintain history
Down by the delta Once Kismet has sent the initial burst of old data New data is sent once per second as it changes F.E. A BSSID record will be sent every second while a network is in range The client is expected to merge this cleanly with existing known data
Most useful *BSSID – Networks seen *SSID – Network SSID records *CLIENT – Wireless client records *GPS – (Obviously) GPS records *ALERT – Alerts / IDS functions
Cheap ways to talk `netcat' Bash Sed Incomprensible but easy
Talking with bash echo -e '\n!0 enable channel channel,packets' | nc localhost 2501 | awk 'BEGIN { CHN = 0; }; /CHANNEL:/ { chnum[CHN]=$2; chval[CHN]=$3; CHN=CHN+1; }; /TIME/ { if (CHN != 0) { printf("["); for (x = 0; x < CHN; x++) { printf("{\"id\":%s,\"value\":%s}", chnum[x], chval[x]); if (x < (CHN-1)) printf(",") } printf("]\n"); CHN=0; fflush(""); } };'
Breaking it down echo -e '\n!0 enable channel channel,packets' Send a command to enable the CHANNEL sentence, with the fields 'channel' and 'packets'
Breaking it down nc localhost 2501 Netcat is a great tool for talking to tcp (or UDP) network hosts from scripts
Breaking it down awk 'BEGIN { CHN = 0; }; /CHANNEL:/ { chnum[CHN]=$2; chval[CHN]=$3; CHN=CHN+1; }; /TIME/ { if (CHN != 0) … Awk is a book in itself, but we begin by setting the # of channels to 0, then when we get the CHANNEL sentence recording it to an array When we get the TIME sentence we know we've gotten all the channels, so we output it
Breaking it down printf("["); for (x = 0; x < CHN; x++) { printf("{\"id\":%s,\"value\":%s}", chnum[x], chval[x]); if (x < (CHN-1)) printf(",") } printf("]\n"); CHN=0; fflush(""); } };' More awk nastiness, basically just iterates through our array of channels and prints them At the end, flush the output
The result [{"id":1,"value":75202},{"id":2,"value":28589},{"id":3,"value":8613},{"id":4,"value":6042},{"id":5,"value":9890},{"id":6,"value":27937},{"id":7,"value":19615},{"id":8,"value":8644},{"id":9,"value":761895},{"id":10,"value":27690},{"id":11,"value":47546},{"id":48,"value":15994},{"id":149,"value":1322071},{"id":165,"value":1},{"id":28928,"value":1617419}] Kismet TCP socket to JSON for an AJAX channel display in 1 line of shell!
How it works Kismet sends the TIME sentence once per second, so we can use it for timing We know if we see a TIME sentence, we've gotten all the channels Kismet knows about Normally we'd index by channel #, but this is hard in awk, so we cheat
More intuitive Ruby interface to Kismet People seem to like Ruby. I'm not sure I do If you don't, it's easy to port this to perl, python, etc – patches welcome! Committed to SVN already with examples
Basic API setup Require 'kismet' Standard Ruby module Kis = Kismet.new(host, port) Defaults to localhost, 2501 Kis.connect Kis.run Connect and run as thread
Subscribing Kismet.rb allows subscribing to sentences with callbacks Callbacks called with a dictionary of fields returned Secondary callbacks when a command completes (more on this soon)
Subscription kis.subscribe("bssid", ["bssid", "manuf", "channel"], Proc.new {|*args| bssidcb(*args)}) Subscribe to a sentence (“bssid”) with a list of fields, and a callback Ruby doesn't do function passing per se, so we use Proc to make a passable block. Bssidcb is our callback function
Callback def bssidcb(proto, fields) puts "Kismet saw network #{fields['bssid']} manuf #{fields['manuf']} on channel #{fields['channel']}" end Callback function with sentence and fields Fields in hash indexed by name
Ack callbacks Called when command completes When requesting a sentence with historical data, Kismet sends the historical data, then the ACK We can use this to trigger that we've gotten the complete current state It's a bit of a kluge but...
Ack to die def bssiddiecb(text) $k.kill exit end Ack-cb just calls “exit” - we only want to list the networks we've seen so far
Keep on trucking Kismet.rb runs the network code in a separate thread To keep running with subscribed callbacks, call the 'wait' function Will wait for the Kismet session to end (either naturally or via a kill command elsewhere)
What we've made easy Kismet to Syslog bridge (subscribe to ALERT and use Ruby logger) Kismet to JSON Programmatic handling of rogue networks Pretty much any arbitrary use of Kismet data
LORCON Loss Of Radio CONtrol Writing the same code for different drivers sucks Writing the same code for different platforms sucks Hopefully LORCON doesn't suck
LORCON2 Unfortunately, LORCON kind of sucked LORCON2 API much cleaner Designed to match the libpcap API Really easy to use C, Ruby API, Python under development http://802.11ninja.net
Super simple Automatically determines the type of card Automatically creates injection VAPs Supports sniff, inject, or sniff+inject where possible Send arbitrary bytes OR use the packet assembly API
It's even easy in C lorcon_driver_t *dri; lorcon_t *ctx; uint8_t packet[...]; dri = lorcon_auto_driver(“wlan0”); ctx = lorcon_create(“wlan0”, dri); lorcon_open_injmon(ctx); lorcon_set_channel(ctx, 6); lorcon_send_bytes(ctx, sizeof(packet), packet);
And it comes with ruby require "Lorcon2" pp Lorcon.version pp Lorcon.drivers pp Lorcon.find_driver("mac80211") pp Lorcon.auto_driver(“wlan0”) tx = Lorcon::Device.new(intf) tx.openinjmon()
Goal: Simplicity There's a lot of weird modes you can put a card in Most of the time you just want inject+monitor Most of the time you just want to send bytes And it'd be nice if it worked like pcap
Pcap + Lorcon def safe_loop(wifi) @q = Queue.new reader = Thread.new do wifi.each_packet {|pkt| @q << pkt } end Some TLC needed (see test.rb in Lorcon) but we integrate with each_packet
Simple in C, too void apitest_packet_hdlr(lorcon_t *context, lorcon_packet_t *packet, u_char *user) { ... } dri = lorcon_auto_driver(interface); ctx = lorcon_create(interface, dri) lorcon_open_injmon(ctx) lorcon_loop(ctx, 0, apitest_packet_hdlr, NULL);
Modeled on pcap_loop Lorcon handles pcap internals (if you want it to) lorcon_loop calls the provided function for each packet Easy access to dot3 via lorcon_packet_to_dot3
Building packets In Ruby, Racket handles most of the packet assembly duties There are other packet builders too But a lot of them are REALLY REALLY slow Orders of magnitude slower No great dot11 generator, but Lorcon can translate dot3 automatically
Racket L2 – Looks like ether response = Racket.new response.l2 = Ethernet.new("01234567890123") response.l2.dst_mac = eth.src_mac response.l2.src_mac = eth.dst_mac response.l2.ethertype = 0x0800
Racket L3 response.l3 = IPv4.new response.l3.src_ip = ip.dst_ip response.l3.dst_ip = ip.src_ip response.l3.protocol = ip.protocol response.l3.ttl = ip.ttl
+ Lorcon injpkt = Lorcon::Packet.new() injpkt.dot3 = response.pack injpkt.bssid = pkt.bssid injpkt.direction = Lorcon::Packet::LORCON_FROM_DS; tx.inject(injpkt) or puts "Failed to inject: " + tx.error
Lorcon Packet Forge Packet assembly made easy for 802.11 Uses a linked list of temporary data Packets can be manipulated/appended at will Exported into an array for transmit
LCPF notes Lcpa_foo – Lorcon Packet Assembly, basic functions for manipulating packets Lcpf_foo – Lorcon Packet Forge, packet creation