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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/lib/psrp.rb +94 -72
- data/lib/version.rb +1 -1
- data/test_psrp.rb +28 -4
- metadata +2 -3
- data/script.ps1 +0 -2958
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c0eb58f46fa0b746b0d8f1fe2157764c22c8586
|
4
|
+
data.tar.gz: ad6ab72fdf78ead6c2b1a0a22497ef546529574d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f0c16ebb4d24c80d0c13efff3f7a6cd0e6d5f0ff12d850bb2c15fc8750edbafd2afb66efe6bff8970d7fe4a5771619cd233d9339d7008e013866b9583e61357
|
7
|
+
data.tar.gz: 7df6cac6ea30fbf62dd765a5aa5d51872ed70df2a216b6fe8ee9c1b2fe0cebda19cc2c1390cf0de98b8315e96e74723b9f1b432b0722e5a980d7294168232716
|
data/.gitignore
CHANGED
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
|
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
|
-
|
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
|
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
|
-
@
|
109
|
-
|
110
|
-
|
111
|
-
|
105
|
+
@opened = true
|
106
|
+
return true
|
107
|
+
end
|
108
|
+
end
|
112
109
|
|
113
|
-
|
114
|
-
|
110
|
+
return false
|
111
|
+
end
|
115
112
|
|
116
|
-
|
113
|
+
def run_ps(command, shell_opts = {})
|
117
114
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
-
|
144
|
-
|
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
|
-
|
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
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
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
|
-
|
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
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
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
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.
|
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-
|
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:
|