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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.document +6 -0
  3. data/.github/workflows/ruby.yml +31 -0
  4. data/.gitignore +13 -0
  5. data/.rspec +1 -0
  6. data/.ruby-version +1 -0
  7. data/.yardopts +1 -0
  8. data/API_SPEC.md +235 -0
  9. data/COPYING.txt +165 -0
  10. data/ChangeLog.md +23 -0
  11. data/Gemfile +36 -0
  12. data/README.md +245 -0
  13. data/Rakefile +34 -0
  14. data/examples/bind_shell.rb +19 -0
  15. data/gemspec.yml +25 -0
  16. data/lib/ronin/post_ex/cli/shell_shell.rb +66 -0
  17. data/lib/ronin/post_ex/cli/system_shell.rb +811 -0
  18. data/lib/ronin/post_ex/remote_dir.rb +190 -0
  19. data/lib/ronin/post_ex/remote_file/stat.rb +174 -0
  20. data/lib/ronin/post_ex/remote_file.rb +417 -0
  21. data/lib/ronin/post_ex/remote_process.rb +170 -0
  22. data/lib/ronin/post_ex/resource.rb +144 -0
  23. data/lib/ronin/post_ex/sessions/bind_shell.rb +60 -0
  24. data/lib/ronin/post_ex/sessions/remote_shell_session.rb +48 -0
  25. data/lib/ronin/post_ex/sessions/reverse_shell.rb +67 -0
  26. data/lib/ronin/post_ex/sessions/rpc_session.rb +779 -0
  27. data/lib/ronin/post_ex/sessions/session.rb +73 -0
  28. data/lib/ronin/post_ex/sessions/shell_session.rb +618 -0
  29. data/lib/ronin/post_ex/system/fs.rb +650 -0
  30. data/lib/ronin/post_ex/system/process.rb +422 -0
  31. data/lib/ronin/post_ex/system/shell.rb +1037 -0
  32. data/lib/ronin/post_ex/system.rb +191 -0
  33. data/lib/ronin/post_ex/version.rb +26 -0
  34. data/lib/ronin/post_ex.rb +22 -0
  35. data/ronin-post_ex.gemspec +61 -0
  36. data/spec/sessions/bind_shell_spec.rb +31 -0
  37. data/spec/sessions/remote_shell_session_spec.rb +28 -0
  38. data/spec/sessions/reverse_shell_spec.rb +49 -0
  39. data/spec/sessions/rpc_session_spec.rb +500 -0
  40. data/spec/sessions/session_spec.rb +61 -0
  41. data/spec/sessions/shell_session_spec.rb +482 -0
  42. data/spec/spec_helper.rb +9 -0
  43. data/spec/system_spec.rb +66 -0
  44. 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