SHARKFEST ‘10 | Stanford University | June 14–17, 2010 Scripting Wifi Security Software...

Preview:

Citation preview

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Scripting Wifi Security SoftwareSharkfest 10

Mike Kershaw / DragornAruba Networks / Kismet

SHARKFEST ‘10Stanford UniversityJune 14-17, 2010

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Where We're Going

Why we'd script stuffScripting KismetWriting new toolsScripting LORCONReal world tools

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

What's the point?

AutomationAlternate interfacesLoggingDynamic alertsExtremely fast prototype and tool developmentReal world security

tools

(Boring, but useful)

(Exciting and scary!)

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Kismet

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Talking to Kismet

Kismet is pretty easy to scriptBut no-one seems toActually 2 programs – kismet_server and

kismet_clientTalks over standard TCPAnd it's even a human-readable protocol, similar

to IMAP

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Where are you?

Kismet listens to port 2501 by defaultTalk to it with netcatOr telnetOr any other TCP socket tools

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Commands

Commands are !ID command parametersThe ID may be incremented or repeatingKismet will include the ID in responsesUseful for figuring out if a queued command

completed

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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)

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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 commandClient is responsible for handling de-mux of

multiple protocol requests – Kismet will only listen to the last req

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Initial burst

Kismet tracks things all the timeClients are only connected sometimesNon-realtime tracking records are sent in a burst

when a sentence is enabledF.E. Enabling BSSID will cause Kismet to send all

existing BSSID recordsSome protocols don't maintain history

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Down by the delta

Once Kismet has sent the initial burst of old dataNew data is sent once per second as it changesF.E. A BSSID record will be sent every second

while a network is in rangeThe client is expected to merge this cleanly with

existing known data

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Most useful

*BSSID – Networks seen*SSID – Network SSID records*CLIENT – Wireless client records*GPS – (Obviously) GPS records*ALERT – Alerts / IDS functions

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Cheap ways to talk

`netcat'BashSed

Incomprensible but easy

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Talking with bashecho -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(""); } };'

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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'

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Breaking it down

nc localhost 2501

Netcat is a great tool for talking to tcp (or UDP) network hosts from scripts

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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!

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

More intuitive

Ruby interface to KismetPeople seem to like Ruby. I'm not sure I doIf you don't, it's easy to port this to perl, python,

etc – patches welcome!Committed to SVN already with examples

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Basic API setup

Require 'kismet'

Standard Ruby moduleKis = Kismet.new(host, port)

Defaults to localhost, 2501Kis.connect

Kis.run

Connect and run as thread

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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)

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Callback

def bssidcb(proto, fields)

puts "Kismet saw network #{fields['bssid']} manuf #{fields['manuf']} on channel #{fields['channel']}"

end

Callback function with sentence and fieldsFields in hash indexed by name

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Ack callbacks

Called when command completesWhen 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...

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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)

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

What we've made easy

Kismet to Syslog bridge (subscribe to ALERT and use Ruby logger)

Kismet to JSONProgrammatic handling of rogue networksPretty much any arbitrary use of Kismet data

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

LORCON

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

LORCON

Loss Of Radio CONtrolWriting the same code for different drivers sucksWriting the same code for different platforms

sucksHopefully LORCON doesn't suck

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

LORCON2

Unfortunately, LORCON kind of suckedLORCON2 API much cleanerDesigned to match the libpcap APIReally easy to useC, Ruby API, Python under developmenthttp://802.11ninja.net

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Super simple

Automatically determines the type of cardAutomatically creates injection VAPsSupports sniff, inject, or sniff+inject where

possibleSend arbitrary bytes OR use the packet assembly

API

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

It's even easy in Clorcon_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);

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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()

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Goal: Simplicity

There's a lot of weird modes you can put a card in

Most of the time you just want inject+monitorMost of the time you just want to send bytesAnd it'd be nice if it worked like pcap

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

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);

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Modeled on pcap_loop

Lorcon handles pcap internals (if you want it to)lorcon_loop calls the provided function for each

packetEasy access to dot3 via lorcon_packet_to_dot3

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Building packets

In Ruby, Racket handles most of the packet assembly duties

There are other packet builders tooBut a lot of them are REALLY REALLY slowOrders of magnitude slowerNo great dot11 generator, but Lorcon can

translate dot3 automatically

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Racket L2 – Looks like etherresponse = 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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Racket L3response.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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

+ 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

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Lorcon Packet Forge

Packet assembly made easy for 802.11Uses a linked list of temporary dataPackets can be manipulated/appended at willExported into an array for transmit

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

LCPF notes

Lcpa_foo – Lorcon Packet Assembly, basic functions for manipulating packets

Lcpf_foo – Lorcon Packet Forge, packet creation

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Building with LCPFmetapack = lcpa_init();

tx80211_initpacket(&txpack);

lcpf_randmac(sourcemac, 1);

lcpf_randmac(bssidmac, 1);

lcpf_80211headers(metapack, WLAN_FC_TYPE_DATA, WLAN_FC_SUBTYPE_DATANULL, 0x02, /* fcflags, FromDS */ 0x00, /* duration */, targetmac, bssidmac, sourcemac, NULL, /* addr4 */ 0, /* Fragment number */, 0); /* Sequence number */

lcpa_freeze(metapack, &txpack);

stuff();

lcpa_free(metapack);

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

What can we do now?

Kismet + Lorcon + RubySelective interaction with networks“Aggresssive” IDS attacking rogue networks in

your building“Renderman friendly network decloak” … Send a

probe req to a SSID w/ suspected names, let Kismet decloak response

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Putting it in the real world(AKA “the fun part of the talk”)

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Putting this in the real world

Not a bunch of teenagers on MTVAlready part of MetasploitLORCON + Ruby + MSF220 lines of codeAll scripting code (native Ruby)

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

The inspiration

Wifi session hijackingAbout 5 years ago, Airpwn was debuted by Toast

at DefconTCP stream hijacking on 802.11Everyone forgot about this...Not just for shock porn!

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Corps of Engineers

Rerouting TCP streams“Ye Olde” 1990 shared media attackTCP is only “secure” against hijacking because

the seq/ack numbers are randomI see your seq/ack over wireless

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Anatomy of a Session

Handshake (syn/synack/ack)Client-> Server

“GET /foo HTTP/1.0”Seq 123 Ack 0

Server-> Client“HTTP headers, content”Seq 10 ack 189

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

What it takes

Lets add this to MSFLORCON + Lorcon-Ruby wrapperRacket (Ruby packet creator)Ruby-PCAPA little TLC

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

An evil session

HandshakeClient->Server (GET)MSF <-Client (Hijack data)MSF <-Client (FIN!)Server <-Client (Real data, ignored)

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

In action

msf > use auxiliary/spoof/wifi/airpwn

msf auxiliary(airpwn) > set INTERFACE alfa0

INTERFACE => alfa0

msf auxiliary(airpwn) > set RESPONSE "Airpwn - MSF!"

RESPONSE => Airpwn – MSF!

msf auxiliary(airpwn) > run

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Results

msf auxiliary(airpwn) > run

[*] AIRPWN: Response packet has no HTTP headers, creating some.

[*] Auxiliary module execution completed

msf auxiliary(airpwn) >

[*] AIRPWN: 10.10.100.42 -> 208.127.144.14 HTTP GET [/files/racket/src/doc/] TCP SEQ 542050816

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

And because it's Ruby

Fine tuning in YAMLRegex matchingDynamic content generationFile injection or fragment in runtime

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Step 3: Profit

What does all this get us?

Arbitrary HTTP content replacement

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Or in other words

Full control of the DOMControl over formsControl over the browser environmentAccess to anything in the security context of the

hijacked website

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Obviously scripted

So we can replace contentBig deal, what now?Nearly every web-2.0-y site uses gobs of

background javascriptWhat happens if we replace one of those?

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

It's not news, it's JS

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Fragments of JS

Especially attractive as a targetTotally invisible to the userMultiple requests = multiple opportunies to land

attackRun in same privilege domain as web page

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

I'm in your browser

… Rewriting your DOMDOM – Document Object ModelProgrammatic representation of page contentOnce we're in the DOM we can anything

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

It's not stupid, it's advanced

var embeds = document.getElementsByTagName('div');

for(var i=0; i < embeds.length; i++){ if (embeds[i].getAttribute("class") == "cnnT1Img") { embeds[i].innerHTML = "..."; } else if (embeds[i].getAttribute("class") == "cnnT1Txt") { embeds[i].innerHTML = "..."; }}

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

DOM is tasty

What other mischief can we do?Rewrite all forms to proxy through a loggerRewrite all HTTPS to HTTPPoison content topical to a conference?

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

HTTP, not so S

var refs = document.getElementsByTagName('a');

for (var i = 0; i < refs.length; i++){

var rval = refs[i].getAttribute("href");

if (rval == null) { continue; }

refs[i].setAttribute("href", rval.replace(/^https:/, "http:");

}

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

This really matters

This matters

Like, a lot

No, seriously

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Persistence pays off

Who has read rsnakes VPN paper?

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Quick cache

Short version:Browsers have cacheCache sticks aroundUsers don't noticeWhen I own your TCP session I own your cache

control

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

In control

Client fed spiked JS fileMalicious contentCache headers say “keep for 10 years”Malicious file is re-used every time they revisit

the siteFrom inside their company network!

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Don't think it's a problem?

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

What can we do now?

User has spiked, cached fileBrowser will re-use itIframe attacks? Kaminsky socket/sucket? New

browser exploits?But a user would NEVER go to twitter at work,

right?

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Poison the well

How many sites use Analytics?Loading urchin.js from the same url?And what happens if we poison that URL?For every site loading it

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Calling home to Mom

Cache modified JS that loads content from an attacker-controlled server

Maybe no good browser vulns this week?Wait for a browser 0day then flip the switchEveryone w/ cached callbacks gets owned

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

There are no innocents

No website is “innocent”Websites that don't ask for logins are just as

capable as feeding the browser exploitsAny website can have browser-owning code

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Well aren't you clever

I'm smart!I use a VPN!

-or-I force my users to use a VPN via UACThis won't work against me!

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Yeah, but...

Yeah, it wouldn't work...Except your browser has no concept of security

domainsSomething cached in an insecure domain...Is still cached in a secure domain!

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

“Click OK to agree”

Many hotspots have a landing page to agree to EULA

Many landing pages are not encryptedUnencrypted page on an open network? Perfect

targetNow we can feed the user pre-VPN content

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Magic (h)8 ball

If the attacker controls your pre-vpn landing page

They control your browserThey control what gets loadedIframes? Pop-unders? AJAX?

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Americas top 40

Attacker hijacks VPN landing pageInjects code to load things over AJAXLoads the top 40 pages the victim may be likely

to visit in the backgroundCache-poison page requested in the background

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Smarter JS

Attacker can examine fetched contentIf poison code not present...Request it again!We will load your websiteAnd hit it with a brickWe will not run out of bricks

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Frequent landings

Take it one step furtherVPN can access internal pages too, right?We control L2, right?Soo....

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Dumb Network Stuff

Can we use LORCON to attack other protocols?Sure can!Racing DNS isn't hardCapture query, set QR bit, supply our own

response

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Your intranet is showing

We control DNSWe control page queryWe can be sure a request went throughWhat stops us guessing pages like

http://intranet/ ?

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Hint: Nothing

Nothing!How about some JS that loads the original

intranet content...Then crawls the DOM and ships it all off to the

attacker via POST?Or rewrites your form DOMs to proxy out?

SHARKFEST ‘10 | Stanford University | June 14–17, 2010

Summary

Kismet is easy to talk toLORCON is easy to write forOpen wifi is terrifying

http://www.kismetwireless.nethttp://802.11ninja.net