قالب وردپرس درنا توس
Home / Tips and Tricks / How to analyze browser extensions for potentially malicious software and other malicious activity «Zero Byte :: WonderHowTo

How to analyze browser extensions for potentially malicious software and other malicious activity «Zero Byte :: WonderHowTo



Browser extensions are extremely useful because they can extend browsers like Google Chrome and Mozilla Firefox beyond their built-in features. However, we do not always know who is behind a browser extension or what it does in addition to what is advertised. This is where ExtAnalysis comes into play.

ExtAnalysis will unpack an extension so we can see what’s really going on inside. To start using it, you just need to use either Chrome or Firefox, as well as an add-on that you want to investigate for any malicious background activity. We will examine a Firefox add-on from a computer science student to see how a more amateur add-on will leak its hidden intentions.

Requirement

  • Chrome (or Brave) or Firefox
  • Installed or uninstalled add-ons from Chrome Web Store or Firefox Addons
  • Linux or Windows PC (or macOS only for uninstalled extensions)

ExtAnalysis functions

ExtAnalysis is somewhat similar to Jupyter Notebook in that it is some Python code that will run, create a user interface and open in a browser window. It is also a really interactive experience that allows us to easily use the tool without relying on a particular hardware or operating system. It is a platform platform, easy to install and easy to use.

There are many things that ExtAnalysis can do, such as VirusTotal scans, RetireJS JavaScript vulnerability scans, viewing and editing HTML, JSON, JavaScript and CSS files, but we̵

7;ll just give you a general overview of what done from a simple scan of an extension.

Step 1: Install ExtAnalysis

We will go through the installation and use of ExtAnalysis on Kali Linux. To install it, just clone it from the GitHub repository git clone.

~$ git clone https://github.com/Tuhinshubhra/ExtAnalysis.git

Cloning into 'ExtAnalysis'...
remote: Enumerating objects: 30, done.
remote: Counting objects: 100% (30/30), done.
remote: Compressing objects: 100% (23/23), done.
remote: Total 638 (delta 7), reused 15 (delta 6), pack-reused 608
Receiving objects: 100% (638/638), 10.28 MiB | 4.95 MiB/s, done.
Resolving deltas: 100% (221/221), done.

Then switch to their directory with CD.

~$ cd ExtAnalysis
~/ExtAnalysis$

If you want, you can list its contents with ls to see what’s there.

~/ExtAnalysis$ ls

CHANGELOG        db              LICENSE           settings.json
core             Dockerfile      plugins           static
CREDITS          extanalysis.py  README.md         templates
current_version  frontend        requirements.txt

We need to install the requirements.txt file for ExtAnalysis to work, so use pip3 install -r to get the job done. And that’s it for the installation.

~/ExtAnalysis$ pip3 install -r requirements.txt

Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: flask in /usr/lib/python3/dist-packages (from -r requirements.txt (line 1)) (1.1.2)
Collecting python-whois
  Downloading python-whois-0.7.3.tar.gz (91 kB)
     |████████████████████████████████| 91 kB 968 kB/s
Collecting futures
  Downloading futures-3.1.1-py3-none-any.whl (2.8 kB)
Requirement already satisfied: requests in /usr/lib/python3/dist-packages (from -r requirements.txt (line 4)) (2.23.0)
Requirement already satisfied: maxminddb in /usr/lib/python3/dist-packages (from -r requirements.txt (line 5)) (1.4.1)
Requirement already satisfied: Flask-WTF in /usr/lib/python3/dist-packages (from -r requirements.txt (line 6)) (0.14.3)
Requirement already satisfied: future in /usr/lib/python3/dist-packages (from python-whois->-r requirements.txt (line 2)) (0.18.2)
Building wheels for collected packages: python-whois
  Building wheel for python-whois (setup.py) ... done
  Created wheel for python-whois: filename=python_whois-0.7.3-py3-none-any.whl size=87701 sha256=55c0fc88867dd7568ca3ce381f919cc1cd4233a9a6f963717ed76e0880606ed8
  Stored in directory: /home/kali/.cache/pip/wheels/7d/0b/b2/50bf00862456cf788d83cb6525be163d8bf753ca7968d8d50d
Successfully built python-whois
Installing collected packages: python-whois, futures
Successfully installed futures-3.1.1 python-whois-0.7.3
WARNING: You are using pip version 20.2.2; however, version 20.2.3 is available.
You should consider upgrading via the '/usr/bin/python3 -m pip install --upgrade pip' command.

Step 2: Run ExtAnalysis

To use ExtAnalysis we just need to be in the right folder, call Python and run the tool with extanalysis.py. So let’s do it to open the web interface.

~/ExtAnalysis$ python3 extanalysis.py

     _____     _   _____         _         _
    |   __|_ _| |_|  _  |___ ___| |_ _ ___|_|___
    |   __|_'_|  _|     |   | .'| | | |_ -| |_ -|
    |_____|_,_|_| |__|__|_|_|__,|_|_  |___|_|___|
    => Browser Extension Analysis |___| Framework
    => Version 1.0.4 By r3dhax0r

[i] Created empty reports file
[!] Virustotal api was not specified... Files won't be scanned
[i] Creating lab directory: /home/kali/ExtAnalysis/lab

[~] Starting ExtAnalysis at: http://127.0.0.1:13337

 * Serving Flask app "ExtAnalysis - Browser Extension Analysis Toolkit" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
Sandbox: seccomp sandbox violation: pid 1625, tid 1625, syscall 315, args 1625 140296477792640 56 0 10 140296477792640.
Sandbox: seccomp sandbox violation: pid 1647, tid 1647, syscall 315, args 1647 139671689964608 56 0 10 139671689964608.
[i] Accessed Main page

After a few moments, the browser opens for a web page on 127.0.0.1:13337. As you can see from the beginning, the web app has a very nice user interface that is easy to navigate.

Best of all, everything you do in the web app will be displayed in your terminal if you want to see the information that way. But you can also see things that are printed to the terminal directly in the web app further down the page.

Step 3: Find an extension to analyze

As an example, we use the PCC RMP Integration extension, which is available as Chrome extension and Firefox extension.

This supplement is written by a computer science student at Pasadena City College. It is designed to transfer the RateMyProfessor points for different teachers to the university’s course catalog. That way, people who sign up for classes at the school will not get a professor who has a terrible score.

Step 4: Analyze the extension

From the web interface, there are several ways to analyze an extension that you can navigate to using the tabs at the top of the page.

  • A link from the Chrome Web Store
  • A link from the Firefox Addon directory
  • A locally installed extension in Chrome, Brave or Firefox
  • An add-on that can be uploaded in .crx, .xpi or .zip format

For our example, we’ll use the first option, where we simply provide ExtAnalysis with a link to a Chrome extension in the Chrome Web Store. This is a great option whether you are doing it for Chrome, Brave or Firefox as it allows you to examine an extension before actually installing it.

Enter the link in the field, then click “Download and Analyze.” A popup will appear asking you to save the extension as a custom name, so enter everything you want here where you can find it later. Click “Download & Analyze” again after naming it.

In a few seconds, it should tell you that the add-on was analyzed and that the report was saved under a unique ID. Click on “Show analysis” to see the results.

Step 5: Read the analysis (basic information and files)

This is where things get fun. Right away we can see that an “unknown” person created our PCC RMP add-on. This alone may prevent you from installing the extension.

Other things we can see right away are the type of extensions, as well as the number of permissions required, unique domains, extracted URLs and external JaveScript. For the latter, there is nothing in our example, but if there was a lot, it could be a suspicious sign indicating that it is a coin mine or something else you may not want to install. You will also see the contents of the manifest.json file.

On the “Files” tab, there is a tilt Files and URL charts that you can interact with to see which files and URLs are linked to each other. There is also one Statistics section and a View source code for files section.

To see the source code of any item in the list, just click “View Source” next to it. It appears in a new tab in your browser. Below is what is displayed for the pcc-rmp.js file. Needless to say, this can show you a lot of what goes on behind the scenes, and the comments can help you understand how and why the tool was developed and how advanced they are when it comes to building extensions.

On the website itself, there are options to “Beautify Selected Code” and “Beautify Full Code” to give you different views on the source.

// TODO: Add a "Why am I getting this?" link to professors with more than one professor
//  explain that it is difficult to distinguish professors with the same name
//  instead of making a guess and potentially providing an incorrect rating,
//  we have chosen to link to the search page instead
//  oftentimes, there will be duplicate professors
//  This is a greater hassle because the reviews will be segmented
//  You can help by reporting duplicate professors on RateMyProfessor
/**
 * Professor object
 * @typedef {Object} Professor
 * @property {string} name The professor's name
 * @property {string} requestURL The URL to access the professor's information
 * @property {Array} elementArray Contains all elements in the page associated with the professor
 * @property {number} score The professor's RateMyProfessor score
 * @property {number} scoreCount The professor's amount of ratings
 * @property {number} id The professor's RateMyProfessor ID
 * @property {string} department The professor's department
 * @property {string} RMP_URL URL to the professor's RateMyProfessor page
 * @property {string} error Error type
 */
class Professor {
  /**
   * Sets professor's name and formats the request URL
   * @constructor
   * @param  {string} name Professor's name
   */
  constructor(name) {
    this.name = name;
    this.requestURL = formatRequestURL(name);
    this.elementArray = [];
  }

  /**
   * Saves data to Professor object, then sets the elements
   * 

TODO: Should this function also set the elements?

* @param {Array} data Contains professor's data */ loadData(data) { //console.log("loading data for " + this.name); this.score = data[0]; this.scoreCount = data[1]; this.id = data[2]; this.department = data[3]; this.RMP_URL = "https://www.ratemyprofessors.com/ShowRatings.jsp?tid=" + this.id.toString(); setElements(this); } /** * Saves error * @param {string} errorMsg */ error(errorMsg) { this.error = errorMsg; setError(this); } } /** * Adds error message to all the Professor object's elements * @param {Professor} prof */ function setError(prof) { var br = document.createElement("br"); var profError = document.createElement("span"); profError.textContent = prof.error; profError.style.fontSize = "10px"; for(var i = 0; i < prof.elementArray.length; i++) { prof.elementArray[i].appendChild(br.cloneNode(true)); prof.elementArray[i].appendChild(profError.cloneNode(true)); } } /** * Sets all Professor object's elements to reflect the professor's RMP rating *
    *
  • Changes background color of element according to RMP score
  • *
  • Displays score next to professor's name
  • *
  • Displays amount of ratings below professor's name
  • *
  • Adds link to professor's RateMyProfessor page
  • *
* @param {Professor} prof */ function setElements(prof) { //console.log("Setting elements for " + prof.name); if(prof.score === null) { //console.log("Error on " + prof.name + ", You should not be seeing this message."); return; } var br = document.createElement("br"); var profLink = document.createElement("a"); profLink.href = prof.RMP_URL; profLink.target = "_blank"; profLink.style.fontSize = "10px"; profLink.textContent = prof.scoreCount + " Ratings"; var profText = prof.name + " (" + prof.score.toFixed(1) + ")"; var color; if(prof.score < 3) { color = "#ff9999"; } else if (prof.score < 4){ color = "#ffff99"; } else if (prof.score < 4.5) { color = "#bbff99"; } else { color = "#99ff99"; } for(var i = 0; i < prof.elementArray.length; i++) { prof.elementArray[i].style.backgroundColor = color; prof.elementArray[i].textContent = profText; prof.elementArray[i].title = prof.department; prof.elementArray[i].appendChild(br.cloneNode(true)); prof.elementArray[i].appendChild(profLink.cloneNode(true)); } } /** * Creates a URL to access RMP data for a specified professor * @param {string} profName The professor's name * @returns {string} URL to access RMP data */ function formatRequestURL(profName) { let requestURL = "https://pcc-rmp.com/solr/rmp/select/?solrformat=true&rows=20&wt=json&q=PROFNAME+AND+schoolid_s:2649"; profName = profName.replace(/s/g, "+"); requestURL = requestURL.replace(/PROFNAME/g, profName); return requestURL; } /** * Scrapes page for elements that contain a professor's name * @returns {Array} Elements containing a professor's name */ function getProfElements() { let profElements = []; var selector = "td.default1[nowrap][valign=top], td.default2[nowrap][valign=top]"; var selectedElements = document.querySelectorAll(selector); var re = /d||Online|^.$|^[A-Zs.]+$|Needs Assignment|^Th$|^Su$|Staff|ABILITYsFIRSTs-sKinneola/g; for(var i = 0; i < selectedElements.length; i++) { let elementText = selectedElements[i].textContent; let matches = elementText.match(re); if(matches === null) { profElements.push(selectedElements[i]); } } return profElements; } /** * Searches an array of Professor objects for a specified name *
    *
  1. If the name exists, return the Professor object with that name
  2. *
  3. Otherwise, create a new Professor object with that name, add it to the Professor array, * and return that Professor
  4. * * @param {Array.} profsArray An array of Professor objects * @param {string} profName The professor to search for * @returns {Professor} A Professor object */ function searchProfs(profsArray, profName) { for(var i = 0; i < profsArray.length; i++) { if(profsArray[i].name == profName) { return profsArray[i]; } } profsArray.push(new Professor(profName)); return profsArray[profsArray.length - 1]; } /** * Searches for all unique professors * @returns {Array.} An array containing a Professor object for all professors on the page */ function getUniqueProfs() { let profElements = getProfElements(); let uniqueProfs = []; for(var i = 0; i < profElements.length; i++) { let profName = profElements[i].textContent; searchProfs(uniqueProfs, profName).elementArray.push(profElements[i]); } return uniqueProfs; } /** * Grabs RateMyProfessor data and gives it to the Professor object *

    TODO: This function does too much

    * @param {Professor} prof */ function getProfData(prof) { var request = new XMLHttpRequest(); request.open("GET", prof.requestURL, true); request.onload = function() { if (this.status >= 200 && this.status < 400) { var data = JSON.parse(this.response); var profData = extractProfData(data); if(profData == -1) { //console.log("No professors found matching: " + prof.name); prof.error("No professors found"); } else if(profData == -2) { //console.log("More than one professor found matching: " + prof.name); prof.error("More than one professor found"); } else if (profData == -3){ //console.log("Zero ratings found for " + prof.name); prof.error("No ratings found"); } else { prof.loadData(profData); //console.log(prof.name + ": " + prof.score + " " + prof.scoreCount); } } else { //console.log("Server error: " + this.status); } }; request.onerror = function() { //console.log("Could not reach server."); }; request.send(); } /** * Reads JSON data from argument *
      *
    1. If there are 0 or more than 1 professors found, * return a number representing the error
    2. *
    3. Otherwise return an array containing the pertinent information
    4. * * @param {JSON} responseData * @returns {number|Array} Error code or professor information */ function extractProfData(responseData) { if(responseData.response.numFound == 0) { return -1; } else if(responseData.response.numFound > 1) { return -2; } else if(responseData.response.docs[0].total_number_of_ratings_i == 0) { return -3; } var profScore = responseData.response.docs[0].averageratingscore_rf; var profScoreCount = responseData.response.docs[0].total_number_of_ratings_i; var profID = responseData.response.docs[0].pk_id; var profDepartment = responseData.response.docs[0].teacherdepartment_s; //console.log("Found data: " + profScore + " " + profScoreCount + " " + profID); return [profScore, profScoreCount, profID, profDepartment]; } //console.log("Starting PCC-RMP..."); var uniqueProfs = getUniqueProfs(); for(var i = 0; i < uniqueProfs.length; i++) { //console.log("Trying to access RMP for " + uniqueProfs[i].name); getProfData(uniqueProfs[i]); }

Step 6: Read the analysis (permissions)

There is also a "Permissions" tab that you can check to see if there are any suspicious things that the extensions "need" to work. Items you need to be careful about are camera, microphone, location and other device permissions.

Step 7: Read the analysis (URLs and domains)

The "URLs and Domains" tab shows just that. Here you can see some of the fascinating things that have already been pulled, such as the domains that the tool calls. Our tool is called ratemyprofessor.com, which makes sense, and the tool's website and a Google server, none of which look unusual. Each link has the ability to request information from "Whois", "VT Report" and "GEO IP Lookup."

You can also see Extracted URLs from files, which can help you quickly determine if the extension is calling a domain that you do not think needs calling. Suspicious activity will really show up here. In our case, it looks harmless. Each link has the ability to request information from "Whois", "Source" and "HTTP Headers."

A Whois report can help you determine if the domain owner is someone sketchy. The VirusTotal report helps you determine if the scanner has received anything.

There is also a section for External JavaScript files which can also highlight some unpleasant activities that the extension has under the carpet.

Step 8: Read the analysis (Gathered Intels)

Finally, there is the "Gathered Intels" tab. This shows the extracted IP addresses, Bitcoin addresses, email addresses and comments. Bitcoin can help you decide if something can happen that should not be, because bitcoin addresses are common in code when someone tries to break or lift cryptocurrency. Email addresses can identify suspects who may look challenging. The comments can help you see things the author is saying, which can help shed light on why the tool was made.

There are also Base64 encoded strings that are extracted, if any, that you can analyze.

ExtAnalysis is a great tool for awareness

ExtAnalysis is an excellent tool for digging just about any browser extension to see if hidden activities are going on behind the scenes - either before or after installing the extension. It's great to just be curious about supplements, discover malicious code and learn how others build supplements if you need some inspiration for yourself.

Do you want to start making money as a white hat hacker? Start your career with white-hat hacking with our 2020 Premium Ethical Hacking Certification Training Bundle from the new Null Byte Shop and get more than 60 hours of training from ethical hacking professionals.

Buy now (90% off)>

Cover image and screenshots of Retia / Null Byte

Source link