Hunter Tip #1 Response To Request Injection (RTRI)

Response To Request Injection (RTRI)



 



Summary



 



The title to this paper sounds super cool, but it is really not that cool and not that complicated, however it is clearly overlooked by the developers of applications and researchers hunting for their next bounty.  After you have finished reading it, it may seem blindingly obvious, but if this was the case, I would not be having the success I do with it as these vulnerabilities should have already been discovered.



These types of attacks have been extremely successful for me over the last two years in Bug Hunting.  In fact so successful that, I can easily attribute over $250,000 worth of bounties to this class of Insecure Direct Object Reference (IDOR) attack.



Examples include, from one program I received two $15,000 awards, from another at total of $18,000 and a partial payment for another of just under $13,000 (still waiting to see what the balance will be on it) and the recent H1-702 event I received an award for $10,000.  There are many more examples.



I think it is also worth pointing out a couple of quick facts




  1. ALL of these programs have been running for well over a year some nearly three years, and this class of IDOR escaped hundreds of pairs of “hacking eyes” yet I am still finding this class of attack present

  2. As you can tell by the example bounty payments some of these are large companies



For this paper, I am going to use an example that I actually found today (well a couple of days ago now) whilst dicking around with a Bug Bounty Program.  This vulnerability ended up as a zeroday in an off the shelf product and is classed as an Insecure Direct Object Reference Vulnerability



Step (1) – Discovery



 



Whilst looking over the target, there was an option to become an affiliate.  I figured I may as well try and register because if accepted it would open up the scope of the target for me.  Sure enough, an email dropped in 24 hours later.



Once I was logged into my new affiliate account, I immediately noticed in the top right hand corner



Affiliate Software by Post Affiliate Pro

version 5.5.10.7



Awesome, thanks for letting me know and saving me some time on google searches.  So instead of playing around with the target, I immediately looked to see if I could download the product so I could determine things on a local and therefore more informed basis - “white-box” testing could be a lot more informative than just hammering away at the exposed surface.  Unfortunately a download was not available, but the next best thing was, an online demo on the vendor’s site:



http://demo.postaffiliatepro.com/affiliates/





The first thing to try was the Merchant Login (wherever possible I always start with the highest privilege account I can, then work backwards)





Also, whenever I can, some of the first things I always focus on from an application administrator point of view are:




  1. adding a low privileged user

  2. adding an “admin” user



As we are logged in as the “admin” account, I created an affiliate account





And the POST data for creating the Affiliate account





Examining the POST data, the one thing that catches my eye is



[“rstatus”,”A”] – this is clearly the value for a user being approved.  With this class of IDOR however, the RESPONSE is actually more important.  We see - ["rtype","A",null,""] so at this point I assume this is setting the account type as “A” for Affiliate (see appendix A-1 for text format)



 





 



Now we move on to creating a Merchant (admin) account





The POST data for creating a Merchant Account





What is immediately clear is the [“roleid”,”pap_merc”] self explanatory



When looking at the response, I noticed the following ["rtype","M",null,""] (see Appendix A-2 for text format)





This is clearly setting the account type, with “M” being Merchant



For our final test, we now self-register an account as an unauthenticated user.  In the bug bounty target’s scenario, the affiliate registration required manual approval by the target Admin, or in this case the target Merchant Account.



Still using the demo account, I want to see what the POST request looks like and the Response





The self-registration POST data





Nothing exactly interesting there, but the response however is somewhat more interesting.



["rtype","A",null,""] – it has set us as an Affiliate (obviously)



["roleid","pap_aff",null,""] – it has allocated us with the role of Affiliate



["rstatus","P",null,""] – it has set our account in a Pending state as it requires manual approval by the Merchant  (see Appendix A-3 for text format)



 





A common mistake I am seeing regularly is the developers are trusting user supplied data on a POST (create) !!! even though it is NEVER expected within a request.  So for a quick demo



 



2) The Attack



We are going to self-register an account again, but this time adding to our POST data –



["rtype","M"],["roleid","pap_merc"],["rstatus","A"]



Note:




  1. at NO time has the parameter “rType” ever been present within a POST request, it is ONLY ever returned in responsesTHIS IS EXTEREMLY COMMON IN RTRI attacks.  Pay good attention to the responses.

  2. If we send ["roleid","pap_merc"] without the “rtype” value, your account sits in limbo land.  You can’t even log into the application because you will have an rtype of Affiliate, yet you have a role of Merchant.  The application is a little confused at this point :)





Response - (see Appendix A-4 for text format)





Now viewing the Merchants as the Merchant we see our account is added and its status is marked as approved





As easy as that :) Clearly at this point we have not managed to create a password, so we use the Forgot Password tool and then reset it and log in.





So in summary we went from an unauthenticated user to authenticated, bypassed the manual approval process and elevated privileges to Merchant (admin) all in a single request.



With this particular attack on the target I could




  1. View Customer PII and PCI data (limited to Bank Accounts / Swift Codes / PayPal Accounts etc)

  2. Set payouts of money to anyone – including myself of course.  An example transaction on the site was for $23,500.00

  3. Edit all affiliate accounts

  4. Edit the entire portal

  5. The vulnerability increased my attack surface area which introduced further vulnerabilities – examples found were, downloading of files from the file system, server side request forgery attacks that even returned the raw HTML of the target

  6. Ability to install plugins that would further increase my attack surface area hopefully introducing more vulnerabilities that could allow remote code execution.



On so many occasions, I have taken data from the response and literally crafted my own requests with some devastating effects against the application, hence some of the very large bounties that have been awarded.



Another common attack, still using the same principle is you will see are batch requests.  Yahoo Gemini or Yahoo Mail are classic examples.  These batch requests contain other requests within the POST data (99% of the time JSON) for example



{“method”:”POST”, “url”:”http://www.foobar.com” ,”data”:”mydata”}



In most cases, I see that the POST is always on a create action.  For example, create a new user.  When updating a user, the batch data will either be PUT or a PATCH but will also contain other unique data relevant to the existing session say for example the userID value.



So the attack here is to look at the response data on a POST request and note the values returned.  Using our example of creating a user, you will likely see a userid and some other really interesting info being returned.



Now make the POST request again, passing in some of these values.  As mentioned previously, I have seen this on many bug bounty programs.  Using the simple example of creating a user account and the userID is returned with the POST request, if I now make the POST request again but this time adding in an arbitrary userid, I literally end up hijacking the account, or a soft delete, meaning we now own that userId but the previous data attached to that userid is now replaced with our own.



If we tried to update the userid using the PUT / PATCH, the application 99% of the time would give a forbidden error message.  But, because the application sees a create action (POST), it does not bother to check the data and trusts the data being passed directly to it and simply overwrites the existing entry.



And finally another example is simple POST / PUT requests.  I had some great success with this against Square - https://squareup.com/



Example:



POST /appointments/api/staff – Creates a staff member.  The response returns the new staff_id



PUT /appointments/api/staff/12345678-1234-1234-1234-123456789012 – Updates a staff member



Using their own application, when booking an appointment, you chose the member of staff from the company which gave us the staff_id GUID.  So for this attack, we would always go after the owner J



Using the same principle, we made the POST request again, but added into our JSON POST data



“id”:”GUID-OF-THE-TARGET”



Again, the application was trusting the user supplied data sent on a POST (create).  Trying this on a PUT (update), the application responded correctly with a permission error.  The end result of this attack allowed a hijack of the owners account and a $3,000.00 bounty.



I have many examples; some are completely insane literally building up my own POST requests with around 7 additional parameters and values to finally get the attack to work.  That particular one took some time but paid $15,000.00



I would love to share more real examples of these and I will seek to get permission on some of them from the various bug bounty programs, but hopefully the above gives you, the developer, and you the bug hunter the general idea.



A big thanks to Mack and my brother David for proof reading my effort



 



 



Appendix – A



(1)



[{"fields":[["name","value","values","error"],["Id","afb3ceb2",null,""],["username","foo@bar.com",null,""],["rpassword","AGZ4K7hsFC42nchnk4QSclfWwfo68qet",null,""],["firstname","Foo",null,""],["lastname","Bar",null,""],["photo","",null,""],["rstatus","A",null,""],["note","",null,""],["dontSendEmail","N",null,null],["createSignupReferralComm","N",null,null],["agreeWithTerms","Y",null,null],["parentuserid","",null,""],["refid","121212",null,""],["data1","http:\/\/www.foo.com",null,""],["data2","Foobar",null,""],["data3","Foo",null,""],["data4","Bar",null,""],["data5","NV",null,""],["data6","US",null,""],["data7","98444",null,""],["data8","",null,""],["data9","",null,""],["userid","afb3ceb2",null,""],["numberuserid","1",null,""],["rtype","A",null,""],["dateinserted","2016-08-29 13:20:52",null,""],["dateapproved","2016-08-29 13:20:52",null,""],["deleted","N",null,""],["accountuserid","ec24e2ae",null,""],["minimumpayout","300",null,""],["payoutoptionid",null,null,""],["originalparentuserid",null,null,""],["data10",null,null,""],["data11",null,null,""],["data12",null,null,""],["data13",null,null,""],["data14",null,null,""],["data15",null,null,""],["data16",null,null,""],["data17",null,null,""],["data18",null,null,""],["data19",null,null,""],["data20",null,null,""],["data21",null,null,""],["data22",null,null,""],["data23",null,null,""],["data24",null,null,""],["data25",null,null,""],["authid","7d9e60bd",null,""],["accountid","default1",null,""],["roleid","pap_aff",null,""],["lastlogin",null,null,""],["loginscount",null,null,""],["salt","oEofC0rbLSinbGT0zzddX6efnKaWnyuMcT1PTt0Elj2wZWxzvKMtR0IfLTb8rGUD",null,""],["authtoken","34d5d76beb2814a76cc2469da581d4d7",null,""],["notificationemail",null,null,""],["ip","71.2.69.51",null,""],["openid_user_id",null,null,""]],"success":"Y","message":"Affiliate was successfully added"},{"rows":[["id","userid","refid","firstname","lastname","username","rstatus","dateinserted","parentuserid","parentfirstname","parentlastname"],["afb3ceb2","afb3ceb2","121212","Foo","Bar","foo@bar.com","A","2016-08-29 13:20:52",null,null,null],["11111111","11111111","testaff","Test","Affiliate","affiliate@example.com","A","2016-08-29 13:00:56",null,null,null]],"count":2}]



(2)



[{"fields":[["name","value","values","error"],["Id","6e933d74",null,""],["firstname","Hi",null,""],["lastname","Jack",null,""],["username","bar@foo.com",null,""],["rpassword","dAUVTjMIqCm\/CYlPeWkUz6QMCt5oU\/oQ",null,""],["retypepassword","P@ssw0rd!!",null,null],["roleid","pap_merc",null,""],["photo","",null,""],["userid","6e933d74",null,""],["refid","1a5f96f2",null,""],["numberuserid",null,null,""],["rtype","M",null,""],["dateinserted","2016-08-29 13:27:07",null,""],["dateapproved","2016-08-29 13:27:07",null,""],["deleted","N",null,""],["accountuserid","1a5f96f2",null,""],["parentuserid",null,null,""],["minimumpayout","300",null,""],["payoutoptionid",null,null,""],["note",null,null,""],["originalparentuserid",null,null,""],["data1",null,null,""],["data2",null,null,""],["data3",null,null,""],["data4",null,null,""],["data5",null,null,""],["data6","bar@foo.com",null,""],["data7",null,null,""],["data8",null,null,""],["data9",null,null,""],["data10",null,null,""],["data11",null,null,""],["data12",null,null,""],["data13",null,null,""],["data14",null,null,""],["data15",null,null,""],["data16",null,null,""],["data17",null,null,""],["data18",null,null,""],["data19",null,null,""],["data20",null,null,""],["data21",null,null,""],["data22",null,null,""],["data23",null,null,""],["data24",null,null,""],["data25",null,null,""],["authid","fa6ea33b",null,""],["accountid","default1",null,""],["rstatus","A",null,""],["lastlogin",null,null,""],["loginscount",null,null,""],["salt","NDkxUoqA8raobBz2pmFNeVHnsbNa25hPJBmDZNe8fpwq16tqs8dH3V5v6TG8YXYI",null,""],["authtoken","366b39065032b9d013bf16ab6f81a8da",null,""],["notificationemail",null,null,""],["ip","71.2.69.51",null,""],["openid_user_id",null,null,""]],"success":"Y","message":"Admin was successfully added"}]



(3)



[{"fields":[["name","value","values","error"],["Id","b4b47799",null,""],["username","xxx@xxx.com",null,""],["firstname","xxx",null,""],["lastname","xxx",null,""],["agreeWithTerms","Y",null,null],["parentuserid","",null,""],["refid","65757",null,""],["data1","http:\/\/www.ggg.com",null,""],["data2","xxx",null,""],["data3","xxx",null,""],["data4","xxx",null,""],["data5","xxx",null,""],["data6","US",null,""],["data7","98444",null,""],["data8","",null,""],["data9","",null,""],["lang",null,null,null],["userid","b4b47799",null,""],["payoutoptionid","8444af30",null,""],["numberuserid","1",null,""],["rtype","A",null,""],["dateinserted","2016-08-29 13:35:55",null,""],["dateapproved",null,null,""],["deleted","N",null,""],["accountuserid","6c2fdb96",null,""],["minimumpayout","300",null,""],["note",null,null,""],["photo",null,null,""],["originalparentuserid",null,null,""],["data10",null,null,""],["data11",null,null,""],["data12",null,null,""],["data13",null,null,""],["data14",null,null,""],["data15",null,null,""],["data16",null,null,""],["data17",null,null,""],["data18",null,null,""],["data19",null,null,""],["data20",null,null,""],["data21",null,null,""],["data22",null,null,""],["data23",null,null,""],["data24",null,null,""],["data25",null,null,""],["authid","a69ad936",null,""],["accountid","default1",null,""],["roleid","pap_aff",null,""],["rstatus","P",null,""],["lastlogin",null,null,""],["loginscount",null,null,""],["rpassword","Th0VoPJj",null,""],["salt",null,null,""],["authtoken","e7d289c907b453caa3f28adfdedcfcae",null,""],["notificationemail",null,null,""],["ip","71.2.69.51",null,""],["openid_user_id",null,null,""]],"success":"Y","message":"Affiliate was successfully added"}]



(4)



[{"fields":[["name","value","values","error"],["Id","d59aa0e7",null,""],["username","hijacker@hijack.com",null,""],["firstname","Hax",null,""],["lastname","Or",null,""],["rtype","M",null,""],["roleid","pap_merc",null,""],["rstatus","A",null,""],["agreeWithTerms","Y",null,null],["parentuserid","",null,""],["refid","10101",null,""],["data1","http:\/\/www.hijacked.com",null,""],["data2","xxx",null,""],["data3","xxx",null,""],["data4","xxx",null,""],["data5","xxx",null,""],["data6","US",null,""],["data7","98444",null,""],["data8","",null,""],["data9","",null,""],["lang",null,null,null],["userid","d59aa0e7",null,""],["payoutoptionid","8444af30",null,""],["numberuserid","1",null,""],["dateinserted","2016-08-29 13:42:41",null,""],["dateapproved","2016-08-29 13:42:41",null,""],["deleted","N",null,""],["accountuserid","1072b8a1",null,""],["minimumpayout","300",null,""],["note",null,null,""],["photo",null,null,""],["originalparentuserid",null,null,""],["data10",null,null,""],["data11",null,null,""],["data12",null,null,""],["data13",null,null,""],["data14",null,null,""],["data15",null,null,""],["data16",null,null,""],["data17",null,null,""],["data18",null,null,""],["data19",null,null,""],["data20",null,null,""],["data21",null,null,""],["data22",null,null,""],["data23",null,null,""],["data24",null,null,""],["data25",null,null,""],["authid","532d5465",null,""],["accountid","default1",null,""],["lastlogin",null,null,""],["loginscount",null,null,""],["rpassword","ftN3fNlfLABZKrUudxdS1LCqbMbI10gW",null,""],["salt","u3KqtcaNmRtSEWnN44uxT0DrwdPLnLHROrihEs40kyTYuhMymh5ghJHNWwzjigb6",null,""],["authtoken","1499336f6ac1140f9b4d404c7cacb792",null,""],["notificationemail",null,null,""],["ip","71.2.69.51",null,""],["openid_user_id",null,null,""]],"success":"Y","message":"Affiliate was successfully added"}]