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,190 @@
|
|
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
|
+
# The {RemoteDir} class represents directories on a remote system.
|
25
|
+
#
|
26
|
+
class RemoteDir
|
27
|
+
|
28
|
+
include Enumerable
|
29
|
+
|
30
|
+
# The path of the directory
|
31
|
+
attr_reader :path
|
32
|
+
|
33
|
+
# The current position in the open directory.
|
34
|
+
#
|
35
|
+
# @return [Integer]
|
36
|
+
attr_reader :pos
|
37
|
+
|
38
|
+
#
|
39
|
+
# Creates a new Dir object.
|
40
|
+
#
|
41
|
+
# @param [String] path
|
42
|
+
# The path to the directory.
|
43
|
+
#
|
44
|
+
# @param [Array<String>] entries
|
45
|
+
# The entries of the directory.
|
46
|
+
#
|
47
|
+
def initialize(path,entries=[])
|
48
|
+
@path = path
|
49
|
+
@entries = entries
|
50
|
+
@pos = 0
|
51
|
+
@closed = false
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Returns the position in the opened directory.
|
56
|
+
#
|
57
|
+
# @return [Integer]
|
58
|
+
# The position of the opened directory.
|
59
|
+
#
|
60
|
+
# @raise [IOError]
|
61
|
+
# The directory is closed.
|
62
|
+
#
|
63
|
+
def tell
|
64
|
+
if @closed
|
65
|
+
raise(IOError,"closed directory")
|
66
|
+
end
|
67
|
+
|
68
|
+
return @pos
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Rewinds the opened directory.
|
73
|
+
#
|
74
|
+
# @return [Dir]
|
75
|
+
#
|
76
|
+
# @raise [IOError]
|
77
|
+
# The directory is closed.
|
78
|
+
#
|
79
|
+
def rewind
|
80
|
+
if @closed
|
81
|
+
raise(IOError,"closed directory")
|
82
|
+
end
|
83
|
+
|
84
|
+
@pos = 0
|
85
|
+
return self
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Sets the position within the open directory.
|
90
|
+
#
|
91
|
+
# @param [Integer] new_pos
|
92
|
+
# The new position within the open directory.
|
93
|
+
#
|
94
|
+
# @return [Dir]
|
95
|
+
#
|
96
|
+
# @raise [Errno::EINVAL]
|
97
|
+
# The new position was out of bounds.
|
98
|
+
#
|
99
|
+
# @raise [IOError]
|
100
|
+
# The directory is closed.
|
101
|
+
#
|
102
|
+
def seek(new_pos)
|
103
|
+
if @closed
|
104
|
+
raise(IOError,"closed directory")
|
105
|
+
end
|
106
|
+
|
107
|
+
if (new_pos < 0) || (new_pos >= @entries.length)
|
108
|
+
raise(Errno::EINVAL,"invalid seek position")
|
109
|
+
end
|
110
|
+
|
111
|
+
@pos = new_pos
|
112
|
+
return self
|
113
|
+
end
|
114
|
+
|
115
|
+
#
|
116
|
+
# Iterates through the entries within the directory.
|
117
|
+
#
|
118
|
+
# @yield [entry]
|
119
|
+
# The given block will be passed each entry.
|
120
|
+
#
|
121
|
+
# @yieldparam [String] entry
|
122
|
+
# An entry from the directory.
|
123
|
+
#
|
124
|
+
# @return [Enumerator]
|
125
|
+
# An enumerator will be returned if no block is given.
|
126
|
+
#
|
127
|
+
# @raise [IOError]
|
128
|
+
# The directory is closed.
|
129
|
+
#
|
130
|
+
def each
|
131
|
+
return enum_for(__method__) unless block_given?
|
132
|
+
|
133
|
+
if @closed
|
134
|
+
raise(IOError,"closed directory")
|
135
|
+
end
|
136
|
+
|
137
|
+
@pos = 0
|
138
|
+
|
139
|
+
@entries.each do |entry|
|
140
|
+
yield entry
|
141
|
+
@pos += 1
|
142
|
+
end
|
143
|
+
|
144
|
+
return self
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
# Reads the next entry from the directory.
|
149
|
+
#
|
150
|
+
# @return [String, nil]
|
151
|
+
# The next entry from the opened directory.
|
152
|
+
# If all entries have been read, `nil` is returned.
|
153
|
+
#
|
154
|
+
# @raise [IOError]
|
155
|
+
# The directory is closed.
|
156
|
+
#
|
157
|
+
def read
|
158
|
+
if @closed
|
159
|
+
raise(IOError,"closed directory")
|
160
|
+
end
|
161
|
+
|
162
|
+
if @pos < @entries.length
|
163
|
+
next_entry = @entries[@pos]
|
164
|
+
|
165
|
+
@pos += 1
|
166
|
+
return next_entry
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
#
|
171
|
+
# Closes the opened directory.
|
172
|
+
#
|
173
|
+
def close
|
174
|
+
@closed = true
|
175
|
+
return nil
|
176
|
+
end
|
177
|
+
|
178
|
+
#
|
179
|
+
# Inspects the directory.
|
180
|
+
#
|
181
|
+
# @return [String]
|
182
|
+
# The inspected directory.
|
183
|
+
#
|
184
|
+
def inspect
|
185
|
+
"<#{self.class}:#{@path}>"
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,174 @@
|
|
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/resource'
|
22
|
+
|
23
|
+
module Ronin
|
24
|
+
module PostEx
|
25
|
+
class RemoteFile < Resource
|
26
|
+
#
|
27
|
+
# Represents the status information of a remote file. The {Stat} class
|
28
|
+
# using the `fs_stat` or `file_stat` method defined by the API object to
|
29
|
+
# request the remote status information.
|
30
|
+
#
|
31
|
+
# ## Supported API Methods
|
32
|
+
#
|
33
|
+
# * `file_stat(fd : Integer) -> Hash[Symbol, Object] | nil`
|
34
|
+
# * `fs_stat(path : String) -> Hash[Symbol, Object] | nil`
|
35
|
+
#
|
36
|
+
class Stat
|
37
|
+
|
38
|
+
# The path of the file
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
attr_reader :path
|
42
|
+
|
43
|
+
# The size of the file (in bytes)
|
44
|
+
#
|
45
|
+
# @return [Integer]
|
46
|
+
attr_reader :size
|
47
|
+
|
48
|
+
# The number of native file-system blocks
|
49
|
+
#
|
50
|
+
# @return [Integer]
|
51
|
+
attr_reader :blocks
|
52
|
+
|
53
|
+
# The native file-system block size.
|
54
|
+
#
|
55
|
+
# @return [Integer]
|
56
|
+
attr_reader :blocksize
|
57
|
+
|
58
|
+
# The Inode number
|
59
|
+
#
|
60
|
+
# @return [Integer]
|
61
|
+
attr_reader :inode
|
62
|
+
|
63
|
+
# The number of hard links to the file
|
64
|
+
#
|
65
|
+
# @return [Integer]
|
66
|
+
attr_reader :nlinks
|
67
|
+
|
68
|
+
# The mode of the file
|
69
|
+
#
|
70
|
+
# @return [Integer]
|
71
|
+
attr_reader :mode
|
72
|
+
|
73
|
+
# The owner's UID of the file.
|
74
|
+
#
|
75
|
+
# @return [Integer]
|
76
|
+
attr_reader :uid
|
77
|
+
|
78
|
+
# The owner's GID of the file.
|
79
|
+
#
|
80
|
+
# @return [Integer]
|
81
|
+
attr_reader :gid
|
82
|
+
|
83
|
+
# The access time of the file.
|
84
|
+
#
|
85
|
+
# @return [Time, nil]
|
86
|
+
attr_reader :atime
|
87
|
+
|
88
|
+
# The creation time of the file.
|
89
|
+
#
|
90
|
+
# @return [Time]
|
91
|
+
attr_reader :ctime
|
92
|
+
|
93
|
+
# The modification time of the file.
|
94
|
+
#
|
95
|
+
# @return [Time]
|
96
|
+
attr_reader :mtime
|
97
|
+
|
98
|
+
#
|
99
|
+
# Creates a new File Stat object.
|
100
|
+
#
|
101
|
+
# @param [Sessions::Session##fs_stat] session
|
102
|
+
# The object controlling file-system stat.
|
103
|
+
#
|
104
|
+
# @param [String] path
|
105
|
+
# The path to stat.
|
106
|
+
#
|
107
|
+
# @param [Integer] fd
|
108
|
+
# The file description to stat.
|
109
|
+
#
|
110
|
+
# @raise [ArgumentError]
|
111
|
+
# Neither the `path:` or `fd:` keyword arguments were given.
|
112
|
+
#
|
113
|
+
# @raise [NotImplementedError]
|
114
|
+
# The leveraging object does not define `fs_stat` or `file_stat`
|
115
|
+
# needed by {Stat}.
|
116
|
+
#
|
117
|
+
# @raise [Errno::ENOENT]
|
118
|
+
# The remote file does not exist.
|
119
|
+
#
|
120
|
+
# @note
|
121
|
+
# This method requires `session` define the `fs_stat` API method.
|
122
|
+
#
|
123
|
+
def initialize(session, path: nil, fd: nil)
|
124
|
+
if path
|
125
|
+
unless session.respond_to?(:fs_stat)
|
126
|
+
raise(NotImplementedError,"#{session.inspect} does not define #fs_stat")
|
127
|
+
end
|
128
|
+
elsif fd
|
129
|
+
unless session.respond_to?(:file_stat)
|
130
|
+
raise(NotImplementedError,"#{session.inspect} does not define #file_stat")
|
131
|
+
end
|
132
|
+
else
|
133
|
+
raise(ArgumentError,"#{self.class}#initialize must be given either the path: or fd: keyword argument")
|
134
|
+
end
|
135
|
+
|
136
|
+
@session = session
|
137
|
+
@path = path.to_s
|
138
|
+
|
139
|
+
unless (stat = @session.fs_stat(@path))
|
140
|
+
raise(Errno::ENOENT,"No such file or directory #{@path.dump}")
|
141
|
+
end
|
142
|
+
|
143
|
+
@size = stat[:size]
|
144
|
+
@blocks = stat[:blocks]
|
145
|
+
@blocksize = stat[:blocksize]
|
146
|
+
@inode = stat[:inode]
|
147
|
+
@nlinks = stat[:nlinks]
|
148
|
+
|
149
|
+
@mode = stat[:mode]
|
150
|
+
@uid = stat[:uid]
|
151
|
+
@gid = stat[:gid]
|
152
|
+
|
153
|
+
@atime = stat[:atime]
|
154
|
+
@ctime = stat[:ctime]
|
155
|
+
@mtime = stat[:mtime]
|
156
|
+
end
|
157
|
+
|
158
|
+
alias ino inode
|
159
|
+
alias blksize blocksize
|
160
|
+
|
161
|
+
#
|
162
|
+
# Determines whether the file has zero size.
|
163
|
+
#
|
164
|
+
# @return [Boolean]
|
165
|
+
# Specifies whether the file has zero size.
|
166
|
+
#
|
167
|
+
def zero?
|
168
|
+
@size == 0
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|