• Twitter
  • Facebook
  • Youtube

Monday, September 4, 2017

Gathering employees information by capturing GUIDs



Hi everyone, this is Shawar Khan and today i am going to share one of my recent discovery in a famous tech giant. I will keep the company name private as they are not allowing any kind of disclosure related to their company so i will use REDACTED.com instead of the company domain.

So, i got an invitation to a program and started hunting it. The first thing before starting the actual test i do is to gathering information about the target, always make sure to test areas that are less explored.

Got around 2000 subdomains of the web applications by gathering information about it from different sources and by using tools like sublister. Afterwards, i performed a mass information gathering nmap script that i recently coded and i got many files having sensitive information on the subdomains but as this write-up is limited to the GUID issue so i will show you the file i got. Nmap http-enum NSE script discovered a test.html file on of of the subdomain with nmap:

It is always best to enumerate files in order to find something that the developers left on the server. Sometimes you can find functionalities in files that will give you access to password protected areas and sometimes you will get access to sensitive areas.

So, i accessed the server on port 443 and viewed test.html and got the following contents:

The file was some kind of redirection page which redirects the user to a password protected panel. It was having an input area which takes some kind of number and when submitted, redirects the user to https://subdomain.REDACTED.com/REDACTED-partner-gateway/initiate. Was not having any info about what it was made for and how it works. After checking the source i found something interesting. When the submit button is clicked, a submitForm() javascript function is executed:


and here is the javascript code that i found in the source code:



In the above code you can clearly see what the submitForm() function does. The functions grabs the value which we enter in the input field and places it in as GUID key's value in the following JSON template:

{"accountInfo":{"accountId":"REDACTED-dev1"},"campaignInfo":{},"pageInfo":{"localizedName":"Sign+In","logicalName":"Sign+In","errorMessage":"","loginMessage":"Normal+Login"},"userInfo":{"guid":"EIDM NUM HERE","language":"ENU","country":"US"}}

the whole value is base64 encoded afterwards and then it is set as the value of subportal-tracking-service cookie. So, the cookie is holding a base64 value, next what the function does is it redirects the user to https://subdomain.REDACTED.com/REDACTED-partner-gateway/initiate

After the redirection, 3 requests are sent to the server. The interesting one is the 3rd request:

POST /REDACTED-partner-gateway/loading HTTP/1.1
Host: subdomain.REDACTED.com
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/JSON
X-Requested-With: XMLHttpRequest
Cookie: subportal-tracking-service=eyJhY2NvdW50SW5mbyI6eyJhY2NvdW50SWQiOiJSRURBQ1RFRC1kZXYxIn0sImNhbXBhaWduSW5mbyI6e30sInBhZ2VJbmZvIjp7ImxvY2FsaXplZE5hbWUiOiJTaWduK0luIiwibG9naWNhbE5hbWUiOiJTaWduK0luIiwiZXJyb3JNZXNzYWdlIjoiIiwibG9naW5NZXNzYWdlIjoiTm9ybWFsK0xvZ2luIn0sInVzZXJJbmZvIjp7Imd1aWQiOiIxMTExMTEiLCJsYW5ndWFnZSI6IkVOVSIsImNvdW50cnkiOiJVUyJ9fQ==;
Connection: close
Content-Length: 0

a POST request is sent to a loading endpoint which returns the following response:
HTTP/1.1 200 OK
Date: Mon, 04 Sep 2017 16:16:53 GMT
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 42
Connection: close

{"url":"/REDACTED-partner-gateway/servererror"}



the response is a JSON string having a 'url' key value. This is an invalid response which means if we enter an invalid GUID key, we get this response. Now here comes the interesting part, the javascript code above the submitForm() function contains multiple commented base64 strings:


String 1: eyJhY2NvdW50SW5mbyI6eyJhY2NvdW50SWQiOiJSRURBQ1RFRC1kZXYxIn0sImNhbXBhaWduSW5mbyI6e30sInBhZ2VJbmZvIjp7ImxvY2FsaXplZE5hbWUiOiJTaWduK0luIiwibG9naWNhbE5hbWUiOiJTaWduK0luIiwiZXJyb3JNZXNzYWdlIjoiIiwibG9naW5NZXNzYWdlIjoiTm9ybWFsK0xvZ2luIn0sInVzZXJJbmZvIjp7Imd1aWQiOiIyMDE0MTEyNjE3MzU3ODYiLCJsYW5ndWFnZSI6IkVOVSIsImNvdW50cnkiOiJVUyJ9fQ==

String 2: eyJhY2NvdW50SW5mbyI6eyJhY2NvdW50SWQiOiJSRURBQ1RFRC1kZXYxIn0sImNhbXBhaWduSW5mbyI6e30sInBhZ2VJbmZvIjp7ImxvY2FsaXplZE5hbWUiOiJTaWduK0luIiwibG9naWNhbE5hbWUiOiJTaWduK0luIiwiZXJyb3JNZXNzYWdlIjoiIiwibG9naW5NZXNzYWdlIjoiTm9ybWFsK0xvZ2luIn0sInVzZXJJbmZvIjp7Imd1aWQiOiIyMDE2MDYyOTA2NTI2MTEiLCJsYW5ndWFnZSI6IkVOVSIsImNvdW50cnkiOiJVUyJ9fQ==

String 3: eyJhY2NvdW50SW5mbyI6eyJhY2NvdW50SWQiOiJSRURBQ1RFRC1kZXYxIn0sImNhbXBhaWduSW5mbyI6e30sInBhZ2VJbmZvIjp7ImxvY2FsaXplZE5hbWUiOiJTaWduK0luIiwibG9naWNhbE5hbWUiOiJTaWduK0luIiwiZXJyb3JNZXNzYWdlIjoiIiwibG9naW5NZXNzYWdlIjoiTm9ybWFsK0xvZ2luIn0sInVzZXJJbmZvIjp7Imd1aWQiOiIxMTI0MzQ3Njc1MjA3MDciLCJsYW5ndWFnZSI6IkVOVSIsImNvdW50cnkiOiJVUyJ9fQ==



which are having the following JSON strings if base64 decoded:


String 1: {"accountInfo":{"accountId":"REDACTED-dev1"},"campaignInfo":{},"pageInfo":{"localizedName":"Sign+In","logicalName":"Sign+In","errorMessage":"","loginMessage":"Normal+Login"},"userInfo":{"guid":"201411261735786","language":"ENU","country":"US"}}

String 2: {"accountInfo":{"accountId":"REDACTED-dev1"},"campaignInfo":{},"pageInfo":{"localizedName":"Sign+In","logicalName":"Sign+In","errorMessage":"","loginMessage":"Normal+Login"},"userInfo":{"guid":"201606290652611","language":"ENU","country":"US"}}

String 3: {"accountInfo":{"accountId":"REDACTED-dev1"},"campaignInfo":{},"pageInfo":{"localizedName":"Sign+In","logicalName":"Sign+In","errorMessage":"","loginMessage":"Normal+Login"},"userInfo":{"guid":"112434767520707","language":"ENU","country":"US"}}


from the decoded values we got the following GUIDs:

1. 201411261735786
2. 201606290652611
3. 112434767520707

These are the GUIDs which works as unique identifier. If the cookies contains a valid employee GUID, it responds with a JSON data having all information about the specific employee. As we got the GUIDs of some emloyees we can now get their data.

We can directly use the base64 encoded strings as cookies that we found in the javascript code or we can just enter the GUID in the input field of test.html file. We will send the following POST request having a valid cookie with valid GUID inside:


POST /REDACTED-partner-gateway/loading HTTP/1.1
Host: subdomain.REDACTED.com
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/JSON
X-Requested-With: XMLHttpRequest
Cookie:  subportal-tracking-service=eyJhY2NvdW50SW5mbyI6eyJhY2NvdW50SWQiOiJhdXRvZGVzay1kZXYxIn0sImNhbXBhaWduSW5mbyI6e30sInBhZ2VJbmZvIjp7ImxvY2FsaXplZE5hbWUiOiJTaWduK0luIiwibG9naWNhbE5hbWUiOiJTaWduK0luIiwiZXJyb3JNZXNzYWdlIjoiIiwibG9naW5NZXNzYWdlIjoiTm9ybWFsK0xvZ2luIn0sInVzZXJJbmZvIjp7Imd1aWQiOiIyMDE2MDYyOTA2NTI2MTEiLCJsYW5ndWFnZSI6IkVOVSIsImNvdW50cnkiOiJVUyJ9fQ==; 
Connection: close
Content-Length: 0

and we will get the JSON data in response:


Then i used python to parse the data properly, and used the following code:


And got this data:



So, Thats it! Got the information, just be knowing the GUID, we can get information of the employees. The issue was reported and is under fix.


Never forget to review the source code

If you love this writeup, Share! :) 

Contact

Get in touch with me