Commit 21775020 authored by Sophie Brun's avatar Sophie Brun

Merge tag 'upstream/1.5.9' into kali/master

Upstream version 1.5.9
parents 5e9ecdd9 05f92cef
......@@ -5,15 +5,15 @@
Gem::Specification.new do |s|
s.name = "bettercap"
s.version = "1.5.8"
s.version = "1.5.9"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Simone Margaritelli"]
s.date = "2016-08-26"
s.date = "2016-12-14"
s.description = "BetterCap is the state of the art, modular, portable and easily extensible MITM framework featuring ARP, DNS and ICMP spoofing, sslstripping, credentials harvesting and more."
s.email = "evilsocket@gmail.com"
s.executables = ["bettercap"]
s.files = ["LICENSE.md", "README.md", "bin/bettercap", "lib/bettercap.rb", "lib/bettercap/banner", "lib/bettercap/context.rb", "lib/bettercap/discovery/agents/arp.rb", "lib/bettercap/discovery/agents/base.rb", "lib/bettercap/discovery/agents/icmp.rb", "lib/bettercap/discovery/agents/udp.rb", "lib/bettercap/discovery/thread.rb", "lib/bettercap/error.rb", "lib/bettercap/firewalls/base.rb", "lib/bettercap/firewalls/bsd.rb", "lib/bettercap/firewalls/linux.rb", "lib/bettercap/firewalls/redirection.rb", "lib/bettercap/loader.rb", "lib/bettercap/logger.rb", "lib/bettercap/memory.rb", "lib/bettercap/monkey/celluloid/actor.rb", "lib/bettercap/monkey/celluloid/io/udp_socket.rb", "lib/bettercap/monkey/em-proxy/proxy.rb", "lib/bettercap/monkey/openssl/server.rb", "lib/bettercap/monkey/packetfu/pcap.rb", "lib/bettercap/monkey/packetfu/utils.rb", "lib/bettercap/monkey/system.rb", "lib/bettercap/network/arp_reader.rb", "lib/bettercap/network/hw-prefixes", "lib/bettercap/network/network.rb", "lib/bettercap/network/packet_queue.rb", "lib/bettercap/network/protos/base.rb", "lib/bettercap/network/protos/dhcp.rb", "lib/bettercap/network/protos/mysql.rb", "lib/bettercap/network/protos/ntlm.rb", "lib/bettercap/network/protos/snmp.rb", "lib/bettercap/network/protos/teamviewer.rb", "lib/bettercap/network/servers/dnsd.rb", "lib/bettercap/network/servers/httpd.rb", "lib/bettercap/network/services", "lib/bettercap/network/target.rb", "lib/bettercap/network/validator.rb", "lib/bettercap/options/core_options.rb", "lib/bettercap/options/options.rb", "lib/bettercap/options/proxy_options.rb", "lib/bettercap/options/server_options.rb", "lib/bettercap/options/sniff_options.rb", "lib/bettercap/options/spoof_options.rb", "lib/bettercap/pluggable.rb", "lib/bettercap/proxy/http/module.rb", "lib/bettercap/proxy/http/modules/injectcss.rb", "lib/bettercap/proxy/http/modules/injecthtml.rb", "lib/bettercap/proxy/http/modules/injectjs.rb", "lib/bettercap/proxy/http/proxy.rb", "lib/bettercap/proxy/http/request.rb", "lib/bettercap/proxy/http/response.rb", "lib/bettercap/proxy/http/ssl/authority.rb", "lib/bettercap/proxy/http/ssl/bettercap-ca.pem", "lib/bettercap/proxy/http/ssl/server.rb", "lib/bettercap/proxy/http/sslstrip/cookiemonitor.rb", "lib/bettercap/proxy/http/sslstrip/lock.ico", "lib/bettercap/proxy/http/sslstrip/strip.rb", "lib/bettercap/proxy/http/streamer.rb", "lib/bettercap/proxy/stream_logger.rb", "lib/bettercap/proxy/tcp/module.rb", "lib/bettercap/proxy/tcp/proxy.rb", "lib/bettercap/proxy/thread_pool.rb", "lib/bettercap/shell.rb", "lib/bettercap/sniffer/parsers/base.rb", "lib/bettercap/sniffer/parsers/cookie.rb", "lib/bettercap/sniffer/parsers/creditcard.rb", "lib/bettercap/sniffer/parsers/custom.rb", "lib/bettercap/sniffer/parsers/dhcp.rb", "lib/bettercap/sniffer/parsers/dict.rb", "lib/bettercap/sniffer/parsers/ftp.rb", "lib/bettercap/sniffer/parsers/httpauth.rb", "lib/bettercap/sniffer/parsers/https.rb", "lib/bettercap/sniffer/parsers/irc.rb", "lib/bettercap/sniffer/parsers/mail.rb", "lib/bettercap/sniffer/parsers/mpd.rb", "lib/bettercap/sniffer/parsers/mysql.rb", "lib/bettercap/sniffer/parsers/nntp.rb", "lib/bettercap/sniffer/parsers/ntlmss.rb", "lib/bettercap/sniffer/parsers/pgsql.rb", "lib/bettercap/sniffer/parsers/post.rb", "lib/bettercap/sniffer/parsers/redis.rb", "lib/bettercap/sniffer/parsers/rlogin.rb", "lib/bettercap/sniffer/parsers/snmp.rb", "lib/bettercap/sniffer/parsers/snpp.rb", "lib/bettercap/sniffer/parsers/teamviewer.rb", "lib/bettercap/sniffer/parsers/url.rb", "lib/bettercap/sniffer/parsers/whatsapp.rb", "lib/bettercap/sniffer/sniffer.rb", "lib/bettercap/spoofers/arp.rb", "lib/bettercap/spoofers/base.rb", "lib/bettercap/spoofers/icmp.rb", "lib/bettercap/spoofers/none.rb", "lib/bettercap/update_checker.rb", "lib/bettercap/version.rb"]
s.files = ["LICENSE.md", "README.md", "bin/bettercap", "lib/bettercap.rb", "lib/bettercap/banner", "lib/bettercap/context.rb", "lib/bettercap/discovery/agents/arp.rb", "lib/bettercap/discovery/agents/base.rb", "lib/bettercap/discovery/agents/icmp.rb", "lib/bettercap/discovery/agents/udp.rb", "lib/bettercap/discovery/thread.rb", "lib/bettercap/error.rb", "lib/bettercap/firewalls/base.rb", "lib/bettercap/firewalls/bsd.rb", "lib/bettercap/firewalls/linux.rb", "lib/bettercap/firewalls/redirection.rb", "lib/bettercap/loader.rb", "lib/bettercap/logger.rb", "lib/bettercap/memory.rb", "lib/bettercap/monkey/celluloid/actor.rb", "lib/bettercap/monkey/celluloid/io/udp_socket.rb", "lib/bettercap/monkey/em-proxy/proxy.rb", "lib/bettercap/monkey/openssl/server.rb", "lib/bettercap/monkey/packetfu/pcap.rb", "lib/bettercap/monkey/packetfu/utils.rb", "lib/bettercap/monkey/system.rb", "lib/bettercap/network/arp_reader.rb", "lib/bettercap/network/hw-prefixes", "lib/bettercap/network/network.rb", "lib/bettercap/network/packet_queue.rb", "lib/bettercap/network/protos/base.rb", "lib/bettercap/network/protos/dhcp.rb", "lib/bettercap/network/protos/mysql.rb", "lib/bettercap/network/protos/ntlm.rb", "lib/bettercap/network/protos/snmp.rb", "lib/bettercap/network/protos/teamviewer.rb", "lib/bettercap/network/servers/dnsd.rb", "lib/bettercap/network/servers/httpd.rb", "lib/bettercap/network/services", "lib/bettercap/network/target.rb", "lib/bettercap/network/validator.rb", "lib/bettercap/options/core_options.rb", "lib/bettercap/options/options.rb", "lib/bettercap/options/proxy_options.rb", "lib/bettercap/options/server_options.rb", "lib/bettercap/options/sniff_options.rb", "lib/bettercap/options/spoof_options.rb", "lib/bettercap/pluggable.rb", "lib/bettercap/proxy/http/module.rb", "lib/bettercap/proxy/http/modules/injectcss.rb", "lib/bettercap/proxy/http/modules/injecthtml.rb", "lib/bettercap/proxy/http/modules/injectjs.rb", "lib/bettercap/proxy/http/modules/redirect.rb", "lib/bettercap/proxy/http/proxy.rb", "lib/bettercap/proxy/http/request.rb", "lib/bettercap/proxy/http/response.rb", "lib/bettercap/proxy/http/ssl/authority.rb", "lib/bettercap/proxy/http/ssl/bettercap-ca.pem", "lib/bettercap/proxy/http/ssl/server.rb", "lib/bettercap/proxy/http/sslstrip/cookiemonitor.rb", "lib/bettercap/proxy/http/sslstrip/lock.ico", "lib/bettercap/proxy/http/sslstrip/strip.rb", "lib/bettercap/proxy/http/streamer.rb", "lib/bettercap/proxy/stream_logger.rb", "lib/bettercap/proxy/tcp/module.rb", "lib/bettercap/proxy/tcp/proxy.rb", "lib/bettercap/proxy/thread_pool.rb", "lib/bettercap/shell.rb", "lib/bettercap/sniffer/parsers/base.rb", "lib/bettercap/sniffer/parsers/cookie.rb", "lib/bettercap/sniffer/parsers/custom.rb", "lib/bettercap/sniffer/parsers/dhcp.rb", "lib/bettercap/sniffer/parsers/dict.rb", "lib/bettercap/sniffer/parsers/ftp.rb", "lib/bettercap/sniffer/parsers/httpauth.rb", "lib/bettercap/sniffer/parsers/https.rb", "lib/bettercap/sniffer/parsers/irc.rb", "lib/bettercap/sniffer/parsers/mail.rb", "lib/bettercap/sniffer/parsers/mpd.rb", "lib/bettercap/sniffer/parsers/mysql.rb", "lib/bettercap/sniffer/parsers/nntp.rb", "lib/bettercap/sniffer/parsers/ntlmss.rb", "lib/bettercap/sniffer/parsers/pgsql.rb", "lib/bettercap/sniffer/parsers/post.rb", "lib/bettercap/sniffer/parsers/redis.rb", "lib/bettercap/sniffer/parsers/rlogin.rb", "lib/bettercap/sniffer/parsers/snmp.rb", "lib/bettercap/sniffer/parsers/snpp.rb", "lib/bettercap/sniffer/parsers/teamviewer.rb", "lib/bettercap/sniffer/parsers/url.rb", "lib/bettercap/sniffer/parsers/whatsapp.rb", "lib/bettercap/sniffer/sniffer.rb", "lib/bettercap/spoofers/arp.rb", "lib/bettercap/spoofers/base.rb", "lib/bettercap/spoofers/icmp.rb", "lib/bettercap/spoofers/none.rb", "lib/bettercap/update_checker.rb", "lib/bettercap/version.rb"]
s.homepage = "http://github.com/evilsocket/bettercap"
s.licenses = ["GPL-3.0"]
s.rdoc_options = ["--charset=UTF-8"]
......
......@@ -13,6 +13,9 @@
=end
# Ensure bettercap is running with root privileges.
abort 'This software must run as root.' unless Process.uid.zero?
require 'bettercap'
begin
......
......@@ -17,52 +17,41 @@
Encoding.default_external = Encoding::UTF_8
Encoding.default_internal = Encoding::UTF_8
require 'base64'
require 'packetfu'
require 'em-proxy'
require 'webrick'
require 'rubydns'
require 'colorize'
require 'digest'
require 'ipaddr'
require 'json'
require 'net/dns'
require 'net/http'
require 'openssl'
require 'optparse'
require 'packetfu'
require 'pcaprub'
require 'resolv'
require 'rubydns'
require 'socket'
require 'stringio'
require 'thread'
require 'uri'
require 'webrick'
require 'zlib'
require 'em-proxy'
Object.send :remove_const, :Config rescue nil
Config = RbConfig
def bettercap_autoload( path = '' )
def bettercap_autoload(path = '')
dir = File.dirname(__FILE__) + "/bettercap/#{path}"
deps = []
files = []
monkey = []
Dir[dir+"**/*.rb"].each do |filename|
filename = filename.gsub( dir, '' ).gsub('.rb', '')
Dir[dir + '**/*.rb'].each do |filename|
filename = filename.gsub(dir, '').gsub('.rb', '')
filename = "bettercap/#{path}#{filename}"
next if filename.include?('proxy/http/modules')
# Proxy modules must be loaded at runtime.
unless filename =~ /.+\/inject[a-z]+$/i
if filename.end_with?('/base') or filename.include?('pluggable')
deps << filename
elsif filename.include?('monkey')
monkey << filename
else
files << filename
end
if filename.end_with?('/base') || filename.include?('pluggable')
deps << filename
elsif filename.include?('monkey')
monkey << filename
else
files << filename
end
end
( deps + files + monkey ).each do |file|
(deps + files + monkey).each do |file|
require file
end
end
......
......@@ -40,8 +40,8 @@ class Context
attr_reader :timeout
# Instance of BetterCap::PacketQueue.
attr_reader :packets
# Instance of BetterCap::Memory.
attr_reader :memory
# Precomputed list of possible addresses on the current network.
attr_reader :endpoints
@@instance = nil
......@@ -65,7 +65,6 @@ class Context
@options = Options.new iface
@discovery = Discovery::Thread.new self
@firewall = Firewalls::Base.get
@memory = Memory.new
@iface = nil
@original_mac = nil
@gateway = nil
......@@ -76,6 +75,7 @@ class Context
@proxies = []
@redirections = []
@packets = nil
@endpoints = []
end
# Update the Context state parsing network related informations.
......@@ -105,6 +105,8 @@ class Context
@gateway = Network::Target.new gw
@targets = @options.core.targets unless @options.core.targets.nil?
@iface = Network::Target.new( cfg[:ip_saddr], cfg[:eth_saddr], cfg[:ip4_obj], cfg[:iface] )
raise BetterCap::Error, "Could not determine MAC address of '#{@options.core.iface}', make sure this interface "\
'is active and connected.' unless Network::Validator::is_mac?(@iface.mac)
Logger.info "[#{@iface.name.green}] #{@iface.to_s(false)}"
......@@ -117,6 +119,21 @@ class Context
@packets = Network::PacketQueue.new( @iface.name, @options.core.packet_throttle, 4 )
# Spoofers need the context network data to be initialized.
@spoofer = @options.spoof.parse_spoofers
if @options.core.discovery?
tstart = Time.now
Logger.info "[#{'DISCOVERY'.green}] Precomputing list of possible endpoints, this could take a while depending on your subnet ..."
net = ip = @iface.network
# loop each ip in our subnet and push it to the queue
while net.include?ip
if ip != @gateway.ip and ip != @iface.ip
@endpoints << ip
end
ip = ip.succ
end
tend = Time.now
Logger.info "[#{'DISCOVERY'.green}] Done in #{(tend - tstart) * 1000.0} ms"
end
end
# Find a target given its +ip+ and +mac+ addresses inside the #targets
......
......@@ -24,13 +24,8 @@ class Base
@address = address
if @address.nil?
net = ip = @ctx.iface.network
# loop each ip in our subnet and push it to the queue
while net.include?ip
unless skip_address?(ip)
@ctx.packets.push( get_probe(ip) )
end
ip = ip.succ
@ctx.endpoints.each do |ip|
@ctx.packets.push( get_probe(ip) )
end
else
if skip_address?(@address)
......@@ -46,21 +41,11 @@ class Base
# Return true if +ip+ must be skipped during discovery, otherwise false.
def skip_address?(ip)
# don't send probes to the gateway if we already have its MAC.
if ip == @ctx.gateway.ip
return !@ctx.gateway.mac.nil?
# don't send probes to our device
elsif ip == @ctx.iface.ip
return true
# don't stress endpoints we already discovered
else
target = @ctx.find_target( ip.to_s, nil )
# known target?
return false if target.nil?
# do we still need to get the mac for this target?
return ( target.mac.nil?? false : true )
end
target = @ctx.find_target( ip.to_s, nil )
# known target?
return false if target.nil?
# do we still need to get the mac for this target?
return ( target.mac.nil?? false : true )
end
# Each Discovery::Agent::Base derived class should implement this method.
......
......@@ -119,7 +119,6 @@ class Thread
prev = @ctx.targets
@ctx.memory.optimize!
sleep(1) if @ctx.options.core.discovery?
end
end
......
......@@ -70,7 +70,7 @@ module Logger
# Log a +message+ as it is.
def raw(message)
@@queue.push( formatted_message( message, nil ) )
@@queue.push( formatted_message( message, nil ) ) unless @@silent
end
# Wait for the messages queue to be empty.
......
......@@ -44,7 +44,6 @@ class PacketQueue
# Push a packet to the queue.
def push(packet)
@queue.push(packet)
@ctx.memory.optimize! if ( @queue.size == 1 )
end
# Wait for the packet queue to be empty.
......
......@@ -157,7 +157,7 @@ class Options
'https-proxy' => ( @proxies.proxy_https ? on : off ),
'sslstrip' => ( @proxies.sslstrip? ? on : off ),
'http-server' => ( @servers.httpd ? on : off ),
'dns-server' => ( @proxies.sslstrip? or @servers.dnsd ? on : off )
'dns-server' => ( (@proxies.sslstrip? or @servers.dnsd) ? on : off )
}
msg = "Starting [ "
......@@ -167,9 +167,6 @@ class Options
msg += "] ...\n\n"
Logger.info msg
Logger.warn "You are running an unstable/beta version of this software, please" \
" update to a stable one if available." if BetterCap::VERSION =~ /[\d\.+]b/
end
end
end
......@@ -38,6 +38,8 @@ class ProxyOptions
attr_accessor :allow_local_connections
# If true, log HTTP responses too.
attr_accessor :log_response
# If true, suppress HTTP requests logs.
attr_accessor :no_http_logs
# If true, TCP proxy will be enabled.
attr_accessor :tcp_proxy
# TCP proxy local port.
......@@ -72,6 +74,7 @@ class ProxyOptions
@sslstrip = true
@allow_local_connections = false
@log_response = false
@no_http_logs = false
@tcp_proxy = false
@tcp_proxy_port = 2222
......@@ -103,7 +106,7 @@ class ProxyOptions
opts.on( '--tcp-proxy-module MODULE', "Ruby TCP proxy module to load." ) do |v|
@tcp_proxy_module = File.expand_path(v)
Proxy::TCP::Module.load( @tcp_proxy_module )
Proxy::TCP::Module.load( @tcp_proxy_module, opts )
end
opts.on( '--tcp-proxy-port PORT', "Set local TCP proxy port, default to #{@tcp_proxy_port.to_s.yellow} ." ) do |v|
......@@ -167,6 +170,10 @@ class ProxyOptions
@log_response = true
end
opts.on( '--no-http-logs', 'Suppress HTTP requests and responses logs.' ) do
@no_http_logs = true
end
opts.on( '--proxy-module MODULE', "Ruby proxy module to load, either a custom file or one of the following: #{Proxy::HTTP::Module.available.map{|x| x.yellow}.join(', ')}." ) do |v|
Proxy::HTTP::Module.load(ctx, opts, v)
@proxy = true
......
......@@ -74,6 +74,11 @@ class SniffOptions
@parsers = Parsers::Base.from_cmdline(v)
end
opts.on( '--disable-parsers PARSERS', "Comma separated list of packet parsers to disable ( NOTE: Will set -X to true )" ) do |v|
@enabled = true
@parsers = Parsers::Base.from_exclusion_list(v)
end
opts.on( '--custom-parser EXPRESSION', 'Use a custom regular expression in order to capture and show sniffed data ( NOTE: Will set -X to true ).' ) do |v|
@enabled = true
@parsers = ['CUSTOM']
......
......@@ -25,6 +25,8 @@ class InjectHTML < BetterCap::Proxy::HTTP::Module
@@iframe = nil
# HTML data to be injected.
@@data = nil
# Position of the injection, 0 = just after <body>, 1 = before </body>
@@position = 0
# Add custom command line arguments to the +opts+ OptionParser instance.
def self.on_options(opts)
......@@ -45,6 +47,16 @@ class InjectHTML < BetterCap::Proxy::HTTP::Module
opts.on( '--html-iframe-url URL', 'URL of the iframe that will be injected, if this option is specified an "iframe" tag will be injected.' ) do |v|
@@iframe = v
end
opts.on( '--html-position POSITION', 'Position of the injection, valid values are START for injecting after the <body> tag and END to inject just before </body>.' ) do |v|
if v == 'START'
@@position = 0
elsif v == 'END'
@@position = 1
else
raise BetterCap::Error, "#{v} invalid position, only START or END values are accepted."
end
end
end
# Create an instance of this module and raise a BetterCap::Error if command
......@@ -61,12 +73,16 @@ class InjectHTML < BetterCap::Proxy::HTTP::Module
BetterCap::Logger.info "[#{'INJECTHTML'.green}] Injecting HTML code into #{request.to_url}"
if @@data.nil?
replacement = "<iframe src=\"#{@@iframe}\" frameborder=\"0\" height=\"0\" width=\"0\"></iframe></body>"
replacement = "<iframe src=\"#{@@iframe}\" frameborder=\"0\" height=\"0\" width=\"0\"></iframe>"
else
replacement = "#{@@data}</body>"
replacement = "#{@@data}"
end
response.body.sub!( /<\/body>/i ) { replacement }
if @@position == 0
response.body.sub!( /<body([^>]*)>/i ) { "<body#{$1}>#{replacement}" }
else
response.body.sub!( /<\/body>/i ) { "#{replacement}</body>" }
end
end
end
end
# encoding: UTF-8
=begin
BETTERCAP
Author : Simone 'evilsocket' Margaritelli
Email : evilsocket@gmail.com
Blog : http://www.evilsocket.net/
This project is released under the GPL 3 license.
=end
# This proxy module will redirect to a custom URL.
class Redirect < BetterCap::Proxy::HTTP::Module
meta(
'Name' => 'Redirect',
'Description' => 'This proxy module will redirect the target(s) to a custom URL.',
'Version' => '1.0.0',
'Author' => "Simone 'evilsocket' Margaritelli",
'License' => 'GPL3'
)
# URL to redirect the target(s) to.
@@url = nil
# Optional regex filter for redirections.
@@filter = nil
# Add custom command line arguments to the +opts+ OptionParser instance.
def self.on_options(opts)
opts.separator ""
opts.separator "Redirect Proxy Module Options:"
opts.separator ""
opts.on( '--redirect-url URL', 'URL to redirect the target(s) to.' ) do |v|
@@url = v
end
opts.on( '--redirect-filter EXPRESSION', 'Optional regex filter for redirections.' ) do |v|
@@filter = Regexp.new(v)
end
end
# Create an instance of this module and raise a BetterCap::Error if command
# line arguments weren't correctly specified.
def initialize
raise BetterCap::Error, "No --redirect-url option specified for the proxy module." if @@url.nil?
raise BetterCap::Error, "Invalid URL specified." unless @@url =~ /\A#{URI::regexp}\z/
end
def on_request( request, response )
if response.content_type =~ /^text\/html.*/ and !@@url.include?(request.host)
if @@filter.nil? or @@filter.match(request.to_url)
BetterCap::Logger.info "[#{'REDIRECT'.green}] Redirecting #{request.to_url} to #{@@url} ..."
response.redirect!(@@url)
end
end
end
end
......@@ -110,22 +110,22 @@ class Request
name = $1
value = $2
case name
when 'Host'
case name.downcase
when 'host'
@host = value
if @host =~ /([^:]*):([0-9]*)$/
@host = $1
@port = $2.to_i
end
when 'Content-Length'
when 'content-length'
@content_length = value.to_i
# we don't want to have hundreds of threads running
when 'Connection'
# we don't want to have hundreds of threads running
when 'connection'
value = 'close'
when 'Proxy-Connection'
when 'proxy-connection'
name = 'Connection'
# disable gzip, chunked, etc encodings
when 'Accept-Encoding'
# disable gzip, chunked, etc encodings
when 'accept-encoding'
value = 'identity'
end
......
......@@ -102,6 +102,15 @@ class Response
@body = response.body || ''
end
# Convert this response object to a 302 redirect to +url+.
def redirect!(url)
@code = '302'
@status = 'Moved'
@body = nil
@headers['Location'] = url
@headers['Connection'] = 'close'
end
# Parse a single response +line+.
def <<(line)
# we already parsed the heders, collect response body
......
......@@ -52,12 +52,16 @@ class StrippedObject
# Return a normalized version of +url+.
def self.normalize( url, schema = 'https' )
has_schema = url.include?('://')
# add schema if needed
unless url.include?('://')
if has_schema
has_slash = ( url =~ /^.+:\/\/.+\/.*$/ )
else
has_slash = ( url =~ /^.+\/.*$/ )
url = "#{schema}://#{url}"
end
# add path if needed
unless url.end_with?('/')
# add slash if needed
unless has_slash
url = "#{url}/"
end
url
......
......@@ -67,7 +67,7 @@ class Streamer
response = r
end
if response.textual? or request.method == 'DELETE'
if @ctx.options.proxies.no_http_logs == false and ( response.textual? or request.method == 'DELETE' )
StreamLogger.log_http( request, response )
else
Logger.debug "[#{request.client}] -> #{request.to_url} [#{response.code}]"
......
......@@ -27,6 +27,8 @@ module TCP
# end
# end
class Module < BetterCap::Pluggable
def on_options( opts ); end
def check_opts; end
# This callback is called when the target is sending data to the upstream server.
# +event+ is an instance of the BetterCap::Proxy::TCP::Event class.
def on_data( event ); end
......@@ -41,6 +43,15 @@ class Module < BetterCap::Pluggable
@@loaded = {}
class << self
# Register custom options for each available module.
def register_options(opts)
@@loaded.each do |name,mod|
if mod.respond_to?(:on_options)
mod.on_options(opts)
end
end
end
# Called when a class inherits this base class.
def inherited(subclass)
name = subclass.name.upcase
......@@ -48,7 +59,7 @@ class Module < BetterCap::Pluggable
end
# Load +file+ as a proxy module.
def load( file )
def load( file, opts )
begin
require file
rescue LoadError => e
......@@ -58,6 +69,8 @@ class Module < BetterCap::Pluggable
@@loaded.each do |name,mod|
@@loaded[name] = mod.new
end
self.register_options(opts)
end
# Execute method +even_name+ for each loaded module instance using +event+
......
......@@ -18,6 +18,7 @@ module Shell
# Execute +command+ and return its output.
# Raise +BetterCap::Error+ if the return code is not 0.
def execute(command)
Logger.debug command
r = ''
10.times do
begin
......
......@@ -44,6 +44,21 @@ class Base
list
end
# Parse the +v+ command line argument and return a list of parser names
# disabling the ones specified.
# Will raise BetterCap::Error if one or more parser names are not valid.
def from_exclusion_list(v)
raise BetterCap::Error, "No parser names provided" if v.nil?
avail = available
list = v.split(',').collect(&:strip).collect(&:upcase).reject{ |c| c.empty? }
list.each do |parser|
raise BetterCap::Error, "Invalid parser name '#{parser}'." unless avail.include?(parser)
end
avail - list
end
# Return a list of BetterCap::Parsers instances by their +parsers+ names.
def load_by_names(parsers)
loaded = []
......@@ -70,15 +85,30 @@ class Base
def initialize
@filters = []
@name = 'BASE'
@port = nil
end
def match_port?( pkt )
return true unless !@port.nil?
begin
if pkt.respond_to?(:tcp_dst) and pkt.tcp_dst == @port
return true
elsif pkt.respond_to?(:udp_dst) and pkt.udp_dst == @port
return true
end
rescue; end
false
end
# This method will be called from the BetterCap::Sniffer for each
# incoming packet ( +pkt ) and will apply the parser filter to it.
def on_packet( pkt )
s = pkt.to_s
@filters.each do |filter|
if s =~ filter
StreamLogger.log_raw( pkt, @name, pkt.payload )
if match_port?(pkt)
@filters.each do |filter|
if s =~ filter
StreamLogger.log_raw( pkt, @name, pkt.payload )
end
end
end
end
......
=begin
BETTERCAP
Author : Simone 'evilsocket' Margaritelli
Email : evilsocket@gmail.com
Blog : http://www.evilsocket.net/
This project is released under the GPL 3 license.
=end
module BetterCap
module Parsers
# CC parser.
class CreditCard < Base
PARSERS = [
# All major cards.
/(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|3(?:0[0-5]|[68][0-9])[0-9]{11}|3[47][0-9]{13})/m,
# American Express
/(3[47][0-9]{13})/m,
# Diners Club
/(3(?:0[0-5]|[68][0-9])[0-9]{11})/m,
# Discover
/(6011[0-9]{12})/m,
# MasterCard
/(5[1-5][0-9]{14})/m,
# Visa
/(4[0-9]{12}(?:[0-9]{3})?)/m
].freeze
def on_packet( pkt )
begin
payload = pkt.to_s
PARSERS.each do |expr|
matches = payload.scan( expr )
matches.each do |m|
StreamLogger.log_raw( pkt, 'CREDITCARD', m ) if luhn?(m)
end
break unless matches.empty?
end
rescue; end
end
# Validate +cc+ with Lughn algorithm.
def luhn?(cc)
digits = cc.split(//).map(&:to_i)
last = digits.pop
products = digits.reverse.map.with_index do |n,i|
i.even? ? n*2 : n*1
end.reverse
sum = products.inject(0) { |t,p| t + p.to_s.split(//).map(&:to_i).inject(:+) }
checksum = 10 - (sum % 10)
checksum == 10 ? 0 : checksum
( last == checksum )
end
end
end
end
......@@ -18,6 +18,7 @@ class Ftp < Base
def initialize
@filters = [ /(USER|PASS)\s+.+/ ]
@name = 'FTP'
@port = 21
end
end
end
......
......@@ -16,8 +16,9 @@ module Parsers
# POP/IMAP authentication parser.
class Mail < Base
def initialize
@filters = [ /(\d+ )?(auth|authenticate) ([a-z\-_0-9]+)/i ]
@filters = [ /(USER|PASS)\s+.+/ ]
@name = 'MAIL'
@port = 110
end
end
end
......
......@@ -128,10 +128,13 @@ class Arp < Base
# Return true if the +pkt+ packet is an ARP 'who-has' query coming
# from some network endpoint.
def is_arp_query?(pkt)
# we're only interested in 'who-has' packets
pkt.arp_opcode == 1 and \
pkt.arp_dst_mac.to_s == '00:00:00:00:00:00' and \
pkt.arp_src_ip.to_s != @ctx.iface.ip
begin
# we're only interested in 'who-has' packets
return ( pkt.arp_opcode == 1 and \
pkt.arp_dst_mac.to_s == '00:00:00:00:00:00' and \
pkt.arp_src_ip.to_s != @ctx.iface.ip )
rescue; end
false
end
# Will watch for incoming ARP requests and spoof the source address.
......
......@@ -12,7 +12,7 @@ This project is released under the GPL 3 license.
=end
module BetterCap
# Current version of bettercap.
VERSION = '1.5.8'
VERSION = '1.5.9'
# Program banner.
BANNER = File.read( File.dirname(__FILE__) + '/banner' ).gsub( '#VERSION#', "v#{VERSION}")
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment