ronin-post_ex 0.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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,650 @@
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
+ require 'ronin/post_ex/remote_file'
23
+ require 'ronin/post_ex/remote_file/stat'
24
+ require 'ronin/post_ex/remote_dir'
25
+
26
+ require 'hexdump'
27
+
28
+ module Ronin
29
+ module PostEx
30
+ class System < Resource
31
+ #
32
+ # Provides access to a system's a File System (FS).
33
+ #
34
+ # # Supported API Methods
35
+ #
36
+ # The File System resource uses the following post-exploitation methods,
37
+ # defined by the {#session} object:
38
+ #
39
+ # * `fs_getcwd() -> String`
40
+ # * `fs_chdir(path : String)`
41
+ # * `fs_readlink(path : String) -> String`
42
+ # * `fs_readdir(path : String) -> Array[String]`
43
+ # * `fs_glob(pattern : String) -> Array[String]`
44
+ # * `fs_mktemp(basename : String) -> String`
45
+ # * `fs_mkdir(new_path : String)`
46
+ # * `fs_copy(src : String, dest : String)`
47
+ # * `fs_unlink(path : String)`
48
+ # * `fs_rmdir(path : String)`
49
+ # * `fs_move(src : String, dest : String)`
50
+ # * `fs_link(src : String, dest : String)`
51
+ # * `fs_chgrp(group : String, path : String)`
52
+ # * `fs_chown(user : String, path : String)`
53
+ # * `fs_chmod(mode : Integer, path : String)`
54
+ # * `fs_stat(path : String) => Hash[Symbol, Object] | nil`
55
+ #
56
+ class FS < Resource
57
+
58
+ #
59
+ # Gets the current working directory.
60
+ #
61
+ # @return [String]
62
+ # The path of the current working directory.
63
+ #
64
+ # @note
65
+ # May call the `fs_getcwd` method, if defined by the {#session}
66
+ # object.
67
+ #
68
+ def getcwd
69
+ if @session.respond_to?(:fs_getcwd)
70
+ @cwd = @session.fs_getcwd
71
+ end
72
+
73
+ return @cwd
74
+ end
75
+ resource_method :getcwd, [:fs_getcwd]
76
+
77
+ alias getwd getcwd
78
+ alias pwd getcwd
79
+
80
+ #
81
+ # Changes the current working directory.
82
+ #
83
+ # @param [String] path
84
+ # The path to use as the new current working directory.
85
+ #
86
+ # @return [String]
87
+ # The new current working directory.
88
+ #
89
+ # @note
90
+ # May call the `fs_chdir` method, if defined by the {#session}
91
+ # object.
92
+ #
93
+ def chdir(path)
94
+ path = expand_path(path)
95
+ old_cwd = @cwd
96
+
97
+ @cwd = if @session.respond_to?(:fs_chdir)
98
+ @session.fs_chdir(path)
99
+ else
100
+ path
101
+ end
102
+
103
+ if block_given?
104
+ yield @cwd
105
+ chdir(old_cwd)
106
+ end
107
+
108
+ return @cwd
109
+ end
110
+ resource_method :chdir
111
+
112
+ #
113
+ # Joins the path with the current working directory.
114
+ #
115
+ # @param [String] path
116
+ # The path to join.
117
+ #
118
+ # @return [String]
119
+ # The absolute path.
120
+ #
121
+ def expand_path(path)
122
+ if (@cwd && path[0,1] != '/')
123
+ ::File.expand_path(::File.join(@cwd,path))
124
+ else
125
+ path
126
+ end
127
+ end
128
+
129
+ #
130
+ # Reads the full contents of a file.
131
+ #
132
+ # @param [String] path
133
+ # The path to the file.
134
+ #
135
+ # @return [String]
136
+ # The contents of the file.
137
+ #
138
+ # @note
139
+ # Requires the `fs_readfile` method be defined by the {#session}
140
+ # object.
141
+ #
142
+ def readfile(path)
143
+ @session.fs_readfile(path)
144
+ end
145
+ resource_method :readfile, [:fs_readfile]
146
+
147
+ #
148
+ # Reads the destination of a link.
149
+ #
150
+ # @param [String] path
151
+ # The path to the link.
152
+ #
153
+ # @return [String]
154
+ # The destination of the link.
155
+ #
156
+ # @note
157
+ # Requires the `fs_readlink` method be defined by the {#session}
158
+ # object.
159
+ #
160
+ def readlink(path)
161
+ @session.fs_readlink(path)
162
+ end
163
+ resource_method :readlink, [:fs_readlink]
164
+
165
+ #
166
+ # Opens a directory for reading.
167
+ #
168
+ # @param [String] path
169
+ # The path to the directory.
170
+ #
171
+ # @return [RemoteDir]
172
+ # The opened directory.
173
+ #
174
+ # @note
175
+ # Requires the `fs_readdir` method be defined by the {#session}
176
+ # object.
177
+ #
178
+ def readdir(path)
179
+ path = expand_path(path)
180
+ entries = @session.fs_readdir(path)
181
+
182
+ return RemoteDir.new(path,entries)
183
+ end
184
+ resource_method :readdir, [:fs_readdir]
185
+
186
+ #
187
+ # Searches the file-system for matching paths.
188
+ #
189
+ # @param [String] pattern
190
+ # A path-glob pattern.
191
+ #
192
+ # @yield [path]
193
+ # The given block, will be passed each matching path.
194
+ #
195
+ # @return [String] path
196
+ # A path in the file-system that matches the pattern.
197
+ #
198
+ # @return [Array<String>]
199
+ # If no block is given, the matching paths will be returned.
200
+ #
201
+ # @example
202
+ # exploit.fs.glob('*.txt')
203
+ # # => [...]
204
+ #
205
+ # @example
206
+ # exploit.fs.glob('**/*.xml') do |path|
207
+ # # ...
208
+ # end
209
+ #
210
+ # @note
211
+ # Requires the `fs_glob` method be defined by the {#session} object.
212
+ #
213
+ def glob(pattern,&block)
214
+ path = expand_path(pattern)
215
+ paths = @session.fs_glob(pattern)
216
+
217
+ paths.each(&block) if block
218
+ return paths
219
+ end
220
+ resource_method :glob, [:fs_glob]
221
+
222
+ #
223
+ # Opens a file for reading.
224
+ #
225
+ # @param [String] path
226
+ # The path to file.
227
+ #
228
+ # @param [String] mode
229
+ # The mode to open the file in.
230
+ #
231
+ # @yield [file]
232
+ # If a block is given, it will be passed the newly opened file.
233
+ # After the block has returned, the file will be closed and
234
+ # `nil` will be returned.
235
+ #
236
+ # @yieldparam [RemoteFile] file
237
+ # The temporarily opened remote file.
238
+ #
239
+ # @return [RemoteFile, nil]
240
+ # If no block was given, then the newly opened remote file will be
241
+ # returned.
242
+ #
243
+ # @see RemoteFile.open
244
+ #
245
+ def open(path,mode='r',&block)
246
+ RemoteFile.open(@session,expand_path(path),mode,&block)
247
+ end
248
+ resource_method :open
249
+
250
+ #
251
+ # Hexdumps the contents of a file.
252
+ #
253
+ # @param [String] path
254
+ # The path of the file.
255
+ #
256
+ # @param [IO] output
257
+ # The output stream to write the hexdump to.
258
+ #
259
+ # @return [nil]
260
+ #
261
+ def hexdump(path,output=STDOUT)
262
+ open(path) { |file| Hexdump.dump(file,output: output) }
263
+ end
264
+ resource_method :hexdump, [:fs_read]
265
+
266
+ #
267
+ # Writes data to a file.
268
+ #
269
+ # @param [String] path
270
+ # The path to the file.
271
+ #
272
+ # @param [String] data
273
+ # The data to write.
274
+ #
275
+ # @return [nil]
276
+ #
277
+ def write(path,data)
278
+ open(path) { |file| file.write(data) }
279
+ end
280
+ resource_method :write, [:fs_write]
281
+
282
+ #
283
+ # Touches a file.
284
+ #
285
+ # @param [String] path
286
+ # The path of the file.
287
+ #
288
+ # @return [nil]
289
+ #
290
+ def touch(path)
291
+ open(path) { |file| file << '' }
292
+ end
293
+ resource_method :touch, [:fs_write]
294
+
295
+ #
296
+ # Opens a tempfile.
297
+ #
298
+ # @param [String] basename
299
+ # The base-name to use in the tempfile.
300
+ #
301
+ # @yield [tempfile]
302
+ # The given block will be passed the newly opened tempfile.
303
+ # After the block has returned, the tempfile will be closed
304
+ # and `nil` will be returned.
305
+ #
306
+ # @yieldparam [RemoteFile] tempfile
307
+ # The temporarily opened tempfile.
308
+ #
309
+ # @return [RemoteFile, nil]
310
+ # The newly opened tempfile.
311
+ #
312
+ # @note
313
+ # Requires the `fs_mktemp` method be defined by the {#session} object.
314
+ #
315
+ def tmpfile(basename,&block)
316
+ open(@session.fs_mktemp(basename),&block)
317
+ end
318
+ resource_method :tmpfile, [:fs_mktemp]
319
+
320
+ #
321
+ # Creates a directory.
322
+ #
323
+ # @param [String] path
324
+ # The path of the directory.
325
+ #
326
+ # @return [true]
327
+ # Specifies that the directory was successfully created.
328
+ #
329
+ # @note
330
+ # Requires the `fs_mkdir` method be defined by the {#session} object.
331
+ #
332
+ def mkdir(path)
333
+ @session.fs_mkdir(path)
334
+ return true
335
+ end
336
+ resource_method :mkdir, [:fs_mkdir]
337
+
338
+ #
339
+ # Copies a file.
340
+ #
341
+ # @param [String] path
342
+ # The path of the file to copy.
343
+ #
344
+ # @param [String] new_path
345
+ # The destination path to copy to.
346
+ #
347
+ # @return [true]
348
+ # Specifies that the file was successfully copied.
349
+ #
350
+ # @note
351
+ # Requires the `fs_copy` method be defined by the {#session} object.
352
+ #
353
+ def copy(path,new_path)
354
+ @session.fs_copy(expand_path(path),expand_path(new_path))
355
+ return true
356
+ end
357
+ resource_method :copy, [:fs_copy]
358
+
359
+ #
360
+ # Unlinks a file.
361
+ #
362
+ # @param [String] path
363
+ # The path of the file.
364
+ #
365
+ # @return [true]
366
+ # Specifies that the file was successfully removed.
367
+ #
368
+ # @note
369
+ # Requires the `fs_unlink` method be defined by the {#session} object.
370
+ #
371
+ def unlink(path)
372
+ @session.fs_unlink(expand_path(path))
373
+ return true
374
+ end
375
+ resource_method :unlink, [:fs_unlink]
376
+
377
+ alias rm unlink
378
+
379
+ #
380
+ # Removes a directory.
381
+ #
382
+ # @param [String] path
383
+ # The path of the directory.
384
+ #
385
+ # @return [true]
386
+ # Specifies that the directory was successfully removed.
387
+ #
388
+ # @note
389
+ # Requires the `fs_rmdir` method be defined by the {#session} object.
390
+ #
391
+ def rmdir(path)
392
+ @session.fs_rmdir(expand_path(path))
393
+ return true
394
+ end
395
+ resource_method :rmdir, [:fs_rmdir]
396
+
397
+ #
398
+ # Moves a file or directory.
399
+ #
400
+ # @param [String] path
401
+ # The path of the file or directory to be moved.
402
+ #
403
+ # @param [String] new_path
404
+ # The destination path for the file or directory to be moved to.
405
+ #
406
+ # @return [true]
407
+ # Specifies that the file or directory was successfully moved.
408
+ #
409
+ # @note
410
+ # Requires the `fs_move` method be defined by the {#session} object.
411
+ #
412
+ def move(path,new_path)
413
+ @session.fs_move(expand_path(path),expand_path(new_path))
414
+ return true
415
+ end
416
+ resource_method :move, [:fs_move]
417
+
418
+ alias rename move
419
+
420
+ #
421
+ # Creates a symbolic link.
422
+ #
423
+ # @param [String] path
424
+ # The path that the link will point to.
425
+ #
426
+ # @param [String] new_path
427
+ # The path of the link.
428
+ #
429
+ # @return [true]
430
+ # Specifies that the symbolic link was successfully created.
431
+ #
432
+ # @note
433
+ # Requires the `fs_link` method be defined by the {#session} object.
434
+ #
435
+ def link(path,new_path)
436
+ @session.fs_link(path,new_path)
437
+ return true
438
+ end
439
+ resource_method :link, [:fs_link]
440
+
441
+ #
442
+ # Changes ownership of a file or directory.
443
+ #
444
+ # @param [String, (String,String)] owner
445
+ # the user and/or group that will own the file or directory.
446
+ #
447
+ # @param [String] path
448
+ # The path of the file or directory.
449
+ #
450
+ # @return [true]
451
+ # Specifies that the ownership was successfully changed.
452
+ #
453
+ # @example
454
+ # exploit.fs.chown('www', 'one.html')
455
+ #
456
+ # @example
457
+ # exploit.fs.chown(['alice', 'users'], 'one.html')
458
+ #
459
+ # @note
460
+ # Requires the `fs_chown` method be defined by the {#session} object.
461
+ #
462
+ def chown(owner,path)
463
+ user, group = owner
464
+
465
+ chgrp(group,path) if group
466
+
467
+ @session.fs_chown(user,expand_path(path))
468
+ return true
469
+ end
470
+ resource_method :chown, [:fs_chown]
471
+
472
+ #
473
+ # Changes group ownership on one or more files or directories.
474
+ #
475
+ # @param [String] group
476
+ # The group that will own the file or directory.
477
+ #
478
+ # @param [String] path
479
+ # The path of the file or directory.
480
+ #
481
+ # @return [true]
482
+ # Specifies that the group ownership was successfully changed.
483
+ #
484
+ # @example
485
+ # exploit.fs.chgrp('www', 'one.html')
486
+ #
487
+ # @note
488
+ # Requires the `fs_chgrp` method be defined by the {#session} object.
489
+ #
490
+ def chgrp(group,path)
491
+ @session.fs_chgrp(group,expand_path(path))
492
+ return true
493
+ end
494
+ resource_method :chgrp, [:fs_chgrp]
495
+
496
+ #
497
+ # Changes permissions on one or more file or directorie.
498
+ #
499
+ # @param [Integer] mode
500
+ # The new mode for the file or directory.
501
+ #
502
+ # @param [String] path
503
+ # The path of the file or directory.
504
+ #
505
+ # @return [true]
506
+ # Specifies that the permissions were successfully changed.
507
+ #
508
+ # @example
509
+ # exploit.fs.chmod(0665, 'one.html')
510
+ #
511
+ # @note
512
+ # Requires the `fs_chmod` method be defined by the {#session} object.
513
+ #
514
+ def chmod(mode,path)
515
+ @session.fs_chmod(mode,expand_path(path))
516
+ return true
517
+ end
518
+ resource_method :chmod, [:fs_chmod]
519
+
520
+ #
521
+ # Gathers statistics on a file or directory.
522
+ #
523
+ # @param [String] path
524
+ # The path of the file or directory.
525
+ #
526
+ # @return [RemoteFile::Stat]
527
+ # The statistics on the file or directory.
528
+ #
529
+ # @see RemoteFile::Stat#initialize
530
+ #
531
+ def stat(path)
532
+ RemoteFile::Stat.new(@session,expand_path(path))
533
+ end
534
+ resource_method :stat, [:fs_stat]
535
+
536
+ #
537
+ # Tests whether a file or directory exists.
538
+ #
539
+ # @param [String] path
540
+ # The path of the file or directory in question.
541
+ #
542
+ # @return [Boolean]
543
+ # Specifies whether the file or directory exists.
544
+ #
545
+ def exists?(path)
546
+ begin
547
+ stat(path)
548
+ return true
549
+ rescue Errno::ENOENT
550
+ return false
551
+ end
552
+ end
553
+ resource_method :exists?, [:fs_stat]
554
+
555
+ #
556
+ # Tests whether a file exists.
557
+ #
558
+ # @param [String] path
559
+ # The path of the file in question.
560
+ #
561
+ # @return [Boolean]
562
+ # Specifies whether the file exists.
563
+ #
564
+ def file?(path)
565
+ begin
566
+ stat(path).file?
567
+ rescue Errno::ENOENT
568
+ return false
569
+ end
570
+ end
571
+ resource_method :file?, [:fs_stat]
572
+
573
+ #
574
+ # Tests whether a directory exists.
575
+ #
576
+ # @param [String] path
577
+ # The path of the directory in question.
578
+ #
579
+ # @return [Boolean]
580
+ # Specifies whether the directory exists.
581
+ #
582
+ def directory?(path)
583
+ begin
584
+ stat(path).directory?
585
+ rescue Errno::ENOENT
586
+ return false
587
+ end
588
+ end
589
+ resource_method :directory?, [:fs_stat]
590
+
591
+ #
592
+ # Tests whether a FIFO pipe exists.
593
+ #
594
+ # @param [String] path
595
+ # The path of the FIFO pipe in question.
596
+ #
597
+ # @return [Boolean]
598
+ # Specifies whether the FIFO pipe exists.
599
+ #
600
+ def pipe?(path)
601
+ begin
602
+ stat(path).pipe?
603
+ rescue Errno::ENOENT
604
+ return false
605
+ end
606
+ end
607
+ resource_method :pipe?, [:fs_stat]
608
+
609
+ #
610
+ # Tests whether a UNIX socket exists.
611
+ #
612
+ # @param [String] path
613
+ # The path of the UNIX socket in question.
614
+ #
615
+ # @return [Boolean]
616
+ # Specifies whether the UNIX socket exists.
617
+ #
618
+ def socket?(path)
619
+ begin
620
+ stat(path).socket?
621
+ rescue Errno::ENOENT
622
+ return false
623
+ end
624
+ end
625
+ resource_method :socket?, [:fs_stat]
626
+
627
+ #
628
+ # Tests whether a file is empty.
629
+ #
630
+ # @param [String] path
631
+ # The path of the file in question.
632
+ #
633
+ # @return [Boolean]
634
+ # Specifies whether the file is empty.
635
+ #
636
+ def zero?(path)
637
+ begin
638
+ stat(path).zero?
639
+ rescue Errno::ENOENT
640
+ return false
641
+ end
642
+ end
643
+ resource_method :zero?, [:fs_stat]
644
+
645
+ alias empty? zero?
646
+
647
+ end
648
+ end
649
+ end
650
+ end