ssrf_proxy 0.0.3 → 0.0.4
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 +8 -8
- data/LICENSE.md +1 -1
- data/README.md +87 -62
- data/bin/console +10 -8
- data/bin/ssrf-proxy +212 -99
- data/lib/ssrf_proxy.rb +4 -2
- data/lib/ssrf_proxy/banner.rb +15 -0
- data/lib/ssrf_proxy/http.rb +857 -436
- data/lib/ssrf_proxy/server.rb +98 -61
- data/lib/ssrf_proxy/version.rb +2 -10
- metadata +134 -92
data/lib/ssrf_proxy/server.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
#
|
3
|
-
# Copyright (c) 2015-
|
2
|
+
# Copyright (c) 2015-2017 Brendan Coles <bcoles@gmail.com>
|
4
3
|
# SSRF Proxy - https://github.com/bcoles/ssrf_proxy
|
5
4
|
# See the file 'LICENSE.md' for copying permission
|
6
5
|
#
|
@@ -16,18 +15,20 @@ module SSRFProxy
|
|
16
15
|
include Celluloid::IO
|
17
16
|
finalizer :shutdown
|
18
17
|
|
18
|
+
# @return [Logger] logger
|
19
|
+
attr_reader :logger
|
20
|
+
|
19
21
|
#
|
20
22
|
# SSRFProxy::Server errors
|
21
23
|
#
|
22
24
|
module Error
|
23
|
-
# SSRFProxy::Server
|
25
|
+
# SSRFProxy::Server errors
|
24
26
|
class Error < StandardError; end
|
25
|
-
exceptions = %w
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
RemoteHostUnresponsive )
|
27
|
+
exceptions = %w[InvalidSsrf
|
28
|
+
ProxyRecursion
|
29
|
+
AddressInUse
|
30
|
+
RemoteProxyUnresponsive
|
31
|
+
RemoteHostUnresponsive]
|
31
32
|
exceptions.each { |e| const_set(e, Class.new(Error)) }
|
32
33
|
end
|
33
34
|
|
@@ -51,7 +52,7 @@ module SSRFProxy
|
|
51
52
|
#
|
52
53
|
# @example Start SSRF Proxy server with the default options
|
53
54
|
# ssrf_proxy = SSRFProxy::Server.new(
|
54
|
-
# SSRFProxy::HTTP.new('http://example.local
|
55
|
+
# SSRFProxy::HTTP.new('http://example.local/?url=xxURLxx'),
|
55
56
|
# '127.0.0.1',
|
56
57
|
# 8081)
|
57
58
|
# ssrf_proxy.serve
|
@@ -59,7 +60,6 @@ module SSRFProxy
|
|
59
60
|
def initialize(ssrf, interface = '127.0.0.1', port = 8081)
|
60
61
|
@banner = 'SSRF Proxy'
|
61
62
|
@server = nil
|
62
|
-
@max_request_len = 8192
|
63
63
|
@logger = ::Logger.new(STDOUT).tap do |log|
|
64
64
|
log.progname = 'ssrf-proxy-server'
|
65
65
|
log.level = ::Logger::WARN
|
@@ -79,20 +79,24 @@ module SSRFProxy
|
|
79
79
|
"Proxy recursion error: #{@ssrf.proxy}"
|
80
80
|
end
|
81
81
|
if port_open?(@ssrf.proxy.host, @ssrf.proxy.port)
|
82
|
-
print_good(
|
82
|
+
print_good('Connected to remote proxy ' \
|
83
|
+
"#{@ssrf.proxy.host}:#{@ssrf.proxy.port} successfully")
|
83
84
|
else
|
84
85
|
raise SSRFProxy::Server::Error::RemoteProxyUnresponsive.new,
|
85
|
-
|
86
|
+
'Could not connect to remote proxy ' \
|
87
|
+
"#{@ssrf.proxy.host}:#{@ssrf.proxy.port}"
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
89
91
|
# if no upstream proxy is set, check if the remote server is responsive
|
90
92
|
if @ssrf.proxy.nil?
|
91
|
-
if port_open?(@ssrf.host, @ssrf.port)
|
92
|
-
print_good(
|
93
|
+
if port_open?(@ssrf.url.host, @ssrf.url.port)
|
94
|
+
print_good('Connected to remote host ' \
|
95
|
+
"#{@ssrf.url.host}:#{@ssrf.url.port} successfully")
|
93
96
|
else
|
94
97
|
raise SSRFProxy::Server::Error::RemoteHostUnresponsive.new,
|
95
|
-
|
98
|
+
'Could not connect to remote host ' \
|
99
|
+
"#{@ssrf.url.host}:#{@ssrf.url.port}"
|
96
100
|
end
|
97
101
|
end
|
98
102
|
|
@@ -103,7 +107,8 @@ module SSRFProxy
|
|
103
107
|
@server = TCPServer.new(interface, port.to_i)
|
104
108
|
rescue Errno::EADDRINUSE
|
105
109
|
raise SSRFProxy::Server::Error::AddressInUse.new,
|
106
|
-
"Could not bind to #{interface}:#{port}
|
110
|
+
"Could not bind to #{interface}:#{port}" \
|
111
|
+
' - address already in use'
|
107
112
|
end
|
108
113
|
end
|
109
114
|
|
@@ -117,14 +122,10 @@ module SSRFProxy
|
|
117
122
|
#
|
118
123
|
def port_open?(ip, port, seconds = 10)
|
119
124
|
Timeout.timeout(seconds) do
|
120
|
-
|
121
|
-
|
122
|
-
true
|
123
|
-
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError
|
124
|
-
false
|
125
|
-
end
|
125
|
+
TCPSocket.new(ip, port).close
|
126
|
+
true
|
126
127
|
end
|
127
|
-
rescue Timeout::Error
|
128
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError, Timeout::Error
|
128
129
|
false
|
129
130
|
end
|
130
131
|
|
@@ -155,15 +156,6 @@ module SSRFProxy
|
|
155
156
|
puts '[-] '.red + msg
|
156
157
|
end
|
157
158
|
|
158
|
-
#
|
159
|
-
# Logger accessor
|
160
|
-
#
|
161
|
-
# @return [Logger] class logger object
|
162
|
-
#
|
163
|
-
def logger
|
164
|
-
@logger
|
165
|
-
end
|
166
|
-
|
167
159
|
#
|
168
160
|
# Run proxy server asynchronously
|
169
161
|
#
|
@@ -172,7 +164,7 @@ module SSRFProxy
|
|
172
164
|
end
|
173
165
|
|
174
166
|
#
|
175
|
-
# Handle shutdown of
|
167
|
+
# Handle shutdown of server socket
|
176
168
|
#
|
177
169
|
def shutdown
|
178
170
|
logger.info 'Shutting down'
|
@@ -189,8 +181,9 @@ module SSRFProxy
|
|
189
181
|
start_time = Time.now
|
190
182
|
_, port, host = socket.peeraddr
|
191
183
|
logger.debug("Client #{host}:#{port} connected")
|
192
|
-
request = socket.
|
193
|
-
logger.debug("Received client request (#{request.length} bytes):\n
|
184
|
+
request = socket.read
|
185
|
+
logger.debug("Received client request (#{request.length} bytes):\n" \
|
186
|
+
"#{request}")
|
194
187
|
|
195
188
|
response = nil
|
196
189
|
if request.to_s =~ /\ACONNECT ([_a-zA-Z0-9\.\-]+:[\d]+) .*$/
|
@@ -200,45 +193,62 @@ module SSRFProxy
|
|
200
193
|
|
201
194
|
if response['code'].to_i == 502 || response['code'].to_i == 504
|
202
195
|
logger.info("Connection to #{host} failed")
|
203
|
-
socket.write("#{response['status_line']}\n
|
196
|
+
socket.write("#{response['status_line']}\n" \
|
197
|
+
"#{response['headers']}\n" \
|
198
|
+
"#{response['body']}")
|
204
199
|
raise Errno::ECONNRESET
|
205
200
|
end
|
206
201
|
|
207
202
|
logger.info("Connected to #{host} successfully")
|
208
203
|
socket.write("HTTP/1.0 200 Connection established\r\n\r\n")
|
209
|
-
request = socket.
|
210
|
-
logger.debug("Received client request (#{request.length} bytes):\n
|
204
|
+
request = socket.read
|
205
|
+
logger.debug("Received client request (#{request.length} bytes):\n" \
|
206
|
+
"#{request}")
|
207
|
+
|
208
|
+
# CHANGE_CIPHER_SPEC 20 0x14
|
209
|
+
# ALERT 21 0x15
|
210
|
+
# HANDSHAKE 22 0x16
|
211
|
+
# APPLICATION_DATA 23 0x17
|
212
|
+
if request.to_s.start_with?("\x14", "\x15", "\x16", "\x17")
|
213
|
+
logger.warn("Received SSL/TLS client request. SSL/TLS tunneling is not supported. Aborted.")
|
214
|
+
raise Errno::ECONNRESET
|
215
|
+
end
|
211
216
|
end
|
212
217
|
|
213
218
|
response = send_request(request.to_s)
|
214
|
-
socket.write("#{response['status_line']}\n
|
219
|
+
socket.write("#{response['status_line']}\n" \
|
220
|
+
"#{response['headers']}\n" \
|
221
|
+
"#{response['body']}")
|
215
222
|
raise Errno::ECONNRESET
|
216
|
-
rescue EOFError, Errno::ECONNRESET
|
223
|
+
rescue EOFError, Errno::ECONNRESET, Errno::EPIPE
|
217
224
|
socket.close
|
218
225
|
logger.debug("Client #{host}:#{port} disconnected")
|
219
226
|
end_time = Time.now
|
220
|
-
duration = end_time - start_time
|
221
|
-
|
227
|
+
duration = ((end_time - start_time) * 1000).round(3)
|
228
|
+
if response.nil?
|
229
|
+
logger.info("Served 0 bytes in #{duration} ms")
|
230
|
+
else
|
231
|
+
logger.info("Served #{response['body'].length} bytes in #{duration} ms")
|
232
|
+
end
|
222
233
|
end
|
223
234
|
|
224
235
|
#
|
225
236
|
# Send client HTTP request
|
226
237
|
#
|
227
|
-
# @param [String] client HTTP request
|
238
|
+
# @param [String] request client HTTP request
|
228
239
|
#
|
229
240
|
# @return [Hash] HTTP response
|
230
241
|
#
|
231
242
|
def send_request(request)
|
232
|
-
response_error = {
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
'body' => '' }
|
243
|
+
response_error = { 'uri' => '',
|
244
|
+
'duration' => '0',
|
245
|
+
'http_version' => '1.0',
|
246
|
+
'headers' => "Server: #{@banner}\n",
|
247
|
+
'body' => '' }
|
238
248
|
|
239
249
|
# parse client request
|
240
250
|
begin
|
241
|
-
if request.to_s !~ %r{\A(CONNECT|GET|HEAD|DELETE|POST|PUT) https?://}
|
251
|
+
if request.to_s !~ %r{\A(CONNECT|GET|HEAD|DELETE|POST|PUT|OPTIONS) https?://}
|
242
252
|
if request.to_s !~ /^Host: ([^\s]+)\r?\n/
|
243
253
|
logger.warn('No host specified')
|
244
254
|
raise SSRFProxy::HTTP::Error::InvalidClientRequest,
|
@@ -249,11 +259,12 @@ module SSRFProxy
|
|
249
259
|
req.parse(StringIO.new(request))
|
250
260
|
rescue => e
|
251
261
|
logger.info('Received malformed client HTTP request.')
|
252
|
-
error_msg =
|
262
|
+
error_msg = 'Error -- Invalid request: ' \
|
263
|
+
"Received malformed client HTTP request: #{e.message}"
|
253
264
|
print_error(error_msg)
|
254
265
|
response_error['code'] = '502'
|
255
266
|
response_error['message'] = 'Bad Gateway'
|
256
|
-
response_error['status_line'] =
|
267
|
+
response_error['status_line'] = "HTTP/#{response_error['http_version']}"
|
257
268
|
response_error['status_line'] << " #{response_error['code']}"
|
258
269
|
response_error['status_line'] << " #{response_error['message']}"
|
259
270
|
return response_error
|
@@ -262,10 +273,10 @@ module SSRFProxy
|
|
262
273
|
|
263
274
|
# send request
|
264
275
|
response = nil
|
265
|
-
logger.info("
|
276
|
+
logger.info("Requesting URL: #{uri}")
|
266
277
|
status_msg = "Request -> #{req.request_method}"
|
267
278
|
status_msg << " -> PROXY[#{@ssrf.proxy.host}:#{@ssrf.proxy.port}]" unless @ssrf.proxy.nil?
|
268
|
-
status_msg << " -> SSRF[#{@ssrf.host}:#{@ssrf.port}] -> URI[#{uri}]"
|
279
|
+
status_msg << " -> SSRF[#{@ssrf.url.host}:#{@ssrf.url.port}] -> URI[#{uri}]"
|
269
280
|
print_status(status_msg)
|
270
281
|
|
271
282
|
begin
|
@@ -276,7 +287,33 @@ module SSRFProxy
|
|
276
287
|
print_error(error_msg)
|
277
288
|
response_error['code'] = '502'
|
278
289
|
response_error['message'] = 'Bad Gateway'
|
279
|
-
response_error['status_line'] =
|
290
|
+
response_error['status_line'] = "HTTP/#{response_error['http_version']}"
|
291
|
+
response_error['status_line'] << " #{response_error['code']}"
|
292
|
+
response_error['status_line'] << " #{response_error['message']}"
|
293
|
+
return response_error
|
294
|
+
rescue SSRFProxy::HTTP::Error::InvalidResponse => e
|
295
|
+
logger.info(e.message)
|
296
|
+
error_msg = 'Response <- 503'
|
297
|
+
error_msg << " <- PROXY[#{@ssrf.proxy.host}:#{@ssrf.proxy.port}]" unless @ssrf.proxy.nil?
|
298
|
+
error_msg << " <- SSRF[#{@ssrf.url.host}:#{@ssrf.url.port}] <- URI[#{uri}]"
|
299
|
+
error_msg << " -- Error: #{e.message}"
|
300
|
+
print_error(error_msg)
|
301
|
+
response_error['code'] = '503'
|
302
|
+
response_error['message'] = 'Service Unavailable'
|
303
|
+
response_error['status_line'] = "HTTP/#{response_error['http_version']}"
|
304
|
+
response_error['status_line'] << " #{response_error['code']}"
|
305
|
+
response_error['status_line'] << " #{response_error['message']}"
|
306
|
+
return response_error
|
307
|
+
rescue SSRFProxy::HTTP::Error::ConnectionFailed => e
|
308
|
+
logger.info(e.message)
|
309
|
+
error_msg = 'Response <- 503'
|
310
|
+
error_msg << " <- PROXY[#{@ssrf.proxy.host}:#{@ssrf.proxy.port}]" unless @ssrf.proxy.nil?
|
311
|
+
error_msg << " <- SSRF[#{@ssrf.url.host}:#{@ssrf.url.port}] <- URI[#{uri}]"
|
312
|
+
error_msg << " -- Error: #{e.message}"
|
313
|
+
print_error(error_msg)
|
314
|
+
response_error['code'] = '503'
|
315
|
+
response_error['message'] = 'Service Unavailable'
|
316
|
+
response_error['status_line'] = "HTTP/#{response_error['http_version']}"
|
280
317
|
response_error['status_line'] << " #{response_error['code']}"
|
281
318
|
response_error['status_line'] << " #{response_error['message']}"
|
282
319
|
return response_error
|
@@ -284,22 +321,22 @@ module SSRFProxy
|
|
284
321
|
logger.info(e.message)
|
285
322
|
error_msg = 'Response <- 504'
|
286
323
|
error_msg << " <- PROXY[#{@ssrf.proxy.host}:#{@ssrf.proxy.port}]" unless @ssrf.proxy.nil?
|
287
|
-
error_msg << " <- SSRF[#{@ssrf.host}:#{@ssrf.port}] <- URI[#{uri}]"
|
324
|
+
error_msg << " <- SSRF[#{@ssrf.url.host}:#{@ssrf.url.port}] <- URI[#{uri}]"
|
288
325
|
error_msg << " -- Error: #{e.message}"
|
289
326
|
print_error(error_msg)
|
290
327
|
response_error['code'] = '504'
|
291
328
|
response_error['message'] = 'Timeout'
|
292
|
-
response_error['status_line'] =
|
329
|
+
response_error['status_line'] = "HTTP/#{response_error['http_version']}"
|
293
330
|
response_error['status_line'] << " #{response_error['code']}"
|
294
331
|
response_error['status_line'] << " #{response_error['message']}"
|
295
332
|
return response_error
|
296
333
|
rescue => e
|
297
334
|
logger.warn(e.message)
|
298
|
-
error_msg = "Error -- Unexpected error: #{e.
|
335
|
+
error_msg = "Error -- Unexpected error: #{e.backtrace.join("\n")}"
|
299
336
|
print_error(error_msg)
|
300
337
|
response_error['code'] = '502'
|
301
338
|
response_error['message'] = 'Bad Gateway'
|
302
|
-
response_error['status_line'] =
|
339
|
+
response_error['status_line'] = "HTTP/#{response_error['http_version']}"
|
303
340
|
response_error['status_line'] << " #{response_error['code']} "
|
304
341
|
response_error['status_line'] << " #{response_error['message']}"
|
305
342
|
return response_error
|
@@ -308,7 +345,7 @@ module SSRFProxy
|
|
308
345
|
# return response
|
309
346
|
status_msg = "Response <- #{response['code']}"
|
310
347
|
status_msg << " <- PROXY[#{@ssrf.proxy.host}:#{@ssrf.proxy.port}]" unless @ssrf.proxy.nil?
|
311
|
-
status_msg << " <- SSRF[#{@ssrf.host}:#{@ssrf.port}] <- URI[#{uri}]"
|
348
|
+
status_msg << " <- SSRF[#{@ssrf.url.host}:#{@ssrf.url.port}] <- URI[#{uri}]"
|
312
349
|
status_msg << " -- Title[#{response['title']}]" unless response['title'].eql?('')
|
313
350
|
status_msg << " -- [#{response['body'].size} bytes]"
|
314
351
|
print_good(status_msg)
|
data/lib/ssrf_proxy/version.rb
CHANGED
@@ -1,18 +1,10 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
#
|
3
|
-
# Copyright (c) 2015-
|
2
|
+
# Copyright (c) 2015-2017 Brendan Coles <bcoles@gmail.com>
|
4
3
|
# SSRF Proxy - https://github.com/bcoles/ssrf_proxy
|
5
4
|
# See the file 'LICENSE.md' for copying permission
|
6
5
|
#
|
7
6
|
|
8
7
|
module SSRFProxy
|
9
8
|
# Gem version
|
10
|
-
VERSION = '0.0.
|
11
|
-
# Elite font ASCII art from: http://patorjk.com/software/taag/
|
12
|
-
BANNER = " \n" \
|
13
|
-
" .▄▄ · .▄▄ · ▄▄▄ ·▄▄▄ ▄▄▄·▄▄▄ ▐▄• ▄ ▄· ▄▌ \n" \
|
14
|
-
" ▐█ ▀. ▐█ ▀. ▀▄ █·▐▄▄· ▐█ ▄█▀▄ █·▪ █▌█▌▪▐█▪██▌ \n" \
|
15
|
-
" ▄▀▀▀█▄▄▀▀▀█▄▐▀▀▄ ██▪ ██▀·▐▀▀▄ ▄█▀▄ ·██· ▐█▌▐█▪ \n" \
|
16
|
-
" ▐█▄▪▐█▐█▄▪▐█▐█•█▌██▌. ▐█▪·•▐█•█▌▐█▌.▐▌▪▐█·█▌ ▐█▀·. \n" \
|
17
|
-
" ▀▀▀▀ ▀▀▀▀ .▀ ▀▀▀▀ .▀ .▀ ▀ ▀█▄▀▪•▀▀ ▀▀ ▀ • \n".freeze
|
9
|
+
VERSION = '0.0.4'.freeze
|
18
10
|
end
|
metadata
CHANGED
@@ -1,281 +1,315 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ssrf_proxy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brendan Coles
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: coveralls
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.8.21
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.8.21
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: minitest
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '5.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '5.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: minitest-reporters
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '1.1'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ~>
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '1.1'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ~>
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
75
|
+
version: '12.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ~>
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
82
|
+
version: '12.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: rdoc
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - ~>
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
89
|
+
version: '6.0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ~>
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
96
|
+
version: '6.0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: rubocop
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - ~>
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
103
|
+
version: '0.52'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - ~>
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
110
|
+
version: '0.52'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: simplecov
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- -
|
115
|
+
- - ~>
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
117
|
+
version: '0.14'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- -
|
122
|
+
- - ~>
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
124
|
+
version: '0.14'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: terminal-table
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- -
|
129
|
+
- - ~>
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
131
|
+
version: '1.6'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
|
-
- -
|
136
|
+
- - ~>
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
138
|
+
version: '1.6'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
140
|
+
name: typhoeus
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
|
-
- -
|
143
|
+
- - ~>
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: '
|
145
|
+
version: '1.3'
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
|
-
- -
|
150
|
+
- - ~>
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: '
|
152
|
+
version: '1.3'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
154
|
+
name: yard
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
|
-
- -
|
157
|
+
- - ~>
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: '0'
|
160
|
-
type: :
|
159
|
+
version: '0.9'
|
160
|
+
type: :development
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
|
-
- -
|
164
|
+
- - ~>
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version: '0'
|
166
|
+
version: '0.9'
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
|
-
name:
|
168
|
+
name: base32
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
170
170
|
requirements:
|
171
|
-
- -
|
171
|
+
- - ~>
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version: '0'
|
173
|
+
version: '0.3'
|
174
174
|
type: :runtime
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
|
-
- -
|
178
|
+
- - ~>
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version: '0'
|
180
|
+
version: '0.3'
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
|
-
name:
|
182
|
+
name: celluloid
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
|
-
- -
|
185
|
+
- - ~>
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version:
|
187
|
+
version: 0.17.3
|
188
188
|
type: :runtime
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
|
-
- -
|
192
|
+
- - ~>
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version:
|
194
|
+
version: 0.17.3
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
|
-
name: celluloid
|
196
|
+
name: celluloid-io
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
198
198
|
requirements:
|
199
|
-
- -
|
199
|
+
- - ~>
|
200
200
|
- !ruby/object:Gem::Version
|
201
201
|
version: 0.17.3
|
202
202
|
type: :runtime
|
203
203
|
prerelease: false
|
204
204
|
version_requirements: !ruby/object:Gem::Requirement
|
205
205
|
requirements:
|
206
|
-
- -
|
206
|
+
- - ~>
|
207
207
|
- !ruby/object:Gem::Version
|
208
208
|
version: 0.17.3
|
209
209
|
- !ruby/object:Gem::Dependency
|
210
|
-
name:
|
210
|
+
name: colorize
|
211
211
|
requirement: !ruby/object:Gem::Requirement
|
212
212
|
requirements:
|
213
|
-
- -
|
213
|
+
- - ~>
|
214
214
|
- !ruby/object:Gem::Version
|
215
|
-
version: 0.
|
215
|
+
version: '0.8'
|
216
216
|
type: :runtime
|
217
217
|
prerelease: false
|
218
218
|
version_requirements: !ruby/object:Gem::Requirement
|
219
219
|
requirements:
|
220
|
-
- -
|
220
|
+
- - ~>
|
221
221
|
- !ruby/object:Gem::Version
|
222
|
-
version: 0.
|
222
|
+
version: '0.8'
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: htmlentities
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - ~>
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '4.3'
|
230
|
+
type: :runtime
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - ~>
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '4.3'
|
223
237
|
- !ruby/object:Gem::Dependency
|
224
238
|
name: ipaddress
|
225
239
|
requirement: !ruby/object:Gem::Requirement
|
226
240
|
requirements:
|
227
|
-
- -
|
241
|
+
- - ~>
|
228
242
|
- !ruby/object:Gem::Version
|
229
|
-
version: '0'
|
243
|
+
version: '0.8'
|
230
244
|
type: :runtime
|
231
245
|
prerelease: false
|
232
246
|
version_requirements: !ruby/object:Gem::Requirement
|
233
247
|
requirements:
|
234
|
-
- -
|
248
|
+
- - ~>
|
235
249
|
- !ruby/object:Gem::Version
|
236
|
-
version: '0'
|
250
|
+
version: '0.8'
|
237
251
|
- !ruby/object:Gem::Dependency
|
238
|
-
name:
|
252
|
+
name: logger
|
239
253
|
requirement: !ruby/object:Gem::Requirement
|
240
254
|
requirements:
|
241
|
-
- -
|
255
|
+
- - ~>
|
242
256
|
- !ruby/object:Gem::Version
|
243
|
-
version: '
|
257
|
+
version: '1.2'
|
244
258
|
type: :runtime
|
245
259
|
prerelease: false
|
246
260
|
version_requirements: !ruby/object:Gem::Requirement
|
247
261
|
requirements:
|
248
|
-
- -
|
262
|
+
- - ~>
|
249
263
|
- !ruby/object:Gem::Version
|
250
|
-
version: '
|
264
|
+
version: '1.2'
|
251
265
|
- !ruby/object:Gem::Dependency
|
252
|
-
name:
|
266
|
+
name: mimemagic
|
253
267
|
requirement: !ruby/object:Gem::Requirement
|
254
268
|
requirements:
|
255
|
-
- -
|
269
|
+
- - ~>
|
256
270
|
- !ruby/object:Gem::Version
|
257
|
-
version: '0'
|
271
|
+
version: '0.3'
|
258
272
|
type: :runtime
|
259
273
|
prerelease: false
|
260
274
|
version_requirements: !ruby/object:Gem::Requirement
|
261
275
|
requirements:
|
262
|
-
- -
|
276
|
+
- - ~>
|
263
277
|
- !ruby/object:Gem::Version
|
264
|
-
version: '0'
|
278
|
+
version: '0.3'
|
265
279
|
- !ruby/object:Gem::Dependency
|
266
280
|
name: socksify
|
267
281
|
requirement: !ruby/object:Gem::Requirement
|
268
282
|
requirements:
|
283
|
+
- - ~>
|
284
|
+
- !ruby/object:Gem::Version
|
285
|
+
version: '1.7'
|
286
|
+
type: :runtime
|
287
|
+
prerelease: false
|
288
|
+
version_requirements: !ruby/object:Gem::Requirement
|
289
|
+
requirements:
|
290
|
+
- - ~>
|
291
|
+
- !ruby/object:Gem::Version
|
292
|
+
version: '1.7'
|
293
|
+
- !ruby/object:Gem::Dependency
|
294
|
+
name: webrick
|
295
|
+
requirement: !ruby/object:Gem::Requirement
|
296
|
+
requirements:
|
297
|
+
- - ~>
|
298
|
+
- !ruby/object:Gem::Version
|
299
|
+
version: '1.3'
|
269
300
|
- - ! '>='
|
270
301
|
- !ruby/object:Gem::Version
|
271
|
-
version: 1.
|
302
|
+
version: 1.3.1
|
272
303
|
type: :runtime
|
273
304
|
prerelease: false
|
274
305
|
version_requirements: !ruby/object:Gem::Requirement
|
275
306
|
requirements:
|
307
|
+
- - ~>
|
308
|
+
- !ruby/object:Gem::Version
|
309
|
+
version: '1.3'
|
276
310
|
- - ! '>='
|
277
311
|
- !ruby/object:Gem::Version
|
278
|
-
version: 1.
|
312
|
+
version: 1.3.1
|
279
313
|
description: SSRF Proxy is a multi-threaded HTTP proxy server designed to tunnel client
|
280
314
|
HTTP traffic through HTTP servers vulnerable to HTTP Server-Side Request Forgery
|
281
315
|
(SSRF).
|
@@ -284,7 +318,9 @@ email:
|
|
284
318
|
executables:
|
285
319
|
- ssrf-proxy
|
286
320
|
extensions: []
|
287
|
-
extra_rdoc_files:
|
321
|
+
extra_rdoc_files:
|
322
|
+
- README.md
|
323
|
+
- LICENSE.md
|
288
324
|
files:
|
289
325
|
- LICENSE.md
|
290
326
|
- README.md
|
@@ -292,6 +328,7 @@ files:
|
|
292
328
|
- bin/setup
|
293
329
|
- bin/ssrf-proxy
|
294
330
|
- lib/ssrf_proxy.rb
|
331
|
+
- lib/ssrf_proxy/banner.rb
|
295
332
|
- lib/ssrf_proxy/http.rb
|
296
333
|
- lib/ssrf_proxy/server.rb
|
297
334
|
- lib/ssrf_proxy/version.rb
|
@@ -300,14 +337,19 @@ licenses:
|
|
300
337
|
- MIT
|
301
338
|
metadata: {}
|
302
339
|
post_install_message:
|
303
|
-
rdoc_options:
|
340
|
+
rdoc_options:
|
341
|
+
- --title
|
342
|
+
- SSRF Proxy
|
343
|
+
- --main
|
344
|
+
- README.md
|
345
|
+
- --line-numbers
|
304
346
|
require_paths:
|
305
347
|
- lib
|
306
348
|
required_ruby_version: !ruby/object:Gem::Requirement
|
307
349
|
requirements:
|
308
350
|
- - ! '>='
|
309
351
|
- !ruby/object:Gem::Version
|
310
|
-
version:
|
352
|
+
version: 2.2.2
|
311
353
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
312
354
|
requirements:
|
313
355
|
- - ! '>='
|
@@ -321,4 +363,4 @@ specification_version: 4
|
|
321
363
|
summary: SSRF Proxy facilitates tunneling HTTP communications through servers vulnerable
|
322
364
|
to SSRF.
|
323
365
|
test_files: []
|
324
|
-
has_rdoc:
|
366
|
+
has_rdoc: true
|