HTTP2 requests through PROXY, ruby - ruby-on-rails

I have some remote REST API running through HTTP2. It runs through SSL using certificate. The goal is to send and receive data via HTTP2 with SSL certificate via Proxy.
There are http-2 & net-http2 gems that allow to send requests with HTTP2. But what about proxy? In a standard Net::HTTP library, there is a child class, Net::HTTP::Proxy that duplicates behavior of parent's Net::HTTP class except the fact it sends requests via proxy-server. But HTTP2 gems does not support it.
The closes idea I came up is to make something similar to Proxy implementation of http1.1 - to write "Host:" and "Proxy-Authorization: " fields to the socket, that Net-Http2 gem uses:
#socket.writeline sprintf('CONNECT %s:%s HTTP/%s',
#address, #port, HTTPVersion)
#socket.writeline "Host: #{#address}:#{#port}"
if proxy_user
credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
credential.delete!("\r\n")
#socket.writeline "Proxy-Authorization: Basic #{credential}"
end
#socket.writeline ''
But it ends up with:
SSL_connect SYSCALL returned=5 errno=0 state=SSLv2/v3 read server hello A
I might miss some technical knowledge to achieve this, so any help related to direction of research is appreciated.

After all, I finished my idea with an example present in net/http standard library and created a pull request for Net-http2 gem: https://github.com/ostinelli/net-http2/pull/11
The idea was correct, all we have to do is to send proxy "CONNECT" message using any tcp socket, with an address where we want to connect, so it creates a TCP tunnel which bypass all the data in and out, doesn't matter if it is HTTP1.1 or HTTP2, or anything else.
Here is a part of code:
def self.proxy_tcp_socket(uri, options)
proxy_addr = options[:proxy_addr]
proxy_port = options[:proxy_port]
proxy_user = options[:proxy_user]
proxy_pass = options[:proxy_pass]
proxy_uri = URI.parse("#{proxy_addr}:#{proxy_port}")
# create a regular TCP socket (with or w/o SSL, if needed)
proxy_socket = tcp_socket(proxy_uri, options)
# The majority of proxies do not explicitly support HTTP/2 protocol,
# while they successfully create a TCP tunnel
# which can pass through binary data of HTTP/2 connection.
# So we’ll keep HTTP/1.1
http_version = '1.1'
buf = "CONNECT #{uri.host}:#{uri.port} HTTP/#{http_version}\r\n"
buf << "Host: #{uri.host}:#{uri.port}\r\n"
if proxy_user
credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
credential.delete!("\r\n")
buf << "Proxy-Authorization: Basic #{credential}\r\n"
end
buf << "\r\n"
proxy_socket.write(buf)
validate_proxy_response!(proxy_socket)
proxy_socket
end

Related

Ruby Telnet: How to send http request using telnet

I am using ruby telnet library to make HTTP get request(http://127.0.0.1:3000/test) but i am not able to make http get request to my server.
Below is the code that i am trying
require 'net/telnet'
webserver = Net::Telnet::new('Host' => '127.0.0.1', 'Port' => 3000, 'Telnetmode' => false)
size = 0
webserver.cmd("GET / HTTP/1.1\nHost: 127.0.0.1/test") do |c|
print c
end
Please let me know what wrong i am doing here.
You need to end your input HTTP with a carriage return and line ending, otherwise the HTTP server will wait for more headers:
webserver.cmd("GET /test HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n") do |c|
print c
end
But telnet really isn't the right thing to use (unless you're just experimenting). If you want to make HTTP requests for a real-world program, you should definitely use a proper HTTP library (net/http at the least, or something like Faraday would be even better). HTTP seems simple, but there are many hidden complexities that mean creating a writer/parser from scratch is a lot of work.

How to use $remote_addr with rails and nginx secure_link

I have a rails application that makes calls to another server via net::http to retrieve documents.
I have set up Nginx with secure_link.
The nginx config has
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr mySecretCode";
On the client side (which is in fact my rails server) I have to create the secure url something like:
time = (Time.now + 5.minute).to_i
hmac = Digest::MD5.base64digest("#{time}/#{file_path}#{IP_ADDRESS} mySecretCode").tr("+/","-_").gsub("==",'')
return "#{DOCUMENT_BASE_URL}/#{file_path}?md5=#{hmac}&expires=#{time}"
What I want to know is the best way to get the value above for IP_ADDRESS
There are multiple answers in SO on how to get the ip address but alot of them do not seem as reliable as actually making a request to a web service that returns the ip address of the request as this is what the nginx secure link will see (we don't want some sort of localhost address).
I put the following method on my staging server:
def get_client_ip
data=Hash.new
begin
data[:ip_address]=request.ip
data[:error]=nil
rescue Exception =>ex
data[:error]=ex.message
end
render :json=>data
end
I then called the method from the requesting server:
response = Net::HTTP.get_response(URI("myserver.com/web_service/get_client_ip"))
if response.class==Net::HTTPOK
response_hash=JSON.parse response.body
ip=response_hash["ip_address"] unless response_hash[:error]
else
#deal with error
end
After getting the ip address successfully I just cached it and did not keep on calling the web service method.

LuaSocket (UDP) not receiving datagrams

I'm experimenting with LuaSocket for a project I'm working on. I've chosen UDP as my protocol.
Looking for docs and tutorials online, I've attempted to create a client-server pair for testing and learning.
According to what I've read, the following code should work. However, only the server seems to be working properly. The client sends a message, but it will not receive the reply from the server.
Thank you for any help anyone can provide.
Server:
-- Server
#!/usr/bin/env lua5.1
local socket = require("socket")
udp = socket.udp()
udp:setsockname("*", 53474)
udp:settimeout(0)
while true do
data, ip, port = udp:receivefrom()
if data then
print("Received: ", data, ip, port)
udp:sendto(data, ip, port)
end
socket.sleep(0.01)
end
Client:
-- Client
#!/usr/bin/env lua5.1
local socket = require("socket")
udp = socket.udp()
udp:setpeername("127.0.0.1", 53474)
udp:settimeout(0)
udp:send("Data!")
data = udp:receive()
if data then
print("Received: ", data)
end
The timeout value you set is 0, which causes the client timeout every time.
To fix it, give it a positive timeout value:
udp:settimeout(1)
Or set it to nil or a negative value, so it blocks indefinitely:
udp:settimeout()
or
udp:settimeout(-1)

Metasploit: send_request_cgi returns nil for HTTPS connections

I am currently trying to write an auxiliary module for Metasploit. The module basically tries multiple default credentials to get access to the router's management page. The authentication is done via web, i.e. HTTP POST.
Currently, the module works as expected for plain HTTP connections, i.e. unsecured connections, however every connection attempt via HTTPS (port 443), returns nil. Below is the function used within the Metasploit class to retrieve the login page:
def get_login_page(ip)
begin
response = send_request_cgi(
'uri' => '/',
'method' => 'GET'
)
# Some models of ZyXEL ZyWALL return a 200 OK response
# and use javascript to redirect to the rpAuth.html page.
if response && response.body =~ /changeURL\('rpAuth.html'\)/
vprint_status "#{ip}- Redirecting to rpAuth.html page..."
response = send_request_cgi(
'uri' => '/rpAuth.html',
'method' => 'GET'
)
end
rescue ::Rex::ConnectionError
vprint_error "#{ip} - Failed to connect to Web management console."
end
return response
end
When trying to connect via HTTPS, the first send_request_cgi call returns nil. No exception are caught or thrown. I have tried with 3 different hosts to make sure the issue was not with a specific endpoint. All my 3 attempts failed to return a response. At every attempt, I set the RPORT option to 443;
RHOSTS 0.0.0.0 yes The target address range or CIDR identifier
RPORT 443 yes The target port
Note that I have replaced the real IP with 0.0.0.0. Using a web browser, I can actually connect to the router via HTTPS with no issue (other than having to add an exception since the certificate is untrusted) and am presented the login page. With Wireshark, I tried to look at the generated traffic. I can clearly see that nothing is sent by the router. I notice the 3-way handshake being completed and the HTTP GET request being made:
GET / HTTP/1.1
Host: 0.0.0.0
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
There are 3-4 ACK after and then a FIN/PUSH sent by the server.
Based on this page on Metasploit's GitHub, I was under the impression that connections to HTTPS websites were handled by the underlying framework. I have not seen any articles/tutorial/source that leads me to believe otherwise. The doc about the send_request_cgi does not specify any specific requirement to establish a HTTPS connection. Other posts did not had the exact same issue I'm having. At this point I suspect either the OS, the framework or me forgetting to enable something. Other modules I have looked at either only targets HTTP websites - which I doubt - or do not have any special handling for HTTPS connections.
Any help determining the cause would be greatly appreciated.
Version of Metasploit:
Framework: 4.9.3-2014060501
Console : 4.9.3-2014060501.15168
Version of OS:
SMP Debian 3.14.5-1kali1 (2014-06-07)
As per this post on SecurityStreet, the solution was to set SSL to true in the DefaultOptions in the initialize function:
def initialize
super(
...
'DefaultOptions' =>
{
...
'SSL' => true
}
)
...
end
Connections to routers using HTTPS worked afterwards.

How to set the timeout for a proxy connection in Ruby

I know how to set the open/read timeout for the request going through the proxy. My problem, however, is that occasionally my proxy goes down, and therefore I am unable to ever connect to the proxy. So I want to be able to set the timeout to connect to the proxy to some value, and then handle the timeout by trying something else. Any idea how I can set the timeout value for connecting to an http proxy? Thanks!
First the code, then a bit of explaination below:
# get an instance of Net::HTTP that has proxy settings embedded
# see the source: http://ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTP.html#method-c-Proxy
proxyclass = Net::HTTP::Proxy("proxy_host");
# Create a new instance of the URL you want to connect to
# NOTE: no connection is attempted yet
proxyinstance = proxyclass.new("google.com");
# Make your setting changes, specifically the timeouts
proxyinstance.open_timeout = 5;
proxyinstance.read_timeout = 5;
# now, attempt connecting through the proxy with the desired
# timeout settings.
proxyinstance.start do |http|
# do something with the http instance
end
The key is realizing open_timeout and read_timeout are instance variables and that Net::HTTP::Proxy actually returns a decorated Net::HTTP class.
You would run into this same problem with similar Net::HTTP usage. You must construct it the "long" way, not using the Net::HTTP.start() class method shortcut.

Resources