{
	"id": "7ca69a51-db8e-43aa-aadf-e8d720d5fda7",
	"created_at": "2026-04-06T00:16:06.951109Z",
	"updated_at": "2026-04-10T13:12:14.780169Z",
	"deleted_at": null,
	"sha1_hash": "28c01d7f3d435aa4890f0a0413a6593d70046b3e",
	"title": "RATatouille: Cooking Up Chaos in the I2P Kitchen",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1141529,
	"plain_text": "RATatouille: Cooking Up Chaos in the I2P Kitchen\r\nBy Pierre Le Bourhis\r\nPublished: 2025-02-11 · Archived: 2026-04-05 21:11:35 UTC\r\nThis article was originally distributed as a private FLINT report to our customers on 29 January 2025.\r\nTable of contents\r\nIntroduction\r\nSample overview\r\nI2PRAT Malware Loader\r\nPrivileges review\r\nRPC elevation\r\nParent ID spoofing\r\nHow I2PRAT Uses Dynamic API Resolution for Evasion ?\r\nAnti debug\r\nString obfuscation\r\nI2PRAT (C2) Communication via I2P\r\nDefense deactivation\r\nI2PRAT installer\r\nI2PRAT components\r\nI2PRAT DLLs breakdown\r\nI2PRAT C2 hunting\r\nI2PRAT Detection Opportunities\r\nPrivilege Escalation\r\nPrivilege Escalation via process migration\r\nCatch C2 communication\r\nI2PRAT detection\r\nChange RDP settings\r\nRogue service creation\r\nDetection overview in sandbox\r\nConclusion\r\nIntroduction\r\nDuring our daily tracking and analysis routine at TDR (Threat Detection \u0026 Research), we have been monitoring a\r\ntechnique known as ClickFix12. One of the payloads dropped in a campaign starting from November 2024 drew\r\nour attention due to the absence of a signature and the lack of documented behaviour and network patterns in\r\npublic reports. This discovery initiated our investigation into the new piece of malware I2PRAT.\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 1 of 23\n\nThe malware was recently identified as a multi-stage RAT (Remote Access Trojan). The first stage is protected by\r\nan initial layer of obfuscation, which is a commodity packer. Developed in C++, the malware employs several\r\nadvanced techniques to fully compromise its victims. This FLINT report covers the various techniques identified\r\nduring its reverse engineering. These techniques range from defense evasion, such as parent process ID\r\nspoofing, to privilege escalation by abusing RPC mechanisms, and include dynamic API resolution. This report\r\nalso covers the functionalities of the RAT named I2PRAT that employ the I2P network to anonymise its final\r\nCommand and Control (C2). The last part of this FLINT gives tracking and detection opportunities on the\r\ndifferent stages of the newly identified threat.\r\nSample overview\r\nBefore delving into the analysis of this undocumented threat, here is an overview of the infection chain. The\r\nmalware is composed of three layers, the first one is perceived as a binder / packer, which executes in memory\r\nthe second stage. This second stage, is the first topic covered in this FLINT, it is a sophisticated loader that\r\nemploys various techniques to elevate its privilege and bypass defenses. \r\nFinally, the remaining subject is the analysis of an utility used to expose the compromised devices on the I2P\r\nanonymisation network to provide the attacker with consequent bot access.\r\nFigure 1. ClickFix campaign delivering advanced loader that drops I2PRAT\r\nI2PRAT Malware Loader\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 2 of 23\n\nPrivileges review\r\nThe first task the malware (p.exe in the Figure 1) performs on the infected device is to verify its privileges. To do\r\nthis, it retrieves the token information3 for its process. It uses the NtOpenProcess function to acquire a handle to\r\nitself. It then obtains the associated access token using NtOpenProcessToken with the desired access set to\r\nTOKEN_QUERY, which allows querying most information classes via the NtQueryInformationToken function.   \r\nThe malware looks for the information class “TokenOrigin | TokenType”. The TokenOrigin contains the Locally\r\nUnique IDentifier (LUID) for the logon session, and the TokenInformation is a pointer to a Security Identifier\r\n(SID). The SID is then passed to the GetSidSubAuthority function (from Advapi32.dll), which returns a relative\r\nidentifier (RID). The RID is used to verify that the current process has the\r\nSECURITY_MANDATORY_SYSTEM_RID, which is the RID of the NT Authority\\SYSTEM account.\r\nSubsequently, the malware also queries the current process token information by requesting the token information\r\nclass “TokenAuditPolicy | TokenOwner”. However, to query the TokenAuditPolicy, the current account must have\r\nthe SeSecurityPrivilege, as it serves as a verification method for the malware.\r\nDepending on the results of these privilege verifications, the malware behaves differently. There are three possible\r\nscenarios:\r\nIf the current process is not run by the SYSTEM account and does not have the SeSecurityPrivilege\r\nprivilege, the malware abuses an RPC behavior (see section: RPC elevation for additional information) to\r\nelevate its privileges and ends in the second scenario.\r\nIf the current process is not run by the SYSTEM account but has the SeSecurityPrivilege privilege, the\r\nmalware migrates itself using SeDebugPrivilege (see section: Parent ID spoofing  for additional\r\ninformation).\r\nIf the current process is run by the SYSTEM account, IP2RAT enters its bot mode, where the malware\r\nperforms most of its actions and it interacts with its command and control.\r\nRPC elevation\r\nIn a typical case of malware execution, when it does not have high privileges on the infected device, a malware\r\nattempts to elevate its privileges. Here, the loader attempts to gain the local admin privileges by abusing a Remote\r\nProcedure Call (RPC) mechanism. \r\nThe loader connects using a RPC stub to the RPC server exposed by the APPINFO4 service whose interface ID is\r\n201ef99a-7fa0-444c-9399-19ba84f12a1a. \r\nNevertheless, from the various detonations of the malware with various samples none successfully exploited the\r\nRPC to bypass the User Access Control (UAC) and gain local admin access rights. The root cause of this failure\r\nis the Windows security patch KB50313565. With the security update, the malware pops the usual UAC prompt to\r\nask for the local admin account credentials.\r\nParent ID spoofing\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 3 of 23\n\nIn the second scenario, where the malware is executed by the local administrator, the loader leverages the\r\nSeDebugPrivilege before replicating itself into an elevated newly spawned process with the NT Authority\\System\r\naccount. \r\nTo that end, it iterates over the running processes to identify one with the\r\nSECURITY_MANDATORY_SYSTEM_RID permission, using native functions.\r\nForemost, the malware adjusts its token privilege to gain SeDebugPrivilege using the AdjustTokenPrivileges from\r\nadvapi32 DLL. This permission is required to allow the current process to open a handle to another process.\r\nSubsequently, it calls the NtQuerySystemInformation function to retrieve the\r\n_SYSTEM_PROCESS_INFORMATION6 structure. This structure contains two members that are useful for\r\nmalware: NextEntryOffset, which specifies the offset from the beginning of the output buffer to the next process\r\nentry, and UniqueProcessID (the PID).\r\nThe criteria for the targeted process is to have the RID set to 0x4000, corresponding to the SYSTEM RID. The\r\nRID lookup is the same as previously explained in the section Privileges review. \r\nOnce the targeted process is found, the loader obtains a handle to it and creates a new child process with specific\r\nparameters and attributes copied from the elevated process.\r\nFigure 2. Loader migration into a child of an elevated process\r\nThe notable aspect of this newly created process is that it is a copy of the elevated process. The malware uses the\r\nNtDuplicateObject function with the desired access set to PROCESS_ALL_ACCESS. To inherit from the\r\nduplicated process, the malware assigns to the new process the following attributes:\r\n“PROCESS_CREATE_FLAGS_BREAKAWAY | PROCESS_CREATE_FLAGS_INHERIT_HANDLES |\r\nPROCESS_CREATE_FLAG_CREATE_STORE”.\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 4 of 23\n\nThis allows the malware to elevate its privileges on the infected device from local admin to\r\nNT_AUTHORIY\\SYSTEM. Additionally the process hijacks the parent process ID.\r\nFigure 3. Decompiled code used to set the process attributes and create the elevated process during the elevation\r\nto NT Authority\\System\r\nAs shown by Process Explorer in the  image below: the p.exe process (the loader) duplicates itself from process\r\nID 6028 to 8912, spawning a subprocess of the winlogon.exe process (the Windows Winlogon service).\r\nFigure 4. Task manager screenshot that highlights the elevation process\r\nNB: The targeted RID (0x4000) is used by services and other system-level applications (such as Wininit,\r\nWinlogon, Smss, etc.).\r\nHow I2PRAT Uses Dynamic API Resolution for Evasion ?\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 5 of 23\n\nThe native API functions are obfuscated to conceal the malware behavior. The malware uses a technique widely\r\nused in the cybercrime ecosystem: dynamic API resolution. In this context of our investigation, the developer used\r\na custom function that takes a hash as a parameter which is resolved at runtime to retrieve the address of a\r\nfunction located in a DLL. The functions load the required DLL in the prologue of the function and then unload in\r\nthe epilogue using the LdrLoadDll and LdrUnloadDll couple. \r\nThe hashing algorithm is not documented in open source as of January 2025. To identify the function by resolving\r\nthe hash  used by the program for its exploitation, we created a memory dump of the process. Subsequently, we\r\nused Dumpulator7 to emulate the function that resolves the hashes, allowing us to finally rename and retype the\r\nsample correctly.\r\nNB: With this method to resolve correctly all hashes from various DLL we need to explicitly load some DLLs (in\r\nthe xdbg) for the process being dumped, such as (advapi32.dll, mscoree.dll, rpcrt4.dll and ws2_32.dll) using the\r\nxdbg command “loadlib”. This step is required because at the early stage of its execution the malware did not\r\nalready dynamically load these libraries.\r\nTo retrieve and resolve the hashes, we developed an IDA script to extract them from the PE file. The direct\r\nresolution wrapper function uses the __cdecl calling convention and accepts only two parameters: a handle to the\r\nDLL in which the search is conducted and the hash. Below is an example of how the function is called:\r\nmov edx, 0x1234fe // the hash\r\nmov rcx, rax\r\ncall resolve_hashing\r\nCode 1: Example a call to the function that resolves library function hash\r\nIn IDA, we search for references to the resolve function and examine the preceding instructions to identify the one\r\nthat moves a value into the EDX register, which serves as the function’s second argument. The script detailing this\r\nprocess is provided in Annex 1.\r\nThe correlation hash – function is provided in this gist8.\r\nAnti debug\r\nThe I2PRAT installer is executed at the final stage of the loader’s execution. To prevent the installer from being\r\ndebugged, the loader employs the suspending-techniques9: \r\nFirst, a debugger creates a debug object (aka debug port) and then attaches it to the target process.\r\nStarting from this point, every time an event of interest occurs in the target process (be it thread\r\ncreation, exception, or a breakpoint hit), the system pauses its execution and posts a message to the\r\ndebug port, waiting for an acknowledgment. Additionally, attaching itself generates a process creation\r\nand a few module loading events. Luckily for us, the system does not enforce any time constraints on the\r\nresponses, so we can delay them indefinitely, keeping the target paused.\r\nTweet this!\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 6 of 23\n\nTypically, debuggers roughly implement a loop:\r\n1. Create a debug object: NtCreateDebugObject;\r\n2. Attach this object to targeted process: NtDebugActiveProcess;\r\n3. Wait for a particular event (e.g. thread creation, exception raised, breakpoint hit, etc.):\r\nNtWaitForDebugEvent;\r\n4. The user performs actions;\r\n5. Debuggers return to process execution until a new event occurs using : NtDebugContinue.\r\nIn the case of the I2PRAT loader, the malware puts the process in a waiting state, the debug object waits for a new\r\nprocess creation event (DbgCreateProcessStateChange). By doing this, the malware places the newly created\r\nprocess in a pending state, preventing a debugger from being attached to the process at that moment.\r\nwhile ntWaitForDebugEvent(debugObjectHandle, 1u, 0LL, \u0026debug_wait_state) \u003e= 0\r\n{\r\nif ( debug_wait_state == DbgCreateProcessStateChange )\r\nNtDebugContinue_0(debugObjectHandle, \u0026ClientId, DBG_CONTINUE);\r\nif ( pHandle )\r\n{\r\nlpTargetApp[0] = *a1;\r\nuser_process = use_nt_to_create_user_process(v13, lpTargetApp, 1);\r\n_NtClose(pHandle);\r\nv15 = !user_process ? 7 : 0;\r\ngoto leave_func;\r\n}\r\n}\r\nCode 2: Decompiled code of the function implementing the suspending-techniques \r\nString obfuscation\r\nThe loader obfuscates its strings using XOR operations. The variables are pushed on the stack using XMM\r\ninstruction making the decompilation a bit more tedious to analyse.\r\nThe C2 can be de-obfuscated using the following Python snippet:\r\nimport struct\r\nkey: bytes = 0x9BD595AF851D8BE7.to_bytes(8, 'little')\r\nc2: bytes = 0xD1BF33BC9ABBE4ABC9BA2BB795A4E4AADE8B.to_bytes(18, 'big')\r\ncleartext: bytes = bytearray()\r\nfor idx, value in enumerate(c2):\r\ncleartext += (value ^ key[idx % len(key)]).to_bytes()\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 7 of 23\n\nprint(f\"c2 decoded: {cleartext.decode()}\")\r\nCode 3: Python snippet used to de-obfuscate string\r\nThe execution of the above script gives the C2 server ip and port: 64.95.10[.]162:1119\r\nI2PRAT (C2) Communication via I2P\r\nThe loader communicates with its C2 server over a raw TCP connection. Based on our observations, the port\r\nvaries from 1110 to 1130. The contents of the packets are partially encrypted using AES-128 in Cipher Block\r\nChaining (CBC) mode. For each execution, the encryption key and Initial Vector (IV) are unique. The sequence\r\nfor generating the cryptographic material is as follows:\r\n1. The malware sends 24 random bytes generated using the Mersenne Twister10\r\n pseudorandom number\r\ngenerator algorithm, which we refer as ‘the random’;\r\n2. The C2 server replies with 8 random bytes, which we refer as  ‘the seed’;\r\nNB: From this point forward, the structure of the messages (from both client and server) consists of the size of the\r\npacket followed by the encrypted message. \r\n3. The malware sends an encrypted ‘hello’ message;\r\n4. If the C2 server decrypts the message correctly using the previously computed AES key and IV, it responds\r\nwith an encrypted ‘ok’ message;\r\n5. The malware sends the victim’s fingerprint, including information such as elevated status, OS build, OS\r\nversion (major and minor), and the username;\r\n6. The C2 server acknowledges receipt of the fingerprint;\r\n7. The C2 server sends a PowerShell script to disable certain Windows Defender options;\r\n8. The malware requests the next stage;\r\n9. The C2 server replies with the next stage, which is obfuscated and corresponds to the I2PRAT installer;\r\n10. The malware regularly beacons the C2 server for updates.\r\nFrom the initial exchange (steps 1 and 2 of the above listing), both the C2 server and the implant derive an AES\r\nkey and an IV. The derivation process is as follows:\r\n1. Compute the smallest odd divisor of the seed. This returns the result and the divisor;\r\n2. Concatenate in the following format: RESULT + RANDOM + DIVISOR to create the AES key (32\r\nbytes);\r\n3. Hash the AES key using the SHA-256 algorithm, then use the last 16 bytes to create the Initial Vector.\r\nA Python version of the odd divisor is the following:\r\n\u003cpre class=\"wp-block-code\"\u003e\u003ccode\u003eimport struct\r\nfrom typing import Tuple\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 8 of 23\n\ndef seed(num: int) -\u003e Tuple[int, int]:\r\n_num = struct.unpack(\"\u003cq\", num)[0]=\"\" div,=\"\" value=\"3,\" 0=\"\" while=\"\" _num=\"\" %=\"\" div:=\"\"\r\nCode 4: Python version of the algorithm used for the seed computation\r\nP.S: A keen eye on the seed function spot a performance issue. \r\nFigure 5. I2PRAT loader: TCP sequence that initiate the encryption\r\nDefense deactivation\r\nThroughout multiple executions of the collected sample of this threat, we observed that the C2 server\r\nsystematically sends an initial PowerShell script to execute on the infected host. This script comprises three\r\ncommands designed to deactivate specific Windows Defender options.\r\n@echo off\r\npowershell.exe -NoLogo -Command \"Set-MpPreference -SubmitSamplesConsent NeverSend\"\r\npowershell.exe -NoLogo -Command \"Set-MpPreference -MAPSReporting 0\"\r\npowershell.exe -NoLogo -Command \"Add-MpPreference -ExclusionPath '%HOMEDRIVE%\\Users\\'\"\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 9 of 23\n\nexit 1\r\nCode 5: I2PRAT loader PowerShell script that deactivate Microsoft Defender security options\r\nWhile there is nothing particularly unusual about this script, as it disables Microsoft Defender to prevent file\r\nsubmission to their remote analysis solution, it is important to note the locations where further scripts or\r\nexecutables will be dropped and executed. By default, the path “%HOMEDRIVE%\\Users\\” resolves to:\r\n“C:\\Users”.\r\nI2PRAT installer\r\nThe last stage is downloaded to the infected host over a raw encrypted communication channel. Once decrypted, it\r\nis a valid Windows PE file that is written to the %temp% directory with a randomly generated filename. The\r\nloader executes it using RtlCreateProcessParametersEx and NtCreateUserProcess.\r\nThe sample executes another file in the temporary directory with a different random filename. This file’s purpose\r\nis to block specific network traffic related to security solutions. Subsequently, the payload drops another\r\nexecutable in the temporary directory with yet another random name. This second executable is the installer of the\r\nfinal payload, I2PRAT.\r\nThe first dropped payload is a defense evasion tool that attempts to bypass the Windows Filtering Platform by\r\nblocking outbound traffic from the infected device to the following services:\r\nWuauserv\r\nDoSvc\r\nWaaSMedicSvc\r\nSubsequently, it uses the CLSID “20d04fe0-3aea-1069-a2d8-08002b30309d” to access the Computer Folder.\r\nNB: The above CLSID stands for the Public Computer folder11\r\nThis folder is used to store various RAT components. In the analysed case, the RAT is consistently dropped into\r\nthe “C:\\Users\\Public\\Computer.{20d04fe0-3aea-1069-a2d8-08002b30309d}” directory. This location explains the\r\ninitial exception added to Windows Defender with the command: powershell.exe -NoLogo -Command “Add-MpPreference -ExclusionPath ‘%HOMEDRIVE%\\Users\\”, executed by the previous stage. \r\nAdditionally, the installer drops several DLLs – cncclient.dll, libi2p.dll, eventsrv.dll, swlmgr.dll, prgmgr.dll,\r\nrdpctl.dll, and samctl.dll – which are used by the final payload. The I2PRAT sample is located in the ‘Public\r\nComputer’ directory and is consistently named main.exe. The installer is also responsible for ensuring the\r\npersistence of I2PRAT by creating an autostart service named “RDP-Controller”.\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 10 of 23\n\nFigure 6. The auto start service named RDP-Controller that starts main.exe \r\nI2PRAT components\r\nThe final component present on the infected device is a Remote Access Trojan (RAT) reported as I2PRAT by\r\nGDataSoftware12. The malware loads multiple DLLs, each responsible for a specific function of the RAT. The\r\nparticularity of this RAT is that it communicates over the Invisible Internet Project (I2P) network13.\r\nI2PRAT is event-driven, with the core component initially loading the cnccli.dll and libi2p.dll. The libi2p library\r\nenables access to the I2P network, while cnccli.dll connects to the final C2 server and relays messages from the\r\nC2 server to various DLLs.\r\nTo facilitate communication, a DLL named evtsrv.dll binds a socket on the localhost at port 41673. When the C2\r\nserver sends a command, cnccli.dll receives it and relays it to evtsrv.dll using the localhost:41673 connection it\r\nwas previously connected to, which broadcasts the event to the other DLLs. Each DLL can parse the message\r\nheader and has its own signature indicating that the message is intended for it.\r\nFor example the DLL dwlmgr.dll, which manages  file uploads and downloads, has for message header the\r\nfollowing string: -DWLMGR- (see Figure 7 below).\r\nFigure 7. Module dispatcher function with the message parsing of the dwlmgr DLL\r\nI2PRAT DLLs breakdown\r\nEach DLL of the RAT exports two functions: unit_init and unit_cleanup. These functions are used by the core of\r\nthe RAT to start or stop a module, with each DLL serving its specific purpose on the infected host. The hypothesis\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 11 of 23\n\nbehind this modular separation could be twofold:\r\n1. It simplifies code maintenance.\r\n2. If the I2PRAT malware is developed by multiple developers, this structure helps distribute tasks and\r\nmanage the project more easily and efficiently. Based on the file paths found in the strings of various\r\nDLLs, each project component seems to be located on different disks (e.g., evtsrv.dll is on the D:\\ drive,\r\nwhile cnccli.dll is on the C:\\ drive).\r\nAll the DLLs communicate over an event bus:\r\ncnccli.dll (I2P connection and communication): it forwards the message received from the C2 to the event\r\nbus that dispatches the order to the DLL in charge of the requested action;\r\ndwlrgr.dll (the file manager): it is used to delete, upload and download files on the infected host;\r\nrdpctl.dll: manages the RDP configuration and exposure of the infected host;\r\nsamctl.dll: manages user accounts (get, update, create, delete account);\r\nprgmgr.dll: launches scheduled task using schtasks subdirectory to collect information on the host\r\n(memory status, network setup, installed web browser).\r\nFigure 8. I2PRAT DLLs communication architecture\r\nI2PRAT C2 hunting\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 12 of 23\n\nWhen I2PRAT is installed and is running on an infected device, the malware leaves some interesting artifacts\r\nbehind that can be used to investigate its infrastructure. Although the malware communicates over an anonymous\r\nnetwork, which makes the identification of the final server harder, a specific log file created by the RAT named\r\ncnccli.log contains valuable data.\r\n[I] (debug_init) -\u003e Log open success(flog_path=C:\\Users\\Public\\Computer.{20d04fe0-3aea-1069-a2d8-08002b30309d}\\\r\n[I] (debug_init) -\u003e Done\r\n[D] (ini_get_sec) -\u003e Done(name=main)\r\n[D] (ini_get_var) -\u003e Done(sec=main,name=version,value=400004957b19a09d)\r\n[I] (module_load) -\u003e Done(name=ntdll.dll,ret=0x0000000077050000)\r\n[D] (module_get_proc) -\u003e Done(hnd=0x0000000077050000,name=RtlGetVersion,ret=0x0000000077079380)\r\n[I] (sys_init) -\u003e GetWindowsDirectoryA done(sys_win_dir=C:\\Windows)\r\n[D] (registry_get_value) -\u003e Done(root=0xffffffff80000002,key=SOFTWARE\\Microsoft\\Cryptography,param=MachineGuid)\r\n[I] (sys_init) -\u003e GetWindowsDirectoryA done(sys_mach_guid=406423b7-a2ea-4fbd-b6fa-074d6f2f9150)\r\n[I] (sys_init) -\u003e GetVolumeInformationA done(vol=C:\\,vol_sn=a9e4f8de)\r\n[I] (sys_init) -\u003e Done(sys_uid=a2ea0d02a9e4f8de,sys_os_ver=6.1.7601.1.0)\r\n[I] (net_init) -\u003e Done\r\n[I] (ebus_init) -\u003e Done\r\n[D] (ini_get_sec) -\u003e Done(name=cnccli)\r\n[D] (ini_get_var) -\u003e Done(sec=cnccli,name=server_host,value=c21a8709)\r\n[D] (ini_get_sec) -\u003e Done(name=cnccli)\r\n[D] (ini_get_var) -\u003e Done(sec=cnccli,name=server_port,value=41674)\r\n[D] (ini_get_sec) -\u003e Done(name=cnccli)\r\n[D] (ini_get_var) -\u003e Done(sec=cnccli,name=server_timeo,value=15000)\r\n[D] (ini_get_sec) -\u003e Done(name=cnccli)\r\n[D] (ini_get_var) -\u003e Done(sec=cnccli,name=i2p_try_num,value=10)\r\n[D] (ini_get_sec) -\u003e Done(name=cnccli)\r\n[D] (ini_get_var) -\u003e Done(sec=cnccli,name=i2p_sam3_timeo,value=30000)\r\n[D] (ini_get_sec) -\u003e Done(name=cnccli)\r\n[D] (ini_get_var) -\u003e Done(sec=cnccli,name=i2p_addr,value=2lyi6mgj6tn4eexl6gwnujwfycmq7dcus2x42petanvpwpjlqrhq.b3\r\nIn this log file, the host is represented as an integer in hexadecimal format which gives the IP address:\r\n“194.26.135[.]9”. The IP address is indexed by Censys and has a specific TCP service exposed on port 41674,\r\nwhich matches the trace identified in the log file (see the figure below).\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 13 of 23\n\nFigure 9. I2PRAT C2 service host banner on Censys\r\nThe server only exposed the port 41674, which corresponds to the one left in the log file by the cnccli.dll. \r\nA search on Censys engine for the beginning of the hex banner of the TCP service (port 41674) provides another\r\ninteresting result, the same AS (CHANGWAY-AS: 57523) with the same port with the neighbour IP address:\r\n“194.26.135[.]10”\r\nPS: the Censys query is “services.banner_hex:”60000000000000000000000000000000*””\r\nSince the beginning of this investigation in November 2024, the final C2 address has been changed to\r\n“154.216.20[.]137” which fortunately exposed on the same port as the previous servers an identical beginning\r\nTPC response .\r\nFigure 10. Result of a scan on port 41674 with the specific service banner\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 14 of 23\n\nI2PRAT Detection Opportunities\r\nReverse engineering analysis of the malware reveals several detectable behaviors like Defender bypass, notably\r\nduring the privilege escalation phase and its communication with the C2 server.\r\nPrivilege Escalation\r\nAs detailed in the Privileges review chapter, the malware checks whether it has system-level privileges. If not, it\r\nattempts to acquire them by either migrating to a process with the required privileges or executing an RPC call.\r\nPrivilege Escalation via process migration\r\nIn this scenario, as described in the chapter Parent ID spoofing, the malware must first acquire SeDebug\r\nprivileges. This can be detected through event 4703 – A user right was adjusted. The malware then scans active\r\nprocesses to identify one with system-level privileges. Once located, it attempts to conceal itself by impersonating\r\nthe parent process (the system process) through the creation of a remote thread. Finally, the malware migrates to\r\nthe targeted process, thereby obtaining system privileges, and terminates its original process.\r\nThis privilege escalation technique is not specific and can be used by various types of malware. Its behaviour\r\ncould be detected through a generic temporal correlation rule, concentrating on the sequence of these events. \r\npriv: detect non-system processes running from C:/temp or C:/users that have acquired SeDebug privileges.\r\nrthread: detect the creation of a remote thread targeting a process executed from C:/temp or C:/users.\r\nprocess: detect the creation of a process with system privileges originating from C:/temp or C:/users.\r\nA time correlation rule groups these three events by process and hostname. The rule triggers if the same process\r\nmeets all three conditions on the same machine within a two-minute window.\r\nname: priv\r\ndetection:\r\nselection:\r\naction.properties.EnabledPrivilegeList: 'SeDebugPrivilege'\r\nprocess.executable|startswith:\r\n- 'C:\\users\\'\r\n- 'C:\\temp\\'\r\nfilter:\r\nuser.id: 'S-1-5-18'\r\ncondition: selection and not filter\r\n---\r\nname: rthread\r\ndetection:\r\nselection:\r\nsekoiaio.target_process.executable|startswith:\r\n- 'C:\\users\\'\r\n- 'C:\\temp\\'\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 15 of 23\n\ncondition: selection\r\n---\r\nname: process\r\ndetection:\r\nselection:\r\nuser.name: 'SYSTEM'\r\nprocess.executable|startswith:\r\n- 'C:\\users\\'\r\n- 'C:\\temp\\'\r\ncondition: selection\r\n---\r\naction: correlation\r\ntype: temporal\r\nrule:\r\n- priv\r\n- rthread\r\n- process\r\naliases:\r\ncorrelprocess:\r\nthread:\r\n- sekoiaio.target_process.executable\r\npriv:\r\n- process.executable\r\nprocess:\r\n- process.executable\r\ngroup-by:\r\n- correlprocess\r\n- host.name\r\ntimespan: 2m\r\nordered: false\r\nCatch C2 communication\r\nThe communication initialization phase with the Command and Control (C2) server, as outlined in the C2\r\ncommunication chapter, is noteworthy enough to sign this specific TCP sequence. After establishing a TCP\r\nconnection, the victim sends the first packet, which is 24 bytes in size, using TCP flags ACK and PUSH. The C2\r\nserver’s response has a fixed size of 8 bytes and also utilizes the ACK and PUSH flags. \r\nWhile Suricata cannot directly identify this behavior with a single rule, for experimental purposes, it is feasible to\r\ncreate one rule to detect the client-to-server exchange and another to identify the server’s response. As they\r\noperate independently, each of these rules can potentially generate false positives. The “TCP” class type is used to\r\nsimplify filtering.\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 16 of 23\n\nalert tcp any any -\u003e any any (msg:\"Ploader-cli-random_bytes\"; flow:to_server, established; dsize:24; flags:AP;\r\nalert tcp any any -\u003e any any (msg:\"Ploader-srv-random_bytes\"; flow:to_client, established; dsize:8; flags:AP; cl\r\nSince Suricata alerts are integrated into Sekoia XDR, these two alerts can be refined and correlated using a Sigma\r\nCorrelation rule. This is achieved using a temporal correlation rule, which is triggered if the two Suricata\r\nsignatures are generated for the same victim-C2 pair within a 1-minute interval. \r\nAs Suricata signatures detect a client-to-server flow followed by a server-to-client flow, the source and destination\r\naddress IPs are reversed. To address this, aliases are used to reorder them appropriately.\r\nname: ploaderseq1\r\ndetection:\r\nselection:\r\naction.properties.signature: 'Ploader-cli-random_bytes'\r\ncondition: selection\r\n---\r\nname: ploaderseq2\r\ndetection:\r\nselection:\r\naction.properties.signature: 'Ploader-srv-random_bytes'\r\ncondition: selection\r\n---\r\naction: correlation\r\ntype: temporal\r\nrule:\r\n- ploaderseq1\r\n- ploaderseq2\r\naliases:\r\nc2:\r\nploaderseq1:\r\n- destination.ip\r\nploaderseq2:\r\n- source.ip\r\nvictim:\r\nploaderseq1:\r\n- source.ip\r\nploaderseq2:\r\n- destination.ip\r\ngroup-by:\r\n- c2\r\n- victim\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 17 of 23\n\ntimespan: 1m\r\nordered: true\r\nI2PRAT detection\r\nInstalling and executing IP2RAT presents several detection opportunities. The malware is known to drop multiple\r\nDLLs essential for its operation, including noteworthy examples like libi2p and cncclient. Detection can be\r\nenhanced by employing a correlation rule to identify the presence of these dropped DLLs, which serves as a\r\nreliable indicator of malware installation.\r\nname: dll_drop\r\ndetection:\r\nselection:\r\nfile.name:\r\n- 'cnccli.dll'\r\n- 'dwlmgr.dll'\r\n- 'evtsrv.dll'\r\n- 'prgmgr.dll'\r\n- 'rdpctl.dll'\r\n- 'samctl.dll'\r\n- 'termsrv32.dll'\r\n- 'libi2p.dll'\r\n- 'rfxvmt.dll'\r\nfile.path|contains:\r\n- 'temp'\r\n- 'users'\r\n- 'appadata'\r\nprocess.executable|contains:\r\n- 'temp'\r\n- 'users'\r\n- 'appadata'\r\ncondition: selection\r\n---\r\naction: correlation\r\ntype: value_count\r\nrule: dll_drop\r\ngroup-by:\r\n- process.executable\r\n- host.name\r\ntimespan: 2m\r\nfield: file.name\r\ncondition:\r\ngte: 8\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 18 of 23\n\nChange RDP settings\r\nIn certain instances, the malware has been observed altering the RDP configuration on the compromised system.\r\nKey parameters are adjusted, such as enabling a single user to open multiple simultaneous sessions on a Terminal\r\nServer or changing the DLL utilised by the Terminal Services service. The following Sigma rule can help identify\r\nthese types of modifications.\r\ndetection:\r\nselection_reg:\r\n- registry.key|endswith:\r\n- '\\services\\TermService\\Parameters\\ServiceDll'\r\n- '\\Control\\Terminal Server\\fSingleSessionPerUser'\r\n- '\\Control\\Terminal Server\\fDenyTSConnections'\r\n- '\\Policies\\Microsoft\\Windows NT\\Terminal Services\\Shadow'\r\n- '\\Control\\Terminal Server\\WinStations\\RDP-Tcp\\InitialProgram'\r\n- '\\Control\\Terminal Server\\WinStations\\RDP-Tcp\\UserAuthentication'\r\n- registry.path|endswith:\r\n- '\\services\\TermService\\Parameters\\ServiceDll'\r\n- '\\Control\\Terminal Server\\fSingleSessionPerUser'\r\n- '\\Control\\Terminal Server\\fDenyTSConnections'\r\n- '\\Policies\\Microsoft\\Windows NT\\Terminal Services\\Shadow'\r\n- '\\Control\\Terminal Server\\WinStations\\RDP-Tcp\\InitialProgram'\r\n- '\\Control\\Terminal Server\\WinStations\\RDP-Tcp\\UserAuthentication'\r\ncondition: selection_reg\r\nRogue service creation\r\nAs outlined in the reverse engineering section, the malware achieves persistence by creating an autostart service\r\nnamed RDP-controller. It accomplishes this using the sc.exe utility. The associated command line is particularly\r\nnoteworthy. More broadly, the Sigma rule provided below can help detect this type of behavior.\r\ndetection:\r\nselection:\r\n- process.name: sc.exe\r\nprocess.command_line|contains|all:\r\n- create\r\n- binpath\r\n- action.properties.ScriptBlockText|contains|all:\r\n- New-Service\r\n- BinaryPathName\r\ncondition: selection\r\nDetection overview in sandbox\r\nThe loader and the installer stages can be identified using various Sigma rules.\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 19 of 23\n\nDuring its installation, it runs a PowerShell script to exempt itself from Defender scans.\r\nIt establishes persistence by creating an autostart service.\r\nIt communicates with multiple IPs, including notable interactions with I2P nodes.\r\nDefault RDP configuration modification, the default port is changed for the port 54227, it removed the\r\nrestriction of one session per user (c.f.: HKLM\\\\System\\\\CurrentControlSet\\\\Control\\\\Terminal\r\nServer\\\\fSingleSessionPerUser) \r\nConclusion\r\nThe analysis of the infection indicates that I2PRAT is an emerging threat, with activity observed from its\r\ndiscovery in late October 2024 to January 2025. The malware is an advanced threat composed of multiple layers,\r\neach incorporating sophisticated mechanisms. The use of an anonymisation network complicates tracking and\r\nhinders the identification of the threat’s magnitude and spread in the wild.\r\nOur analysis based on various sandbox executions indicates with high confidence that the threat actor(s) behind\r\nI2PRAT act quickly following a successful device infection.\r\nI2PRAT’s starting with the initial infection vector and progressing through a series of modules that execute\r\nspecific tasks. TDR analysts have noted its ability to communicate over encrypted channels using the I2P network,\r\nwhich adds a layer of complexity to its operation. Analyzing the command and control (C2) communications and\r\nthe network traffic patterns can provide insights into its behavior and objectives. By focusing on these technical\r\naspects, analysts  can better understand how the malware operates and develop appropriate defenses.\r\nTo provide our customers with actionable intelligence, Sekoia will continue to actively monitor the threat actor’s\r\ninfrastructure and payloads across each layer, from delivery techniques to the loader and the final payload\r\nexecuted on the machine.\r\nAnnexes \r\nAnnexe 1 – IDA script to get the hashes\r\nimport idc\r\nimport idautils\r\nresolve_func_addr = 0x00014000BE08 # to adapt to your context\r\nhashes = []\r\nfor ref in idautils.XrefsTo(resolve_func_addr):\r\nfor ea in idautils.Heads(ref.frm - 10, ref.frm):\r\ninsn = idaapi.insn_t()\r\nlength = idaapi.decode_insn(insn, ea)\r\nmnemonic = print_insn_mnem(ea)\r\nif mnemonic == \"mov\":\r\noperand_1 = print_operand(ea, 0)\r\nfn_hash = idc.get_operand_value(ea, 1)\r\nif operand_1 == \"edx\":\r\nprint(f\"0x{ea:\u003c10x} | {mnemonic} {operand_1} 0x{fn_hash:x}\")\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 20 of 23\n\nhashes.append(fn_hash)\r\nfor h in hashes:\r\nprint(f\"0x{h:x}\", end=\", \")\r\nAnnexe 2 - Python script to emulate hash resolution\r\nfrom dumpulator import Dumpulator, modules\r\nADDR_CRYPT_FUNC = 0x14000BE08 # to replace according to the sample\r\ndef get_dlls(dumpulator: Dumpulator) -\u003e list:\r\ndlls: list = []\r\nfor mem in dp.memory.map():\r\nif mem.info:\r\nif type(mem.info[0]) == modules.Module:\r\nprint(f\"Add {mem.info[0].name} to the loaded DLLs\")\r\ndlls.append(mem.info[0])\r\nreturn dlls\r\ndef resolve_address(dll, addr: int) -\u003e str | None:\r\nfor export in dll.exports:\r\nif export.address == addr and addr:\r\nreturn export.name\r\ndef emulate_hash(dp: Dumpulator, dlls, myhash: int) -\u003e str:\r\nfunction_name = \"\"\r\nfor dll in dlls:\r\ndp.call(ADDR_CRYPT_FUNC, [dll.base, myhash, 0])\r\naddr = dp.regs.rax\r\nfunction_name = resolve_address(dll, addr)\r\nif function_name:\r\nbreak\r\nfunction_name = \"\" if function_name is None else function_name\r\nif function_name == \"\":\r\nprint(f\"! hash 0x{myhash:\u003c8x} unknown rax: 0x{addr:x}\")\r\nreturn function_name, dll.name\r\ndump_path = 'stage2_all_dlls.dmp'\r\ndp = Dumpulator(dump_path, quiet=True)\r\ndlls = get_dlls(dp)\r\nMITRE ATT\u0026CK TTPs\r\nTactic Technique\r\nCommand and\r\nControl\r\nT1573.001 - Encrypted Channel: Symmetric Cryptography\r\nCommand and\r\nControl\r\nT1104 - Multi-Stage Channels\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 21 of 23\n\nCommand and\r\nControl\r\nT1095 - Non-Application Layer Protocol\r\nCommand and\r\nControl\r\nT1571 - Non-Standard Port\r\nCommand and\r\nControl\r\nT1090.003 - Proxy: Multi-hop Proxy\r\nExiltration\r\nT1048.001 - Exfiltration Over Symmetric Encrypted Non-C2\r\nProtocol\r\nDefense Evasion T1547 - Abuse Elevation Control Mechanism\r\nDefense Evasion T1622 - Debugger Evasion\r\nDefense Evasion T1140 - Deobfuscate/Decode Files or Information\r\nDefense Evasion T1562.001 - Disable or Modify Tools\r\nDefense Evasion T1036 - Masquerading\r\nDefense Evasion T1055.003 - Process Injection: Thread Execution Hijacking\r\nDefense Evasion T1055.012 - Process Injection: Process Hollowing\r\nDefense Evasion T1027.002 - Software Packing\r\nDefense Evasion T1027.007 - Dynamic API Resolution\r\nDefense Evasion T1027.013 - Encrypted/Encoded File\r\nPersistence T1543.003 - Create or Modify System Process: Windows Service\r\nExecution T1059.001 - Command and Scripting Interpreter: PowerShell\r\n1. https://blog.sekoia.io/clickfix-tactic-the-phantom-meet/ ↩︎\r\n2. https://blog.sekoia.io/clickfix-tactic-revenge-of-detection/ ↩︎\r\n3. https://learn.microsoft.com/en-us/windows/win32/secauthz/access-tokens ↩︎\r\n4. https://googleprojectzero.blogspot.com/2019/12/calling-local-windows-rpc-servers-from.html ↩︎\r\n5. build: 19044.3570 and 19045.3570 ↩︎\r\n6. https://ntdoc.m417z.com/system_process_information ↩︎\r\n7. https://github.com/mrexodia/dumpulator ↩︎\r\n8. https://gist.github.com/lbpierre/318898548d9825d1a3610ee08c841916 ↩︎\r\n9. https://github.com/diversenok/Suspending-Techniques?tab=readme-ov-file#suspend-via-a-debug-object ↩︎\r\n10. https://en.wikipedia.org/wiki/Mersenne_Twister ↩︎\r\n11. https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/hh127464(v=vs.85) ↩︎\r\n12. https://www.gdatasoftware.com/blog/2024/12/38093-I2PRAT-malware ↩︎\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 22 of 23\n\n13. https://geti2p.net/en/: “The Invisible Internet Project is an anonymous network layer that allows for\r\ncensorship-resistant, peer-to-peer communication. Anonymous connections are achieved by encrypting the\r\nuser's traffic, and sending it through a volunteer-run network of roughly 55,000 computers distributed\r\naround the world. “ ↩︎\r\nShare\r\nCybercrime Malware Reverse\r\nShare this post:\r\nSource: https://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nhttps://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/\r\nPage 23 of 23\n\nfn_hash if operand_1 = idc.get_operand_value(ea, == \"edx\": 1) \nprint(f\"0x{ea:\u003c10x} | {mnemonic} {operand_1} 0x{fn_hash:x}\")\n  Page 20 of 23",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://blog.sekoia.io/ratatouille-cooking-up-chaos-in-the-i2p-kitchen/"
	],
	"report_names": [
		"ratatouille-cooking-up-chaos-in-the-i2p-kitchen"
	],
	"threat_actors": [],
	"ts_created_at": 1775434566,
	"ts_updated_at": 1775826734,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/28c01d7f3d435aa4890f0a0413a6593d70046b3e.pdf",
		"text": "https://archive.orkl.eu/28c01d7f3d435aa4890f0a0413a6593d70046b3e.txt",
		"img": "https://archive.orkl.eu/28c01d7f3d435aa4890f0a0413a6593d70046b3e.jpg"
	}
}