Class: Arachni::HTTP::ProxyServer

Inherits:
WEBrick::HTTPProxyServer
  • Object
show all
Includes:
UI::Output
Defined in:
lib/arachni/http/proxy_server.rb

Overview

We add our own type of WEBrick::HTTPProxyServer class that does not restrict header exchange and supports SSL interception.

SSL interception is achieved by redirecting traffic via a 2nd (SSL enabled) instance of this server by hijacking the browser’s CONNECT request.

Author:

Constant Summary collapse

CACHE =
{
    format_field_name: Support::Cache::LeastRecentlyPushed.new( 100 )
}
SKIP_HEADERS =
Set.new( HopByHop | ['content-encoding'] )
INTERCEPTOR_CA_CERTIFICATE =
File.dirname( __FILE__ ) + '/proxy_server/ssl-interceptor-cacert.pem'
INTERCEPTOR_CA_KEY =
File.dirname( __FILE__ ) + '/proxy_server/ssl-interceptor-cakey.pem'

Instance Method Summary collapse

Methods included from UI::Output

#debug?, #debug_off, #debug_on, #disable_only_positives, #included, #mute, #muted?, #only_positives, #only_positives?, #print_bad, #print_debug, #print_debug_backtrace, #print_debug_level_1, #print_debug_level_2, #print_debug_level_3, #print_error, #print_error_backtrace, #print_exception, #print_info, #print_line, #print_ok, #print_status, #print_verbose, #reroute_to_file, #reroute_to_file?, reset_output_options, #unmute, #verbose?, #verbose_on

Constructor Details

#initialize(options = {}) ⇒ ProxyServer

Returns a new instance of ProxyServer.

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :address (String) — default: '0.0.0.0'

    Address to bind to.

  • :port (Integer)

    Port number to listen on – defaults to a random port.

  • :timeout (Integer)

    HTTP time-out for each request in milliseconds.

  • :concurrency (Integer) — default: OptionGroups::HTTP#request_concurrency

    Maximum number of concurrent connections.

  • :response_handler (Block)

    Block to be called to handle each response as it arrives – will be passed the request and response.

  • :request_handler (Block)

    Block to be called to handle each request as it arrives – will be passed the request and response.

  • :ssl_certificate (String)

    SSL certificate.

  • :ssl_private_key (String)

    SSL private key.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/arachni/http/proxy_server.rb', line 57

def initialize( options = {} )
    @options = {
        address:              '0.0.0.0',
        port:                 Utilities.available_port,
        ssl_certificate_name: [ [ 'CN', 'Arachni' ] ]
    }.merge( options )

    @logger = WEBrick::Log.new( $stderr, 5 )
    # Will force the proxy to stfu.
    @logger.close if !Arachni::UI::Output.debug?( 3 )

    @interceptor_ports = {}
    @interceptors      = {}

    super(
        BindAddress:        @options[:address],
        Port:               @options[:port],
        MaxClients:         @options[:concurrency] || Options.http.request_concurrency,
        ProxyVia:           false,
        DoNotReverseLookup: true,
        AccessLog:          [],
        Logger:             @logger,
        Timeout:            @options[:timeout],
        SSLEnable:          @options.include?( :ssl_certificate ) &&
                                @options.include?( :ssl_private_key ),
        SSLCertName:        @options[:ssl_certificate_name],
        SSLCertificate:     @options[:ssl_certificate],
        SSLPrivateKey:      @options[:ssl_private_key]
    )
end

Instance Method Details

#active_connectionsInteger

Returns Amount of active connections.

Returns:

  • (Integer)

    Amount of active connections.



119
120
121
# File 'lib/arachni/http/proxy_server.rb', line 119

def active_connections
    @tokens.max - @tokens.size
end

#addressString

Returns Proxy server URL.

Returns:

  • (String)

    Proxy server URL.



107
108
109
# File 'lib/arachni/http/proxy_server.rb', line 107

def address
    "#{@options[:address]}:#{@options[:port]}"
end

#has_connections?Bool

Returns ‘true` if the proxy has active connections, `false` otherwise.

Returns:

  • (Bool)

    ‘true` if the proxy has active connections, `false` otherwise.



113
114
115
# File 'lib/arachni/http/proxy_server.rb', line 113

def has_connections?
    active_connections != 0
end

#running?Bool

Returns ‘true` if the server is running, `false` otherwise.

Returns:

  • (Bool)

    ‘true` if the server is running, `false` otherwise.



102
103
104
# File 'lib/arachni/http/proxy_server.rb', line 102

def running?
    @status == :Running
end

#shutdownObject



123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/arachni/http/proxy_server.rb', line 123

def shutdown
    print_debug_level_2 'Shutting down..'

    print_debug_level_2 "-- Interceptors: #{@interceptors.size}"
    @interceptors.each do |_, interceptor|
        print_debug_level_2 "---- Interceptor: #{interceptor}"
        interceptor.shutdown
    end

    super

    print_debug_level_2 'Shutdown.'
end

#start_asyncObject

Starts the server without blocking, it’ll only block until the server is up and running and ready to accept connections.



90
91
92
93
94
95
96
97
98
# File 'lib/arachni/http/proxy_server.rb', line 90

def start_async
    print_debug_level_2 'Starting'

    Thread.new { start }
    sleep 0.1 while !running?

    print_debug_level_2 'Started'
    nil
end