Web Server and Proxy

Web Server

You can run Ruby as web server for any folder/file on any unused port, here's a oneliner code
1
ruby -run -e httpd /var/www/ -p 8000
Copied!
or
1
require 'webrick'
2
server = WEBrick::HTTPServer.new :Port => 8000, :DocumentRoot => '/var/www/'
3
# WEBrick::Daemon.start # Stating WEBRick as a daemon
4
server.start
Copied!
HTTPS server
1
require 'webrick'
2
require 'webrick/https'
3
4
cert = [
5
%w[CN localhost],
6
]
7
8
server = WEBrick::HTTPServer.new(:Port => 8000,
9
:SSLEnable => true,
10
:SSLCertName => cert,
11
:DocumentRoot => '/var/www/')
12
server.start
Copied!
Advanced HTTP Server
During working on CVE-2016-4971(Wget) exploit, more advanced & custom behavior needed. Here is a web server with a fake login form that saves the collected credentials to a text file. This comes in handy when you don't need to make customizations on apache config or you don't have enough privileges to do so. It require no knowledge for web frameworks like Rails or Senatra.
1
#!/usr/bin/env ruby
2
#
3
# KING SABRI | @KINGSABRI
4
#
5
require 'webrick'
6
7
#
8
# Servlet: Is a Web Server with custom behavior class
9
# It's a subclass of WEBrick::HTTPServlet::AbstractServlet
10
#
11
class RubyfuServlet < WEBrick::HTTPServlet::AbstractServlet
12
13
# Control 'GET' request/response
14
def do_GET(req, res)
15
res.status = 200
16
res['Content-Type'] = "text/html; charset=UTF-8"
17
res['Server'] = "Rubyfu WebServer"
18
res['Cache-Control'] = "no-store, no-cache,"
19
res.body = print_login(req)
20
end
21
22
private
23
# Show login
24
def print_login(req)
25
html = %q{
26
<center>
27
<table cellpadding="3" border="1">
28
<tr><td colspan="2"><center><h4><b>Enter your Username and Password</b></h4></center></td></tr>
29
<form method="POST" action="/login">
30
<tr><td><strong><b>Username:</b></strong></td><td><input name="username" type="text"></td></tr>
31
<tr><td><strong><b>Password:</b></strong></td><td><input name="password" type="password"></td></tr>
32
<tr><td colspan="2"><center><h1><b><input type="submit" value="Login" /></b></h1></center></td></tr>
33
</form>
34
</table>
35
</center>
36
}
37
end
38
39
end
40
41
class Login < WEBrick::HTTPServlet::AbstractServlet
42
43
# Control 'POST' request/response
44
def do_POST(req, res)
45
status, content_type, body = save_login(req)
46
res.body = body
47
end
48
49
# Save POST request
50
def save_login(req)
51
username, password = req.query['username'], req.query['password']
52
53
if !(username && password).empty?
54
# Print Credentials to console
55
puts "\n-----[ START OF POST ]-----"
56
puts "[+] #{username}:#{password}"
57
puts "-----[ END OF POST ]-----\n\n"
58
# Write Credentials to file
59
File.open("credentials.txt", '+a') {|f| f.puts "#{username}:#{password}"}
60
return 200, 'text/plain', 'Success! Thank you.'
61
else
62
puts "[!] Empty username and password."
63
return 404, 'text/plain', 'Wrong username or password!'
64
end
65
66
end
67
end
68
69
70
begin
71
port = ARGV[0]
72
raise if ARGV.size < 1
73
74
# Start Web Server
75
puts "[+] Starting HTTP server on port: #{port}\n"
76
server = WEBrick::HTTPServer.new(ServerName: "Rubyfu HTTP Server",
77
Port: port,
78
BindAddress: '0.0.0.0',
79
AccessLog: [],
80
Logger: WEBrick::Log.new(File.open(File::NULL, 'w'))
81
)
82
server.mount("/", RubyfuServlet)
83
server.mount("/login", Login)
84
trap "INT" do server.shutdown end
85
server.start
86
87
rescue Exception => e
88
puts "ruby #{__FILE__} <WEB_SERVER_PORT>" if ARGV.size < 1
89
puts e, e.backtrace
90
exit 0
91
end
Copied!
Run it
1
ruby webrick-server.rb 8080
2
[+] Starting HTTP server on port: 8080
3
4
-----[ START OF POST ]-----
5
6
-----[ END OF POST ]-----
7
8
9
-----[ START OF POST ]-----
10
[+] support:Puppies
11
-----[ END OF POST ]-----
12
13
[!] Empty username and password.
14
15
-----[ START OF POST ]-----
16
[+] user1:12345678
17
-----[ END OF POST ]-----
Copied!
You'll find credentials have been saved in 'credentials.txt'
References

Web Proxy

As we can run web server, we can run a proxy server, here's a oneliner code to run a web proxy server in ruby
1
ruby -r webrick/httpproxy -e 's = WEBrick::HTTPProxyServer.new(:Port => 8080, :RequestCallback => Proc.new{|req,res| puts req.request_line, req.raw_header}); trap("INT"){s.shutdown}; s.start'
Copied!

Transparent Web Proxy

1
require 'webrick'
2
require 'webrick/httpproxy'
3
4
handler = proc do |req, res|
5
puts "[*] Request"
6
puts req.inspect
7
request = req.request_line.split
8
puts "METHOD: " + "#{request[0]}"
9
puts "Request URL: " + "#{request[1]}"
10
puts "Request path: "+ "#{req.path}"
11
puts "HTTP: " + "#{request[2]}"
12
puts "Referer: " + "#{req['Referer']}"
13
puts "User-Agent: " + "#{req['User-Agent']}"
14
puts "Host: " + "#{req['Host']}"
15
puts "Cookie: " + "#{req['Cookie']}"
16
puts "Connection: " + "#{req['Connection']}"
17
puts "Accept: " + "#{req['accept']}"
18
puts "Full header: " + "#{req.header}"
19
puts "Body: " + "#{req.body}"
20
puts "----------[END OF REQUEST]----------"
21
puts "\n\n"
22
23
puts "[*] Response"
24
puts res.inspect
25
puts "Full header: " + "#{res.header}"
26
puts "Body: " + "#{res.body}"
27
puts "----------[END OF RESPONSE]----------"
28
puts "\n\n\n"
29
end
30
31
proxy = WEBrick::HTTPProxyServer.new Port: 8000,
32
ServerName: "RubyFuProxyServer",
33
ServerSoftware: "RubyFu Proxy",
34
ProxyContentHandler: handler
35
36
trap 'INT' do proxy.shutdown end
37
38
proxy.start
Copied!

Transparent Web Proxy with Authentication

Well, it was great to know that building a proxy server is that easy. Now we need to Force authentication to connect to the proxy server
To enable authentication for requests in WEBrick you will need a user database and an authenticator. To start, here's a htpasswd database for use with a DigestAuth authenticator:
The :Realm is used to provide different access to different groups across several resources on a server. Typically you'll need only one realm for a server.
1
#!/usr/bin/env ruby
2
require 'webrick'
3
require 'webrick/httpproxy'
4
5
# Start creating the config
6
config = { :Realm => 'RubyFuSecureProxy' }
7
# Create an htpasswd database file in the same script path
8
htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'rubyfuhtpasswd'
9
# Set authentication type
10
htpasswd.auth_type = WEBrick::HTTPAuth::DigestAuth
11
# Add user to the password config
12
htpasswd.set_passwd config[:Realm], 'rubyfu', '[email protected]'
13
# Flush the database (Save changes)
14
htpasswd.flush
15
# Add the database to the config
16
config[:UserDB] = htpasswd
17
# Create a global DigestAuth based on the config
18
@digest_auth = WEBrick::HTTPAuth::DigestAuth.new config
19
20
# Authenticate requests and responses
21
handler = proc do |request, response|
22
@digest_auth.authenticate request, response
23
end
24
25
26
proxy = WEBrick::HTTPProxyServer.new Port: 8000,
27
ServerName: "RubyFuSecureProxy",
28
ServerSoftware: "RubyFu Proxy",
29
ProxyContentHandler: handler
30
31
trap 'INT' do proxy.shutdown end
32
33
proxy.start
Copied!
If you do it right, you'll get an authentication pop-up in your browser just like below.
References