قالب وردپرس درنا توس
Home / Tips and Tricks / Analyzing web browser extensions for possible malware and other harmful activities «Null Byte :: WonderHowTo

Analyzing web browser extensions for possible malware and other harmful activities «Null Byte :: WonderHowTo



Browser extensions are extremely useful as they can extend web browsers like Google Chrome and Mozilla Firefox beyond their built-in functionality. However, we don’t always know who is behind a browser add-on or what it does beyond the advertised ones. This is where ExtAnalysis comes in.

ExtAnalysis extracts an extension so we can see what is really going on inside. To use it, all you have to do is use either Chrome or Firefox plus an extension that you want to investigate for possible background malicious activity. We’re going to be investigating a computer science student’s Firefox extension to see how a more amateur add-on reveals its hidden intentions.

requirement

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

ExtAnalysis functions

ExtAnalysis is similar to Jupyter Notebook in that it is Python code that runs, creates a user interface, and opens it in a browser window. It̵

7;s also a really interactive experience that allows us to easily use the tool without relying on any specific hardware or operating system. It’s cross-platform, easy to install, and straightforward to use.

ExtAnalysis can do many things, such as: B. VirusTotal scans, RetireJS vulnerability scans for JavaScript files, viewing and editing of HTML, JSON, JavaScript and CSS files. However, we are just giving a general overview of what can be done from a simple scan of an extension.

Step 1: Install ExtAnalysis

We will go through installing and using ExtAnalysis on Kali Linux. To install, just clone it from the GitHub repository using 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.

Next change to its directory with CD.

~$ cd ExtAnalysis
~/ExtAnalysis$

If you want, you can list the content 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 require.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 correct folder, go to Python and run the tool with extanalysis.py. Let’s do that 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, your web browser will open to a website at 127.0.0.1:13337. As you can see from the start, the web app has a very nice user interface that is easy to navigate.

Best of all, whatever you do on the web app will show up in your terminal if you want to see the information that way. But you can also see things that are printed directly on the terminal at the bottom of the page in the web app.

Step 3: Find an extension to analyze

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

This particular extension was written by a computer science student at Pasadena City College. It is designed to translate various teachers’ RateMyProfessor score onto the college’s course catalog. That way, people who sign up for classes at the school don’t get a professor who has a terrible score.

Step 4: analyze the extension

There are several ways to analyze an extension through the web interface, which 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 add-on catalog
  • A locally installed extension in Chrome, Brave, or Firefox
  • An uploadable extension in .crx, .xpi, or .zip format

In our example we use the first option where we simply give ExtAnalysis a link to a Chrome extension in the Chrome Web Store. This is a good option whether you’re doing this for Chrome, Brave, or Firefox, as it allows you to examine an add-on before actually installing it.

Enter the link in the field and click “Download & Analyze”. A popup will ask you to save the extension as a custom name. So put in anything you want here where you can find it later. After naming it, click “Download & Analyze” again.

In seconds it should show that the extension has been analyzed and the report has been saved under a unique ID. Click “View Analysis” to view the results.

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

It’s fun here. We can immediately see that an “unknown” person created our PCC-RMP extension. That alone can mean that you don’t want to install the add-on.

Other things that we can see right away are the type of extension as well as the number of permissions required, unique domains, extracted URLs, and external JaveScript. For the latter, there aren’t any in our example, but if there were many it could be a suspicious sign suggesting that it is a coin miner or something else that you may not want to install. You can also see the contents of the manifest.json file.

There is a shake in the Files tab Files & url diagram that you can interact with to see what files and URLs are linked. There is also a statistics Section and a Display the source code of the files Section.

To view the source code for an item in the list, simply click the “View Source Code” button next to it. It will appear in a new tab in your browser. Below is what is shown for the pcc-rmp.js file. Of course, this can show you a lot about what’s going on behind the scenes and the comments can help you understand how and why the tool was developed and how advanced they are in building extensions.

On the website itself there are the options “Beautify Selected Code” and “Beautify Entire Code” to give you different views of 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's also a Permissions tab that lets you see if there are any suspicious looking things that the extensions “need” to work. Attention must be paid to camera, microphone, location and other device authorizations.

Step 7: Read the Analysis (URLs & Domains)

The URLs & Domains tab shows you just that. Here's a look at some of the fascinating things that have already been pulled, such as: B. the domains that the tool calls. Our tool goes to ratemyprofessor.com, which makes sense, and the tool's website and a Google server, neither of which look unusual. Each link offers the possibility to request information from "Whois", "VT Report" and "GEO IP Lookup".

You can see those too Extracted URLs from filesThis can help you quickly determine if the extension is calling a domain that you don't think needs to be called. Suspicious activity will really show up here. In our case it looks harmless. Each link offers the possibility to request information from "Whois", "Source" and "HTTP headers".

You can use a whois report to determine if the domain owner is a sketchy person. The VirusTotal report can help you determine if the scanner has detected anything.

There is also a section for External JavaScript files This could also highlight some nefarious activity the extension has under the rug.

Step 8: read the analysis (information gathered)

Finally, there is the Gathered Intels tab. The extracted IP addresses, Bitcoin addresses, email addresses and comments are displayed here. The Bitcoin helps you determine if something is possibly happening that shouldn't be, as Bitcoin addresses are a common feature in the code when someone tries to mine or pick up the cryptocurrency. The email addresses can indicate suspicious-looking addresses that may be offensive. The comments can help you see what the author is saying and explain why the tool was made.

There are also Base64-encoded strings that can be extracted if necessary, and that you can parse.

ExtAnalysis is a great tool for awareness

ExtAnalysis is a great tool that lets you check almost any browser extension to see if there is any hidden activity going on - either before or after installing the add-on. It's great to just get curious about extensions, discover malware, and learn how others create extensions when you need inspiration for your own.

Would you like to make money as a hacker with a white hat? Start your white hat hacking career with our 2020 Premium Ethical Hacking Certification Training Bundle from the new Null Byte Shop and receive over 60 hours of training from ethical hacking professionals.

Buy now (90% discount)>

Cover picture and screenshots from Retia / Null Byte

Source link