πŸ”ŽStatic Analysis of Client-Side JavaScript for pen testers and bug bounty hunters

JavaScript has become one of the most ubiquitous technologies in the modern web browsers. Applications built using client-side JavaScript frameworks such as AngularJS, ReactJS and Vue.js push a lot of functionality and logic to the front-end.

With the increased functionality/logic on the client-side, the attack surface on the client-side also increases.

As a security tester it is essential for us to understand the attack surface of these applications. It is also important for us to know what information to look for, where to look for and how to look for the information that will lead to the discovery of potential security issues in the applications.

In this blog post we will look at performing static analysis of client-side JavaScript code in order to uncover potential security issues in the applications.

In this blog post we are particularly interested in performing static analysis to uncover security issues. We will not delve into performance analysis or functional testing.

What to look for?

As a penetration tester, when we are performing static analysis of client-side JavaScript, we are more or less interested in the information that will fall under following categories β€”

  1. Information that’ll increase the attack surface (URLs, domains etc)

  2. Sensitive information (Passwords, API keys, Storage etc)

  3. Potentially dangerous areas in code(eval, dangerouslySetInnerHTML etc)

  4. Components with known vulnerabilities (Outdated frameworks etc)

Steps to perform static analysis

We’ll perform static analysis by breaking it down into following steps:

1. Identifying and gathering JavaScript files in an application 2. Making the gathered JavaScript code readable (Unminify/Deobfuscate) 3. Identifying information that may lead to discovery of security issues

Gathering JavaScript files

1.If you use Burp Suite for testing applications then there are multiple ways to gather all the JavaScript files in an application.

At Appsecco, We follow user-driven workflow for testing web applications where we start testing by navigating the entirety of the application like an end user would do.

Navigate through an application while the traffic is being sent through Burp proxy. Once you are done with the navigation, you can use Burp’s tool-set to extract all the JavaScript files.

  • If you are using Burp Suite Community Edition, you can navigate to proxy > HTTP history and use the display filters to only display the JavaScript files used by the application. You can also copy the URLs for all the JavaScript files displayed.

  • If you are using Burp Suite Professional, You can not only copy the URLs for all the JavaScript files in an application but also export all the scripts. Under Target > Site map right click on the site of interest and select Engagement tools > Find scripts . Using this feature you can export all the scripts in that application and also copy URLs.

2.Another interesting technique to quickly list JavaScript files in an application is to dig through internet archive databases such as Wayback Machine. This technique is completely passive because we are not sending any request to the target application server.

Digging through internet archives such as Wayback Machine is quite useful in identifying JavaScript files in an application. Sometimes you’ll be able to find older JavaScript files that are not deleted on the server.

  • waybackurls is a neat tool to search for JavaScript files(or any other URLs for that matter) that belong to a site of interest using Wayback Machine

go get github.com/tomnomnom/waybackurls
waybackurls internet.org | grep "\.js" | uniq | sort
  • Using Wayback Machine might result in false-positives i.e. JavaScript files that don’t exist on the server anymore. Once you have gathered the list of URLs for JavaScript files, you can use curl to quickly check for the status of the JavaScript files on the server

cat js_files_url_list.txt | parallel -j50 -q curl -w 'Status:%{http_code}\t Size:%{size_download}\t %{url_effective}\n' -o /dev/null -sk
  • Using curl to check for the status of the JavaScript files on the server could be cumbersome. There are utilities that make the process of finding the status of files straight forward. hakcheckurl is one such utility written in Golang that I use often for it’s simplicity and speed.

go get github.com/hakluke/hakcheckurl
cat lyftgalactic-js-urls.txt | hakcheckurl

Making the gathered JavaScript code readable

Sometimes the JavaScript files you gathered might not be immediately intelligible or readable. This can happen because the developer might have minified or obfuscated the JavaScript code.

Minification refers to the process of removing unnecessary or redundant data without affecting how the resource is processed by the browser β€” e.g. code comments and formatting, removing unused code, using shorter variable and function names, and so on.

Obfuscation involves making modifications to the program, changing the names of variables, functions, and members, making the program much harder to understand.

  • There are various tools that can minify JavaScript. UglifyJS is a neat tool to minify JS code and it also available as npm package

  • There are various tools that can un-minify JavaScript. JS Beautifier is a tool that can beautify and also deobfuscate certain obfuscation schemes. You can use this tool via node.js, python, online or in a code editor like VS Code.

When performing deobfuscation, especially when reversing malware there is no one size fits all technique or tool. You’ll have to try various tools, deobfuscation schemes and perform some manual analysis. There are various tools out there that can help you deobfuscate JavaScript code. Some of the tools we often use are JStillery, JSDetox, JS-Beautifier, IlluminateJs, JSNice etc.

Identifying interesting information in JavaScript

1.One of the key information to look for in JavaScript files is endpoints i.e full URLs, relative paths etc.

Identifying full URLs, relative paths in JavaScript files will help us uncover the attack surface and potentially find more vulnerabilities

  • relative-url-extractor by Jobert Abma is quite handy to quickly identify all the relative paths in a JavaScript file. This tool can work on both local and remote JavaScript files. This tool can work directly on minified JavaScript

  • LinkFinder by Gerben Javado is quite handy in identifying all the endpoints and their parameters in JavaScript files. This tool can also work directly on minified JavaScript and it uses jsbeautifier to unminify JavaScript. This tool can also be run against a domain to enumerate all the JavaScript files

python linkfinder.py -i xample.com -d -o cli

2.JavaScript files might also contain sensitive information such as credentials and API keys. Broadly speaking, we can identify secrets in source code files using either regex or entropy. Regex search will be able to identify credentials that are set by users such as usernames and passwords. Entropy based search is effective in identifying sufficiently random secrets such as API keys and tokens.

  • DumpsterDiver, Repo-supervisor and truffleHog are some fantastic tools to search for secrets in source code files. Most of these tools support both entropy based and regex based search. They are also easily and highly customisable both in regex search and entropy search.

  • Don’t forget that grep/sed/awk are also quite powerful when searching for specific sensitive information the source code files.

3.When looking into JavaScript files, it is important to identify dangerous places in code i.e. places where developers tend to make mistakes that will lead to potential security issues.

  • Usage of innerHTML indicates that there might be possible XSS issue. In the modern client-side JavaScript frameworks innerHTML equivalents do exist such as the aptly named dangerouslytSetInnerHTML in React framework and they did result in serious security vulnerabilities in the past . Improper usage of bypassSecurityTrustX methods in Angular can also lead to XSS issues. eval function is another place where things can go wrong both on client-side and server side.

  • postMessage API is an alternative to JSONP, XHR with CORS headers and other methods enabling sending data between origins by bypassing Same Origin Policy(SOP). The idea of bypassing SOP and communicating with different origin should be of interest to attackers. There are various security pitfalls when using postMessage. Once you understand the possible security issues associated with postMessage, you can look for the implementation in JavaScript files. On the message sender side, look for window.postMessage and on the receiver end look for a listener window.addEventListener . You’ll have to keep in mind that a lot of frameworks implement wrappers around postMessage

  • localStorage and sessionStorage are HTML Web Storage Objects. With web storage, web applications can store data locally within the user’s browser. It is important to identify what is being stored using the Web Storage especially storing anything sensitive can lead to potential security issues. In the JavaScript, you can look for window.localStorage and window.sessionStorage.

Looking for dangerous places in JavaScript that might lead to potential security issues is highly dependent on stack that is being used. You should identify what frameworks are being used, identify dangerous functions in the framework and then look for them in the source code.

5.Using security linters and static security scanners will make it easy to identify low hanging vulnerabilities in JavaScript code. JSPrime is a static analysis tool for finding security issues in JavaScript code but the project hasn’t been updated in a while. ESLint is one of the most popular JavaScript linters. ESLint is easily customisable by adding custom rules. A lot of custom security rules are available for ESLint especially targeting modern frameworks like Angular, React etc.

6.When performing security assessments, it is important to identify old and vulnerable JavaScript frameworks/libraries being used in the application. Retire.js is a tool that can identify outdated JavaScript frameworks in use. This tool can be used as a stand alone tool, browser extension, grunt plugin or Burp/ZAP extension. RetireJS Burp extension is especially useful if you are performing your testing in a user-driven manner. Although RetireJS can report some false positives and not everything reported by RetireJS is vulnerable

Conclusion

In this blog post we have covered a generic approach to perform static-analysis of client-side JavaScript code. What we have covered is just one workflow that will take you from gathering JavaScript files to finding security issues using the JavaScript code.

This brings us to the end of this post. If there are static analysis techniques, tools or tricks that you frequently use that have yielded you interesting results and if you would like to share those, please do leave a comment.

Until next time, happy bug hunting!!

References

At Appsecco we provide advice, testing, training and insight around software and website security, especially anything that’s online, and its associated hosting infrastructure β€” Websites, e-commerce sites, online platforms, mobile technology, web-based services etc.

Last updated