Search code examples
rubytor

How to Build and Send an HTTP Request to a Tor Hidden Service with Ruby


I've spent the last couple of days looking for a solution to this problem, and though there are quite a few semi-relevant questions, none of the answers show a successful use case for sending a successful HTTP request over Tor to a hidden service using Ruby.

One thing that seems unclear in all the answers is how the Tor browser bundle acts as a proxy for requests.

I've tried multiple avenues of attack, the most recent being an attempt to adapt the PHP code here for sending curl requests to hidden services using Ruby CURL libraries.

This is my code using the Curb gem, which implements some of the libcurl bindings for Ruby:

require 'curb'

url = 'http://am4wuhz3zifexz5u.onion' #a known, functioning hidden service

c = Curl::Easy.new(url) do |curl| 
  curl.headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.0" #the user agent string from the most recent version of the tor browser
  curl.verbose = true
end

c.perform
c.inspect

I then tried to run this through socksify, using the IP address and port specified by the Tor browser bundle's proxy settings:

$ socksify_ruby 127.0.0.1 9150 tor-test/tor-test.rb

This produced the following output:

* Adding handle: conn: 0x7fb1fe195e00
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7fb1fe195e00) send_pipe: 1, recv_pipe: 0
* Could not resolve host: jhiwjjlqpyawmpjx.onion
* Closing connection 0

Every approach I've tried has produced a similar result: the URI for the hidden service cannot be resolved

Can anyone help me out here or point me in the right direction? I feel that since the Tor browser can connect programmatically to hidden services, we all should be able to as well : )


Solution

  • Curl only uses a proxy if you set it up in your "curl"-block.

    For example:

    c = Curl::Easy.new() do |curl| 
        curl.proxy_tunnel = true
        curl.proxy_type = Curl::CURLPROXY_SOCKS5 # also available and default Curl::CURLPROXY_HTTP
        curl.proxy_url = '127.0.0.1:9050' # local tor client/proxy
        curl.headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.0" #the user agent string from the most recent version of the tor browser
        curl.verbose = true
        curl.url = url # your example url
        curl.perform
        curl.inspect
    end
    

    Unfortunately curl does not use the proxy for hostname resolution. In other words, I did't find a way to force curl to use the proxy for hostname resolution.

    But you can try

    #enable socksify debug
    Socksify::debug = true
    
    #own try via direct use of socksify and Net::HTTP
    uri = URI.parse('http://am4wuhz3zifexz5u.onion/') #a known, functioning hidden service
    
    # some debug stuff - just ignore ;-)
    puts uri
    puts uri.host
    puts uri.port
    puts uri.path
    
    res1 = Net::HTTP.SOCKSProxy('127.0.0.1', 9050).start(uri.host, uri.port) do |http| 
        http.get(uri.path)
    end