ronin-post_ex 0.1.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +6 -0
- data/.github/workflows/ruby.yml +31 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/API_SPEC.md +235 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +23 -0
- data/Gemfile +36 -0
- data/README.md +245 -0
- data/Rakefile +34 -0
- data/examples/bind_shell.rb +19 -0
- data/gemspec.yml +25 -0
- data/lib/ronin/post_ex/cli/shell_shell.rb +66 -0
- data/lib/ronin/post_ex/cli/system_shell.rb +811 -0
- data/lib/ronin/post_ex/remote_dir.rb +190 -0
- data/lib/ronin/post_ex/remote_file/stat.rb +174 -0
- data/lib/ronin/post_ex/remote_file.rb +417 -0
- data/lib/ronin/post_ex/remote_process.rb +170 -0
- data/lib/ronin/post_ex/resource.rb +144 -0
- data/lib/ronin/post_ex/sessions/bind_shell.rb +60 -0
- data/lib/ronin/post_ex/sessions/remote_shell_session.rb +48 -0
- data/lib/ronin/post_ex/sessions/reverse_shell.rb +67 -0
- data/lib/ronin/post_ex/sessions/rpc_session.rb +779 -0
- data/lib/ronin/post_ex/sessions/session.rb +73 -0
- data/lib/ronin/post_ex/sessions/shell_session.rb +618 -0
- data/lib/ronin/post_ex/system/fs.rb +650 -0
- data/lib/ronin/post_ex/system/process.rb +422 -0
- data/lib/ronin/post_ex/system/shell.rb +1037 -0
- data/lib/ronin/post_ex/system.rb +191 -0
- data/lib/ronin/post_ex/version.rb +26 -0
- data/lib/ronin/post_ex.rb +22 -0
- data/ronin-post_ex.gemspec +61 -0
- data/spec/sessions/bind_shell_spec.rb +31 -0
- data/spec/sessions/remote_shell_session_spec.rb +28 -0
- data/spec/sessions/reverse_shell_spec.rb +49 -0
- data/spec/sessions/rpc_session_spec.rb +500 -0
- data/spec/sessions/session_spec.rb +61 -0
- data/spec/sessions/shell_session_spec.rb +482 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/system_spec.rb +66 -0
- metadata +155 -0
@@ -0,0 +1,144 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-post_ex - a Ruby API for Post-Exploitation.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-post_ex is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-post_ex is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-post_ex. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
module Ronin
|
22
|
+
module PostEx
|
23
|
+
#
|
24
|
+
# A base-class for all post-exploitation resources.
|
25
|
+
#
|
26
|
+
class Resource
|
27
|
+
|
28
|
+
# The object providing control of the resource.
|
29
|
+
#
|
30
|
+
# @return [Sessions::Session]
|
31
|
+
attr_reader :session
|
32
|
+
|
33
|
+
#
|
34
|
+
# Creates a new Resource.
|
35
|
+
#
|
36
|
+
# @param [Object] session
|
37
|
+
# The object controlling the Resource.
|
38
|
+
#
|
39
|
+
def initialize(session)
|
40
|
+
@session = session
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Determines whether the {#session} object supports the resource's
|
45
|
+
# method(s).
|
46
|
+
#
|
47
|
+
# @param [Array<Symbol>] method_names
|
48
|
+
# The name of the Resource method.
|
49
|
+
#
|
50
|
+
# @return [Boolean]
|
51
|
+
# Specifies whether the {#session} object supports the method.
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# fs.supports?(:read, :write)
|
55
|
+
# # => true
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
#
|
59
|
+
def supports?(*method_names)
|
60
|
+
method_names.all? do |method_name|
|
61
|
+
method_name = method_name.to_sym
|
62
|
+
session_methods = self.class.resource_methods[method_name]
|
63
|
+
|
64
|
+
session_methods && session_methods.all? { |session_method|
|
65
|
+
@session.respond_to?(session_method)
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Determines which Resource methods are supported by the controlling
|
72
|
+
# object.
|
73
|
+
#
|
74
|
+
# @return [Array<Symbol>]
|
75
|
+
# The names of the supported Resource methods.
|
76
|
+
#
|
77
|
+
def supports
|
78
|
+
self.class.resource_methods.keys.select do |method_name|
|
79
|
+
supports?(method_name)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# Allows resources to spawn interactive consoles.
|
85
|
+
#
|
86
|
+
# @abstract
|
87
|
+
#
|
88
|
+
def interact
|
89
|
+
raise(NotImplementedError,"#{self.class} does not provide a console")
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
#
|
95
|
+
# The defined Resource methods.
|
96
|
+
#
|
97
|
+
# @return [Hash{Symbol => Array<Symbol>}]
|
98
|
+
# The names of the Resource methods and their required API methods.
|
99
|
+
#
|
100
|
+
# @api semipublic
|
101
|
+
#
|
102
|
+
def self.resource_methods
|
103
|
+
@resource_methods ||= {}
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Specifies that a Resource method requires certain methods define by the
|
108
|
+
# {#session} object.
|
109
|
+
#
|
110
|
+
# @param [Symbol] method_name
|
111
|
+
# The name of the Resource method.
|
112
|
+
#
|
113
|
+
# @param [Array<Symbol>] control_methods
|
114
|
+
# The methods that must be defined by the {#session} object.
|
115
|
+
#
|
116
|
+
# @api semipublic
|
117
|
+
#
|
118
|
+
def self.resource_method(method_name,control_methods=[])
|
119
|
+
resource_methods[method_name.to_sym] = control_methods.map(&:to_sym)
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
# Requires that the controlling object define the given method.
|
124
|
+
#
|
125
|
+
# @param [Symbol] name
|
126
|
+
# The name of the method that is required.
|
127
|
+
#
|
128
|
+
# @return [true]
|
129
|
+
# The method is defined.
|
130
|
+
#
|
131
|
+
# @raise [NotImplementedError]
|
132
|
+
# The method is not defined by the controlling object.
|
133
|
+
#
|
134
|
+
def requires_method!(name)
|
135
|
+
unless @session.respond_to?(name)
|
136
|
+
raise(NotImplementedError,"#{@session.inspect} does not define #{name}")
|
137
|
+
end
|
138
|
+
|
139
|
+
return true
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-post_ex - a Ruby API for Post-Exploitation.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-post_ex is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-post_ex is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-post_ex. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/post_ex/sessions/remote_shell_session'
|
22
|
+
|
23
|
+
require 'socket'
|
24
|
+
|
25
|
+
module Ronin
|
26
|
+
module PostEx
|
27
|
+
module Sessions
|
28
|
+
#
|
29
|
+
# Session class for interacting with bind shells.
|
30
|
+
#
|
31
|
+
# ## Examples
|
32
|
+
#
|
33
|
+
# session = Ronin::PostEx::Sessions::BindShell.connect(host,port)
|
34
|
+
# system = session.system
|
35
|
+
#
|
36
|
+
# system.shell.ls('/')
|
37
|
+
# # => "..."
|
38
|
+
#
|
39
|
+
class BindShell < RemoteShellSession
|
40
|
+
|
41
|
+
#
|
42
|
+
# Connects to a remote bind shell.
|
43
|
+
#
|
44
|
+
# @param [String] host
|
45
|
+
# The host to connect to.
|
46
|
+
#
|
47
|
+
# @param [Integer] port
|
48
|
+
# The port to connect to.
|
49
|
+
#
|
50
|
+
# @return [BindShell]
|
51
|
+
# The new bind shell session.
|
52
|
+
#
|
53
|
+
def self.connect(host,port)
|
54
|
+
new(TCPSocket.new(host,port))
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-post_ex - a Ruby API for Post-Exploitation.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-post_ex is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-post_ex is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-post_ex. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/post_ex/sessions/shell_session'
|
22
|
+
|
23
|
+
module Ronin
|
24
|
+
module PostEx
|
25
|
+
module Sessions
|
26
|
+
#
|
27
|
+
# Session base class for all other remote shell sessions.
|
28
|
+
#
|
29
|
+
class RemoteShellSession < ShellSession
|
30
|
+
|
31
|
+
#
|
32
|
+
# Initializes the remote shell session.
|
33
|
+
#
|
34
|
+
# @param [TCPSocket, UDPSocket] socket
|
35
|
+
# The underlying socket for the remote shell session.
|
36
|
+
#
|
37
|
+
def initialize(socket)
|
38
|
+
super(socket)
|
39
|
+
|
40
|
+
addrinfo = socket.remote_address
|
41
|
+
|
42
|
+
@name = "#{addrinfo.ip_address}:#{addrinfo.ip_port}"
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-post_ex - a Ruby API for Post-Exploitation.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-post_ex is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-post_ex is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-post_ex. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/post_ex/sessions/remote_shell_session'
|
22
|
+
|
23
|
+
require 'socket'
|
24
|
+
|
25
|
+
module Ronin
|
26
|
+
module PostEx
|
27
|
+
module Sessions
|
28
|
+
#
|
29
|
+
# Session class for interacting with reverse shells.
|
30
|
+
#
|
31
|
+
# ## Examples
|
32
|
+
#
|
33
|
+
# session = Ronin::PostEx::Sessions::ReverseShell.listen(host,port)
|
34
|
+
# system = session.system
|
35
|
+
#
|
36
|
+
# system.shell.ls('/')
|
37
|
+
# # => "..."
|
38
|
+
#
|
39
|
+
class ReverseShell < RemoteShellSession
|
40
|
+
|
41
|
+
#
|
42
|
+
# Listens for and accepts a reverse shell connection.
|
43
|
+
#
|
44
|
+
# @param [String, nil] host
|
45
|
+
# The host to connect to.
|
46
|
+
#
|
47
|
+
# @param [Integer] port
|
48
|
+
# The port to connect to.
|
49
|
+
#
|
50
|
+
# @return [ReverseShell]
|
51
|
+
# The new reverse shell session.
|
52
|
+
#
|
53
|
+
def self.listen(host=nil,port)
|
54
|
+
server_socket = TCPServer.new(port,host)
|
55
|
+
server_socket.listen(1)
|
56
|
+
|
57
|
+
begin
|
58
|
+
new(server_socket.accept)
|
59
|
+
ensure
|
60
|
+
server_socket.close
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|