Browser-based vulnerabilities in web applications
Web browsers or mobile browsers are software applications that act as the intermediary applications between a user and the World Wide Web and are used to access information from the Web. Some of the popular browsers which we are using in our daily life are Google Chrome, Mozilla Firefox, Internet Explorer, Opera, Safari, etc. With their wide usage and increasing popularity, they have become one of the major targets for exploitation by hackers. A small mistake during the coding of the application may result in it being vulnerable to intrusions i.e. the need for secure coding. This article is going to cover a few browser-based attacks, which are not browser specific and can be exploited on any browser if not closed by the application developers during writing or designing the application.
The following browser-based attacks, along with the mitigation, are going to be covered in this article:
- Browser cache: Obtaining sensitive information from the cache stored in browsers.
- Back and Refresh attack: Obtaining credentials and other sensitive data by using the Back button and Refresh feature of the browser.
- Passwords in browser memory: Getting the password or credit card details stored in the browser’s physical memory.
- Autocomplete: Obtaining the credentials of a user from the stored password in the browser.
- Browser history: Sensitive information leaked through the URL from the browser’s history.
Every time when a website is opened, the contents of that web page are sent to the browser’s temporary cache folder of a user’s machine. If those contents on that web page need to load again, the browser opens the page from the cache instead of downloading the page again. If some web application stores and shows the sensitive information to the user (such as their address, credit card details, username), this information could also be stored for caching, and hence it is retrievable through examining the browser’s cache.
In IE, these pages are stored in C:Users<user_name>AppDataLocalMicrosoftWindowsTemporary Internet Files
In Firefox, these pages are stored in C:Users<user_name>AppDataLocalMozillaFirefoxProfiles<profile-id>Cache
Or by typing the following URL in the address bar of the browser: about:cache
In Chrome, these pages are stored in C:Users<user_name>AppDataLocalGoogleChromeUser DataDefaultCache
Or by typing the following URL in the address bar of the browser: chrome://cache
Proof of concept
This demo is shown in the Mozilla Firefox browser. Log in to the application, access a few pages and then log out of the application. In the address bar, type about:cache. This shows the cache store in the browser. Go through the list and access the cache content of the website you are interested in.
The following screenshot shows the URL for the user dashboard. The user dashboard can have sensitive information like address, phone number, mapped credit card details, e-mail ID, etc.
On opening a specific cache entry, the user dashboard can be seen along with the address, phone number, order history, etc. This is shown in the following screenshot.
This problem can be mitigated by setting proper cache control attributes in the response header.
Mainly there are two types of cache attributes:
The no-cache attribute indicates that the browser should not use the information that is cached for that particular request–response pair. The browser stores the cache, but instead of showing the content from the cache, it sends the request to the server each time. But again, the cache will be only be in the browser and can be easily accessed by an attacker or malicious user.
The no-store attribute indicates that the request–response pair should not be cached and stored in the browser. This applies to the entire page.
You can implement the cache control using Meta tags also. Meta tags can be set as follows:
<meta http-equiv=”Cache-Control” content=”no-cache” />
<meta http-equiv=”Cache-Control” content=”no-store” />
Here, if the cache-control header is manually appended in the HTTP response and set to no-cache, as shown in the following screenshot, the browser will still cache the page.
If the browser cache is accessed, the cached pages of a user’s dashboard can be found. Opening it in Offline mode will show the order details, as shown in the screenshot below.
Now, if the value of a cache-control header is set to no-store, no-cache and the browser cache is accessed, the cached pages of a user’s dashboard will not be found. This is shown in the following screenshots.
Hence, the developer should analyze the web page content and implement proper cache-control attributes on the pages storing sensitive data.
Password in browser memory
Most of the applications and servers store the password in hashed or encrypted format, but such hashing/encryption is not applied while storing passwords in the browser memory. The GET and POST requests on any sensitive page where the user is supplying sensitive information (like credentials, credit card number, etc.) is stored in the browser memory while it is open. An attacker with local access to the system can read the sensitive data using memory-reading tools like WinHex. An adversary with physical access to the user’s open browser, after logout, can thus steal the sensitive data from the memory. Once sensitive data like a password is discovered, attackers can escalate their privileges in the application.
Proof of concept
Access the application. Enter the valid credentials, as shown in the following screenshot, and browse through the application.
The following screenshot shows the request going to the server with username and password.
After logging out of the application, do not close the browser. Open any memory reading tool like “Winhex” and navigate to the following path, as shown in the screenshots below:
Choose a browser (in this case Firefox) Select Entire Memory
Search through the data using the username. The complete login request for that specific application can be obtained, as shown in the screenshot below.
From here, an attacker can steal the login credentials of a user and escalate his privilege.
As this problem is present in the browser/local machine, using SSL will not mitigate this. A user can’t stop the browser from storing the password or other sensitive information. A solution has to be implemented through which the attacker can’t replay the password value obtained from the physical memory.
So, the solution for this is to implement salted hashing. Instead of sending the password to the server, send the salted hash value of the password.
Here is how the salted hashing technique works:
- Store the MD5 hash of the password in the database. (MD5 hash is a cryptographic technique in which the actual value can never be recovered).
- When a client requests for a login page, the server generates a random number called salt and sends it to the user along with the page.
- It then combines the hash value with the salt value and recalculates the hash value.
- This hash value is sent to the server.
- The server picks the hash value of the password from its database, combines it with the salt value and calculates the MD5 hash value.
- If both the values match (it will happen only when the user enters the correct password), the user is authenticated to the application.
Every time the salt value will be different; hence, even if the attacker gets the hashed password from the browser’s memory, he can’t replay it.
Back and Refresh attack
Browsers have the ability to maintain a recent record of pages that were visited by a user. The Back and Forward buttons on browsers use this functionality to display the pages recently browsed. In addition, browsers also keep track of variables like username, password, credit card details, etc. that were POSTed to the server while fetching the page. If a user logs in to the website, performs some actions and then logs out, and an adversary has access to the same machine as the user, he can see the logout page that is displayed on the browser window. He can then click the Back button until he reaches the page shown after a successful login. Here, the attacker can click the Refresh button, and the browser automatically resubmits the request with all the information.
Proof of concept
Consider the Change Password page of an application:
Log in to the application and access the Change Password page. Enter the values in the Current Password and New Password fields and click Submit.
The request and response series for the Change Password request are shown in the following screenshots.
The following screenshot shows that the password gets changed successfully.
Browse through the application and then log out of the application. After logout, leave the machine without closing the browser window.
An attacker who has physical access to this machine can simply click the Back button drop-down list and identify the page which comes after the Change Password page. This is depicted in the following screenshot.
When a specific page is clicked, the browser displays the warning that the page has expired, as shown in the following screenshot.
At this point the attacker can start a browser proxy tool like Burp and configure the browser to send its requests through the proxy.
On the error page, the adversary clicks the Refresh button. The browser shows a pop-up warning to the user about reposting some of the variables in order to access the page, as shown in the screenshot below. The attacker clicks the “Resend” button.
The attacker can see the request going to server using the configured proxy tool and can steal the password value of the user. This is shown in the screenshot below.
Variation of the attack
Many times it has been observed that the site is using redirection on successful login but not on unsuccessful login. If a login page is secured by CAPTCHA and the user provides the correct credentials but the wrong CAPTCHA value, then the user is again served with the login page with an error message.
In this case too, an attacker can steal the credentials using the Back and Refresh features. Even if CAPTCHA is not implemented, an attacker can get some sensitive information like correct username or password.
Proof of Concept
Access the login page of the application and provide the correct username and wrong password, as shown in the following screenshot.
After validating the credentials, the server responds with a “200 OK” with error stating “Username/Password is wrong”. This is shown in the screenshots below.
Click the Back button and access the page which came after providing the incorrect credentials, as shown in the following screenshot.
The browser warns that the document has expired and asks the user to resend the data to the server, as shown in the following screenshot. Configure the proxy between the browser and server and intercept the data going to the server. Click the “Resend” button.
The user credentials can be seen in cleartext in the captured request, as shown in the following screenshot.
Cause of problem
The browser keeps track of the requests sent to server to fetch particular pages. In this case, the Change Password page is “changepass.aspx” and the page which appears after is “changepass1.aspx”. The “changepass1.aspx” page is displayed after providing the Current, New and Confirm Password values. So, the browser remembers the request which is sent to get the “changepass1.aspx” page.
The following steps are present for the existing scenario:
- The user accesses the “changepass.aspx” page.
- The user types the current password, new password, and confirm new password and submits the request which is sent to “changepass1.aspx”.
- The user is authenticated in the “changepass1.aspx” page.
- The user is served with the “changepass1.aspx” page.
When the attacker clicks the “changepass1.aspx” page, the request which was sent to render “changepass1.aspx” is resent to the server. This request contains the current, new and confirm new password values.
The following steps will be performed if an intermediate page is implemented between “changepass.aspx” and “changepass1.aspx”:
- The user accesses the “ChangePass.aspx” page.
- The user types the current password, new password, and confirm new password and submits the request to “CheckPass.aspx”
- The user is authenticated in the “CheckPass.aspx” page.
- The user is redirected to the “ChangePass1.aspx” page.
- The browser sends a new request to fetch the “ChangePass1.aspx” page.
Now, even if an attacker refreshes the “changepass1.aspx” page, the request which the browser used to get “changepass1.aspx” will be sent, which is a redirect request sent by “CheckPass.aspx”. The request will be a simple GET request for fetching “ChangePass1.aspx” and there will be no value going in that request. The solution should be implemented on all the pages where a form is being submitted or some sensitive action is happening.
In many applications, when the user submits credentials, the browser shows a pop-up for remembering the password. If the user clicks “Remember password”, the browser will store the password and automatically enter it when the same application is accessed again. The feature is convenient for users, as they don’t have to remember and enter the password, but it poses a problem if the user is using this feature on a shared or public computer. An attacker can easily retrieve the stored password from the browser.
Even if the stored passwords are encrypted or protected by the master password (a password to access the stored passwords), an attacker can retrieve this password by visiting the application, for which the password is stored, in the browser. An attacker enters the username and the browser automatically fills the password field. An attacker can run a proxy tool like Burp to intercept the request going to server and then can obtain the cleartext or encrypted password going to server.
The saved password can be accessed by navigating to:
Security → Saved Password
Manage password (Under password and forms)
IE: Internet Options
Proof of concept
Here, after entering the credentials, the browser shows a popup asking the user if the password for the website should be remembered. This is depicted in the screenshot below.
If the user clicks “Remember Me”, the password will be stored in the browser. In Firefox, the saved password can be accessed by navigating to Tools →
Saved Password. This is depicted in the following screenshot.
When the “Saved Passwords” button is clicked, the browser shows the list of websites for which the passwords are stored in the browser. This is shown in the following screenshot.
If the “Show Passwords” button is clicked, the user will be able to see the stored passwords, as shown in the screenshot below.
Now, suppose the list of stored passwords is secured by a master password in the browser. Then the user has to enter the master password to access the list, as shown in the screenshot below.
In this case, an adversary needs to use an intermediate proxy tool to intercept the request going to the server.
Go to the application and double click the username field. It will show the list of the stored usernames. Click one username and the browser will automatically fill the password from the stored password list. This password can’t be seen, as it is hidden behind the asterisk symbol. A user can click the Submit button and capture the request going to server using a web proxy tool like Burp. From the intercepted request, it is easy to find the password of submitted username, as the data can be seen in cleartext. This is shown in the following screenshot.
The problem can be solved by setting the Autocomplete attribute in the Login and other sensitive pages. Make sure the Autocomplete attribute for all sensitive pages is set to “off”. A sensitive page can be the Login page, change password page, edit information page, etc. If Autocomplete is not configured on the page, then by default it is “ON” and the application will store the information.
This can be done using the following command:
< form autocomplete=”off”> – It will set Autocomplete to “OFF” for all form fields in the page.
Even if the browser is configured to store the password, the above code will overwrite the browser settings.
The Autocomplete attribute is ignored in the latest versions of all browsers. Hence, the above solution won’t work for the latest versions of the browsers.
As a security best practice, a user should be warned with a generic warning message about storing the cleartext password in the browser.
When a user submits any data, it goes to the server either in a GET request or in a POST request. In a GET request the user data is present in the URL itself, whereas in a POST request the user data is present in the body of the request. The following two screenshots show user data going in GET and POST requests.
All GET requests that are accessed from the browser are stored in the browser’s history and cache. This data can be viewed even if the user is logged out or the browser is closed by checking the history of the browser. So, if an application sends the user’s sensitive information through a GET request, i.e. through URL, an attacker can obtain this data by checking the browser history.
Proof of concept
Here, after entering the credentials on the website when the user clicks the LOG IN button, the credentials are sent in a GET request. This is shown in the following screenshot.
The request going to server is captured in Burp, which shows that the user provided data is sent as a GET request. This is depicted in the following screenshot.
So, an attacker who has physical access to the user’s machine can see these credentials in the browser’s history, as shown in the screenshot below.
In the same way, if an application sends other sensitive data like credit card details through the GET request, the data can be accessed from the browser history.
Never send sensitive information in the GET request. Data containing sensitive information should be sent through the POST request. When sensitive information is sent in the POST request, the data goes in the request body, and hence can’t be accessed from the browser history, because the browser history only shows all the GET requests.
Implement the POST method in the form as shown below:
<form name=”login” action=”index_submit” method=”POST” accept-charset=”utf-8″>
The above screenshots shows that no sensitive data is being stored in the browser history when the application is using POST instead of the GET method.
So, we have now discussed some browser-based attacks in this article. These attacks are applicable on web as well as mobile browsers. To perform any of the above attacks, an attacker has to depend on the following points:
- The attacker should have physical access to the victim’s machine.
- For some attacks, the browser should not be closed.
- The victim should not delete the browsing history, cache, etc.
Due to all these limitations, the risk rating for all the above mentioned attacks ranges from Medium to Low, but depending on the information received, it can be high too. If an attacker can get account/credit/debit card details in the browser’s cache or through the Back and Refresh attack, then the risk rating would be high. All these vulnerabilities can be avoided by implementing the proper controls discussed in this article.