Ruby HTTP Header Injection



EKU-ID: 5651 CVE: OSVDB-ID:
Author: rootredrain Published: 2016-06-28 Verified: Verified
Download:

Rating

☆☆☆☆☆
Home


TIMELINE
rootredrain submitted a report to Ruby.

show raw
Jun 22nd

Hi,

I would like to report a HTTP Header injection vulnerability in
'net/http' that allows attackers to inject arbitrary headers in
request even create a new evil request.

PoC

require 'net/http'
http = Net::HTTP.new('192.168.30.214','80')
res = http.get("/r.php HTTP/1.1\r\nx-injection: memeda")

Example

Server Code:

#!/usr/bin/env ruby
require 'sinatra'
require 'uri'
require 'net/http'

get '/' do
  'hello world'
end

post '/' do
  ip = params[:ip]
  port = params[:port]
  path = params[:path]

  # do what you want
  http = Net::HTTP.new ip, port.to_i
  res = http.get path

  res.body

end

post data:

ip=192.168.30.214&port=80&path=/r.php%20HTTP/1.1%0d%0ax-injection: memeda

print_r all HTTP Headers:

Create an evil request

post data:

server log:

Suggestion:

Should validate URI legality before send request

btw,

Cloud I have a CVEID with this vulnerability? reported by
@redrain(rootredrain@gmail.com) and@ztz(ztz5651483@gmail.com)

4 attachments:
F100918: 123123.png
F100919: 222333.png
F100920: 4444.png
F100921: 5555.png

rootredrain posted a comment.
Jun 22nd (2 days ago)

The problem is this line in lib/net/http/generic_request.rb:324

  def write_header(sock, ver, path)
    buf = "#{@method} #{path} HTTP/#{ver}\r\n"
    each_capitalized do |k,v|
      buf << "#{k}: #{v}\r\n"
    end
    buf << "\r\n"
    sock.write buf
  end

"#{@method} #{path} HTTP/#{ver}\r\n" should be checked here to avoid
malicious input

shugo posted a comment.
Jun 24th (8 hrs ago)

Thanks for your report.

We don't consider this a vulnerability because Net::HTTP#get is not
designed to accept malicious input.
Applications have responsibility to verify input syntactically and
semantically (accepting all RFC2616-compliant input would not be a
good idea).

So we would like to handle this as a normal issue.

rootredrain posted a comment.
Jun 24th (2 hrs ago)

Hi shugo,

Thanks for the reply. Please don't leave this problem to developers,
they have uneven level at developing.

For example, assume we have a demo website, the only thing do is
generate a new HTTP request:

#!/usr/bin/env ruby
require 'sinatra'

get '/' do
  'hello world'
end

post '/' do
  ip = params[:ip]
  port = params[:port]
  path = params[:path]

  # send the request to another site
  http = Net::HTTP.new ip, port.to_i
  res = http.get path

  res.body
end

It's a common demand, right ?

But web developer may not realized that sinatra will auto decode url.
Attacker can encode \r\n to %0a%0d, send to the sinatra, sinatra will
decode url to \r\n and pass to thepath, finally cause a HTTP Header
Injection or CRLF Injection.

Please assume all input is malicious. Here is a similar vulnerability
in python: CVE-2016-5699

Here is what another HTTP lib Faraday do may change your mind.

lib/faraday/connection.rb:308

def url_prefix=(url, encoder = nil)
  uri = url_prefix = Utils.URI(url)
  self.path_prefix = uri.path
  # ... ... ...
  uri
end

uri = url_prefix = Utils.URI(url) try to convert url to URI, It will
raise an error whenurl is invalid.

lib/faraday/connection.rb:399

def build_exclusive_url(url = nil, params = nil, params_encoder = nil)
  url = nil if url.respond_to?(:empty?) and url.empty?
  base = url_prefix
  # ... ... ...
  uri = url ? base + url : base
  # ... ... ...
end

uri = url ? base + url : base will trigger another examination convert_to_uri:

def convert_to_uri(uri)
  if uri.is_a?(URI::Generic)
    uri
  elsif uri = String.try_convert(uri)
    parse(uri)
  else
    raise ArgumentError,
          "bad argument (expected URI object or URI string)"
  end
end

If url is invalid, it will raise an error.

Please let me know if you need more info.

tenderlove posted a comment.
Jun 24th (2 hrs ago)

It's a common demand, right ?

I'm not sure about that.

I think this is a bug we should probably address, but I don't think we
should consider this a vulnerability. Fetching arbitrary paths from
user input seems pretty dubious.

rootredrain posted a comment.
Jun 24th (about 1 hr ago)

Hi tenderlove,

Here is my point :
All input can not be trusted.

We should validate url in Net::HTTP

tenderlove posted a comment.
Jun 24th (about 1 hr ago)

All input can not be trusted.

Yes, people should be whitelisting paths passed in. An open proxy is
already a vulnerability, regardless of header injection.

As I said, we should treat this as a bug. But since an open proxy is
already a security problem (that we cannot fix), then I don't think
this bug should be treated as a security issue.

shugo posted a comment.
Jun 24th (34 mins ago)

But web developer may not realized that sinatra will auto decode url.
Attacker can encode \r\n to %0a%0d, send to the sinatra, sinatra will
decode url to \r\n and pass to the path, finally cause a HTTP Header
Injection or CRLF Injection.

In that case, it seems to be a bug of that application, not Net::HTTP#get.

I'm not against adding argument verification to Net::HTTP#get, though.

rootredrain posted a comment.
Jun 24th (29 mins ago)

But since an open proxy is already a security problem

Yes, an open proxy is already a vulnerability and you can't fix that,
but attack scenarios is not only include an open proxy, but also
include many other parts.

A site like google image, user can paste image url on it, then site
will request the resource. It's possible to suffer this attack.

Some video sites allow user reference outside resource. It's possible
to suffer this attack.

So you can not treat it occur in an unusual scenarios. I still
consider it was a security issue.

rootredrain posted a comment.
Jun 24th (27 mins ago)

If you believe this is not a issue, please allow the public disclosure.

tenderlove closed the report and changed the status to Informative.
Jun 24th (23 mins ago)

I've closed as informative, and I'll allow public disclosure.

tenderlove requested to disclose this report publicly.
Jun 24th (20 mins ago)

rootredrain has requested mediation from HackerOne Support.
Jun 24th (15 mins ago)

The HTTP scheme handler accepts percent-encoded values as part of the URL.

The generic_request.rb allows unsafe characters, it dosen't have any
safe filtration, attackers can cause actual security threat. so we
consider it is a vulnerability