A Library for Detecting Known or Weak Secrets Across Many Web Frameworks
Thanks for reading Black Lantern Security (BLSOPS)! Subscribe for free to receive new posts and support my work.
We all know how much developers love to copy and paste things from Stack overflow.
But, what happens when a cryptographic secret is part of what gets copied? What if a project is forked from another project on GitHub and contains a pre-defined secret? What about when an official example code contains pre-filled in secrets? Looking at you, Microsoft.
Let’s keep picking on Microsoft and look at the Machine Key.
If someone copies this configuration, they are going to be using a Machine Key which is freely available on the internet. Without diving into the details, possession of the Machine Key with .NET apps is equivalent to code execution (if you want to dive into the details, go here).
To exploit this situation, we have used the tool Blacklist3r in the past. Blacklist3r will take a viewstate (a cryptographic product of the Machine Key), and attempt to decrypt/validate the viewstate using a collection of known keys. The key shown in the Microsoft documentation is in Blacklist3r’s key list, so using it would likely lead to someone getting RCE on your application. It’s also interesting to just Google one of the keys (like FBF50941F22D6A3B229EA593F24C41203DA6837F1122EF17) and see just how many results it shows up in. That key even appears in physical books published almost a decade ago.
Diving a bit deeper into Blacklist3r for a moment - it is not without its drawbacks. The main annoyance is that because it is a C# application, it is Windows dependent; unless you want to run Mono which is not without its own pitfalls. It’s also relatively slow; and although slowness is not a big deal when attacking one application, when doing things at scale, it can be very inefficient.
We created a BBOT module (if you do not know about BBOT, stop and go here) which was a wrapper around Blacklist3r to detect known Machine Keys. It worked, but the headaches around having Mono as a dependency got to be too much, and thoughts of making a pure Python Machine Key checker started to materialize.
Recreating C# encryption functionality in Python IS as painful as it sounds, but it would be worth it to remove that dependency? But wait – isn't this a problem on other platforms? There must be a ton of situations where known (or just painfully weak) secrets get used and create security vulnerabilities. ASP.NET Machine Keys were one of the few cases where a tool even existed to exploit this, and Python-based tools for non-Python frameworks just did not exist.
This is the vision of Badsecrets: a 100% pure Python library, which can facilitate checking the cryptographic products for known secrets across many platforms. It has a module-based design, which will make adding additional frameworks later a more straightforward process. And, since we are also the creators of BBOT, we have created an accompanying BBOT module to make finding this type of security weakness efficient at “bighuge” scales.
Currently, there are
ten eleven twelve modules:
ASPNET_Viewstate - Checks the viewstate/generator against a list of known Machine Keys.
Telerik_HashKey - Checks patched (2017+) versions of Telerik UI for a known Telerik.Upload.ConfigurationHashKey.
Telerik_EncryptionKey - Checks patched (2017+) versions of Telerik UI for a known Telerik.Web.UI.DialogParametersEncryptionKey.
Flask_SignedCookies - Checks for weak Flask cookie signing passwords. Wrapper for flask-unsign.
PeopleSoft_PSToken - Can check a PeopleSoft PS_TOKEN for a bad/weak signing password.
Django_SignedCookies - Checks Django's session cookies (when in signed_cookie mode) for known Django secret_key.
Rails_SecretKeyBase - Checks Ruby on Rails signed or encrypted session cookies (from multiple major releases) for known secret_key_base.
Generic_JWT - Checks JWTs for known HMAC secrets or RSA private keys.
Jsf_viewstate - Checks both Mojarra and Myfaces implementations of JavaServer Faces (JSF) for use of known or weak secret keys.
Symfony_SignedURL - Checks Symfony "_fragment" URLs for known HMAC key. Operates on Full URL, including hash.
Express_SignedCookies - Checks express.js signed cookies and session cookies for session secret
Laravel_SignedCookies - Checks 'laravel_session' cookies for known laravel 'APP_KEY'
Just the ASPNET_Viewstate module alone is already a full-blown replacement of Blacklist3r, which is faster and has no non-Python dependencies (we’re not knocking the guys at NotSoSecure who built it – they inspired all of this!).
There are other cases where a Badsecrets module can replace existing tools. The PeopleSoft_PSToken module can fully replace (at least for detection) the now homeless and hard to find TockenChpoken tool from 2015.
Previously, for JavaServer Faces (JSF) Viewstate exploitation, your best bet was one of a handful of random Python scripts floating around which only worked against a specific implementation and version of JSF, which were apparently created for a particular HackTheBox box.
The consequences of using known cryptographic keys vary widely across the modules. In some cases, it will result in an almost 100% chance of an RCE. In other cases, it may merely facilitate a privilege escalation by allowing control of a secure cookie. One thing Badsecrets does not much with is the actual exploitation of these vulnerabilities. It will help you find them, but you are generally on your own from there. Sometimes exploitation will be very straightforward, and in other cases it might require a lot of follow-on work or chaining with other vulnerabilities. This probably won’t change, as we do not really want to enable people to get RCE on systems when they have not put in even basic research to understand the vulnerabilities which they want to exploit.
There are some included “example” scripts. These include a general “CLI” utility (cli.py) which can accept any cryptographic product and try it against all modules at once. Blacklist3r.py is essentially a CLI recreation of Blacklist3r. Telerik_knownkey.py is a brute force tool that utilizes cryptographic functions within the Telerik-based Badsecrets modules. Symfony_knownkey.py can identify known Symfony HMAC keys, even when a sample hash can not be identified.
Despite the provided examples, Badsecrets is designed to be a library used by other tools. The most immediate example of this is the Badsecrets BBOT module, which makes much of its functionality immediately accessible in a way that can identify critical security vulnerabilities at scale.
Badsecrets has a couple of different “levels” it is designed to be used at. The most basic way is to load up a particular module, then submit a corresponding cryptographic product to it, and find out if that product was created with a known or weak secret.
It can also be used to “carve” data out of HTML content. For example, you can hand the carve functionality a page with an ASP.NET viewstate in it, and let it automatically find and test the viewstate without bothering with manually grabbing it.
The way our BBOT module interacts with Badsecrets is by taking advantage of the “carve_all_modules” functionality. Modules can include a special regex which helps the carve functionality find a particular type of secret. The carve_all_modules function checks an HTTP response against every available Badsecrets module. If it finds a matching secret, it moves on to trying to use all its known keys against it, as defined by the detecting module. Any matches get forwarded to BBOT’s event system, and just like that, you have yourself a confirmed critical vulnerability – all from merely parsing HTML content.
This can also be accomplished with the cli.py example script. This is not very fancy, but it is meant to be an example implementation of a CLI-based interface with Badsecrets. You can supply the “product” directly or use the
–url mode to actually visit a page and try to carve for one.
Some of the bad secrets detected by Badsecrets naturally lend themselves quite nicely to massively-scaled detection. This is because the cryptographic product in question is automatically presented on the page, and most or every page within the application. This applies to the ASPNET_Viewstate module, to the Jsf_Viewstate module (looking for JavaServer Faces viewstates), and to a much lesser extent - the Generic_JWT module.
However, not all the modules are going to work well with BBOT because the cryptographic products don’t just automatically appear on their own. In most cases, this is because the product in question is a cookie, which is usually only assigned after authentication. In these cases, it may be easier to manually check the secret, either using cli.py or manually from a Python console. This applies to the Django_SignedCookies, Rails_SecretKeyBase, and Flask_SignedCookies modules. This is why Badsecrets was started as a stand-alone project and later integrated into BBOT, and not just a BBOT component. BBOT can take parts of Badsecrets and make them scale beautifully, but is much less helpful in other cases.
In the case of the Telerik Badsecrets modules, finding a page which directly displays the `DialogParameters` value might be difficult. It will only appear on a page that utilizes the Telerik UI text editor utility. Without diving too far into the technical details of Telerik UI vulnerabilities (we’ve already done that elsewhere), it is the kind of thing that you’d be more likely to spot when looking through your Burp Suite history after testing an application, as opposed to being able to scan a lot of targets for it at once.
However, our included example utility (Telerik_knownkey.py) only requires the Telerik.Web.UI.DialogHandler.aspx endpoint and will brute force with all of the Telerik encryption and/or hash keys, even if a page containing the editor cannot be located or does not exist. This is the only public tool capable of exploiting fully patched versions of Telerik UI!
This is a good example of how one of the biggest benefits of Badsecrets: it’s a repository of various cryptographic implementations which might be otherwise not available in Python. For example, to make the telerik_encryptionkey module work with all known versions of Telerik UI, a Python implementation of C#’s specially modified pbkdf1 key derivation function had to be implemented, which deviates from the standard used by every other language. If anyone else should be unfortunate enough to need this in Python, it is available as a standalone class in helpers.py.
Hopefully, others will find these individual components useful and use them in other tools.
To get the known keys we check against, we used a combination of sources. One is just grabbing what is already out there in the community, such as with Blacklist3r’s existing Machine Keys. We also took a queue from Assetnote and used Google BigQuery to scrape all of GitHub for keys when we could. They have a database which includes all the code on GitHub, which is astounding, and incredibly useful (for both good and evil). This ended up letting us add on to existing collections of keys for some modules and build a good starting set for others which have not had one. But, be cautious with BigQuery – you can rack up hundreds of dollars in charges quickly if you are not careful!
The goal for Badsecrets is to become the standard bearer for this classification of ‘vulnerabilities’ (really, misconfigurations). Hopefully, there will be community contributions which can continue to grow the available modules and cover more web frameworks and utilities. We would LOVE it if someone just made a brand new module and submitted a pull request! But, a fantastic way people can contribute is to add to the known keys lists if they encounter one that we do not have that are also publicly exposed. Even just requests for modules to cover a specific framework would be immensely helpful!
Thanks for reading Black Lantern Security (BLSOPS)! Subscribe for free to receive new posts and support my work.