the payload
I attempted this payload next due to its having the docker container and more solve than the other hard challenge. Gotta admit...it is a more manageable challenge compare to the last 2.

Difficulty: Hard
Narrative:
With the malware extracted, Holmes inspects its logic. The strain spreads silently across the entire network. Its goal? Not destruction-but something more persistent…friends.
NOTE: The downloaded file is active malware. Take the necessary precautions when attempting this challenge.
Now we get into more serious challenge!!!
tldr;
1
During execution, the malware initializes the COM library on its main thread. Based on the imported functions, which DLL is responsible for providing this functionality? (filename.ext)
ole32.dll
Listed in import table; exports CoInitialize / CoCreateInstance used by any.run
2
Which GUID is used by the binary to instantiate the object containing the data and code for execution?
DABCD999-1234-4567-89AB-1234567890FF
Extracted from .rdata structure passed to CoCreateInstance; decompilers (IDA/Binja) show rclsid.
3
Which .NET framework feature is the attacker using to bridge calls between a managed .NET class and an unmanaged native binary? (string)
COM interop
Observed native binary using COM + managed-style dispatched methods via vtable offsets.
4
Which Opcode in the disassembly is responsible for calling the first function from the managed code? (** ** **)
FF 50 68
Indirect call through COM vtable: call qword ptr [rax+68h] in disassembly.
5
Identify the multiplication and addition constants used by the binary’s key generation algorithm for decryption. (*, **h)
7, 42h
Loop sets key bytes: byte[i] = i * 7 + 0x42; seen in decompiled function.
6
Which Opcode in the disassembly is responsible for calling the decryption logic from the managed code? (** ** **)
FF 50 58
Vtable call at call qword ptr [rax+58h] corresponding to method invoking decryption routine.
7
Which Win32 API is being utilized by the binary to resolve the killswitch domain name? (string)
getaddrinfo
Present in WS2_32 import list; used for DNS resolution of target domain.
8
Which network-related API does the binary use to gather details about each shared resource on a server? (string)
NetShareEnum
Imported from NETAPI32; classic enumeration of remote shares for lateral movement.
9
Which Opcode is responsible for running the encrypted payload? (** ** **)
FF 50 60
Indirect call call qword ptr [rax+60h] after payload prep in ScanAndSpread logic.
10
Find → Block → Flag: Identify the killswitch domain, spawn the Docker to block it, and claim the flag. (HTB{_})
HTB{Eternal_Companions_Reunited_Again}
Derived key (i*7+0x42), XOR with Base64-decoded blob “KXgmYHMADxsV8uHiuPPB3w==” → k1v7-echosim.net; blocking domain in challenge environment reveals flag.
what we have?
AetherDesk-v74-77.exe
AetherDesk-v74-77.pdb
well, since it is a .exe file my first instinct is to run it oh hold on.
# DANGER.txt
Dear Player,
This text file is to warn you that the downloaded artifacts for this challenge should be considered to be real malware. This software has been intentionally included for educational purposes and is NOT intended to be executed or used otherwise. Always handle such files in isolated, controlled, and secure environments.
It is strongly recommend that you proceed by:
1 - Running the sample in a controlled environment, for example EP Pwnbox or an isolated virtual machine.
2 - Only analyse the software in this controlled environment,and enjoy analysing!
PLEASE EXERCISE EXTREME CAUTION!
By reading this file and using the provided password to unzip the file, you acknowledge and fully understand the risks as detailed in this warning.Well, there goes my plans. I guess I have to run it in an isolated environment.
This process is dynamic analysis, of course, when talking about dynamic analysis, there are plenty of tools you can use to cheese out the necessary information for investigation. This is my togo tool (for now) https://any.run/.
You can achieve super quick analysis if you are familiar with window overall.


next, you can also put the file into a decompiler to see anything obvious (i just yeet them into dogbolt, 5s no brainer, and I regret shortly after)

solulu
flag 1
During execution, the malware initializes the COM library on its main thread. Based on the imported functions, which DLL is responsible for providing this functionality? (filename.ext)
Google is your best friend, I did a search and some reading to identify the possible dll for COM library. The answer only further confirmed when I have the exact name appear after any.run dynamic analysis. As you can see in the screenshot below. Of course, you can also do this via an IDA or Ghidra. Which just make me feels dumb because I was being lazy and not using it right away.
The answer is ole32.dll


flag: ole32.dll
flag 2
Which GUID is used by the binary to instantiate the object containing the data and code for execution? (********---**-**********)
This is reference from flag 1, which is the COM (Component Object Model) still. In COM every creatable class has a unique Class ID (CLSID), which is just a GUID. When code calls CoCreateInstance, it passes:
CLSID (which class to create)
Optional outer object (usually null)
Context flags (in-proc / local / remote)
Interface ID (IID) of the interface it wants back (often
IID_IUnknownor something specific)Output pointer to receive the new object
So if we find the CoCreateInstance call, we can see which CLSID (GUID) the malware is trying to instantiate.
From dogbolt decompiler I quickly grab these:
# the call
LODWORD(v3) = CoCreateInstance(&rclsid, 0, 0x17u, &riid, &ppv);
# and the data
const IID rclsid = { 3669809561u, 4660u, 17767u,
{ 137u, 171u, 18u, 52u, 86u, 120u, 144u, 255u } };
# This is a C struct of type _GUID / IID:
typedef struct _GUID {
unsigned long Data1; // 32 bits
unsigned short Data2; // 16 bits
unsigned short Data3; // 16 bits
unsigned char Data4[8]; // 8 bytes (big-end formatting when printed)
} GUID;So we have to do some mapping here (manually by hand
my bad, I regretted guys), we know he textual GUID format is:
Data1-Data2-Data3-Data4[0]Data4[1]-Data4[2]Data4[3]Data4[4]Data4[5]Data4[6]Data4[7]Lets convert:
Data1: 3669809561 decimal → 0xDABCD999
Data2: 4660 decimal → 0x1234
Data3: 17767 decimal → 0x4567
Data4 array (already byte values): 137, 171, 18, 52, 86, 120, 144, 255 → hex: 89 AB 12 34 56 78 90 FF
And our flag finally is dabcd999-1234-4567-89ab-1234567890ff
And later when I spin up my binary ninja, the decompiler just do it for you.


flag: dabcd999-1234-4567-89ab-1234567890ff
flag 3
Which .NET framework feature is the attacker using to bridge calls between a managed .NET class and an unmanaged native binary?
So to rephrase the question in googoo gaga term (aka, my language) it wants the name of the .NET feature that lets unmanaged native code and managed .NET code call each other. (Answer: COM interop — the COM interface mechanism, via CoCreateInstance, letting native code spin up and use a managed class.) I did read the official writeup for this one and it seems like my guess could have been a lucky guess, because that is a lot of conditions needed to prove that it is COM interop.

flag: COM interop
flag 4
Which Opcode in the disassembly is responsible for calling the first function from the managed code?
(** ** **)

Okay, this is when my assembly class kicked in, right in main, and after COM object instantiation our code ultimately landed here.

mov rax, qword [rcx]→ load the interface’s vtable pointer fromthis(in Win-x64,thisis inRCX).mov rdx, [rsp+0x68]→ set up the 2nd argument (&var_210).The call itself:
call qword [rax+0x68]
This translate to: rax points at the COM vtable (array of function pointers). Offset 0x68 (i.e., slot 0x68 / 8 = 13) is the interface method that the native stub calls. Because this COM class is implemented in .NET, that function pointer is a CLR/interop thunk that transitions into managed code. That’s why this is the “first function from the managed code.”
What you see in the decompiler matches the above:
(*(rcx_2 + 0x68))(rcx_2, &var_210);Bytes shown as
call qword ptr [rax+68h], hence hex isff 50 68
That is the yapping explanation that I can come up with, but during the competition I just simply...oh look at this...the op code

flag: ff 50 68
flag 5
Identify the multiplication and addition constants used by the binary's key generation algorithm for decryption.
Have to find the key generation algorithm in the the binary first. What could be the constants that generate the key which later gets Base64-encoded and passed into the decryption routine. hmmmm. Oh you look at that...

multiplier = 7
adder = 0x42 (ASCII
'B')
flag: 7, 42h
The formula (explicitly)
key[i] = ( i * 7 + 0x42 ) & 0xFFThis will be useful for the latter flags.
flag 6
Which Opcode in the disassembly is responsible for calling the decryption logic from the managed code?
Okay, now we need to find the calling of "decryption" logic,


You know the drill
flag: FF 50 58
Also at this point, i have a full picture of this .exe file and how the attack went down
Stage 1 (bootstrap): Native stub initializes COM and jumps into a managed COM server via vtable call (
call qword ptr [rax+0x68]).Stage 2 (keygen): Generates a XOR key with
key[i]=i×7+0x42, Base64-encodes it.Stage 3 (decrypt): Calls COM method at vtable+0x58 with the encoded key and a fixed ciphertext to recover a hostname.
Stage 4 (kill switch): If that hostname resolves, the program exits; otherwise it continues.
Stage 5 (worming): Attempts SMB propagation across
192.168.1.0, callingScanAndSpread()for each host.Stage 6 (cleanup): Releases resources and exits.
flag 7
Which Win32 API is being utilized by the binary to resolve the killswitch domain name?
In main (after the COM decrypt returns the plaintext hostname in pNodeName_1) the code does:
WSAStartup(0x202, &wsa)→ initialize Winsock.memset(&hints, 0, 0x30); hints.ai_flags = 1;(basic hints struct).rax_36 = getaddrinfo(pNodeName, NULL, &hints, &pAddrInfo);If
pAddrInfo != 0→freeaddrinfo(pAddrInfo), thenWSACleanup().
Logic (kill-switch)
If either
WSAStartupfails orgetaddrinfofails (non-zero), it prints “[No Kill Switch Detected] Continuing Execution…” and keeps going.If both succeed, it prints “[Kill Switch Triggered] Exiting…” and stops.
That proves the API used to resolve the decrypted hostname is
getaddrinfo

flag: getaddrinfo
flag 8
Which network-related API does the binary use to gather details about each shared resource on a server?

This is NetAPI32 share enumeration used for SMB propagation/recon.
flag: NetShareEnum
flag 9
Which Opcode is responsible for running the encrypted payload?

mov rax, [rbx] ; load vtable pointer from the COM object in rbx
call qword [rax+0x58] ; indirect call through vtable slot at +0x58
struct DNS::ProgramVTable {
char _pad[0x38]; // IUnknown/IDispatch slots etc.
HRESULT (*get_ToString)(...); // at vtable+0x38
HRESULT (*Equals)(...); // +0x40
HRESULT (*GetHashCode)(...); // +0x48
HRESULT (*GetType)(...); // +0x50
HRESULT (*SendEncryptedFlag)(...); //
HRESULT (*Execute)(...); // +0x60 ← flag 9
HRESULT (*Dummy)(...); // +0x68
};You know the drill...
flag: FF 50 60
flag 10
Find → Block → Flag: Identify the killswitch domain, spawn the Docker to block it, and claim the flag. (HTB {___})
Thank you for reading this far you probably know how the entire incident unfolded, this is simply the reverse implementation of the encryption to retrieve the network we have to block.
import base64
data = base64.b64decode("KXgmYHMADxsV8uHiuPPB3w==")
key = bytearray()
for i in range(32):
key.append((i * 7 + 0x42) & 0xFF)
print(bytes([x ^ y for x, y in zip(key, data)]))
# b'k1v7-echosim.net'k1v7-echosim.net
And with that...we got into some cutscene...I'm not gonna comment about them (skip cutscenes button pressed)


flag: HTB{Eternal_Companions_Reunited_Again}
Last updated